feat: widgets and ai chat
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '../../tools';
|
||||
import CheckboxOptionCard from './checkbox-option-card.svelte';
|
||||
|
||||
export interface CheckboxOptionCardOption {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
type SnippetWithOption = import('svelte').Snippet<[option: CheckboxOptionCardOption]>;
|
||||
|
||||
interface Props {
|
||||
options: CheckboxOptionCardOption[];
|
||||
/** Bound array of selected option values */
|
||||
value?: string[];
|
||||
/** Overridable CSS class for the grid container (e.g. grid-cols-2, md:grid-cols-3) */
|
||||
class?: string;
|
||||
titleSuffix?: SnippetWithOption;
|
||||
leading?: SnippetWithOption;
|
||||
footer?: SnippetWithOption;
|
||||
}
|
||||
|
||||
let {
|
||||
options,
|
||||
value = $bindable([]),
|
||||
class: className,
|
||||
titleSuffix: parentTitleSuffix,
|
||||
leading: parentLeading,
|
||||
footer: parentFooter
|
||||
}: Props = $props();
|
||||
|
||||
function toggle(optionValue: string, isChecked: boolean) {
|
||||
if (isChecked) {
|
||||
if (value.includes(optionValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = [...value, optionValue];
|
||||
return;
|
||||
}
|
||||
|
||||
value = value.filter((entry) => entry !== optionValue);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div role="group" data-slot="checkbox-option-card-group" class={cn('ui:grid ui:gap-3', className)}>
|
||||
{#each options as option (option.id)}
|
||||
<CheckboxOptionCard
|
||||
id={option.id}
|
||||
title={option.title}
|
||||
description={option.description}
|
||||
checked={value.includes(option.value)}
|
||||
disabled={option.disabled}
|
||||
onCheckedChange={(isChecked) => toggle(option.value, isChecked)}
|
||||
>
|
||||
{#snippet titleSuffix()}
|
||||
{@render parentTitleSuffix?.(option)}
|
||||
{/snippet}
|
||||
{#snippet leading()}
|
||||
{@render parentLeading?.(option)}
|
||||
{/snippet}
|
||||
{#snippet footer()}
|
||||
{@render parentFooter?.(option)}
|
||||
{/snippet}
|
||||
</CheckboxOptionCard>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -0,0 +1,62 @@
|
||||
<script lang="ts">
|
||||
import { Checkbox } from '../../base/checkbox';
|
||||
import * as Field from '../../base/field';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
checked: boolean;
|
||||
disabled?: boolean;
|
||||
onCheckedChange?: (checked: boolean) => void;
|
||||
titleSuffix?: import('svelte').Snippet;
|
||||
leading?: import('svelte').Snippet;
|
||||
footer?: import('svelte').Snippet;
|
||||
/** Overridable CSS class (e.g. for grid column span or custom layout) */
|
||||
class?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
checked,
|
||||
disabled = false,
|
||||
onCheckedChange,
|
||||
titleSuffix,
|
||||
leading,
|
||||
footer,
|
||||
class: className
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<Field.Label for={id} class={className}>
|
||||
<Field.Field orientation="horizontal">
|
||||
{#if leading}
|
||||
{@render leading()}
|
||||
{/if}
|
||||
<Field.Content>
|
||||
<Field.Title class="ui:flex ui:items-center ui:gap-2">
|
||||
{title}
|
||||
{#if titleSuffix}
|
||||
{@render titleSuffix()}
|
||||
{/if}
|
||||
</Field.Title>
|
||||
{#if description}
|
||||
<Field.Description>{description}</Field.Description>
|
||||
{/if}
|
||||
</Field.Content>
|
||||
<Checkbox
|
||||
{id}
|
||||
aria-label={title}
|
||||
{disabled}
|
||||
{checked}
|
||||
onCheckedChange={(value) => onCheckedChange?.(value === true)}
|
||||
/>
|
||||
</Field.Field>
|
||||
{#if footer}
|
||||
<div class="-mt-1 min-w-0 px-4 pb-3">
|
||||
{@render footer()}
|
||||
</div>
|
||||
{/if}
|
||||
</Field.Label>
|
||||
@@ -0,0 +1,6 @@
|
||||
import CheckboxOptionCard from './checkbox-option-card.svelte';
|
||||
import CheckboxOptionCardGroup from './checkbox-option-card-group.svelte';
|
||||
|
||||
export { CheckboxOptionCard, CheckboxOptionCardGroup };
|
||||
export type { CheckboxOptionCardOption } from './checkbox-option-card-group.svelte';
|
||||
export { CheckboxOptionCard as default };
|
||||
Reference in New Issue
Block a user