Skip to content

Commit

Permalink
reorganize form components
Browse files Browse the repository at this point in the history
Co-Authored-By: Alexander Peras <[email protected]>
Co-Authored-By: Keillor Jennings <[email protected]>
  • Loading branch information
3 people committed Mar 1, 2024
1 parent c7943d3 commit 3d3580c
Show file tree
Hide file tree
Showing 39 changed files with 316 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import type { User, Form } from '$lib/store';
import QuestionInput from './question_input.svelte';
import QuestionInput from '$lib/components/form/question_input/question_input.svelte';
export let data: Form;
export let user: User | undefined = undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import type { Form } from '$lib/store';
import { QuestionType } from '$lib/form';
import QuestionInput from './question_input.svelte';
import QuestionInput from '$lib/components/form/question_input/question_input.svelte';
export let action: string;
export let method: string;
Expand All @@ -19,6 +19,7 @@
<p>Form ID: {data.id}</p>
</div>
</div>

<QuestionInput
data={{
type: QuestionType.TEXT,
Expand All @@ -35,6 +36,7 @@
}}
/>

<!-- TODO: Replace camelCase names with snake_case. -->
<QuestionInput
data={{
type: QuestionType.TEXT,
Expand Down
59 changes: 59 additions & 0 deletions src/lib/components/form/question_input/question_input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script lang="ts">
import type { Question } from '$lib/form';
import { QuestionType } from '$lib/form';
import AvailabilityQuestionInput from '$lib/components/form/questions/availability/availability_question_input.svelte';
import BooleanQuestionInput from '$lib/components/form/questions/boolean/boolean_question_input.svelte';
import ColorQuestionInput from '$lib/components/form/questions/color/color_question_input.svelte';
import DateQuestionInput from '$lib/components/form/questions/date/date_question_input.svelte';
import DatetimeQuestionImput from '$lib/components/form/questions/datetime/datetime_question_imput.svelte';
import NumberQuestionInput from '$lib/components/form/questions/number/number_question_input.svelte';
import RadioGroupQuestionInput from '$lib/components/form/questions/radio_group/radio_group_question_input.svelte';
import TextQuestionInput from '$lib/components/form/questions/text/text_question_input.svelte';
import TextareaQuestionInput from '$lib/components/form/questions/textarea/textarea_question_input.svelte';
import TimeQuestionInput from '$lib/components/form/questions/time/time_question_input.svelte';
import SelectQuestionInput from '$lib/components/form/questions/select/select_question_input.svelte';
import TimezoneQuestionInput from '$lib/components/form/questions/timezone/timezone_question_input.svelte';
export let data: Question;
</script>

<div class="question">
{#if data.type === QuestionType.BOOLEAN}
<BooleanQuestionInput {data} />
{:else if data.type === QuestionType.TEXT}
<TextQuestionInput {data} />
{:else if data.type === QuestionType.RADIO_GROUP}
<RadioGroupQuestionInput {data} />
{:else if data.type === QuestionType.NUMBER}
<NumberQuestionInput {data} />
{:else if data.type === QuestionType.COLOR}
<ColorQuestionInput {data} />
{:else if data.type === QuestionType.TEXTAREA}
<TextareaQuestionInput {data} />
{:else if data.type === QuestionType.DATE}
<DateQuestionInput {data} />
{:else if data.type === QuestionType.AVAILABILITY}
<AvailabilityQuestionInput {data} />
{:else if data.type === QuestionType.DATETIME}
<DatetimeQuestionImput {data} />
{:else if data.type === QuestionType.TIME}
<TimeQuestionInput {data} />
{:else if data.type === QuestionType.SELECT}
<SelectQuestionInput {data} />
{:else if data.type === QuestionType.TIMEZONE}
<TimezoneQuestionInput {data} />
{/if}
</div>

<style>
.question {
padding: 20px 15px;
width: calc(100% - 30px);
margin: 10px auto;
background-color: #ffffff;
border-radius: 10px;
border-color: #c5c8c9;
border-width: 0;
border-style: solid;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import type { QuestionBase } from '$lib/form';
import { QuestionType } from '$lib/form';
import QuestionInput from '$lib/components/form/question_input/question_input.svelte';
export let value: QuestionBase;
</script>

<input type="hidden" name="type" value={value.type} />

<QuestionInput
data={{
type: QuestionType.TEXT,
name: 'Name',
content: 'The unique identifier for the question.',
value: value.name
}}
/>

<QuestionInput
data={{
type: QuestionType.TEXTAREA,
name: 'Content',
content: 'The markdown question content for the form field.',
value: value.content
}}
/>

<QuestionInput
data={{
type: QuestionType.BOOLEAN,
name: 'Required',
content: 'Whether or not the form field is required.',
value: value.required
}}
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
// import type { Question } from '$lib/form';
// import QuestionInput from '$lib/components/form/question_input/question_input.svelte';
// export let value: Question;
</script>

<!-- <QuestionInput
data={{
type: value.type,
name: value.name,
content: value.content,
value: value.value
}}
/> -->
30 changes: 30 additions & 0 deletions src/lib/components/form/question_list_editor/add_item.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts">
import { QuestionType } from '$lib/form';
import type { AddItemProps } from '$lib/components/list_input/list_input';
export let addAction: AddItemProps['addAction'];
let type = QuestionType.TEXT;
function add() {
// TODO: Add a helper function to create a blank question object for each type.
addAction({ type });
}
</script>

<select bind:value={type}>
<option value={QuestionType.TEXT}>Text</option>
<option value={QuestionType.TEXTAREA}>Textarea</option>
<option value={QuestionType.NUMBER}>Number</option>
<option value={QuestionType.BOOLEAN}>Boolean</option>
<option value={QuestionType.COLOR}>Color</option>
<option value={QuestionType.DATE}>Date</option>
<option value={QuestionType.DATETIME}>Datetime</option>
<option value={QuestionType.TIME}>Time</option>
<option value={QuestionType.TIMEZONE}>Timezone</option>
<option value={QuestionType.SELECT}>Select</option>
<option value={QuestionType.RADIO_GROUP}>Radio group</option>
<option value={QuestionType.AVAILABILITY}>Availability</option>
</select>

<button on:click={add}>Add</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import type { DeleteItemProps } from '$lib/components/list_input/list_input';
export let deleteAction: DeleteItemProps['deleteAction'];
</script>

<button on:click={() => deleteAction()}>Delete</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts">
import type { QuestionList } from '$lib/form';
import { QuestionType } from '$lib/form';
import ListInput from '$lib/components/list_input/list_input.svelte';
import QuestionInput from '$lib/components/form/question_input/question_input.svelte';
import QuestionInputEditor from '$lib/components/form/question_input_editor/question_input_editor.svelte';
import AddItem from './add_item.svelte';
import DeleteItem from './delete_item.svelte';
export let value: QuestionList;
</script>

<QuestionInput
data={{
type: QuestionType.BOOLEAN,
name: 'shuffled',
content: 'Shuffled',
value: value.shuffled
}}
/>

<!-- TODO: Figure out how to handle indexed names for the items in the list if needed. -->

<ListInput
components={{
item: QuestionInputEditor,
addItem: AddItem,
deleteItem: DeleteItem
}}
/>
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
max={data.maxEndDatetime}
value={data.value?.[i][0]}
/>
<!-- TODO: Convert break to hr tag. -->
<p>----</p>
<input
type="datetime-local"
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import type { SingleTextSelectQuestion } from '$lib/form';
import type { RadioGroupQuestion } from '$lib/form';
export let data: SingleTextSelectQuestion;
export let data: RadioGroupQuestion;
</script>

<fieldset>
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import type { SelectQuestion } from '$lib/form';
export let data: SelectQuestion;
</script>

<fieldset>
<legend>{data.content}</legend>
<select name={data.name} required={data.required} bind:value={data.value}>
{#each data.options as option}
<option value={option.value}>{option.content}</option>
{/each}
</select>
</fieldset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script lang="ts">
import type { SelectQuestion } from '$lib/form';
import { QuestionType } from '$lib/form';
import SelectQuestionInput from './select_question_input.svelte';
var newOption: string = '';
let data: SelectQuestion = {
type: QuestionType.SELECT,
options: [
{ value: '55', content: 'Apple' },
{ value: '66', content: 'Bananna' }
],
name: '',
content: ''
};
// let other: TextQuestion = {
// type: QuestionType.TEXT,
// name: 'OOP',
// content: newOption
// };
function removeOption(option: unknown) {
var index = (data.options as unknown[]).indexOf(option);
if (index > -1) {
data.options.splice(index, 1);
data.options = data.options;
}
}
function addOptions() {
if (/^.+$/.test(newOption)) {
if (data.options.includes({ value: newOption, content: newOption })) {
console.log('Key / value already exists for this value!');
return;
} else {
// KV does not exist
data.options.push({ value: newOption, content: newOption });
data.options = data.options;
newOption = '';
}
}
}
</script>

<form on:submit|preventDefault={addOptions}>
<input type="text" bind:value={newOption} /><button type="submit">➕</button>
</form>

{#each data.options as option (option.content)}
<p><button on:click={() => removeOption(option)}>🗑️</button>{option.content}</p>
{/each}

<SelectQuestionInput {data} />
Empty file.
Empty file.
Empty file.
Empty file.
29 changes: 29 additions & 0 deletions src/lib/components/list_input/list_input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import type { ItemProps, Components } from './list_input.ts';
export let data: ItemProps[] = [];
export let components: Components;
function deleteItem(i: number): void {
data.splice(i, 1);
// data = [...data];
}
function addItem(item: ItemProps): void {
data.push(item);
}
</script>

<div>
{#each data as item, i}
<div>
<svelte:component this={components.item} {...item} />
<svelte:component this={components.deleteItem} deleteAction={() => deleteItem(i)} />
</div>
{:else}
{#if components.emptySection}
<svelte:component this={components.emptySection} />
{/if}
{/each}
<svelte:component this={components.addItem} addAction={(item) => addItem(item)} />
</div>
22 changes: 22 additions & 0 deletions src/lib/components/list_input/list_input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { ComponentType, SvelteComponent } from 'svelte';

export type ItemProps = Record<string, unknown>;

export interface AddItemProps {
addAction(item: ItemProps): void;
}

export interface DeleteItemProps {
deleteAction(): void;
}

export type ItemComponent = SvelteComponent;
export type AddItemComponent = SvelteComponent<AddItemProps>;
export type DeleteItemComponent = SvelteComponent<DeleteItemProps>;

export interface Components {
item: ComponentType<ItemComponent>;
addItem: ComponentType<AddItemComponent>;
deleteItem: ComponentType<DeleteItemComponent>;
emptySection?: ComponentType<SvelteComponent>;
}
Loading

0 comments on commit 3d3580c

Please sign in to comment.