Code snippet, better UX in questionnaire
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import marked from "marked";
|
||||||
|
|
||||||
|
export let code = "";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-gray-200 p-5 rounded-md mb-3">
|
||||||
|
{@html marked("```js\n" + code + "\n```")}
|
||||||
|
</div>
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import {
|
import {
|
||||||
questionnaire,
|
questionnaire,
|
||||||
handleAddOption,
|
handleAddOption,
|
||||||
handleAddQuestion,
|
|
||||||
handleRemoveOption,
|
handleRemoveOption,
|
||||||
handleRemoveQuestion,
|
handleRemoveQuestion,
|
||||||
|
handleCode,
|
||||||
} from "./store/index";
|
} from "./store/index";
|
||||||
import Delete24 from "carbon-icons-svelte/lib/Delete24";
|
import Delete24 from "carbon-icons-svelte/lib/Delete24";
|
||||||
import AddFilled24 from "carbon-icons-svelte/lib/AddFilled24";
|
import AddFilled24 from "carbon-icons-svelte/lib/AddFilled24";
|
||||||
@@ -14,9 +14,10 @@
|
|||||||
import Checkbox from "../../../../Form/Checkbox.svelte";
|
import Checkbox from "../../../../Form/Checkbox.svelte";
|
||||||
import RadioItem from "../../../../Form/RadioItem.svelte";
|
import RadioItem from "../../../../Form/RadioItem.svelte";
|
||||||
import IconButton from "../../../../IconButton/index.svelte";
|
import IconButton from "../../../../IconButton/index.svelte";
|
||||||
import Select from "../../../../Form/Select.svelte";
|
|
||||||
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
|
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
|
||||||
|
import Dropdown from "../../../../Dropdown/index.svelte";
|
||||||
import { VARIANTS } from "../../../../PrimaryButton/constants";
|
import { VARIANTS } from "../../../../PrimaryButton/constants";
|
||||||
|
import Select from "../../../../Form/Select.svelte";
|
||||||
import QuestionContainer from "../../../../QuestionContainer/index.svelte";
|
import QuestionContainer from "../../../../QuestionContainer/index.svelte";
|
||||||
import {
|
import {
|
||||||
QUESTION_TYPE,
|
QUESTION_TYPE,
|
||||||
@@ -26,39 +27,83 @@
|
|||||||
// import readme from "../../readme.js";
|
// import readme from "../../readme.js";
|
||||||
|
|
||||||
// let value = readme;
|
// let value = readme;
|
||||||
|
const extraActions = ["Code Snippets", "Upload image"];
|
||||||
|
const initialQuestionsLength = $questionnaire.questions.length;
|
||||||
|
|
||||||
|
function shouldScrollToLast(index, questions) {
|
||||||
|
const currentQuestionsLength = questions.length;
|
||||||
|
const isLast = index + 1 === currentQuestionsLength;
|
||||||
|
|
||||||
|
return isLast && initialQuestionsLength !== currentQuestionsLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOptionClick(questionIndex) {
|
||||||
|
return (actionIndex) => {
|
||||||
|
switch (actionIndex) {
|
||||||
|
case 0:
|
||||||
|
handleCode(questionIndex, true);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// uploadImage(questionIndex);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("No option");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root relative">
|
<div class="w-auto m-auto">
|
||||||
<div class="head flex bg-white items-center justify-between sticky right-0">
|
|
||||||
<h3>Home task</h3>
|
|
||||||
<PrimaryButton
|
|
||||||
variant={VARIANTS.OUTLINED}
|
|
||||||
onClick={handleAddQuestion}
|
|
||||||
label="Add Question"
|
|
||||||
mnb
|
|
||||||
v
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<QuestionContainer isTitle={true}>
|
<QuestionContainer isTitle={true}>
|
||||||
<TextField placeholder="Title" bind:value={$questionnaire.title} />
|
<TextField
|
||||||
|
placeholder="Title"
|
||||||
|
bind:value={$questionnaire.title}
|
||||||
|
className="mb-2"
|
||||||
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
placeholder="Description and Rules"
|
placeholder="Description and Rules"
|
||||||
bind:value={$questionnaire.description}
|
bind:value={$questionnaire.description}
|
||||||
/>
|
/>
|
||||||
</QuestionContainer>
|
</QuestionContainer>
|
||||||
|
|
||||||
{#each $questionnaire.questions as question}
|
{#each $questionnaire.questions as question, index}
|
||||||
<QuestionContainer onClose={handleRemoveQuestion(question.id)}>
|
<QuestionContainer
|
||||||
<div class="flex justify-between">
|
onClose={handleRemoveQuestion(question.id)}
|
||||||
|
scrollToQuestion={shouldScrollToLast(index, $questionnaire.questions)}
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
<div class="mr-2 w-3/5">
|
<div class="mr-2 w-3/5">
|
||||||
<TextField placeholder="Question" bind:value={question.title} />
|
<TextField placeholder="Question" bind:value={question.title} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
options={extraActions}
|
||||||
|
handleOptionClick={handleOptionClick(question.id)}
|
||||||
|
>
|
||||||
|
<AddFilled24 class="carbon-icon" />
|
||||||
|
<p class="ml-2 text-gray-600">Add</p>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
<Select bind:value={question.type} options={QUESTION_TYPES} />
|
<Select bind:value={question.type} options={QUESTION_TYPES} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
{#if typeof question.code === "string"}
|
||||||
|
<div class="flex justify-between items-center my-3 w-3/5">
|
||||||
|
<TextArea
|
||||||
|
bind:value={question.code}
|
||||||
|
rows="2"
|
||||||
|
placeholder="Write your code"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
value="write-code"
|
||||||
|
onClick={() => handleCode(question.id, false)}
|
||||||
|
>
|
||||||
|
<Delete24 class="carbon-icon" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="flex flex-col mt-2">
|
||||||
{#each question.options as option}
|
{#each question.options as option}
|
||||||
{#if QUESTION_TYPE.RADIO === question.type}
|
{#if QUESTION_TYPE.RADIO === question.type}
|
||||||
<RadioItem
|
<RadioItem
|
||||||
@@ -86,7 +131,7 @@
|
|||||||
<div slot="iconbutton">
|
<div slot="iconbutton">
|
||||||
<IconButton
|
<IconButton
|
||||||
value={option.id}
|
value={option.id}
|
||||||
onClick={handleRemoveOption(question.id)}
|
onClick={handleRemoveOption(question.id, option.id)}
|
||||||
>
|
>
|
||||||
<Delete24 class="carbon-icon" />
|
<Delete24 class="carbon-icon" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -101,24 +146,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if QUESTION_TYPE.TEXTAREA !== question.type}
|
{#if QUESTION_TYPE.TEXTAREA !== question.type}
|
||||||
<div class="flex items-center">
|
<div class="flex items-center mt-3">
|
||||||
<IconButton onClick={handleAddOption(question.id)}>
|
<PrimaryButton
|
||||||
|
disablePadding={true}
|
||||||
|
className="p-2"
|
||||||
|
variant={VARIANTS.OUTLINED}
|
||||||
|
onClick={handleAddOption(question.id)}
|
||||||
|
>
|
||||||
<AddFilled24 class="carbon-icon" />
|
<AddFilled24 class="carbon-icon" />
|
||||||
</IconButton>
|
<p class="ml-2">Add option</p>
|
||||||
<p class="italic">Add option</p>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</QuestionContainer>
|
</QuestionContainer>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
max-width: 700px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head {
|
|
||||||
top: 63px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import { questionnaire } from "./store/index";
|
import { questionnaire } from "./store/index";
|
||||||
// import RadioQuestion from "../../../../Question/RadioQuestion/index.svelte";
|
import RadioQuestion from "../../../../Question/RadioQuestion/index.svelte";
|
||||||
import CheckboxQuestion from "../../../../Question/CheckboxQuestion/index.svelte";
|
import CheckboxQuestion from "../../../../Question/CheckboxQuestion/index.svelte";
|
||||||
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
|
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
|
||||||
|
|
||||||
|
import {
|
||||||
|
QUESTION_TYPE,
|
||||||
|
QUESTION_TYPES,
|
||||||
|
} from "../../../../Question/constants";
|
||||||
|
import Checkbox from "../../../../Form/Checkbox.svelte";
|
||||||
let answers = {};
|
let answers = {};
|
||||||
let currentQuestionIndex = 0;
|
let currentQuestionIndex = 0;
|
||||||
let currentQuestion = {};
|
let currentQuestion = {};
|
||||||
@@ -34,7 +39,10 @@
|
|||||||
currentQuestionIndex += 1;
|
currentQuestionIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: currentQuestion = questions[currentQuestionIndex - 1];
|
$: {
|
||||||
|
currentQuestion = questions[currentQuestionIndex - 1];
|
||||||
|
console.log("currentQuestion", currentQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
function onPrevious() {
|
function onPrevious() {
|
||||||
currentQuestionIndex -= 1;
|
currentQuestionIndex -= 1;
|
||||||
@@ -43,7 +51,7 @@
|
|||||||
|
|
||||||
{#if currentQuestionIndex === 0}
|
{#if currentQuestionIndex === 0}
|
||||||
<div>
|
<div>
|
||||||
<h2>{title}</h2>
|
<h2 class="my-1">{title}</h2>
|
||||||
<p>{description}</p>
|
<p>{description}</p>
|
||||||
|
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
@@ -57,21 +65,24 @@
|
|||||||
<pre>
|
<pre>
|
||||||
<code>{JSON.stringify(answers)}</code>
|
<code>{JSON.stringify(answers)}</code>
|
||||||
</pre>
|
</pre>
|
||||||
{:else}
|
{:else if QUESTION_TYPE.RADIO === currentQuestion.type}
|
||||||
<!-- <RadioQuestion
|
<RadioQuestion
|
||||||
title={currentQuestionIndex + ". " + currentQuestion.title}
|
title={currentQuestionIndex + ". " + currentQuestion.title}
|
||||||
name={currentQuestion.name}
|
name={`${currentQuestion.id}`}
|
||||||
options={currentQuestion.options}
|
options={currentQuestion.options}
|
||||||
defaultValue={answers[currentQuestion.name] || false}
|
code={currentQuestion.code}
|
||||||
|
defaultValue={answers[`${currentQuestion.id}`] || false}
|
||||||
{onSubmit}
|
{onSubmit}
|
||||||
{onPrevious}
|
{onPrevious}
|
||||||
disablePreviousButton={currentQuestionIndex === 1}
|
disablePreviousButton={currentQuestionIndex === 1}
|
||||||
isLast={currentQuestionIndex === questions.length}
|
isLast={currentQuestionIndex === questions.length}
|
||||||
/> -->
|
/>
|
||||||
|
{:else if QUESTION_TYPE.CHECKBOX === currentQuestion.type}
|
||||||
<CheckboxQuestion
|
<CheckboxQuestion
|
||||||
title={currentQuestionIndex + ". " + currentQuestion.title}
|
title={currentQuestionIndex + ". " + currentQuestion.title}
|
||||||
name={`${currentQuestion.id}`}
|
name={`${currentQuestion.id}`}
|
||||||
options={currentQuestion.options}
|
options={currentQuestion.options}
|
||||||
|
code={currentQuestion.code}
|
||||||
defaultValue={answers[currentQuestion.id] || []}
|
defaultValue={answers[currentQuestion.id] || []}
|
||||||
onSubmit={onCheckboxSubmit}
|
onSubmit={onCheckboxSubmit}
|
||||||
{onPrevious}
|
{onPrevious}
|
||||||
|
|||||||
@@ -1,25 +1,48 @@
|
|||||||
<script>
|
<script>
|
||||||
import PrimaryContainedButton from "../../../../PrimaryContainedButton/index.svelte";
|
import { handleAddQuestion } from "./store/index";
|
||||||
|
import PrimaryButton from "../../../../PrimaryButton/index.svelte";
|
||||||
import PageBody from "../../../../PageBody/index.svelte";
|
import PageBody from "../../../../PageBody/index.svelte";
|
||||||
import EditMode from "./EditMode.svelte";
|
import EditMode from "./EditMode.svelte";
|
||||||
import ViewMode from "./ViewMode.svelte";
|
import ViewMode from "./ViewMode.svelte";
|
||||||
import MODES from "../../../../../utils/constants/mode.js";
|
import MODES from "../../../../../utils/constants/mode.js";
|
||||||
|
import { VARIANTS } from "../../../../PrimaryButton/constants";
|
||||||
|
|
||||||
let mode = MODES.view;
|
let mode = MODES.view;
|
||||||
|
let preview = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<svelte:fragment slot="header">
|
<svelte:fragment slot="header">
|
||||||
<h3>Lesson 2 home exercises</h3>
|
<div class="flex items-center">
|
||||||
<PrimaryContainedButton
|
<PrimaryButton
|
||||||
label={mode === MODES.edit ? "Save" : "Edit"}
|
className="mr-2"
|
||||||
handleClick={() => (mode = mode === MODES.edit ? MODES.view : MODES.edit)}
|
variant={VARIANTS.OUTLINED}
|
||||||
/>
|
label={mode === MODES.edit ? "Save" : "Edit"}
|
||||||
|
onClick={() => (mode = mode === MODES.edit ? MODES.view : MODES.edit)}
|
||||||
|
/>
|
||||||
|
{#if mode === MODES.edit}
|
||||||
|
<PrimaryButton
|
||||||
|
variant={VARIANTS.OUTLINED}
|
||||||
|
label={preview ? "Edit" : "Preview"}
|
||||||
|
onClick={() => (preview = !preview)}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if mode === MODES.edit}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<PrimaryButton
|
||||||
|
variant={VARIANTS.OUTLINED}
|
||||||
|
onClick={handleAddQuestion}
|
||||||
|
label="Add Question"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
{#if mode === MODES.edit}
|
{#if mode === MODES.edit}
|
||||||
<EditMode />
|
<EditMode />
|
||||||
{:else}
|
{:else}
|
||||||
<ViewMode />
|
<ViewMode {preview} />
|
||||||
{/if}
|
{/if}
|
||||||
</PageBody>
|
</PageBody>
|
||||||
|
|||||||
@@ -11,19 +11,23 @@ export const questionnaire = writable({
|
|||||||
questions: [
|
questions: [
|
||||||
{
|
{
|
||||||
id: "react-founder",
|
id: "react-founder",
|
||||||
type: QUESTION_TYPE.CHECKBOX,
|
type: QUESTION_TYPE.RADIO,
|
||||||
title: "Who is the creator of React.js",
|
title: "Who is the creator of React.js",
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
id: 1,
|
||||||
value: "Dan Abrahmov",
|
value: "Dan Abrahmov",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 2,
|
||||||
value: "Google",
|
value: "Google",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 3,
|
||||||
value: "Facebook",
|
value: "Facebook",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 4,
|
||||||
value: "Traversy Media",
|
value: "Traversy Media",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -32,17 +36,26 @@ export const questionnaire = writable({
|
|||||||
id: "vue-founder",
|
id: "vue-founder",
|
||||||
type: QUESTION_TYPE.CHECKBOX,
|
type: QUESTION_TYPE.CHECKBOX,
|
||||||
title: "Who is the creator of Vue.js",
|
title: "Who is the creator of Vue.js",
|
||||||
|
code: `const name = 'Josh Perez';\nconst element = <h1>Hello, {name}</h1>;\n\nReactDOM.render(\n
|
||||||
|
element,\,
|
||||||
|
document.getElementById('root')
|
||||||
|
)
|
||||||
|
`,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
id: 1,
|
||||||
value: "Evan Vue",
|
value: "Evan Vue",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 2,
|
||||||
value: "Mark Zukerberg",
|
value: "Mark Zukerberg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 3,
|
||||||
value: "Prince Charles",
|
value: "Prince Charles",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 4,
|
||||||
value: "Bill Gates",
|
value: "Bill Gates",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -53,34 +66,28 @@ export const questionnaire = writable({
|
|||||||
title: "Who is the creator of Svelte.js",
|
title: "Who is the creator of Svelte.js",
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
id: 1,
|
||||||
value: "Hillary Svelte",
|
value: "Hillary Svelte",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 2,
|
||||||
value: "Mircosoft",
|
value: "Mircosoft",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 3,
|
||||||
value: "Elevate",
|
value: "Elevate",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 4,
|
||||||
value: "Coding Train",
|
value: "Coding Train",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "angular-founder",
|
id: "angular-founder",
|
||||||
type: QUESTION_TYPE.CHECKBOX,
|
type: QUESTION_TYPE.TEXTAREA,
|
||||||
title: "Who is the creator of Angular.js",
|
title: "Who is the creator of Angular.js",
|
||||||
options: [
|
value: "",
|
||||||
{
|
|
||||||
value: "Laryy page",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "Google",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "Sales Force",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -95,6 +102,7 @@ export function handleAddQuestion() {
|
|||||||
{
|
{
|
||||||
...QUESTION_TEMPLATE,
|
...QUESTION_TEMPLATE,
|
||||||
id: questions.length + 1,
|
id: questions.length + 1,
|
||||||
|
value: "",
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -120,7 +128,7 @@ export function handleAddOption(questionId) {
|
|||||||
options: [
|
options: [
|
||||||
...question.options,
|
...question.options,
|
||||||
{
|
{
|
||||||
id: question.options.length + 1,
|
id: question.options[question.options.length - 1].id + 1,
|
||||||
value: "",
|
value: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -143,6 +151,11 @@ export function handleRemoveOption(questionId, optionId) {
|
|||||||
...q,
|
...q,
|
||||||
questions: questions.map((question) => {
|
questions: questions.map((question) => {
|
||||||
if (question.id === questionId) {
|
if (question.id === questionId) {
|
||||||
|
console.log(
|
||||||
|
"filter",
|
||||||
|
optionId,
|
||||||
|
question.options.filter((option) => option.id !== optionId)
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
...question,
|
...question,
|
||||||
options: [
|
options: [
|
||||||
@@ -170,3 +183,23 @@ export function handleRemoveQuestion(questionId) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function handleCode(questionId, shouldAdd = true) {
|
||||||
|
questionnaire.update((q) => {
|
||||||
|
const { questions } = q;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...q,
|
||||||
|
questions: questions.map((question) => {
|
||||||
|
if (question.id === questionId) {
|
||||||
|
return {
|
||||||
|
...question,
|
||||||
|
code: shouldAdd ? "" : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return question;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<script>
|
||||||
|
// import ChevronDown24 from "carbon-icons-svelte/lib/ChevronDown24";
|
||||||
|
|
||||||
|
export let options = [];
|
||||||
|
export let handleOptionClick;
|
||||||
|
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
function onClick(optionIndex) {
|
||||||
|
return () => {
|
||||||
|
open = !open;
|
||||||
|
console.log("onClick", optionIndex);
|
||||||
|
handleOptionClick(optionIndex);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBlur() {
|
||||||
|
// In case an option was clicked, let's wait for the on:click of that button before we close
|
||||||
|
setTimeout(() => (open = false), 100);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
class="flex flex-row items-center border rounded-lg border-grey py-2 px-3 focus:outline-none focus:border-gray-400 focus:bg-gray-200"
|
||||||
|
on:click={() => (open = !open)}
|
||||||
|
on:blur={onBlur}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<!-- <ChevronDown24 class="ml-2" /> -->
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if open}
|
||||||
|
<div
|
||||||
|
class="dropdown w-48 bg-white border border-grey rounded-lg mt-2 py-2 absolute -top-0.5"
|
||||||
|
>
|
||||||
|
{#each options as option, index}
|
||||||
|
<button
|
||||||
|
class="block px-4 py-2 border-b w-full"
|
||||||
|
on:click={onClick(index)}
|
||||||
|
>
|
||||||
|
{option}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.dropdown {
|
||||||
|
box-shadow: 0px 5px 5px -3px rgb(0 0 0 / 20%),
|
||||||
|
0px 8px 10px 1px rgb(0 0 0 / 14%), 0px 3px 14px 2px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
export let isEditable = false;
|
export let isEditable = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center w-full">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-offset-0 focus:ring-indigo-200 focus:ring-opacity-50"
|
class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-offset-0 focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
export let isEditable = false;
|
export let isEditable = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center w-full">
|
||||||
<input
|
<input
|
||||||
class="form-radio"
|
class="form-radio"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
|||||||
@@ -2,18 +2,50 @@
|
|||||||
export let label;
|
export let label;
|
||||||
export let placeholder = "Write your answer...";
|
export let placeholder = "Write your answer...";
|
||||||
export let value;
|
export let value;
|
||||||
|
export let rows = "3";
|
||||||
|
export let maxRows;
|
||||||
|
|
||||||
|
$: minHeight = `${1 + parseInt(rows, 10) * 1.2}em`;
|
||||||
|
$: maxHeight = maxRows ? `${1 + maxRows * 1.2}em` : `auto`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="block">
|
<label class="block w-full relative">
|
||||||
{#if label}
|
{#if label}
|
||||||
<span class="text-gray-700">{label}</span>
|
<span class="text-gray-700">{label}</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<pre
|
||||||
|
aria-hidden="true"
|
||||||
|
style="min-height: {minHeight}; max-height: {maxHeight}">
|
||||||
|
{value + '\n'}
|
||||||
|
</pre>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
class="form-textarea mt-1 block w-full h-24"
|
{rows}
|
||||||
rows="3"
|
|
||||||
{placeholder}
|
{placeholder}
|
||||||
bind:value
|
bind:value
|
||||||
|
class="form-textarea block w-full bg-gray-100 border-t-0 border-l-0 border-r-0 border-b-1"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<slot name="iconbutton" />
|
<slot name="iconbutton" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
pre,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
line-height: 1.2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
export let placeholder;
|
export let placeholder;
|
||||||
export let value;
|
export let value;
|
||||||
export let onKeyDown;
|
export let onKeyDown;
|
||||||
|
export let className = "";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="block mb-3">
|
<label class="block {className}">
|
||||||
{#if label}<h4 class="m-0">{label}</h4>{/if}
|
{#if label}<h4 class="m-0">{label}</h4>{/if}
|
||||||
<input
|
<input
|
||||||
class="form-input p-2 mt-1 block w-full bg-gray-100 border-t-0 border-l-0 border-r-0 border-b-1"
|
class="form-input p-2 mt-1 block w-full bg-gray-100 border-t-0 border-l-0 border-r-0 border-b-1"
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
// import
|
// import
|
||||||
|
// border border-gray-300 rounded-md p-3 bg-blue-200 bg-opacity-25
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="m-3">
|
<div class="root mt-4 mx-auto max-w-3xl relative">
|
||||||
{#if $$slots.header}
|
{#if $$slots.header}
|
||||||
<div
|
<div
|
||||||
class="head flex bg-white items-center justify-between sticky right-0 w-full"
|
class="head flex bg-white items-center justify-between sticky right-0 w-full py-3"
|
||||||
>
|
>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
@@ -15,8 +16,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* .root {
|
||||||
|
max-width: 700px;
|
||||||
|
} */
|
||||||
|
|
||||||
.head {
|
.head {
|
||||||
top: 63px;
|
top: 61px;
|
||||||
z-index: 2;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -6,5 +6,5 @@ export const VARIANTS = {
|
|||||||
export const VARIANTS_CLASS = {
|
export const VARIANTS_CLASS = {
|
||||||
[VARIANTS.CONTAINED]: "bg-blue-700 hover:bg-blue-900 text-white font-bold",
|
[VARIANTS.CONTAINED]: "bg-blue-700 hover:bg-blue-900 text-white font-bold",
|
||||||
[VARIANTS.OUTLINED]:
|
[VARIANTS.OUTLINED]:
|
||||||
"border border-blue-700 hover:border-blue-700 hover:bg-blue-200 text-black",
|
"border border-gray-700 hover:border-black-300 hover:bg-gray-200 text-black",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,15 +6,24 @@
|
|||||||
export let name = "";
|
export let name = "";
|
||||||
export let type;
|
export let type;
|
||||||
export let variant = VARIANTS.CONTAINED;
|
export let variant = VARIANTS.CONTAINED;
|
||||||
|
export let disablePadding = false;
|
||||||
|
export let isDisabled = false;
|
||||||
|
|
||||||
const variantClass = VARIANTS_CLASS[variant];
|
const variantClass = VARIANTS_CLASS[variant];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="h-auto {variantClass} py-1 px-3 rounded {className} transition delay-150 duration-300 ease-in-out"
|
class="{isDisabled &&
|
||||||
|
'bg-opacity-25 hover:bg-opacity-25 cursor-not-allowed'} flex items-center h-auto {variantClass} {!disablePadding &&
|
||||||
|
'py-1 px-5'} rounded {className} transition delay-150 duration-300 ease-in-out "
|
||||||
on:click={onClick}
|
on:click={onClick}
|
||||||
{name}
|
{name}
|
||||||
{type}
|
{type}
|
||||||
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
{label}
|
{#if label}
|
||||||
|
{label}
|
||||||
|
{:else}
|
||||||
|
<slot />
|
||||||
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import PrimaryButton from "../../PrimaryButton/index.svelte";
|
import PrimaryButton from "../../PrimaryButton/index.svelte";
|
||||||
|
import CodeSnippet from "../../CodeSnippet/index.svelte";
|
||||||
import Checkbox from "../../Form/Checkbox.svelte";
|
import Checkbox from "../../Form/Checkbox.svelte";
|
||||||
|
|
||||||
export let title = "";
|
export let title = "";
|
||||||
|
export let code;
|
||||||
export let name = "";
|
export let name = "";
|
||||||
export let options = [];
|
export let options = [];
|
||||||
export let onSubmit = () => {};
|
export let onSubmit = () => {};
|
||||||
@@ -39,22 +41,31 @@
|
|||||||
<form on:submit|preventDefault={handleFormSubmit}>
|
<form on:submit|preventDefault={handleFormSubmit}>
|
||||||
<h2>{title}</h2>
|
<h2>{title}</h2>
|
||||||
|
|
||||||
|
{#if code}
|
||||||
|
<CodeSnippet {code} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
{#each options as option}
|
{#each options as option}
|
||||||
<div>
|
<button
|
||||||
|
class="text-left my-2 border border-gray-300 p-2 rounded-md cursor-pointer hover:bg-gray-200 w-full"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
{name}
|
{name}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
checked={defaultValue.includes(option.value)}
|
checked={defaultValue.includes(option.value)}
|
||||||
label={option.label || option.value}
|
label={option.label || option.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3">
|
<div class="mt-3 flex items-center justify-between w-full">
|
||||||
{#if disablePreviousButton === false}
|
<PrimaryButton
|
||||||
<PrimaryButton onClick={handlePrevious} label="Previous" />
|
onClick={handlePrevious}
|
||||||
{/if}
|
label="Previous"
|
||||||
|
isDisabled={disablePreviousButton}
|
||||||
|
/>
|
||||||
<PrimaryButton type="submit" label={isLast ? "Finish" : "Next"} {name} />
|
<PrimaryButton type="submit" label={isLast ? "Finish" : "Next"} {name} />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import PrimaryButton from "../../PrimaryButton/index.svelte";
|
import PrimaryButton from "../../PrimaryButton/index.svelte";
|
||||||
import RadioItem from "../../Form/RadioItem.svelte";
|
import RadioItem from "../../Form/RadioItem.svelte";
|
||||||
|
import CodeSnippet from "../../CodeSnippet/index.svelte";
|
||||||
|
|
||||||
export let title = "";
|
export let title = "";
|
||||||
|
export let code;
|
||||||
export let name = "";
|
export let name = "";
|
||||||
export let options = [];
|
export let options = [];
|
||||||
export let onSubmit = () => {};
|
export let onSubmit = () => {};
|
||||||
@@ -39,22 +41,31 @@
|
|||||||
<form on:submit|preventDefault={handleFormSubmit}>
|
<form on:submit|preventDefault={handleFormSubmit}>
|
||||||
<h2>{title}</h2>
|
<h2>{title}</h2>
|
||||||
|
|
||||||
|
{#if code}
|
||||||
|
<CodeSnippet {code} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
{#each options as option}
|
{#each options as option}
|
||||||
<div>
|
<button
|
||||||
|
class="text-left my-2 border border-gray-300 p-2 rounded-md cursor-pointer hover:bg-gray-200 w-full"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
<RadioItem
|
<RadioItem
|
||||||
{name}
|
{name}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
checked={option.value === defaultValue}
|
checked={option.value === defaultValue}
|
||||||
label={option.label}
|
label={option.label || option.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3">
|
<div class="mt-3 flex items-center justify-between w-full">
|
||||||
{#if disablePreviousButton === false}
|
<PrimaryButton
|
||||||
<PrimaryButton onClick={handlePrevious} label="Previous" />
|
onClick={handlePrevious}
|
||||||
{/if}
|
label="Previous"
|
||||||
|
isDisabled={disablePreviousButton}
|
||||||
|
/>
|
||||||
<PrimaryButton type="submit" label={isLast ? "Finish" : "Next"} {name} />
|
<PrimaryButton type="submit" label={isLast ? "Finish" : "Next"} {name} />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const QUESTION_TYPES = [
|
|||||||
export const QUESTION_TEMPLATE = {
|
export const QUESTION_TEMPLATE = {
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "",
|
title: "",
|
||||||
|
code: "",
|
||||||
type: QUESTION_TYPE.RADIO,
|
type: QUESTION_TYPE.RADIO,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +1,30 @@
|
|||||||
<script>
|
<script>
|
||||||
|
// import { onMount } from "svelte";
|
||||||
import CloseButton from "../Buttons/Close/index.svelte";
|
import CloseButton from "../Buttons/Close/index.svelte";
|
||||||
export let isTitle = false;
|
export let isTitle = false;
|
||||||
export let onClose;
|
export let onClose;
|
||||||
|
export let scrollToQuestion = false;
|
||||||
|
|
||||||
|
let ref;
|
||||||
|
|
||||||
|
// onMount(() => {
|
||||||
|
// if (scrollToQuestion) {
|
||||||
|
// ref.scrollIntoView({ block: "end", behavior: "smooth" });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (ref && scrollToQuestion) {
|
||||||
|
ref.scrollIntoView({ block: "end", behavior: "smooth" });
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
bind:this={ref}
|
||||||
class="{isTitle
|
class="{isTitle
|
||||||
? 'border'
|
? 'border'
|
||||||
: 'border-2'} border-gray border-r-2 rounded-md mb-6 relative root"
|
: 'border-2'} border-gray border-r-2 rounded-md mb-6 relative root hover:border-blue-700"
|
||||||
>
|
>
|
||||||
{#if isTitle}
|
{#if isTitle}
|
||||||
<div class="title absolute bg-blue-700" />
|
<div class="title absolute bg-blue-700" />
|
||||||
|
|||||||
Reference in New Issue
Block a user