This repository has been archived by the owner on Nov 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3e9f814
Showing
37 changed files
with
2,422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.idea | ||
.DS_Store | ||
node_modules | ||
dist | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { html } from 'lit-html'; | ||
import { component, useEffect, useRef } from 'haunted'; | ||
import { syringeServiceRoot } from "../helpers/page-state.js"; | ||
import useFetch from '../helpers/use-fetch.js' | ||
|
||
function Advisor({host}) { | ||
const syringeServicePrefix = host ? host+'/syringe' : syringeServiceRoot; | ||
const awesompleteRef = useRef(null); | ||
const allLessonRequest = useFetch(`${syringeServicePrefix}/exp/lesson`); | ||
const lessonOptions = allLessonRequest.succeeded | ||
? allLessonRequest.data.lessons.map((l) => ({ | ||
label: l.LessonName, | ||
value: l.LessonId | ||
})) | ||
: []; | ||
|
||
if (lessonOptions.length > 0) { | ||
useEffect(() => { | ||
const input = this.shadowRoot.querySelector('input'); | ||
awesompleteRef.current = new Awesomplete(input, { | ||
list: lessonOptions, | ||
minChars: 0 | ||
}); | ||
}, []); | ||
} | ||
|
||
function select(ev) { | ||
const lessonId = ev.text.value; | ||
location.href = `${host || ''}/advisor/courseplan.html?lessonId=${lessonId}`; | ||
} | ||
|
||
return html` | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nlundquist/nre-styles@latest/dist/styles.css" /> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.css" rel="stylesheet "/> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.base.css" rel="stylesheet" /> | ||
<style> | ||
.awesomplete > ul:before, | ||
.input-wrapper .awesomplete:before{ | ||
display: none; | ||
} | ||
</style> | ||
<div class="advisor canister secondary"> | ||
<h1> | ||
<span>NRE Labs Advisor</span> | ||
<span class="subtitle">Get a customized lesson path</span> | ||
</h1> | ||
<div class="input-wrapper"> | ||
<input type="text" placeholder="I want to learn..." | ||
@awesomplete-select=${select} | ||
class="awesomeplete" /> | ||
</div> | ||
<button class="btn secondary">Search Lesson Content</button> | ||
<aside class="small"> | ||
Use the box above to say what you want to learn, and we’ll work with you | ||
to build a relevant learning path. Try “Python” or “StackStorm”! | ||
</aside> | ||
</div> | ||
`; | ||
} | ||
|
||
Advisor.observedAttributes = ['host']; | ||
|
||
customElements.define('antidote-advisor', component(Advisor)); | ||
|
||
export default Advisor; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import '../contexts.js'; // make sure all contexts are defined | ||
import { html } from 'lit-html'; | ||
import { component, useState } from 'haunted'; | ||
import { syringeServiceRoot } from "../helpers/page-state.js"; | ||
import useFetch from '../helpers/use-fetch.js' | ||
|
||
customElements.define('antidote-catalog-context', component(() => { | ||
const allLessonRequest = useFetch(`${syringeServiceRoot}/exp/lesson`); | ||
const [filteringState, setFilteringState] = useState({ | ||
searchString: null, | ||
Category: null, | ||
Duration: null, | ||
Difficulty: null, | ||
Tags: [] | ||
}); | ||
|
||
return html` | ||
<style> | ||
:host, | ||
antidote-all-lesson-context-provider, | ||
antidote-lesson-filtering-context-provider { | ||
display: block; | ||
height: 100%; | ||
width: 100%; | ||
} | ||
</style> | ||
<antidote-all-lesson-context-provider .value=${allLessonRequest}> | ||
<antidote-lesson-filtering-context-provider .value=${[filteringState, setFilteringState]}> | ||
<slot></slot> | ||
</antidote-lesson-filtering-context-provider> | ||
</antidote-all-lesson-context-provider> | ||
` | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { html } from 'lit-html'; | ||
import { component, useContext } from 'haunted'; | ||
import { AllLessonContext, LessonFilteringContext } from "../contexts.js"; | ||
import debounce from "../helpers/debounce.js"; | ||
|
||
function getOptionSetsFromLessons(lessons) { | ||
const categories = new Set(); | ||
const tags = new Set(); | ||
lessons.forEach((l) => { | ||
categories.add(l.Category); | ||
(l.Tags || []).forEach((t) => tags.add(t)); | ||
}); | ||
return [Array.from(categories), Array.from(tags)]; | ||
} | ||
|
||
function CatalogFilters() { | ||
const allLessonRequest = useContext(AllLessonContext); | ||
const [filterState, setFilterState] = useContext(LessonFilteringContext); | ||
const [categories, tags] = allLessonRequest.succeeded | ||
? getOptionSetsFromLessons(allLessonRequest.data.lessons) | ||
: [[], []]; | ||
|
||
function setFilter(filterName) { | ||
return debounce(function() { | ||
const value = filterName === 'Tags' | ||
? filterState.Tags = this.value.split(',').map((t) => t.trim()).filter((s) => s.length > 0) | ||
: this.value || null; | ||
|
||
filterState[filterName] = value; | ||
setFilterState(filterState); | ||
}, 200); | ||
} | ||
|
||
return html` | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nlundquist/nre-styles@latest/dist/styles.css" /> | ||
<style> | ||
:host { | ||
display: flex; | ||
} | ||
:host > label { | ||
flex-grow: 1; | ||
} | ||
:host > label:not(:first-of-type) { | ||
margin-left: 30px; | ||
} | ||
</style> | ||
<label> | ||
<span>Category</span> | ||
<div> | ||
<antidote-select | ||
placeholder="Label" | ||
.options=${categories} | ||
.change=${setFilter('Category')} /> | ||
</div> | ||
</label> | ||
<label> | ||
<span>Tags</span> | ||
<div> | ||
<antidote-select | ||
placeholder="Label, Label" | ||
multi="true" | ||
.options=${tags} | ||
.change=${setFilter('Tags')} /> | ||
</div> | ||
</label> | ||
`; | ||
} | ||
|
||
customElements.define('antidote-catalog-filters', component(CatalogFilters)); | ||
|
||
export default CatalogFilters; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { html } from 'lit-html'; | ||
import { component, useContext } from 'haunted'; | ||
import { LessonFilteringContext } from "../contexts.js"; | ||
import debounce from "../helpers/debounce.js"; | ||
|
||
function CatalogSearch() { | ||
const [filterState, setFilterState] = useContext(LessonFilteringContext); | ||
|
||
const change = debounce(function change() { | ||
filterState.searchString = this.value.length > 0 ? this.value.toLowerCase() : null; | ||
setFilterState(filterState); | ||
}, 200); | ||
|
||
return html` | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nlundquist/nre-styles@latest/dist/styles.css" /> | ||
<style> | ||
:host { | ||
display: block; | ||
} | ||
</style> | ||
<label> | ||
<span>Search</span> | ||
<input type="text" placeholder="Lesson Title" | ||
@keyup=${change} @change=${change} /> | ||
</label> | ||
`; | ||
} | ||
|
||
customElements.define('antidote-catalog-search', component(CatalogSearch)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { html } from 'lit-html'; | ||
import { component, useContext} from 'haunted'; | ||
import { AllLessonContext, LessonFilteringContext } from "../contexts.js"; | ||
|
||
function doFiltering(lessons, filteringState) { | ||
const filterEntries = Object.entries(filteringState); | ||
|
||
return lessons.filter((lesson) => { | ||
return filterEntries.reduce((acc, [filterProp, filterValue]) => { | ||
if (filterValue !== null) { | ||
if (filterProp === 'Tags') { | ||
return acc && filterValue.every((tag) => (lesson.Tags || []).includes(tag)); | ||
} else if (filterProp === 'searchString') { | ||
return acc && lesson.LessonName.toLowerCase().indexOf(filterValue) > -1; | ||
} else { | ||
return acc && lesson[filterProp] === filterValue; | ||
} | ||
} else { | ||
return acc; | ||
} | ||
}, true); | ||
}); | ||
} | ||
|
||
function CatalogTable() { | ||
const allLessonRequest = useContext(AllLessonContext); | ||
const [filteringState] = useContext(LessonFilteringContext); | ||
const lessons = allLessonRequest.succeeded | ||
? doFiltering(allLessonRequest.data.lessons, filteringState) | ||
: []; | ||
|
||
return html` | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nlundquist/nre-styles@latest/dist/styles.css" /> | ||
<style> | ||
/*todo: move to nre theme?*/ | ||
/*todo: remove row hover ughhhhh */ | ||
.tag { | ||
display: inline-flex; | ||
align-items: center; | ||
padding: 2px 5px; | ||
word-spacing: normal; | ||
border: 2px solid #0096c3; | ||
color: #0096c3; | ||
background-color: white; | ||
margin-top: 10px; | ||
} | ||
.tags { | ||
word-spacing: 10px; | ||
padding: 0 10px 10px 8px; | ||
} | ||
</style> | ||
<table class="catalog"> | ||
<thead> | ||
<tr> | ||
<th>Lesson</th> | ||
<th>Description</th> | ||
<th>Tags</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
${lessons.map((lesson) => html` | ||
<tr> | ||
<td class="title"> | ||
<a href="/labs/?lessonId=${lesson.LessonId}&lessonStage=1"> | ||
${lesson.LessonName} | ||
</a> | ||
</td> | ||
<td>${lesson.Description}</td> | ||
<td class="tags"> | ||
${(lesson.Tags || []).map((tag) => html` | ||
<span class="tag">${tag}</span> | ||
`)} | ||
</td> | ||
</tr> | ||
`)} | ||
</tbody> | ||
</table> | ||
`; | ||
} | ||
|
||
customElements.define('antidote-catalog-table', component(CatalogTable)); | ||
|
||
export default CatalogTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import '../contexts.js'; // make sure all contexts are defined | ||
import { html } from 'lit-html'; | ||
import { component, useState } from 'haunted'; | ||
import { syringeServiceRoot, collectionId } from "../helpers/page-state.js"; | ||
import useFetch from '../helpers/use-fetch.js' | ||
|
||
function CollectionDetails() { | ||
const request = useFetch(`${syringeServiceRoot}/exp/collection/${collectionId}`); | ||
|
||
return html` | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nlundquist/nre-styles@latest/dist/styles.css" /> | ||
<style> | ||
h1 { | ||
text-align: center; | ||
} | ||
</style> | ||
${request.succeeded ? html` | ||
<h1>${request.data.Title}</h1> | ||
<img src="${request.data.Image}" /> | ||
<p>${request.data.LongDescription}</p> | ||
<table> | ||
<tr><td>Type</td><td>${request.data.Type}</td></tr> | ||
<tr> | ||
<td>Website</td> | ||
<td> | ||
<a href="${request.data.Website}">${request.data.Website}</a> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Email</td> | ||
<td> | ||
<a href="mailto:${request.data.ContactEmail}">${request.data.ContactEmail}</a> | ||
</td> | ||
</tr> | ||
</table> | ||
<div class="canister medium-gray"> | ||
${request.data.Lessons ? html` | ||
<h3>Lessons</h3> | ||
${request.data.Lessons.map((lesson, i) => html` | ||
<div> | ||
<a href="/labs/?lessonId=${lesson.lessonId}&lessonStage=1"> | ||
${lesson.lessonName} | ||
</a> | ||
<p> | ||
${lesson.lessonDescription} | ||
</p> | ||
</div> | ||
${request.data.Lessons.length !== i + 1 ? html`<hr/>` : ''} | ||
`)} | ||
` : html ` | ||
<h3>Coming Soon!</h3> | ||
`} | ||
</div> | ||
` : ''} | ||
` | ||
} | ||
|
||
customElements.define('antidote-collection-details', component(CollectionDetails)); | ||
|
||
export default CollectionDetails; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import '../contexts.js'; // make sure all contexts are defined | ||
import { html } from 'lit-html'; | ||
import { component, useState } from 'haunted'; | ||
import { syringeServiceRoot } from "../helpers/page-state.js"; | ||
import useFetch from '../helpers/use-fetch.js' | ||
|
||
customElements.define('antidote-collections-context', component(() => { | ||
const allCollectionRequest = useFetch(`${syringeServiceRoot}/exp/collection`); | ||
const [filteringState, setFilteringState] = useState({ | ||
searchString: null, | ||
Type: null, | ||
}); | ||
|
||
return html` | ||
<style> | ||
:host, | ||
antidote-all-collection-context-provider, | ||
antidote-collection-filtering-context-provider { | ||
display: block; | ||
height: 100%; | ||
width: 100%; | ||
} | ||
</style> | ||
<antidote-all-collection-context-provider .value=${allCollectionRequest}> | ||
<antidote-collection-filtering-context-provider .value=${[filteringState, setFilteringState]}> | ||
<slot></slot> | ||
</antidote-collection-filtering-context-provider> | ||
</antidote-all-collection-context-provider> | ||
` | ||
})); |
Oops, something went wrong.