Parsing questionnaire from yml
This commit is contained in:
Generated
+430
-5887
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
`;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.body {
|
||||
max-width: 1000px;
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<PageNav title="Overview" disableSticky={true} />
|
||||
|
||||
<div class="body">
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user