From 5045d70bf7be280d92467f1fbe79d4140f44af04 Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Tue, 25 Nov 2025 00:36:12 +0100 Subject: [PATCH] feat: add form and layout components to shared-ui (Tier 6b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New molecules: - ModalFooter: Standardized modal footer with button layout - DataCard: Generic card for displaying data items (memos, decks, etc.) - PageHeader: Standardized page header with title, description, actions New organisms: - FormModal: Modal with built-in form handling, validation, loading states All components use Svelte 5 snippets for flexible slot patterns. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/shared-ui/src/index.ts | 5 +- .../shared-ui/src/molecules/DataCard.svelte | 154 ++++++++++++++++++ .../src/molecules/ModalFooter.svelte | 85 ++++++++++ .../shared-ui/src/molecules/PageHeader.svelte | 139 ++++++++++++++++ packages/shared-ui/src/molecules/index.ts | 5 + .../shared-ui/src/organisms/FormModal.svelte | 117 +++++++++++++ packages/shared-ui/src/organisms/index.ts | 1 + 7 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 packages/shared-ui/src/molecules/DataCard.svelte create mode 100644 packages/shared-ui/src/molecules/ModalFooter.svelte create mode 100644 packages/shared-ui/src/molecules/PageHeader.svelte create mode 100644 packages/shared-ui/src/organisms/FormModal.svelte diff --git a/packages/shared-ui/src/index.ts b/packages/shared-ui/src/index.ts index 4f08f1e03..1eacc976c 100644 --- a/packages/shared-ui/src/index.ts +++ b/packages/shared-ui/src/index.ts @@ -20,8 +20,11 @@ export { SkeletonBox, SkeletonText } from './molecules'; // Feedback export { EmptyState } from './molecules'; +// Layout +export { ModalFooter, DataCard, PageHeader } from './molecules'; + // Organisms -export { Modal, ConfirmationModal, AppSlider } from './organisms'; +export { Modal, ConfirmationModal, FormModal, AppSlider } from './organisms'; export type { AppItem } from './organisms'; // Navigation diff --git a/packages/shared-ui/src/molecules/DataCard.svelte b/packages/shared-ui/src/molecules/DataCard.svelte new file mode 100644 index 000000000..0555951ab --- /dev/null +++ b/packages/shared-ui/src/molecules/DataCard.svelte @@ -0,0 +1,154 @@ + + +
{ + if (isClickable && onclick && (e.key === 'Enter' || e.key === ' ')) { + e.preventDefault(); + onclick(); + } + }} + role={isClickable ? 'button' : undefined} + tabindex={isClickable ? 0 : undefined} +> +
+ + {#if icon} +
+ {@render icon()} +
+ {/if} + + +
+
+
+ + + {title} + + + + {#if description} + + {description} + + {/if} +
+ + + {#if badge} +
+ {@render badge()} +
+ {/if} +
+ + + {#if metadata} + + {/if} +
+ + + {#if actions} +
e.stopPropagation()}> + {@render actions()} +
+ {/if} +
+
+ + diff --git a/packages/shared-ui/src/molecules/ModalFooter.svelte b/packages/shared-ui/src/molecules/ModalFooter.svelte new file mode 100644 index 000000000..2d7a96d96 --- /dev/null +++ b/packages/shared-ui/src/molecules/ModalFooter.svelte @@ -0,0 +1,85 @@ + + + diff --git a/packages/shared-ui/src/molecules/PageHeader.svelte b/packages/shared-ui/src/molecules/PageHeader.svelte new file mode 100644 index 000000000..e2bb74f1b --- /dev/null +++ b/packages/shared-ui/src/molecules/PageHeader.svelte @@ -0,0 +1,139 @@ + + + diff --git a/packages/shared-ui/src/molecules/index.ts b/packages/shared-ui/src/molecules/index.ts index dd03d9b1a..0c10faf53 100644 --- a/packages/shared-ui/src/molecules/index.ts +++ b/packages/shared-ui/src/molecules/index.ts @@ -19,3 +19,8 @@ export { SkeletonBox, SkeletonText } from './loaders'; // Feedback components export { EmptyState } from './feedback'; + +// Layout components +export { default as ModalFooter } from './ModalFooter.svelte'; +export { default as DataCard } from './DataCard.svelte'; +export { default as PageHeader } from './PageHeader.svelte'; diff --git a/packages/shared-ui/src/organisms/FormModal.svelte b/packages/shared-ui/src/organisms/FormModal.svelte new file mode 100644 index 000000000..e472394c9 --- /dev/null +++ b/packages/shared-ui/src/organisms/FormModal.svelte @@ -0,0 +1,117 @@ + + + +
+ + {#if error} +
+ + {error} + +
+ {/if} + + + {@render children()} +
+ + {#snippet footer()} +
+ + +
+ {/snippet} +
diff --git a/packages/shared-ui/src/organisms/index.ts b/packages/shared-ui/src/organisms/index.ts index 2dc96f6c6..893900c0e 100644 --- a/packages/shared-ui/src/organisms/index.ts +++ b/packages/shared-ui/src/organisms/index.ts @@ -1,4 +1,5 @@ export { default as Modal } from './Modal.svelte'; export { default as ConfirmationModal } from './ConfirmationModal.svelte'; +export { default as FormModal } from './FormModal.svelte'; export { default as AppSlider } from './AppSlider.svelte'; export type { AppItem } from './AppSlider.types';