Parsing questionnaire from yml

This commit is contained in:
rotimi_best
2021-05-22 22:25:33 +03:00
parent ab92f59c85
commit c1b6ec4eee
14 changed files with 708 additions and 6163 deletions
+430 -5887
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@tailwindcss/forms": "^0.3.2", "@tailwindcss/forms": "^0.3.2",
"compression": "^1.7.1", "compression": "^1.7.1",
"js-yaml": "^4.1.0",
"marked": "^1.2.7", "marked": "^1.2.7",
"node-sass": "^6.0.0", "node-sass": "^6.0.0",
"polka": "next", "polka": "next",
+12
View File
@@ -0,0 +1,12 @@
<script>
let expanded = false;
</script>
<style>
.root {
border-right: 1px solid var(--border-color);
border-left: 1px solid var(--border-color);
}
</style>
<div class="root" />
@@ -13,35 +13,42 @@
const lectures = [ const lectures = [
{ {
title: "Lecture 1", title: "Вводный урок. Soft skills",
link: "/courses/1/lecture/1", link: "/courses/1/lecture/1",
}, },
{ {
title: "Lecture 2", title: "Введение в ReactJS",
link: "/courses/1/lecture/2", link: "/courses/1/lecture/2",
}, },
{ {
title: "Lecture 3", title: "Компоненты",
link: "/courses/1/lecture/3", link: "/courses/1/lecture/3",
}, },
{ {
title: "Lecture 4", title: "Состояние компонентов и пропсы",
link: "/courses/1/lecture/4", link: "/courses/1/lecture/4",
}, },
{ {
title: "Lecture 5", title: "Жизненный цикл",
link: "/courses/1/lecture/5", link: "/courses/1/lecture/5",
}, },
]; ];
function getLectureNo(index) {
if (index < 9) {
return `00${index}`;
}
return `0${index}`;
}
</script> </script>
<style> <style lang="scss">
.root { .root {
height: 90vh; height: 90vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 20%; width: 360px;
max-width: 250px;
position: sticky; position: sticky;
top: 0; top: 0;
border-right: 1px solid var(--border-color); border-right: 1px solid var(--border-color);
@@ -53,9 +60,19 @@
border-left: 3px solid var(--main-primary-color); border-left: 3px solid var(--main-primary-color);
padding-left: 1.5rem; padding-left: 1.5rem;
} }
.course-counter {
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
background-color: inherit;
font-size: 0.6875rem;
font-weight: 600;
line-height: 1.5;
margin-right: 1.5rem;
}
.item:hover { .item {
background-color: #cae2f9; &:hover {
background-color: #cae2f9;
}
} }
</style> </style>
@@ -68,11 +85,11 @@
isGroupActive={$page.path === '/courses/1'} isGroupActive={$page.path === '/courses/1'}
hideSortIcon /> hideSortIcon />
<Expandable label="Lectures"> <Expandable label="Lectures">
{#each lectures as lecture} {#each lectures as lecture, index}
<a <a
class="item {(lecture.link === $page.path || !$page.path.length > 3) && 'active'} pl-7 py-2" class="item {(lecture.link === $page.path || !$page.path.length > 3) && 'active'} pl-7 py-2"
href={lecture.link}> href={lecture.link}>
# <span class="course-counter"> {getLectureNo(index)} </span>
<span>{lecture.title}</span> <span>{lecture.title}</span>
</a> </a>
{/each} {/each}
@@ -1,106 +1,44 @@
<script> <script>
import yaml from "js-yaml";
import RadioQuestion from "../../../RadioQuestion/index.svelte"; import RadioQuestion from "../../../RadioQuestion/index.svelte";
import PrimaryButton from "../../../PrimaryButton/index.svelte"; import PrimaryButton from "../../../PrimaryButton/index.svelte";
import EditMode from "../../../EditMode/index.svelte";
import { generateQuestion } from "./functions";
export let mode;
let someYamlFile = `
about: This is the description of the home task
questions:
- title: Where is the founder of react?
type: radio
options:
- label: Mark Zukerberg
- label: Trake Towa
- label: Emeka Igwe
answer: true
- title: Who is the founder of react?
type: radio
options:
- label: Evan Vue
answer: true
- label: Richard Brandson
- label: Collison True
`;
const questionnaire = yaml.load(someYamlFile, "utf8");
const questions = generateQuestion(questionnaire.questions);
let answers = {}; let answers = {};
let currentQuestionIndex = 0; let currentQuestionIndex = 0;
let currentQuestion = {}; let currentQuestion = {};
const questions = [
{
name: "react-founder",
type: "radio",
title: "Who is the creator of React.js",
options: [
{
label: "Dan Abrahmov",
value: "danabrahmov",
},
{
label: "Google",
value: "google",
},
{
label: "Facebook",
value: "Facebook",
},
{
label: "Traversy Media",
value: "traversymedia",
},
],
},
{
name: "vue-founder",
type: "radio",
title: "Who is the creator of Vue.js",
options: [
{
label: "Evan Vue",
value: "evan-vue",
},
{
label: "Mark Zukerberg",
value: "mark",
},
{
label: "Prince Charles",
value: "prince-charles",
},
{
label: "Bill Gates",
value: "gates-bill",
},
],
},
{
name: "svelte-founder",
type: "radio",
title: "Who is the creator of Svelte.js",
options: [
{
label: "Hillary Svelte",
value: "danabrahmov",
},
{
label: "Mircosoft",
value: "microsoft",
},
{
label: "Elevate",
value: "elevate",
},
{
label: "Coding Train",
value: "coding-train",
},
],
},
{
name: "angular-founder",
type: "radio",
title: "Who is the creator of Angular.js",
options: [
{
label: "Laryy page",
value: "larry-page",
},
{
label: "Google",
value: "google",
},
{
label: "Sales Force",
value: "sales-force",
},
],
},
];
function handleStart() { function handleStart() {
currentQuestionIndex += 1; currentQuestionIndex += 1;
} }
function onPrevious() {
currentQuestionIndex -= 1;
}
function onSubmit(name, value) { function onSubmit(name, value) {
if (!value) return; if (!value) return;
answers = { answers = {
@@ -111,43 +49,35 @@
} }
$: currentQuestion = questions[currentQuestionIndex - 1]; $: currentQuestion = questions[currentQuestionIndex - 1];
function onPrevious() {
currentQuestionIndex -= 1;
}
</script> </script>
<div class="bg-gray-100 rounded-xl p-8" /> <EditMode value={someYamlFile}>
<div slot="preview">
{#if currentQuestionIndex === 0}
<div>
<h2>Home task 1</h2>
<p>{questionnaire.about}</p>
{#if currentQuestionIndex === 0} <PrimaryButton
<div> onClick={handleStart}
<h2>Home task 1</h2> label="Start"
<p> className="my-5"
You will be to answer 10 questions, it isn't timed so you can take your type="button" />
time to answer. You can also continue from where you left off, you don't </div>
need to worry cause everything is automatically syncronized in the cloud. {:else if !currentQuestion}
</p> <pre>
<code>{JSON.stringify(answers)}</code>
<PrimaryButton </pre>
onClick={handleStart} {:else}
label="Start" <RadioQuestion
className="my-5" title={currentQuestionIndex + '. ' + currentQuestion.title}
type="button" name={currentQuestion.name}
/> options={currentQuestion.options}
defaultValue={answers[currentQuestion.name] || false}
{onSubmit}
{onPrevious}
disablePreviousButton={currentQuestionIndex === 1}
isLast={currentQuestionIndex === questions.length} />
{/if}
</div> </div>
{:else if !currentQuestion} </EditMode>
<pre>
<code>{JSON.stringify(answers)}</code>
</pre>
{:else}
<RadioQuestion
title={currentQuestionIndex + ". " + currentQuestion.title}
name={currentQuestion.name}
options={currentQuestion.options}
defaultValue={answers[currentQuestion.name] || false}
{onSubmit}
{onPrevious}
disablePreviousButton={currentQuestionIndex === 1}
isLast={currentQuestionIndex === questions.length}
/>
{/if}
@@ -0,0 +1,23 @@
export function getUniqueValue(label) {
return label.toLowerCase().replace(' ', '');
}
export function generateQuestion(questions) {
const generatedQuestions = [];
for (const question of questions) {
const name = getUniqueValue(question.title);
const options = question.options.map((option) => {
option.value = getUniqueValue(option.label);
return option;
});
generatedQuestions.push({
...question,
name,
options,
});
}
return generatedQuestions;
}
@@ -21,47 +21,29 @@
} }
</script> </script>
<div>
<PageNav
navItems={[
{
label: "README.md",
isActive: tab === "lectures",
href: `${path}?tab=lectures`,
},
{
label: "Class work",
isActive: tab === "classwork",
href: `${path}?tab=classwork`,
},
{
label: "Hometasks",
isActive: tab === "hometasks",
href: `${path}?tab=hometasks`,
},
]}
>
<div slot="widget">
<PrimaryContainedButton
label={modeLabel}
handleClick={handleModeChange}
/>
</div>
</PageNav>
<div class="course">
{#if tab === "lectures"}
<Readme {mode} />
{:else if tab === "classwork"}
<Classwork />
{:else if tab === "hometasks"}
<Homework />
{/if}
</div>
</div>
<style> <style>
.course { .course {
padding: 0 40px; padding: 0 40px;
} }
</style> </style>
<div>
<PageNav
navItems={[{ label: 'README.md', isActive: tab === 'lectures', href: `${path}?tab=lectures` }, { label: 'Class work', isActive: tab === 'classwork', href: `${path}?tab=classwork` }, { label: 'Hometasks', isActive: tab === 'hometasks', href: `${path}?tab=hometasks` }]}>
<div slot="widget">
<PrimaryContainedButton
label={modeLabel}
handleClick={handleModeChange} />
</div>
</PageNav>
<div class="course">
{#if tab === 'lectures'}
<Readme {mode} />
{:else if tab === 'classwork'}
<Classwork />
{:else if tab === 'hometasks'}
<Homework {mode} />
{/if}
</div>
</div>
-7
View File
@@ -15,13 +15,6 @@
`; `;
</script> </script>
<style>
.body {
max-width: 1000px;
margin: 10px;
}
</style>
<PageNav title="Overview" disableSticky={true} /> <PageNav title="Overview" disableSticky={true} />
<div class="body"> <div class="body">
+60
View File
@@ -0,0 +1,60 @@
<script>
export let value;
export let placeholder = ``;
const activeClassName = "border-b-2 border-blue-700";
let isWriteMode = true;
const handleTabClick = (tab) => (event) => {
isWriteMode = tab === 1;
};
</script>
<style>
.root {
width: 100%;
min-height: 200px;
}
textarea {
width: 100%;
height: 500px;
}
.preview {
min-height: 150px;
}
.octicon {
display: inline-block;
vertical-align: text-top;
fill: currentColor;
}
</style>
<div class="root">
<div class="flex justify-center">
<button
on:click={handleTabClick(1)}
class="focus:outline-none p-2 {isWriteMode && `${activeClassName}`}">
Write
</button>
<button
on:click={handleTabClick(2)}
class="focus:outline-none p-2 {!isWriteMode && `${activeClassName}`}">
Preview
</button>
</div>
<div class="m-2 mb-0 p-0">
{#if isWriteMode}
<textarea
bind:value
{placeholder}
class="border border-gray rounded-md p-2" />
{:else}
<article class="preview prose prose-sm sm:prose p-2">
<slot name="preview" />
</article>
{/if}
</div>
</div>
+25 -28
View File
@@ -14,41 +14,15 @@
} }
</script> </script>
<div>
<div
class="item relative flex items-center {isGroupActive && 'active'}"
role="button"
tabindex="0"
on:click={onClick}
>
{#if !hideSortIcon}
<CaretSortDown20
class="carbon-icon-sort {isExpanded ? '' : 'carbon-icon-minimize'}"
/>
{/if}
<span class="pl-6 py-2 font-bold">{label}</span>
</div>
{#if isExpanded}
<div class="flex flex-col">
<!-- {#each subMenuItems as item}
<a class="item {item.isActive && 'active'} pl-6 py-2" href={item.link}>
# <span>{item.title}</span>
</a>
{/each} -->
<slot />
</div>
{/if}
</div>
<style> <style>
:global(svg.carbon-icon-sort) { :global(svg.carbon-icon-sort) {
position: absolute; position: absolute;
top: 3px; top: 8px;
left: 0; left: 0;
} }
:global(svg.carbon-icon-minimize) { :global(svg.carbon-icon-minimize) {
transform: rotate(270deg); transform: rotate(270deg);
top: 10px; top: 13px;
left: -6px; left: -6px;
} }
@@ -61,7 +35,30 @@
padding-left: 1.3rem; padding-left: 1.3rem;
} }
.item span {
padding: 12px 24px;
}
.item:hover { .item:hover {
background-color: #cae2f9; background-color: #cae2f9;
} }
</style> </style>
<div>
<div
class="item relative flex items-center {isGroupActive && 'active'}"
role="button"
tabindex="0"
on:click={onClick}>
{#if !hideSortIcon}
<CaretSortDown20
class="carbon-icon-sort {isExpanded ? '' : 'carbon-icon-minimize'}" />
{/if}
<span class="font-bold">{label}</span>
</div>
{#if isExpanded}
<div class="flex flex-col">
<slot />
</div>
{/if}
</div>
+30 -47
View File
@@ -147,53 +147,6 @@
$: discussions = getDiscussion(filterBy, allDiscussions); $: discussions = getDiscussion(filterBy, allDiscussions);
</script> </script>
<svelte:head>
<title>Unidiscuss - Help students in your university</title>
</svelte:head>
<div class="root md:w-3/4 mx-auto md:mb-20">
<PageNav
title="Talks"
addButtonHref="/ask"
addButtonLabel="New"
navItems={[
{
label: "Popular",
isActive: filterBy === "popular",
href: "?filter=popular",
},
{
label: "Recent",
isActive: filterBy === "recent",
href: "?filter=recent",
},
{
label: "Upvoted",
isActive: filterBy === "upvoted",
href: "?filter=upvoted",
},
]}
/>
{#each discussions as discussion}
<div class="discussion-box">
<Vote value={discussion.votes} />
<div class="discussion-topic-author">
<h4>
<a rel="prefetch" href="discussion/{discussion.id}"
>{discussion.title}</a
>
</h4>
<span>{discussion.author.name} asked 1 day ago</span>
<HashTags tags={discussion.tags} />
</div>
<Space />
<div class="flex items-center">
<AddComment20 />
<span>{discussion.comments}</span>
</div>
</div>
{/each}
</div>
<style> <style>
.root { .root {
max-width: 600px; max-width: 600px;
@@ -227,3 +180,33 @@
font-size: 12px; font-size: 12px;
} }
</style> </style>
<svelte:head>
<title>Unidiscuss - Help students in your university</title>
</svelte:head>
<div class="root md:w-3/4 mx-auto md:mb-20">
<PageNav
title="Talks"
addButtonHref="/ask"
addButtonLabel="Ask"
navItems={[{ label: 'Popular', isActive: filterBy === 'popular', href: '?filter=popular' }, { label: 'Recent', isActive: filterBy === 'recent', href: '?filter=recent' }, { label: 'Upvoted', isActive: filterBy === 'upvoted', href: '?filter=upvoted' }]} />
{#each discussions as discussion}
<div class="discussion-box">
<Vote value={discussion.votes} />
<div class="discussion-topic-author">
<h4>
<a
rel="prefetch"
href="discussion/{discussion.id}">{discussion.title}</a>
</h4>
<span>{discussion.author.name} asked 1 day ago</span>
<HashTags tags={discussion.tags} />
</div>
<Space />
<div class="flex items-center">
<AddComment20 />
<span>{discussion.comments}</span>
</div>
</div>
{/each}
</div>
+4 -1
View File
@@ -1,5 +1,6 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
@@ -26,9 +27,11 @@
the current page has one --> the current page has one -->
%sapper.head% %sapper.head%
</head> </head>
<body> <body>
<!-- The application will be rendered inside this element, <!-- The application will be rendered inside this element,
because `src/client.js` references it --> because `src/client.js` references it -->
<div id="sapper">%sapper.html%</div> <div id="sapper">%sapper.html%</div>
</body> </body>
</html>
</html>
+16 -15
View File
@@ -1,22 +1,23 @@
body { body {
margin: 0; margin: 0;
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen,
font-size: 14px; Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.5; font-size: 14px;
color: #333; line-height: 1.5;
color: #333;
} }
code { code {
font-family: menlo, inconsolata, monospace; font-family: menlo, inconsolata, monospace;
font-size: calc(1em - 2px); font-size: calc(1em - 2px);
color: #555; color: #555;
background-color: #f0f0f0; background-color: #f0f0f0;
padding: 0.2em 0.4em; padding: 0.2em 0.4em;
border-radius: 2px; border-radius: 2px;
} }
@media (min-width: 400px) { @media (min-width: 400px) {
body { body {
font-size: 16px; font-size: 16px;
} }
} }