diff --git a/package-lock.json b/package-lock.json index 621c331..47fa9c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.0.0-next.46", + "tailwind-merge": "^2.5.4", "tailwind-variants": "^0.3.0" }, "devDependencies": { diff --git a/package.json b/package.json index 2d02448..b601c35 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.0.0-next.46", + "tailwind-merge": "^2.5.4", "tailwind-variants": "^0.3.0" } } diff --git a/src/docs/components/Lorem.svelte b/src/docs/components/Lorem.svelte new file mode 100644 index 0000000..ead253f --- /dev/null +++ b/src/docs/components/Lorem.svelte @@ -0,0 +1,12 @@ + + +{#each Array(count) as i} +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. A ipsam tenetur accusantium impedit + beatae omnis necessitatibus. Voluptatum blanditiis libero impedit, harum eius inventore nihil, + officia voluptate dolorum error consequatur animi. +

+{/each} diff --git a/src/lib/common/use-context.svelte.ts b/src/lib/common/use-context.svelte.ts new file mode 100644 index 0000000..1679904 --- /dev/null +++ b/src/lib/common/use-context.svelte.ts @@ -0,0 +1,23 @@ +import { ContextKey } from '$lib/constants.js'; +import { withPrefix } from '$lib/utils.js'; +import { setContext, type Snippet } from 'svelte'; +import { SvelteMap } from 'svelte/reactivity'; + +export const withChildrenSnippets = (key: ContextKey) => { + const map = $state(new SvelteMap()); + + setContext(withPrefix(key), { + register: async (child: ContextKey, snippet: Snippet) => { + if (map.has(child)) { + console.warn(`Snippet with key ${child} already exists in the context`); + return; + } + + map.set(child, snippet); + }, + }); + + return { + getChildren: (key: ContextKey) => map.get(key), + }; +}; diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button/Button.svelte similarity index 100% rename from src/lib/components/Button.svelte rename to src/lib/components/Button/Button.svelte diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte deleted file mode 100644 index 347b255..0000000 --- a/src/lib/components/Card.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/src/lib/components/Card/Card.svelte b/src/lib/components/Card/Card.svelte new file mode 100644 index 0000000..dec9d82 --- /dev/null +++ b/src/lib/components/Card/Card.svelte @@ -0,0 +1,180 @@ + + +{#snippet header()} + {#if expandable} + + {:else} +
+ {@render headerChildren?.()} +
+ {/if} +{/snippet} + +{#snippet body()} +
+ {@render bodyChildren?.()} +
+{/snippet} + +{#snippet footer()} +
+ {@render footerChildren?.()} +
+{/snippet} + +
+ {#if headerChildren} + {@render header()} + {/if} + + {#if bodyChildren && expanded} + {@render body()} + {/if} + + {#if footerChildren} + {@render footer()} + {/if} + + {@render children()} +
diff --git a/src/lib/components/Card/CardBody.svelte b/src/lib/components/Card/CardBody.svelte new file mode 100644 index 0000000..c00b8bc --- /dev/null +++ b/src/lib/components/Card/CardBody.svelte @@ -0,0 +1,15 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/CardDescription.svelte b/src/lib/components/Card/CardDescription.svelte similarity index 100% rename from src/lib/components/CardDescription.svelte rename to src/lib/components/Card/CardDescription.svelte diff --git a/src/lib/components/Card/CardFooter.svelte b/src/lib/components/Card/CardFooter.svelte new file mode 100644 index 0000000..30328bf --- /dev/null +++ b/src/lib/components/Card/CardFooter.svelte @@ -0,0 +1,15 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/Card/CardHeader.svelte b/src/lib/components/Card/CardHeader.svelte new file mode 100644 index 0000000..904c72d --- /dev/null +++ b/src/lib/components/Card/CardHeader.svelte @@ -0,0 +1,15 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/CardTitle.svelte b/src/lib/components/Card/CardTitle.svelte similarity index 100% rename from src/lib/components/CardTitle.svelte rename to src/lib/components/Card/CardTitle.svelte diff --git a/src/lib/components/CardBody.svelte b/src/lib/components/CardBody.svelte deleted file mode 100644 index b92379b..0000000 --- a/src/lib/components/CardBody.svelte +++ /dev/null @@ -1,16 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/src/lib/components/CardFooter.svelte b/src/lib/components/CardFooter.svelte deleted file mode 100644 index 6c262f3..0000000 --- a/src/lib/components/CardFooter.svelte +++ /dev/null @@ -1,16 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/src/lib/components/CardHeader.svelte b/src/lib/components/CardHeader.svelte deleted file mode 100644 index 18fa1d2..0000000 --- a/src/lib/components/CardHeader.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/src/lib/components/Checkbox.svelte b/src/lib/components/Form/Checkbox.svelte similarity index 97% rename from src/lib/components/Checkbox.svelte rename to src/lib/components/Form/Checkbox.svelte index 23334d8..1ec85f6 100644 --- a/src/lib/components/Checkbox.svelte +++ b/src/lib/components/Form/Checkbox.svelte @@ -1,7 +1,7 @@ - - - {#if title} - {title} - {/if} - {#if description} - {description} - {/if} - - diff --git a/src/lib/components/Icon/Icon.svelte b/src/lib/components/Icon/Icon.svelte new file mode 100644 index 0000000..970a814 --- /dev/null +++ b/src/lib/components/Icon/Icon.svelte @@ -0,0 +1,52 @@ + + + + {#if title} + {title} + {/if} + {#if description} + {description} + {/if} + + + + diff --git a/src/lib/components/IconButton.svelte b/src/lib/components/IconButton/IconButton.svelte similarity index 53% rename from src/lib/components/IconButton.svelte rename to src/lib/components/IconButton/IconButton.svelte index 54d0c53..38f3dda 100644 --- a/src/lib/components/IconButton.svelte +++ b/src/lib/components/IconButton/IconButton.svelte @@ -1,11 +1,11 @@ - + diff --git a/src/lib/components/Logo.svelte b/src/lib/components/Logo/Logo.svelte similarity index 100% rename from src/lib/components/Logo.svelte rename to src/lib/components/Logo/Logo.svelte diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts deleted file mode 100644 index f967a29..0000000 --- a/src/lib/components/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { default as Button } from '$lib/components/Button.svelte'; -export { default as Card } from '$lib/components/Card.svelte'; -export { default as CardBody } from '$lib/components/CardBody.svelte'; -export { default as CardDescription } from '$lib/components/CardDescription.svelte'; -export { default as CardFooter } from '$lib/components/CardFooter.svelte'; -export { default as CardHeader } from '$lib/components/CardHeader.svelte'; -export { default as CardTitle } from '$lib/components/CardTitle.svelte'; -export { default as Checkbox } from '$lib/components/Checkbox.svelte'; -export { default as Icon } from '$lib/components/Icon.svelte'; -export { default as IconButton } from '$lib/components/IconButton.svelte'; -export { default as Input } from '$lib/components/Input.svelte'; -export { default as Label } from '$lib/components/Label.svelte'; -export { default as Logo } from '$lib/components/Logo.svelte'; diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 0000000..5e3aae0 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,6 @@ +export enum ContextKey { + Card = 'card', + CardHeader = 'card-header', + CardBody = 'card-body', + CardFooter = 'card-footer', +} diff --git a/src/lib/index.ts b/src/lib/index.ts index bb7d297..5e826bb 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1,14 @@ -export * from '$lib/components/index.js'; +export { default as Button } from '$lib/components/Button/Button.svelte'; +export { default as Card } from '$lib/components/Card/Card.svelte'; +export { default as CardBody } from '$lib/components/Card/CardBody.svelte'; +export { default as CardDescription } from '$lib/components/Card/CardDescription.svelte'; +export { default as CardFooter } from '$lib/components/Card/CardFooter.svelte'; +export { default as CardHeader } from '$lib/components/Card/CardHeader.svelte'; +export { default as CardTitle } from '$lib/components/Card/CardTitle.svelte'; +export { default as Checkbox } from '$lib/components/Form/Checkbox.svelte'; +export { default as Icon } from '$lib/components/Icon/Icon.svelte'; +export { default as IconButton } from '$lib/components/IconButton/IconButton.svelte'; +export { default as Input } from '$lib/components/Form/Input.svelte'; +export { default as Label } from '$lib/components/Form/Label.svelte'; +export { default as Logo } from '$lib/components/Logo/Logo.svelte'; export * from '$lib/types.js'; diff --git a/src/lib/internal/Child.svelte b/src/lib/internal/Child.svelte new file mode 100644 index 0000000..439b738 --- /dev/null +++ b/src/lib/internal/Child.svelte @@ -0,0 +1,20 @@ + diff --git a/src/lib/internal/InternalButton.svelte b/src/lib/internal/InternalButton.svelte index 106266e..03637a4 100644 --- a/src/lib/internal/InternalButton.svelte +++ b/src/lib/internal/InternalButton.svelte @@ -3,6 +3,7 @@ import { cleanClass } from '$lib/utils.js'; import { Button as ButtonPrimitive } from 'bits-ui'; import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'; + import { twMerge } from 'tailwind-merge'; import { tv } from 'tailwind-variants'; const buttonVariants = tv({ @@ -95,19 +96,21 @@ const classList = $derived( cleanClass( - buttonVariants({ - shape, - fullWidth, - textPadding: icon ? undefined : size, - textSize: size, - iconSize: icon ? size : undefined, - roundedSize: shape === 'semi-round' ? size : undefined, - filledColor: variant === 'filled' ? color : undefined, - outlineColor: variant === 'outline' ? color : undefined, - heroColor: variant === 'hero' ? color : undefined, - ghostColor: variant === 'ghost' ? color : undefined, - }), - className, + twMerge( + buttonVariants({ + shape, + fullWidth, + textPadding: icon ? undefined : size, + textSize: size, + iconSize: icon ? size : undefined, + roundedSize: shape === 'semi-round' ? size : undefined, + filledColor: variant === 'filled' ? color : undefined, + outlineColor: variant === 'outline' ? color : undefined, + heroColor: variant === 'hero' ? color : undefined, + ghostColor: variant === 'ghost' ? color : undefined, + }), + className, + ), ), ); diff --git a/src/lib/types.ts b/src/lib/types.ts index 079dfb2..4e794b6 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -3,6 +3,7 @@ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements export type Color = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'; export type Size = 'tiny' | 'small' | 'medium' | 'large' | 'giant'; export type Shape = 'rectangle' | 'semi-round' | 'round'; +export type Variants = 'filled' | 'outline' | 'ghost' | 'hero'; type ButtonOrAnchor = | ({ href?: never } & HTMLButtonAttributes) @@ -13,13 +14,25 @@ type ButtonBaseProps = { color?: Color; size?: Size; shape?: Shape; - variant?: 'filled' | 'outline' | 'ghost' | 'hero'; + variant?: Variants; } & ButtonOrAnchor; -export type IconButtonProps = ButtonBaseProps & { - /** icon from `@mdi/js` (svg string) */ +export type IconProps = { icon: string; + title?: string; + description?: string; + size?: string; + color?: Color | 'currentColor' | string; + flipped?: boolean; + flopped?: boolean; + spin?: boolean; + class?: string; + viewBox?: string; + strokeWidth?: number; + strokeColor?: string; }; + +export type IconButtonProps = ButtonBaseProps & IconProps; export type ButtonProps = ButtonBaseProps & { fullWidth?: boolean }; export type InternalButtonProps = ButtonProps & { /** when true, button width to height ratio is 1:1 */ diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 7c42b9d..1ec1c5c 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,3 +1,5 @@ +import type { ContextKey } from '$lib/constants.js'; + export const cleanClass = (...classNames: unknown[]) => { return classNames .filter((className) => { @@ -9,3 +11,5 @@ export const cleanClass = (...classNames: unknown[]) => { }) .join(' '); }; + +export const withPrefix = (key: ContextKey) => `immich-ui-${key}`; diff --git a/src/routes/examples/card/+page.svelte b/src/routes/examples/card/+page.svelte index f6d717f..728bf06 100644 --- a/src/routes/examples/card/+page.svelte +++ b/src/routes/examples/card/+page.svelte @@ -1,5 +1,7 @@ @@ -8,13 +10,9 @@
- -

- Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quibusdam maxime illo sequi - ipsam possimus rem harum nostrum esse itaque vero blanditiis eius sit ducimus - doloremque, omnis, assumenda mollitia officia aliquid. -

-
+ + Title +
@@ -22,11 +20,7 @@ Card with title -

- Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quibusdam maxime illo sequi - ipsam possimus rem harum nostrum esse itaque vero blanditiis eius sit ducimus - doloremque, omnis, assumenda mollitia officia aliquid. -

+
@@ -35,11 +29,7 @@ Card with title and footer -

- Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quibusdam maxime illo sequi - ipsam possimus rem harum nostrum esse itaque vero blanditiis eius sit ducimus - doloremque, omnis, assumenda mollitia officia aliquid. -

+
Footer goes here @@ -50,14 +40,62 @@ This is the description -

- Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quibusdam maxime illo sequi - ipsam possimus rem harum nostrum esse itaque vero blanditiis eius sit ducimus - doloremque, omnis, assumenda mollitia officia aliquid. -

+
Footer + +
+ {#each colors as color} + + + {color} + + + + + + {/each} +
+ +
+ {#each colors as color} + + + {color} + + + + + + {/each} +
+ +
+ {#each colors as color} + + + {color} + + + + + + {/each} +
+ +
+ {#each colors as color} + + + {color} + + + + + + {/each} +
{/snippet}