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": {
"@tailwindcss/forms": "^0.3.2",
"compression": "^1.7.1",
"js-yaml": "^4.1.0",
"marked": "^1.2.7",
"node-sass": "^6.0.0",
"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 = [
{
title: "Lecture 1",
title: "Вводный урок. Soft skills",
link: "/courses/1/lecture/1",
},
{
title: "Lecture 2",
title: "Введение в ReactJS",
link: "/courses/1/lecture/2",
},
{
title: "Lecture 3",
title: "Компоненты",
link: "/courses/1/lecture/3",
},
{
title: "Lecture 4",
title: "Состояние компонентов и пропсы",
link: "/courses/1/lecture/4",
},
{
title: "Lecture 5",
title: "Жизненный цикл",
link: "/courses/1/lecture/5",
},
];
function getLectureNo(index) {
if (index < 9) {
return `00${index}`;
}
return `0${index}`;
}
</script>
<style>
<style lang="scss">
.root {
height: 90vh;
display: flex;
flex-direction: column;
width: 20%;
max-width: 250px;
width: 360px;
position: sticky;
top: 0;
border-right: 1px solid var(--border-color);
@@ -53,9 +60,19 @@
border-left: 3px solid var(--main-primary-color);
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 {
background-color: #cae2f9;
.item {
&:hover {
background-color: #cae2f9;
}
}
</style>
@@ -68,11 +85,11 @@
isGroupActive={$page.path === '/courses/1'}
hideSortIcon />
<Expandable label="Lectures">
{#each lectures as lecture}
{#each lectures as lecture, index}
<a
class="item {(lecture.link === $page.path || !$page.path.length > 3) && 'active'} pl-7 py-2"
href={lecture.link}>
#
<span class="course-counter"> {getLectureNo(index)} </span>
<span>{lecture.title}</span>
</a>
{/each}
@@ -1,106 +1,44 @@
<script>
import yaml from "js-yaml";
import RadioQuestion from "../../../RadioQuestion/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 currentQuestionIndex = 0;
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() {
currentQuestionIndex += 1;
}
function onPrevious() {
currentQuestionIndex -= 1;
}
function onSubmit(name, value) {
if (!value) return;
answers = {
@@ -111,43 +49,35 @@
}
$: currentQuestion = questions[currentQuestionIndex - 1];
function onPrevious() {
currentQuestionIndex -= 1;
}
</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}
<div>
<h2>Home task 1</h2>
<p>
You will be to answer 10 questions, it isn't timed so you can take your
time to answer. You can also continue from where you left off, you don't
need to worry cause everything is automatically syncronized in the cloud.
</p>
<PrimaryButton
onClick={handleStart}
label="Start"
className="my-5"
type="button"
/>
<PrimaryButton
onClick={handleStart}
label="Start"
className="my-5"
type="button" />
</div>
{:else if !currentQuestion}
<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}
</div>
{:else if !currentQuestion}
<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}
</EditMode>
@@ -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>
<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>
.course {
padding: 0 40px;
}
</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>
<style>
.body {
max-width: 1000px;
margin: 10px;
}
</style>
<PageNav title="Overview" disableSticky={true} />
<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>
<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>
:global(svg.carbon-icon-sort) {
position: absolute;
top: 3px;
top: 8px;
left: 0;
}
:global(svg.carbon-icon-minimize) {
transform: rotate(270deg);
top: 10px;
top: 13px;
left: -6px;
}
@@ -61,7 +35,30 @@
padding-left: 1.3rem;
}
.item span {
padding: 12px 24px;
}
.item:hover {
background-color: #cae2f9;
}
</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);
</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>
.root {
max-width: 600px;
@@ -227,3 +180,33 @@
font-size: 12px;
}
</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>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
@@ -26,9 +27,11 @@
the current page has one -->
%sapper.head%
</head>
<body>
<!-- The application will be rendered inside this element,
because `src/client.js` references it -->
<div id="sapper">%sapper.html%</div>
</body>
</html>
</html>
+16 -15
View File
@@ -1,22 +1,23 @@
body {
margin: 0;
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #333;
margin: 0;
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #333;
}
code {
font-family: menlo, inconsolata, monospace;
font-size: calc(1em - 2px);
color: #555;
background-color: #f0f0f0;
padding: 0.2em 0.4em;
border-radius: 2px;
font-family: menlo, inconsolata, monospace;
font-size: calc(1em - 2px);
color: #555;
background-color: #f0f0f0;
padding: 0.2em 0.4em;
border-radius: 2px;
}
@media (min-width: 400px) {
body {
font-size: 16px;
}
}
body {
font-size: 16px;
}
}