` (auto-imported) |
+| Stylesheet loading | Global import at app entry | Scoped per component, automatic |
+| Theme & colors | `createLapikit()` JS config | CSS custom properties (`:root { --kit-* }`) |
+| Breakpoints | Built into `createLapikit()` | Removed - handle with CSS media queries |
+| JS config file | `src/plugins/lapikit.(js\|ts)` | No longer needed - delete it |
+
+## And guide to migrating from version from 0.2.3 to 0.2.4
+
+Lapikit v0.2.4 introduced major changes to configuration, theming, and the CLI.
+
+### CLI changes
+
+| Before (β€ 0.2.3) | After (β₯ 0.2.4) |
+| ------------------ | --------------- |
+| `npx lapikit init` | `npx lapikit` |
+
+The CLI no longer needs `init`. Running `npx lapikit` will guide you through setup and automatically create your configuration files.
+
+By default, a config file is generated at `src/plugins/lapikit.(js|ts)`. This makes installation faster and ensures a consistent structure across projects.
+
+### New configuration format
+
+Lapikit now uses a single entry point: `createLapikit()`. This simplifies customization and centralizes everything in one place: themes, variables, breakpoints, and store integration.
+
+```typescript
+// src/plugins/lapikit.ts
+import createLapikit from 'lapikit';
+
+export default createLapikit({
+ breakpoints: {
+ devices: {
+ desktop: 1024,
+ tablet: 768,
+ mobile: 640
+
+
+ },
+ thresholds: {
+ base: 0,
+ xs: 448,
+ sm: 640,
+ md: 768,
+ lg: 1024,
+ xl: 1280,
+ '2xl': 1536,
+ '3xl': 1792
+ }
+ },
+ theme: {
+ defaultTheme: 'light',
+ colorScheme: true,
+ themes: {
+ light: {
+ dark: false,
+ colors: {
+ label: {
+ primary: '#000000'
+ }
+ }
+ }
+ },
+ variables: {
+ 'test-variable': '1rem'
+ }
+ },
+ typography: {
+ defaultTypography: 'default',
+ fonts: {
+ default: {
+ serif: ['Merriweather', 'Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif']
+ }
+ }
+ },
+ styles: {
+ spacing: '0.125rem',
+ shape: {
+ sm: '0.125rem'
+ }
+ }
+});
+```
+
+### Breakpoints and hooks
+
+Breakpoints were restructured for clarity and consistency.
+
+| Before (β€ 0.2.3) | After (β₯ 0.2.4) |
+| ---------------------------------------------------------- | -------------------------------------- |
+| `mobileBreakpoint`, `tabletBreakpoint`, `laptopBreakpoint` | `devices: { mobile, tablet, desktop }` |
+
+Breakpoints moved from `rem` to `px`. Lapikit also exposed runes to access breakpoints directly in JS/TS, allowing you to show or hide elements dynamically without relying only on CSS.
+
+### Theming system
+
+The theme system became more modular: each theme is independent and can override colors, tokens, and variables. Light and dark modes can be toggled globally or per component.
+
+### Device utility classes
+
+| Before (β€ 0.2.3) | After (β₯ 0.2.4) |
+| ------------------------------------------------------ | -------------------------------------------------------------------------- |
+| `.hidden-mobile`, `.display-tablet`, `.display-laptop` | `.kit-device--d-mobile`, `.kit-device--h-tablet`, `.kit-device--h-desktop` |
+
+`d` = display, `h` = hide.
+
+### Migration steps summary from 0.2.3 to 0.2.4
+
+1. Replace `npx lapikit init` with `npx lapikit`.
+2. Move your config to `src/plugins/lapikit.(js|ts)`.
+3. Wrap your config in `createLapikit()`.
+4. Update breakpoints to use `devices` and `thresholds`.
+5. Replace `.hidden-*` and `.display-*` classes with `.kit-device--*`.
+6. Update your theme and font structure.
+7. Restart your dev server.
+
+---
+
+## Need help?
+
+You can find detailed release notes and discussions on [Lapikit GitHub Releases](https://github.com/lapikit/lapikit/releases).
+
+If something doesn't work after migration, [open an issue](https://github.com/lapikit/lapikit/issues) or join the discussion on Discord. The community is active and always open to feedback.
diff --git a/src/content/docs/roadmap.md b/src/content/docs/roadmap.md
new file mode 100644
index 00000000..eb590c66
--- /dev/null
+++ b/src/content/docs/roadmap.md
@@ -0,0 +1,88 @@
+---
+title: "roadmap"
+description: "Discover the future developments and enhancements planned for Lapikit. Stay informed about upcoming features and improvements to our component library."
+---
+
+Lapikit keeps moving forward. This page gives you a clear view of whatβs coming next: new components, design updates, and small things that make your workflow smoother. The goal stays the same: keep Lapikit simple, fast, and built for you developers.
+
+## Changes planned for 2026
+
+2026 marks a new phase for Lapikit, with a clear focus:
+Improve integration, strengthen fundamentals, and enrich the ecosystem without complicating the API.
+
+**New core: Lili v1**
+
+Lapikit will introduce **Lili v1**, a new preprocessor Svelte.
+
+Objectives:
+
+- Facilitate the integration of components into existing projects
+- Offer greater flexibility in terms of styles and composition
+- Open the door to new possibilities in terms of tooling.
+
+More details will be shared as it develops.
+
+New components
+
+Strengthening form components, essential for real-world applications :
+
+- **Radio** manages exclusive choices in forms with accessible radio buttons.
+- **Select** is a simple and customizable selection component for drop-down lists.
+- **Checkbox** allows you to enable or disable options via clear and consistent checkboxes.
+- **Input files** selects and manages files with complete style control.
+- **Input textarea** is a multi-line input field for long content and advanced forms.
+
+Simple, accessible components that are consistent with the rest of Lapikit.
+
+Helpers
+
+Added lightweight helpers to avoid repetition in projects:
+
+- Format number offers the possibility to round and shorten numbers
+- Capitalize allows you to capitalize the first letter of a word or sentence
+
+The goal is not to replace a utility library, but to cover common cases.
+
+Internal Helpers
+
+Improvement of internal tools for greater consistency and maintainability:
+
+- ClassName helper will be as close as possible to Svelte class management
+- Centralized style management that will offer the same possibilities as Svelte's style props
+
+Continuous development
+
+Other features may be added during the year.
+Ideas, suggestions, and contributions are welcome. Suggest a feature, start a discussion, or contribute directly on [GitHub](https://github.com/lapikit/lapikit).
+
+Whatβs next steps
+
+After these updates, the focus will shift to: you can track progress on [GitHub](https://github.com/lapikit/lapikit) and join discussions about whatβs next on [Discord](https://discord.gg/gn9ZGtDtK4).
+
+## Contribute to the Lapikit library and it's development
+
+Lapikit is 100% open source. If you want to help out, open a feature request, suggest an idea, or report an issue, you can participate on [GitHub](https://github.com/lapikit/lapikit). Every contribution helps make Svelte's development faster and cleaner for everyone. Your feedback is important!
+
+## History roadmap to Lapikit
+
+**2025**
+
+### Components developed in 2025
+
+- **Alert** are display important messages on your application
+- **App** are define the structure and integration of lapikit tools in your application
+- **Button** are offer link and action management in your application
+- **Card** are display blocks to format your content
+- **Chip** are other types of actions and labeling
+- **Dialog** are display dialog boxes via lapikit (ISO HTML5 dialog element)
+- **Separator** are simple layout divider with more utility
+- **Accordion** are accordion content display management with aria support
+- **Icon** are extended icon library with lighter imports
+- **List** are better variants for menus and structured data
+- **Dropdown** are contextual menu for your application
+- **AspectRatio** are more responsive scaling options
+- **Toolbar** are toolbar to display actions within your application
+- **Tooltip** are when a user hovers over or clicks on a ui element a tiny information message boxes appear
+- **Avatar** are display user profiles via letters or images
+- **Popover** are advanced context menu for greater customization freedom
+- **Modal** are advanced dialog box, with multiple dialog box management and new customization options
diff --git a/src/content/examples/addons/component-without-preprocessor.svelte b/src/content/examples/addons/component-without-preprocessor.svelte
new file mode 100644
index 00000000..dc2f4a4a
--- /dev/null
+++ b/src/content/examples/addons/component-without-preprocessor.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {#snippet activator({ toggle, open }: ModelDropdownProps)}
+ toggle(e.currentTarget)}>
+ {#if open}
+ Component Open
+ {:else}
+ Component Close
+ {/if}
+
+ {/snippet}
+
+
+ Lapikit
+ Is
+ Magic !
+
+
diff --git a/src/content/examples/addons/eslint-config-lapikit.js b/src/content/examples/addons/eslint-config-lapikit.js
new file mode 100644
index 00000000..ee40b496
--- /dev/null
+++ b/src/content/examples/addons/eslint-config-lapikit.js
@@ -0,0 +1,6 @@
+import lapikitConfig from 'eslint-config-lapikit';
+
+export default [
+ ...lapikitConfig
+ // rest of your config
+];
diff --git a/src/content/examples/addons/eslint-config-no-unused-vars.js b/src/content/examples/addons/eslint-config-no-unused-vars.js
new file mode 100644
index 00000000..98016796
--- /dev/null
+++ b/src/content/examples/addons/eslint-config-no-unused-vars.js
@@ -0,0 +1,15 @@
+import lapikitConfig from 'eslint-config-lapikit';
+
+export default [
+ ...lapikitConfig, // first
+ {
+ rules: {
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ {
+ // your custom options here
+ }
+ ]
+ }
+ }
+];
diff --git a/src/content/examples/addons/tsconfig-compiler-options.json b/src/content/examples/addons/tsconfig-compiler-options.json
new file mode 100644
index 00000000..0ec48026
--- /dev/null
+++ b/src/content/examples/addons/tsconfig-compiler-options.json
@@ -0,0 +1,5 @@
+{
+ "compilerOptions": {
+ "noUnusedLocals": false
+ }
+}
diff --git a/src/content/examples/components/accordion/activator.svelte b/src/content/examples/components/accordion/activator.svelte
new file mode 100644
index 00000000..0b145a94
--- /dev/null
+++ b/src/content/examples/components/accordion/activator.svelte
@@ -0,0 +1,38 @@
+
+
+
+
+ {#snippet activator()}
+
+
+
+ Design tokens
+ Colors, spacing, radius
+
+
+ {/snippet}
+
+ Lapikit uses CSS custom properties for colors, spacing, and radius - making theming
+ straightforward without overriding component internals.
+
+
+
+ {#snippet activator()}
+
+
+
+ Preprocessor
+ kit:* syntax at build time
+
+
+ {/snippet}
+
+ The preprocessor transforms kit:* syntax into native Svelte components at build time,
+ with zero runtime overhead.
+
+
diff --git a/src/content/examples/components/accordion/basic.svelte b/src/content/examples/components/accordion/basic.svelte
new file mode 100644
index 00000000..12fa098a
--- /dev/null
+++ b/src/content/examples/components/accordion/basic.svelte
@@ -0,0 +1,49 @@
+
+
+
+
+ Lapikit is a Svelte component library designed to help you build modern, accessible, and
+ customizable user interfaces with minimal effort.
+
+
+
+ Install the package via npm: npm install lapikit, then import the components you
+ need directly into your Svelte files.
+
+
+
+ Yes, all components comply with ARIA standards. In particular, the AccordionItem uses aria-expanded
+ and aria-disabled to ensure proper keyboard navigation.
+
+
+
+ This content is not available because the item is disabled.
+
+
diff --git a/src/content/examples/components/accordion/hide-icon.svelte b/src/content/examples/components/accordion/hide-icon.svelte
new file mode 100644
index 00000000..a1984aee
--- /dev/null
+++ b/src/content/examples/components/accordion/hide-icon.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+ The chevron icon is hidden on all items when hideIcon is set on the parent
+ kit:accordion.
+
+
+
+ hideIcon applies globally to every child item via a CSS rule on the container.
+
+
diff --git a/src/content/examples/components/accordion/indicator.svelte b/src/content/examples/components/accordion/indicator.svelte
new file mode 100644
index 00000000..b27298e7
--- /dev/null
+++ b/src/content/examples/components/accordion/indicator.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+ {#snippet indicator({ open }: ModelAccordionItemProps)}
+
+ {#if open}
+
+ {:else}
+
+ {/if}
+
+ {/snippet}
+ Lapikit is a Svelte component library designed to help you build modern, accessible, and customizable
+ user interfaces with minimal effort.
+
+
+
+ {#snippet indicator({ open }: ModelAccordionItemProps)}
+
+ {#if open}
+
+ {:else}
+
+ {/if}
+
+ {/snippet}
+ Install the package via npm: npm install lapikit, then import the components you
+ need directly into your Svelte files.
+
+
diff --git a/src/content/examples/components/accordion/multiple.svelte b/src/content/examples/components/accordion/multiple.svelte
new file mode 100644
index 00000000..4c401799
--- /dev/null
+++ b/src/content/examples/components/accordion/multiple.svelte
@@ -0,0 +1,39 @@
+
+
+
+ {#each items as item (item)}
+
+ {item.content}
+
+ {/each}
+
diff --git a/src/content/examples/components/accordion/preview.svelte b/src/content/examples/components/accordion/preview.svelte
new file mode 100644
index 00000000..59df97db
--- /dev/null
+++ b/src/content/examples/components/accordion/preview.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+ Lapikit is a Svelte component library designed to help you build modern, accessible, and
+ customizable user interfaces with minimal effort.
+
+
+
+ Install the package via npm: npm install lapikit, then import the components you
+ need directly into your Svelte files.
+
+
diff --git a/src/content/examples/components/accordion/read-only.svelte b/src/content/examples/components/accordion/read-only.svelte
new file mode 100644
index 00000000..74c4f00f
--- /dev/null
+++ b/src/content/examples/components/accordion/read-only.svelte
@@ -0,0 +1,37 @@
+
+
+
+
+ This item is open by default and cannot be collapsed. Use readOnly to lock an item
+ in its current state without applying disabled styling.
+
+
+
+ This item can be toggled normally.
+
+
+
+ This content is unreachable because the item is disabled.
+
+
diff --git a/src/content/examples/components/accordion/spacer.svelte b/src/content/examples/components/accordion/spacer.svelte
new file mode 100644
index 00000000..e75053b8
--- /dev/null
+++ b/src/content/examples/components/accordion/spacer.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+ Lapikit is a Svelte component library designed to help you build modern, accessible, and
+ customizable user interfaces with minimal effort.
+
+
+
+ Install the package via npm: npm install lapikit, then import the components you
+ need directly into your Svelte files.
+
+
diff --git a/src/content/examples/components/alert/closable.svelte b/src/content/examples/components/alert/closable.svelte
new file mode 100644
index 00000000..2ee84acc
--- /dev/null
+++ b/src/content/examples/components/alert/closable.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+ Dismiss this alert by clicking the close button.
+
+
+ {#if !open}
+ (open = true)}>Restore alert
+ {/if}
+
diff --git a/src/content/examples/components/alert/close.svelte b/src/content/examples/components/alert/close.svelte
new file mode 100644
index 00000000..11447e9a
--- /dev/null
+++ b/src/content/examples/components/alert/close.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {#snippet close()}
+
+ {/snippet}
+ Custom close button with an icon from lucide-svelte.
+
diff --git a/src/content/examples/components/alert/density.svelte b/src/content/examples/components/alert/density.svelte
new file mode 100644
index 00000000..87a3fce2
--- /dev/null
+++ b/src/content/examples/components/alert/density.svelte
@@ -0,0 +1,5 @@
+
+ Compact β reduced padding, tighter layout.
+ Default β standard padding.
+ Comfortable β more breathing room around the content.
+
diff --git a/src/content/examples/components/alert/prepend-append.svelte b/src/content/examples/components/alert/prepend-append.svelte
new file mode 100644
index 00000000..fc015b58
--- /dev/null
+++ b/src/content/examples/components/alert/prepend-append.svelte
@@ -0,0 +1,19 @@
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+
+ Your account is verified and secure.
+
+ {#snippet append()}
+
+ Details
+
+ {/snippet}
+
diff --git a/src/content/examples/components/alert/preview.svelte b/src/content/examples/components/alert/preview.svelte
new file mode 100644
index 00000000..933d864b
--- /dev/null
+++ b/src/content/examples/components/alert/preview.svelte
@@ -0,0 +1,33 @@
+
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Your session will expire in 10 minutes. Save your work.
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Changes saved successfully.
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ This action cannot be undone.
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Failed to connect to the server. Please try again.
+
+
diff --git a/src/content/examples/components/alert/tones.svelte b/src/content/examples/components/alert/tones.svelte
new file mode 100644
index 00000000..e73bd63f
--- /dev/null
+++ b/src/content/examples/components/alert/tones.svelte
@@ -0,0 +1,7 @@
+
+ Default tone β neutral feedback or general information.
+ Info tone β informational messages and tips.
+ Success tone β operation completed successfully.
+ Warning tone β potential issue that needs attention.
+ Error tone β something went wrong, action required.
+
diff --git a/src/content/examples/components/alert/variants.svelte b/src/content/examples/components/alert/variants.svelte
new file mode 100644
index 00000000..08dd0e3c
--- /dev/null
+++ b/src/content/examples/components/alert/variants.svelte
@@ -0,0 +1,5 @@
+
+ Filled β default background with tone color.
+ Outline β transparent background with a colored left border.
+ Text β no background or border, tone color only.
+
diff --git a/src/content/examples/components/appbar/class-content.svelte b/src/content/examples/components/appbar/class-content.svelte
new file mode 100644
index 00000000..e5e6e29c
--- /dev/null
+++ b/src/content/examples/components/appbar/class-content.svelte
@@ -0,0 +1,14 @@
+
+ Lapikit
+
+ Docs
+ Components
+
+
+
+
diff --git a/src/content/examples/components/appbar/density.svelte b/src/content/examples/components/appbar/density.svelte
new file mode 100644
index 00000000..a10f3ce1
--- /dev/null
+++ b/src/content/examples/components/appbar/density.svelte
@@ -0,0 +1,16 @@
+
+
+ Compact
+ 3.5rem height
+
+
+
+ Default
+ 4rem height
+
+
+
+ Comfortable
+ 4.5rem height
+
+
diff --git a/src/content/examples/components/appbar/preview.svelte b/src/content/examples/components/appbar/preview.svelte
new file mode 100644
index 00000000..578d9e0d
--- /dev/null
+++ b/src/content/examples/components/appbar/preview.svelte
@@ -0,0 +1,21 @@
+
+
+
+ Lapikit
+
+
+ Docs
+ Components
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/appbar/variants.svelte b/src/content/examples/components/appbar/variants.svelte
new file mode 100644
index 00000000..168b7c72
--- /dev/null
+++ b/src/content/examples/components/appbar/variants.svelte
@@ -0,0 +1,16 @@
+
+
+ Filled
+ default background
+
+
+
+ Outline
+ transparent + border
+
+
+
+ Text
+ no background, no border
+
+
diff --git a/src/content/examples/components/application/root.svelte b/src/content/examples/components/application/root.svelte
new file mode 100644
index 00000000..24d0399a
--- /dev/null
+++ b/src/content/examples/components/application/root.svelte
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/apps/website/src/lib/components/docs/application/application-base.svelte b/src/content/examples/components/application/with-classic-import.svelte
similarity index 57%
rename from apps/website/src/lib/components/docs/application/application-base.svelte
rename to src/content/examples/components/application/with-classic-import.svelte
index 71faf17f..293f4947 100644
--- a/apps/website/src/lib/components/docs/application/application-base.svelte
+++ b/src/content/examples/components/application/with-classic-import.svelte
@@ -2,4 +2,8 @@
import { App } from 'lapikit/components';
-your content here
+
+
+
+
+
diff --git a/src/content/examples/components/aspect-ratio/fit.svelte b/src/content/examples/components/aspect-ratio/fit.svelte
new file mode 100644
index 00000000..6a28ccd2
--- /dev/null
+++ b/src/content/examples/components/aspect-ratio/fit.svelte
@@ -0,0 +1,12 @@
+
+ {#each ['cover', 'contain', 'fill'] as f (f)}
+
+
+
+
+
{f}
+
+ {/each}
+
diff --git a/src/content/examples/components/aspect-ratio/inline.svelte b/src/content/examples/components/aspect-ratio/inline.svelte
new file mode 100644
index 00000000..11626713
--- /dev/null
+++ b/src/content/examples/components/aspect-ratio/inline.svelte
@@ -0,0 +1,7 @@
+
+ Inline usage sits inside text flow:
+
+
+
+ and continues alongside content.
+
diff --git a/src/content/examples/components/aspect-ratio/preview.svelte b/src/content/examples/components/aspect-ratio/preview.svelte
new file mode 100644
index 00000000..4038af40
--- /dev/null
+++ b/src/content/examples/components/aspect-ratio/preview.svelte
@@ -0,0 +1,6 @@
+
+
+
diff --git a/src/content/examples/components/aspect-ratio/ratios.svelte b/src/content/examples/components/aspect-ratio/ratios.svelte
new file mode 100644
index 00000000..80da9f9f
--- /dev/null
+++ b/src/content/examples/components/aspect-ratio/ratios.svelte
@@ -0,0 +1,12 @@
+
+ {#each [['16/9', 'alpine'], ['4/3', 'forest'], ['1/1', 'city'], ['9/16', 'portrait']] as [r, seed] (r)}
+
+
+
+
+
{r}
+
+ {/each}
+
diff --git a/src/content/examples/components/avatar/density.svelte b/src/content/examples/components/avatar/density.svelte
new file mode 100644
index 00000000..9177ad3c
--- /dev/null
+++ b/src/content/examples/components/avatar/density.svelte
@@ -0,0 +1,8 @@
+
+ {#each ['compact', 'default', 'comfortable'] as density (density)}
+
+
+ {density}
+
+ {/each}
+
diff --git a/src/content/examples/components/avatar/image.svelte b/src/content/examples/components/avatar/image.svelte
new file mode 100644
index 00000000..85dda0e2
--- /dev/null
+++ b/src/content/examples/components/avatar/image.svelte
@@ -0,0 +1,7 @@
+
+ {#each ['avatar1', 'avatar2', 'avatar3', 'avatar4'] as seed (seed)}
+
+
+
+ {/each}
+
diff --git a/src/content/examples/components/avatar/label.svelte b/src/content/examples/components/avatar/label.svelte
new file mode 100644
index 00000000..6708aab4
--- /dev/null
+++ b/src/content/examples/components/avatar/label.svelte
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/content/examples/components/avatar/preview.svelte b/src/content/examples/components/avatar/preview.svelte
new file mode 100644
index 00000000..da71b0e4
--- /dev/null
+++ b/src/content/examples/components/avatar/preview.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/avatar/size.svelte b/src/content/examples/components/avatar/size.svelte
new file mode 100644
index 00000000..f3602454
--- /dev/null
+++ b/src/content/examples/components/avatar/size.svelte
@@ -0,0 +1,8 @@
+
+ {#each ['xs', 'sm', 'md', 'lg', 'xl'] as size (size)}
+
+
+ {size}
+
+ {/each}
+
diff --git a/src/content/examples/components/btn/as-link.svelte b/src/content/examples/components/btn/as-link.svelte
new file mode 100644
index 00000000..e22b3b8f
--- /dev/null
+++ b/src/content/examples/components/btn/as-link.svelte
@@ -0,0 +1,16 @@
+
+
+
+ Go to docs
+
+
+ Documentation
+ {#snippet append()}
+
+ {/snippet}
+
+
+ Read more
+
diff --git a/src/content/examples/components/btn/block.svelte b/src/content/examples/components/btn/block.svelte
new file mode 100644
index 00000000..cd829b1f
--- /dev/null
+++ b/src/content/examples/components/btn/block.svelte
@@ -0,0 +1,6 @@
+
+
Block β full width
+
+ Wide β capped at 16rem
+
+
diff --git a/src/content/examples/components/btn/icon.svelte b/src/content/examples/components/btn/icon.svelte
new file mode 100644
index 00000000..c6e47340
--- /dev/null
+++ b/src/content/examples/components/btn/icon.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/btn/prepend-append.svelte b/src/content/examples/components/btn/prepend-append.svelte
new file mode 100644
index 00000000..a87893a1
--- /dev/null
+++ b/src/content/examples/components/btn/prepend-append.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Upload
+
+
+
+ Options
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+ Continue
+ {#snippet append()}
+
+ {/snippet}
+
+
diff --git a/src/content/examples/components/btn/preview.svelte b/src/content/examples/components/btn/preview.svelte
new file mode 100644
index 00000000..2e461d28
--- /dev/null
+++ b/src/content/examples/components/btn/preview.svelte
@@ -0,0 +1,22 @@
+
+
+
+ Default
+ Filled
+ Outline
+ Text
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Download
+
+
+ {#snippet append()}
+
+ {/snippet}
+ Contact
+
+
diff --git a/src/content/examples/components/btn/size.svelte b/src/content/examples/components/btn/size.svelte
new file mode 100644
index 00000000..e736847c
--- /dev/null
+++ b/src/content/examples/components/btn/size.svelte
@@ -0,0 +1,5 @@
+
+ {#each ['xs', 'sm', 'md', 'lg', 'xl'] as size}
+ {size}
+ {/each}
+
diff --git a/src/content/examples/components/btn/states.svelte b/src/content/examples/components/btn/states.svelte
new file mode 100644
index 00000000..bbd29be0
--- /dev/null
+++ b/src/content/examples/components/btn/states.svelte
@@ -0,0 +1,17 @@
+
+
+
+ Disabled
+ Disabled
+ Active
+
+ {loading ? 'Loadingβ¦' : 'Click me'}
+
+
diff --git a/src/content/examples/components/btn/variants.svelte b/src/content/examples/components/btn/variants.svelte
new file mode 100644
index 00000000..5e1c80e8
--- /dev/null
+++ b/src/content/examples/components/btn/variants.svelte
@@ -0,0 +1,6 @@
+
+ Filled
+ Outline
+ Text
+ Link
+
diff --git a/src/content/examples/components/card/density.svelte b/src/content/examples/components/card/density.svelte
new file mode 100644
index 00000000..7ef1591d
--- /dev/null
+++ b/src/content/examples/components/card/density.svelte
@@ -0,0 +1,8 @@
+
+ {#each ['compact', 'default', 'comfortable'] as density (density)}
+
+
+ Padding adjusts with density.
+
+ {/each}
+
diff --git a/src/content/examples/components/card/interactive.svelte b/src/content/examples/components/card/interactive.svelte
new file mode 100644
index 00000000..14038e3a
--- /dev/null
+++ b/src/content/examples/components/card/interactive.svelte
@@ -0,0 +1,11 @@
+
+
+
+ Interactive via href β renders as <a> with hover lift.
+
+
+
+
+ Hover lift and ripple via interactive prop β stays as <div>.
+
+
diff --git a/src/content/examples/components/card/preview.svelte b/src/content/examples/components/card/preview.svelte
new file mode 100644
index 00000000..36ff26ca
--- /dev/null
+++ b/src/content/examples/components/card/preview.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ A breathtaking trail through alpine meadows and rocky peaks.
+
+
+
+
+
+
+ Dense canopy, mossy rocks, and the sound of a distant waterfall.
+
+
+
diff --git a/src/content/examples/components/card/structure.svelte b/src/content/examples/components/card/structure.svelte
new file mode 100644
index 00000000..e09f5067
--- /dev/null
+++ b/src/content/examples/components/card/structure.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+ Learn how to install Lapikit and set up the preprocessor in your Svelte project.
+
+
+
+
diff --git a/src/content/examples/components/card/variants.svelte b/src/content/examples/components/card/variants.svelte
new file mode 100644
index 00000000..69972467
--- /dev/null
+++ b/src/content/examples/components/card/variants.svelte
@@ -0,0 +1,16 @@
+
+
+
+ Accent background with white text.
+
+
+
+
+ Transparent background with accent border.
+
+
+
+
+ No background or border, accent text only.
+
+
diff --git a/src/content/examples/components/chip/label-style.svelte b/src/content/examples/components/chip/label-style.svelte
new file mode 100644
index 00000000..97908fa7
--- /dev/null
+++ b/src/content/examples/components/chip/label-style.svelte
@@ -0,0 +1,6 @@
+
+ New
+ Beta
+ Deprecated
+ Pro
+
diff --git a/src/content/examples/components/chip/prepend-append.svelte b/src/content/examples/components/chip/prepend-append.svelte
new file mode 100644
index 00000000..6fbd4ab8
--- /dev/null
+++ b/src/content/examples/components/chip/prepend-append.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Label
+
+
+
+ {#snippet prepend()}
+
+ {/snippet}
+ Verified
+
+
+ {#each tags as tag (tag)}
+
+ {tag}
+ {#snippet append()}
+ remove(tag)}>
+
+
+ {/snippet}
+
+ {/each}
+
diff --git a/src/content/examples/components/chip/preview.svelte b/src/content/examples/components/chip/preview.svelte
new file mode 100644
index 00000000..1bb5576e
--- /dev/null
+++ b/src/content/examples/components/chip/preview.svelte
@@ -0,0 +1,16 @@
+
+
+
+ {#each filters as f (f)}
+ (active = f)}
+ >
+ {f}
+
+ {/each}
+
diff --git a/src/content/examples/components/chip/size.svelte b/src/content/examples/components/chip/size.svelte
new file mode 100644
index 00000000..ff891eb1
--- /dev/null
+++ b/src/content/examples/components/chip/size.svelte
@@ -0,0 +1,5 @@
+
+ {#each ['xs', 'sm', 'md', 'lg', 'xl'] as size (size)}
+ {size}
+ {/each}
+
diff --git a/src/content/examples/components/chip/states.svelte b/src/content/examples/components/chip/states.svelte
new file mode 100644
index 00000000..fb680fad
--- /dev/null
+++ b/src/content/examples/components/chip/states.svelte
@@ -0,0 +1,6 @@
+
+ Active
+ Disabled
+ Readonly
+ Disabled filled
+
diff --git a/src/content/examples/components/chip/variants.svelte b/src/content/examples/components/chip/variants.svelte
new file mode 100644
index 00000000..bc1b246f
--- /dev/null
+++ b/src/content/examples/components/chip/variants.svelte
@@ -0,0 +1,6 @@
+
+ Filled
+ Outline
+ Text
+ Link
+
diff --git a/src/content/examples/components/dialog/persistent.svelte b/src/content/examples/components/dialog/persistent.svelte
new file mode 100644
index 00000000..4e02e8ad
--- /dev/null
+++ b/src/content/examples/components/dialog/persistent.svelte
@@ -0,0 +1,16 @@
+
+
+ (open = true)}>Open persistent dialog
+
+
+ Unsaved changes
+
+ Clicking outside won't close this dialog. You must choose an action.
+
+
+ (open = false)}>Discard
+ (open = false)}>Save
+
+
diff --git a/src/content/examples/components/dialog/position.svelte b/src/content/examples/components/dialog/position.svelte
new file mode 100644
index 00000000..23cdc555
--- /dev/null
+++ b/src/content/examples/components/dialog/position.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {#each ['top', 'center', 'bottom'] as p (p)}
+ show(p as 'top' | 'center' | 'bottom')}>
+ {p}
+
+ {/each}
+
+
+
+ Dialog positioned at {position} .
+ (open = false)}>Close
+
diff --git a/src/content/examples/components/dialog/preview.svelte b/src/content/examples/components/dialog/preview.svelte
new file mode 100644
index 00000000..45e16c7f
--- /dev/null
+++ b/src/content/examples/components/dialog/preview.svelte
@@ -0,0 +1,16 @@
+
+
+ (open = true)}>Open dialog
+
+
+ Confirm action
+
+ Are you sure you want to continue? This action cannot be undone.
+
+
+ (open = false)}>Cancel
+ (open = false)}>Confirm
+
+
diff --git a/src/content/examples/components/dialog/size.svelte b/src/content/examples/components/dialog/size.svelte
new file mode 100644
index 00000000..5774b5a1
--- /dev/null
+++ b/src/content/examples/components/dialog/size.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {#each ['xs', 'sm', 'md', 'lg', 'xl'] as s (s)}
+ show(s as 'xs' | 'sm' | 'md' | 'lg' | 'xl')}>
+ {s}
+
+ {/each}
+
+
+
+ Size: {size}
+ (open = false)}>Close
+
diff --git a/src/content/examples/components/dropdown/hover.svelte b/src/content/examples/components/dropdown/hover.svelte
new file mode 100644
index 00000000..9573b33e
--- /dev/null
+++ b/src/content/examples/components/dropdown/hover.svelte
@@ -0,0 +1,29 @@
+
+
+
+ {#snippet activator({ open, toggle }: ModelDropdownProps, handleMouse: ModelDropdownHandleProps)}
+ toggle(e.currentTarget as HTMLElement)}
+ onmouseenter={(e: MouseEvent) => handleMouse('open', e.currentTarget as HTMLElement)}
+ onmouseleave={() => handleMouse('close', null)}
+ >
+ Hover me
+ {#snippet append()}
+
+ {/snippet}
+
+ {/snippet}
+
+
+ Option 1
+ Option 2
+ Option 3
+
+
diff --git a/src/content/examples/components/dropdown/position.svelte b/src/content/examples/components/dropdown/position.svelte
new file mode 100644
index 00000000..cd4caf6e
--- /dev/null
+++ b/src/content/examples/components/dropdown/position.svelte
@@ -0,0 +1,27 @@
+
+
+
+ {#each ['top', 'bottom', 'left', 'right'] as pos (pos)}
+
+ {#snippet activator({ open, toggle }: ModelDropdownProps)}
+ toggle(e.currentTarget as HTMLElement)}
+ >
+ {pos}
+
+ {/snippet}
+
+ Item A
+ Item B
+ Item C
+
+
+ {/each}
+
diff --git a/src/content/examples/components/dropdown/preview.svelte b/src/content/examples/components/dropdown/preview.svelte
new file mode 100644
index 00000000..cf69b396
--- /dev/null
+++ b/src/content/examples/components/dropdown/preview.svelte
@@ -0,0 +1,31 @@
+
+
+
+ {#snippet activator({ open, toggle }: ModelDropdownProps)}
+ toggle(e.currentTarget as HTMLElement)}>
+ Account
+ {#snippet append()}
+
+ {/snippet}
+
+ {/snippet}
+
+
+
+ {#snippet prepend()} {/snippet}
+ Profile
+
+
+ {#snippet prepend()} {/snippet}
+ Settings
+
+
+ {#snippet prepend()} {/snippet}
+ Sign out
+
+
+
diff --git a/src/content/examples/components/icon/color.svelte b/src/content/examples/components/icon/color.svelte
new file mode 100644
index 00000000..365ddb37
--- /dev/null
+++ b/src/content/examples/components/icon/color.svelte
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/icon/preview.svelte b/src/content/examples/components/icon/preview.svelte
new file mode 100644
index 00000000..83a06060
--- /dev/null
+++ b/src/content/examples/components/icon/preview.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/icon/size.svelte b/src/content/examples/components/icon/size.svelte
new file mode 100644
index 00000000..94f7dfa9
--- /dev/null
+++ b/src/content/examples/components/icon/size.svelte
@@ -0,0 +1,12 @@
+
+
+
+ {#each ['xs', 'sm', 'md', 'lg', 'xl'] as size (size)}
+
+
+ {size}
+
+ {/each}
+
diff --git a/src/content/examples/components/icon/src.svelte b/src/content/examples/components/icon/src.svelte
new file mode 100644
index 00000000..b6a010b4
--- /dev/null
+++ b/src/content/examples/components/icon/src.svelte
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/src/content/examples/components/list/nav.svelte b/src/content/examples/components/list/nav.svelte
new file mode 100644
index 00000000..f650736b
--- /dev/null
+++ b/src/content/examples/components/list/nav.svelte
@@ -0,0 +1,6 @@
+
+ Documentation
+ Components
+ Hooks
+ Changelog
+
diff --git a/src/content/examples/components/list/prepend-append.svelte b/src/content/examples/components/list/prepend-append.svelte
new file mode 100644
index 00000000..016d6b06
--- /dev/null
+++ b/src/content/examples/components/list/prepend-append.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+ {#snippet prepend()} {/snippet}
+ Profile
+ {#snippet append()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+ Email
+ {#snippet append()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+ Phone
+ {#snippet append()} {/snippet}
+
+
diff --git a/src/content/examples/components/list/preview.svelte b/src/content/examples/components/list/preview.svelte
new file mode 100644
index 00000000..1d72c018
--- /dev/null
+++ b/src/content/examples/components/list/preview.svelte
@@ -0,0 +1,30 @@
+
+
+
+ {#each items as item (item.icon)}
+ (active = item.label)}>
+ {#snippet prepend()}
+ {@const Icon = item.icon}
+
+ {/snippet}
+ {item.label}
+ {#if item.count}
+ {#snippet append()}
+ {item.count}
+ {/snippet}
+ {/if}
+
+ {/each}
+
diff --git a/src/content/examples/components/list/variants.svelte b/src/content/examples/components/list/variants.svelte
new file mode 100644
index 00000000..52a2f750
--- /dev/null
+++ b/src/content/examples/components/list/variants.svelte
@@ -0,0 +1,9 @@
+
+ {#each ['filled', 'outline', 'text'] as variant (variant)}
+
+ Item one
+ Item two
+ Item three
+
+ {/each}
+
diff --git a/src/content/examples/components/modal/persistent.svelte b/src/content/examples/components/modal/persistent.svelte
new file mode 100644
index 00000000..fd5313d7
--- /dev/null
+++ b/src/content/examples/components/modal/persistent.svelte
@@ -0,0 +1,13 @@
+
+
+ (open = true)}>Open persistent modal
+
+
+ Persistent modal
+
+ Pressing Escape will not close this modal. You must use the button.
+
+ (open = false)}>Dismiss
+
diff --git a/src/content/examples/components/modal/position.svelte b/src/content/examples/components/modal/position.svelte
new file mode 100644
index 00000000..74fd0534
--- /dev/null
+++ b/src/content/examples/components/modal/position.svelte
@@ -0,0 +1,21 @@
+
+
+
+ show('top')}>Top
+ show('center')}>Center
+ show('bottom')}>Bottom
+
+
+
+ Position: {position}
+ (open = false)}>Close
+
diff --git a/src/content/examples/components/modal/preview.svelte b/src/content/examples/components/modal/preview.svelte
new file mode 100644
index 00000000..1978dfbf
--- /dev/null
+++ b/src/content/examples/components/modal/preview.svelte
@@ -0,0 +1,16 @@
+
+
+ (open = true)}>Open modal
+
+
+ Confirm action
+
+ Are you sure you want to continue? This action cannot be undone.
+
+
+ (open = false)}>Cancel
+ (open = false)}>Confirm
+
+
diff --git a/src/content/examples/components/modal/size.svelte b/src/content/examples/components/modal/size.svelte
new file mode 100644
index 00000000..c0d31213
--- /dev/null
+++ b/src/content/examples/components/modal/size.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {#each sizes as s (s)}
+ show(s)}>{s}
+ {/each}
+
+
+
+ Size: {size}
+ (open = false)}>Close
+
diff --git a/src/content/examples/components/popover/position.svelte b/src/content/examples/components/popover/position.svelte
new file mode 100644
index 00000000..6c80c163
--- /dev/null
+++ b/src/content/examples/components/popover/position.svelte
@@ -0,0 +1,19 @@
+
+
+
+ {#each positions as position (position)}
+
+ {#snippet activator({ toggle }: ModelPopoverProps)}
+ toggle(e.currentTarget as HTMLElement)}>{position}
+ {/snippet}
+ Position: {position}
+
+ {/each}
+
diff --git a/src/content/examples/components/popover/preview.svelte b/src/content/examples/components/popover/preview.svelte
new file mode 100644
index 00000000..43c6704b
--- /dev/null
+++ b/src/content/examples/components/popover/preview.svelte
@@ -0,0 +1,18 @@
+
+
+
+ {#snippet activator({ toggle }: ModelPopoverProps)}
+ toggle(e.currentTarget as HTMLElement)}>
+ Open popover
+
+ {/snippet}
+
+
+
Popover title
+
+ Rich content can go here β links, buttons, or any component. Closes on click outside.
+
+
+
diff --git a/src/content/examples/components/separator/inset.svelte b/src/content/examples/components/separator/inset.svelte
new file mode 100644
index 00000000..ec16d679
--- /dev/null
+++ b/src/content/examples/components/separator/inset.svelte
@@ -0,0 +1,7 @@
+
+
Item one
+
+
Item two
+
+
Item three
+
diff --git a/src/content/examples/components/separator/orientation.svelte b/src/content/examples/components/separator/orientation.svelte
new file mode 100644
index 00000000..7f954e3f
--- /dev/null
+++ b/src/content/examples/components/separator/orientation.svelte
@@ -0,0 +1,7 @@
+
+ Home
+
+ About
+
+ Contact
+
diff --git a/src/content/examples/components/separator/preview.svelte b/src/content/examples/components/separator/preview.svelte
new file mode 100644
index 00000000..0120741e
--- /dev/null
+++ b/src/content/examples/components/separator/preview.svelte
@@ -0,0 +1,5 @@
+
+ Above the separator
+
+ Below the separator
+
diff --git a/src/content/examples/components/textfield/clearable.svelte b/src/content/examples/components/textfield/clearable.svelte
new file mode 100644
index 00000000..3cf75af7
--- /dev/null
+++ b/src/content/examples/components/textfield/clearable.svelte
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/src/content/examples/components/textfield/message.svelte b/src/content/examples/components/textfield/message.svelte
new file mode 100644
index 00000000..21c94ca6
--- /dev/null
+++ b/src/content/examples/components/textfield/message.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/src/content/examples/components/textfield/prepend-append.svelte b/src/content/examples/components/textfield/prepend-append.svelte
new file mode 100644
index 00000000..28117471
--- /dev/null
+++ b/src/content/examples/components/textfield/prepend-append.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+ {#snippet prependInner()}
+
+ {/snippet}
+
+
+
+ {#snippet appendInner()}
+ (showPassword = !showPassword)}
+ style="display:inline-flex; background:none; border:none; cursor:pointer; color:inherit; padding:0;"
+ >
+
+ {#if showPassword} {:else} {/if}
+
+
+ {/snippet}
+
+
diff --git a/src/content/examples/components/textfield/preview.svelte b/src/content/examples/components/textfield/preview.svelte
new file mode 100644
index 00000000..b4329365
--- /dev/null
+++ b/src/content/examples/components/textfield/preview.svelte
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/src/content/examples/components/textfield/variants.svelte b/src/content/examples/components/textfield/variants.svelte
new file mode 100644
index 00000000..b1431694
--- /dev/null
+++ b/src/content/examples/components/textfield/variants.svelte
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/content/examples/components/toolbar/density.svelte b/src/content/examples/components/toolbar/density.svelte
new file mode 100644
index 00000000..3c0c3260
--- /dev/null
+++ b/src/content/examples/components/toolbar/density.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {#each densities as density (density)}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {/each}
+
diff --git a/src/content/examples/components/toolbar/orientation.svelte b/src/content/examples/components/toolbar/orientation.svelte
new file mode 100644
index 00000000..656db0c2
--- /dev/null
+++ b/src/content/examples/components/toolbar/orientation.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+
diff --git a/src/content/examples/components/toolbar/preview.svelte b/src/content/examples/components/toolbar/preview.svelte
new file mode 100644
index 00000000..26e39ede
--- /dev/null
+++ b/src/content/examples/components/toolbar/preview.svelte
@@ -0,0 +1,32 @@
+
+
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
diff --git a/src/content/examples/components/toolbar/variants.svelte b/src/content/examples/components/toolbar/variants.svelte
new file mode 100644
index 00000000..ab1b24a7
--- /dev/null
+++ b/src/content/examples/components/toolbar/variants.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {#each variants as variant (variant)}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {#snippet prepend()} {/snippet}
+
+
+ {/each}
+
diff --git a/src/content/examples/components/tooltip/arrow.svelte b/src/content/examples/components/tooltip/arrow.svelte
new file mode 100644
index 00000000..00ff6b33
--- /dev/null
+++ b/src/content/examples/components/tooltip/arrow.svelte
@@ -0,0 +1,7 @@
+
+ {#each ['top', 'bottom', 'left', 'right'] as location (location)}
+
+ {location}
+
+ {/each}
+
diff --git a/src/content/examples/components/tooltip/custom.svelte b/src/content/examples/components/tooltip/custom.svelte
new file mode 100644
index 00000000..7adf00ea
--- /dev/null
+++ b/src/content/examples/components/tooltip/custom.svelte
@@ -0,0 +1,13 @@
+
+
+
+ {#snippet tooltip()}
+
+
+ Custom tooltip content
+
+ {/snippet}
+ Rich tooltip
+
diff --git a/src/content/examples/components/tooltip/location.svelte b/src/content/examples/components/tooltip/location.svelte
new file mode 100644
index 00000000..d7c91e04
--- /dev/null
+++ b/src/content/examples/components/tooltip/location.svelte
@@ -0,0 +1,7 @@
+
+ {#each ['top', 'bottom', 'left', 'right'] as location (location)}
+
+ {location}
+
+ {/each}
+
diff --git a/src/content/examples/components/tooltip/preview.svelte b/src/content/examples/components/tooltip/preview.svelte
new file mode 100644
index 00000000..c0b7ae41
--- /dev/null
+++ b/src/content/examples/components/tooltip/preview.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+ Hover me
+
+
+
+
+
+
diff --git a/src/content/examples/essentials/my-custom-button.svelte b/src/content/examples/essentials/my-custom-button.svelte
new file mode 100644
index 00000000..e69de29b
diff --git a/src/content/examples/essentials/regular-import-components.svelte b/src/content/examples/essentials/regular-import-components.svelte
new file mode 100644
index 00000000..8e7737fc
--- /dev/null
+++ b/src/content/examples/essentials/regular-import-components.svelte
@@ -0,0 +1,8 @@
+
+
+Auto-imported button
+Manually imported button
+Custom component
diff --git a/src/content/examples/essentials/s-class-directive-boolean.svelte b/src/content/examples/essentials/s-class-directive-boolean.svelte
new file mode 100644
index 00000000..0a54537b
--- /dev/null
+++ b/src/content/examples/essentials/s-class-directive-boolean.svelte
@@ -0,0 +1,6 @@
+
+
+
+Click
diff --git a/src/content/examples/essentials/s-class-directive-string.svelte b/src/content/examples/essentials/s-class-directive-string.svelte
new file mode 100644
index 00000000..aa11b04f
--- /dev/null
+++ b/src/content/examples/essentials/s-class-directive-string.svelte
@@ -0,0 +1,9 @@
+
+
+
+Click
+
+
+Click
diff --git a/src/content/examples/essentials/s-class-multiple.svelte b/src/content/examples/essentials/s-class-multiple.svelte
new file mode 100644
index 00000000..a8299fc9
--- /dev/null
+++ b/src/content/examples/essentials/s-class-multiple.svelte
@@ -0,0 +1 @@
+Click
diff --git a/src/content/examples/essentials/s-class-object-conditional.svelte b/src/content/examples/essentials/s-class-object-conditional.svelte
new file mode 100644
index 00000000..f1299b00
--- /dev/null
+++ b/src/content/examples/essentials/s-class-object-conditional.svelte
@@ -0,0 +1,10 @@
+
+
+ Click
+
+
+
+Click
diff --git a/src/content/examples/essentials/s-class-s-style-combining.svelte b/src/content/examples/essentials/s-class-s-style-combining.svelte
new file mode 100644
index 00000000..02fe1ad8
--- /dev/null
+++ b/src/content/examples/essentials/s-class-s-style-combining.svelte
@@ -0,0 +1,16 @@
+
+
+ (isActive = !isActive)}
+>
+ Toggle
+
diff --git a/src/content/examples/essentials/s-class.svelte b/src/content/examples/essentials/s-class.svelte
new file mode 100644
index 00000000..4e2611db
--- /dev/null
+++ b/src/content/examples/essentials/s-class.svelte
@@ -0,0 +1 @@
+Click
diff --git a/src/content/examples/essentials/s-style-directive-custom.svelte b/src/content/examples/essentials/s-style-directive-custom.svelte
new file mode 100644
index 00000000..dd66edfb
--- /dev/null
+++ b/src/content/examples/essentials/s-style-directive-custom.svelte
@@ -0,0 +1,5 @@
+
+
+Click
diff --git a/src/content/examples/essentials/s-style-directive.svelte b/src/content/examples/essentials/s-style-directive.svelte
new file mode 100644
index 00000000..bac08281
--- /dev/null
+++ b/src/content/examples/essentials/s-style-directive.svelte
@@ -0,0 +1,12 @@
+
+
+
+Click
+
+
+Click
+
+
+Click
diff --git a/src/content/examples/essentials/s-style-dynamic.svelte b/src/content/examples/essentials/s-style-dynamic.svelte
new file mode 100644
index 00000000..8eacbdeb
--- /dev/null
+++ b/src/content/examples/essentials/s-style-dynamic.svelte
@@ -0,0 +1,5 @@
+
+
+ Themed button
diff --git a/src/content/examples/essentials/s-style.svelte b/src/content/examples/essentials/s-style.svelte
new file mode 100644
index 00000000..d3a9ae44
--- /dev/null
+++ b/src/content/examples/essentials/s-style.svelte
@@ -0,0 +1 @@
+ Styled button
diff --git a/src/content/examples/essentials/use-app-component.svelte b/src/content/examples/essentials/use-app-component.svelte
new file mode 100644
index 00000000..13447700
--- /dev/null
+++ b/src/content/examples/essentials/use-app-component.svelte
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/content/examples/essentials/use-component-with-preprocessor.svelte b/src/content/examples/essentials/use-component-with-preprocessor.svelte
new file mode 100644
index 00000000..f0e28af0
--- /dev/null
+++ b/src/content/examples/essentials/use-component-with-preprocessor.svelte
@@ -0,0 +1 @@
+Click me
diff --git a/src/content/examples/essentials/use-component-without-preprocessor.svelte b/src/content/examples/essentials/use-component-without-preprocessor.svelte
new file mode 100644
index 00000000..9a6d3bae
--- /dev/null
+++ b/src/content/examples/essentials/use-component-without-preprocessor.svelte
@@ -0,0 +1,5 @@
+
+
+Click me
diff --git a/src/content/examples/essentials/use-components.svelte b/src/content/examples/essentials/use-components.svelte
new file mode 100644
index 00000000..bcd2ef0c
--- /dev/null
+++ b/src/content/examples/essentials/use-components.svelte
@@ -0,0 +1,10 @@
+
+
+ Menu
+
+
+
+ New
+ Hello world
+
+
diff --git a/src/content/examples/home/btn-lapikit.svelte b/src/content/examples/home/btn-lapikit.svelte
new file mode 100644
index 00000000..63dbac96
--- /dev/null
+++ b/src/content/examples/home/btn-lapikit.svelte
@@ -0,0 +1 @@
+Lapikit button
diff --git a/apps/website/src/lib/components/docs/homepage-button-tailwind.svelte b/src/content/examples/home/btn-tailwind.svelte
similarity index 96%
rename from apps/website/src/lib/components/docs/homepage-button-tailwind.svelte
rename to src/content/examples/home/btn-tailwind.svelte
index e7624c6b..af8f1bba 100644
--- a/apps/website/src/lib/components/docs/homepage-button-tailwind.svelte
+++ b/src/content/examples/home/btn-tailwind.svelte
@@ -19,5 +19,5 @@
on:mouseout={setDefault}
on:blur={setDefault}
>
- Hello World
+ Tailwind Button
diff --git a/apps/website/src/lib/components/docs/homepage-modal.svelte b/src/content/examples/home/btn.svelte
similarity index 100%
rename from apps/website/src/lib/components/docs/homepage-modal.svelte
rename to src/content/examples/home/btn.svelte
diff --git a/apps/website/src/lib/components/docs/homepage-card-lapikit.svelte b/src/content/examples/home/card-lapikit.svelte
similarity index 50%
rename from apps/website/src/lib/components/docs/homepage-card-lapikit.svelte
rename to src/content/examples/home/card-lapikit.svelte
index b3c9e31b..0fe1634a 100644
--- a/apps/website/src/lib/components/docs/homepage-card-lapikit.svelte
+++ b/src/content/examples/home/card-lapikit.svelte
@@ -1,9 +1,5 @@
-
-
-
+
Welcome to Lapikit!
This is a simple card component using Lapikit.
- Get Started
-
+ Get Started
+
diff --git a/apps/website/src/lib/components/docs/homepage-card-tailwind.svelte b/src/content/examples/home/card-tailwind.svelte
similarity index 100%
rename from apps/website/src/lib/components/docs/homepage-card-tailwind.svelte
rename to src/content/examples/home/card-tailwind.svelte
diff --git a/apps/website/src/lib/components/docs/homepage-card.svelte b/src/content/examples/home/card.svelte
similarity index 100%
rename from apps/website/src/lib/components/docs/homepage-card.svelte
rename to src/content/examples/home/card.svelte
diff --git a/src/content/examples/home/modal-lapikit.svelte b/src/content/examples/home/modal-lapikit.svelte
new file mode 100644
index 00000000..dcc78269
--- /dev/null
+++ b/src/content/examples/home/modal-lapikit.svelte
@@ -0,0 +1,12 @@
+
+
+ (isOpen = true)} active={isOpen}>Open Modal
+
+
+ This is a Modal Lapikit
+ You can put any content you like here.
+ (isOpen = false)}>Close
+
diff --git a/apps/website/src/lib/components/docs/homepage-modal-tailwind.svelte b/src/content/examples/home/modal-tailwind.svelte
similarity index 100%
rename from apps/website/src/lib/components/docs/homepage-modal-tailwind.svelte
rename to src/content/examples/home/modal-tailwind.svelte
diff --git a/src/content/examples/home/modal.svelte b/src/content/examples/home/modal.svelte
new file mode 100644
index 00000000..a900bc74
--- /dev/null
+++ b/src/content/examples/home/modal.svelte
@@ -0,0 +1,127 @@
+
+
+
+ Open Modal
+
+
+{#if isOpen}
+ {
+ if (e.key === 'Escape' || e.key === 'Enter') closeModal();
+ }}
+ tabindex="0"
+ aria-modal="true"
+ role="dialog"
+ >
+
{
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ }
+ }}
+ role="dialog"
+ tabindex="0"
+ >
+
This is a Modal with Pure CSS
+
You can put any content you like here.
+
{
+ if (e.key === 'Escape') closeModal();
+ }}
+ >
+ Close
+
+
+
+{/if}
+
+
diff --git a/src/content/examples/hooks/useTheme-toggle.svelte b/src/content/examples/hooks/useTheme-toggle.svelte
new file mode 100644
index 00000000..1a020d3c
--- /dev/null
+++ b/src/content/examples/hooks/useTheme-toggle.svelte
@@ -0,0 +1,26 @@
+
+
+ {
+ useTheme(mode === 'light' ? 'dark' : 'light');
+ mode = mode === 'light' ? 'dark' : 'light';
+ }}
+ aria-label="Toggle theme"
+ size="lg"
+>
+ {#if mode !== 'light'}
+
+
+
+ {:else}
+
+
+
+ {/if}
+
diff --git a/src/content/examples/introduction-demo.svelte b/src/content/examples/introduction-demo.svelte
new file mode 100644
index 00000000..58625a0d
--- /dev/null
+++ b/src/content/examples/introduction-demo.svelte
@@ -0,0 +1,5 @@
+
+
+ counter++}>Count is: {counter}
diff --git a/src/content/examples/sandbox/my-component.svelte b/src/content/examples/sandbox/my-component.svelte
new file mode 100644
index 00000000..eb63c194
--- /dev/null
+++ b/src/content/examples/sandbox/my-component.svelte
@@ -0,0 +1,7 @@
+
+
+ (count = count - 1)}>-1
+{count}
+ (count = count + 1)}>+1
diff --git a/src/content/examples/started/dark-mode.css b/src/content/examples/started/dark-mode.css
new file mode 100644
index 00000000..d28f3b74
--- /dev/null
+++ b/src/content/examples/started/dark-mode.css
@@ -0,0 +1,13 @@
+[data-theme='dark'] {
+ color-scheme: dark;
+
+ --kit-bg: hsl(222 20% 10%);
+ --kit-fg: hsl(0 0% 98%);
+ --kit-muted: hsl(220 10% 60%);
+
+ --kit-surface-1: hsl(222 20% 10%);
+ --kit-surface-2: hsl(222 18% 14%);
+ --kit-surface-3: hsl(222 16% 18%);
+
+ --kit-border: hsl(220 14% 24%);
+}
diff --git a/src/content/examples/started/initial-style.css b/src/content/examples/started/initial-style.css
new file mode 100644
index 00000000..df22fa31
--- /dev/null
+++ b/src/content/examples/started/initial-style.css
@@ -0,0 +1,46 @@
+:root {
+ color-scheme: light;
+
+ /* Semantic hue values - used to derive status colors */
+ --kit-h-neutral: 220;
+ --kit-h-success: 145;
+ --kit-h-warning: 35;
+ --kit-h-danger: 5;
+ --kit-h-info: 205;
+
+ /* Base colors */
+ --kit-bg: hsl(0 0% 100%);
+ --kit-fg: hsl(222 20% 10%);
+ --kit-muted: hsl(220 10% 45%);
+
+ /* Surface layers */
+ --kit-surface-1: hsl(0 0% 100%);
+ --kit-surface-2: hsl(220 20% 98%);
+ --kit-surface-3: hsl(220 18% 94%);
+
+ /* Border */
+ --kit-border: hsl(220 16% 88%);
+
+ /* Accent */
+ --kit-accent: hsl(220 90% 56%);
+
+ /* Shape */
+ --kit-radius-1: 8px;
+ --kit-radius-2: 12px;
+
+ /* Spacing */
+ --kit-space-1: 6px;
+ --kit-space-2: 10px;
+ --kit-space-3: 14px;
+
+ /* Focus ring */
+ --kit-focus: hsl(35, 90%, 56%);
+
+ /* Disabled state */
+ --kit-disabled-opacity: 0.55;
+
+ /* Typography */
+ --kit-font:
+ ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
+ 'Noto Color Emoji';
+}
diff --git a/src/content/examples/started/introduction-lapikit.svelte b/src/content/examples/started/introduction-lapikit.svelte
new file mode 100644
index 00000000..58625a0d
--- /dev/null
+++ b/src/content/examples/started/introduction-lapikit.svelte
@@ -0,0 +1,5 @@
+
+
+ counter++}>Count is: {counter}
diff --git a/src/content/examples/started/override-style-component.css b/src/content/examples/started/override-style-component.css
new file mode 100644
index 00000000..b1138f08
--- /dev/null
+++ b/src/content/examples/started/override-style-component.css
@@ -0,0 +1,5 @@
+.kit-btn {
+ --kit-btn-bg: hsl(262 80% 50%);
+ --kit-btn-color: #ffffff;
+ --kit-btn-radius: 999px;
+}
diff --git a/src/content/examples/started/override-style.css b/src/content/examples/started/override-style.css
new file mode 100644
index 00000000..eeff7999
--- /dev/null
+++ b/src/content/examples/started/override-style.css
@@ -0,0 +1,6 @@
+:root {
+ --kit-accent: hsl(262 80% 50%);
+ --kit-radius-1: 4px;
+ --kit-radius-2: 8px;
+ --kit-font: 'Inter', sans-serif;
+}
diff --git a/src/content/examples/started/s-class-preprocessor.svelte b/src/content/examples/started/s-class-preprocessor.svelte
new file mode 100644
index 00000000..9e421bba
--- /dev/null
+++ b/src/content/examples/started/s-class-preprocessor.svelte
@@ -0,0 +1,10 @@
+
+
+
+...
+
+
+...
diff --git a/src/content/examples/started/s-style-component.svelte b/src/content/examples/started/s-style-component.svelte
new file mode 100644
index 00000000..95657e38
--- /dev/null
+++ b/src/content/examples/started/s-style-component.svelte
@@ -0,0 +1 @@
+Hello !
diff --git a/src/content/examples/started/s-style-preprocessor.svelte b/src/content/examples/started/s-style-preprocessor.svelte
new file mode 100644
index 00000000..c34f8bfe
--- /dev/null
+++ b/src/content/examples/started/s-style-preprocessor.svelte
@@ -0,0 +1,9 @@
+
+
+
+...
+
+
+...
diff --git a/src/content/examples/started/start-your-project-with-lapikit.svelte b/src/content/examples/started/start-your-project-with-lapikit.svelte
new file mode 100644
index 00000000..de5554cd
--- /dev/null
+++ b/src/content/examples/started/start-your-project-with-lapikit.svelte
@@ -0,0 +1,7 @@
+
+
+
+ counter++}>Count is: {counter}
+
diff --git a/src/content/examples/started/svelte-config-js.js b/src/content/examples/started/svelte-config-js.js
new file mode 100644
index 00000000..03879569
--- /dev/null
+++ b/src/content/examples/started/svelte-config-js.js
@@ -0,0 +1,13 @@
+import adapter from '@sveltejs/adapter-node';
+import { lapikitPreprocess } from 'lapikit/labs/preprocess';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ preprocess: lapikitPreprocess(),
+ kit: {
+ adapter: adapter()
+ },
+ extensions: ['.svelte', '.svx', '.md']
+};
+
+export default config;
diff --git a/apps/website/src/lib/animations/background-star.svelte b/src/lib/@legacy/background-star.svelte
similarity index 100%
rename from apps/website/src/lib/animations/background-star.svelte
rename to src/lib/@legacy/background-star.svelte
diff --git a/apps/website/src/routes/(pages)/_home/addons/color-scheme-preview.svelte b/src/lib/@legacy/color-scheme-preview.svelte
similarity index 96%
rename from apps/website/src/routes/(pages)/_home/addons/color-scheme-preview.svelte
rename to src/lib/@legacy/color-scheme-preview.svelte
index 3980d18c..24df3767 100644
--- a/apps/website/src/routes/(pages)/_home/addons/color-scheme-preview.svelte
+++ b/src/lib/@legacy/color-scheme-preview.svelte
@@ -1,5 +1,5 @@
diff --git a/apps/website/src/routes/(pages)/_home/addons/earth-moon-lapikit.svelte b/src/lib/@legacy/earth-moon-lapikit.svelte
similarity index 93%
rename from apps/website/src/routes/(pages)/_home/addons/earth-moon-lapikit.svelte
rename to src/lib/@legacy/earth-moon-lapikit.svelte
index a48f88c2..9131bd66 100644
--- a/apps/website/src/routes/(pages)/_home/addons/earth-moon-lapikit.svelte
+++ b/src/lib/@legacy/earth-moon-lapikit.svelte
@@ -1,6 +1,6 @@
+
+
+ {pageTitle}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {@html breadcrumbSchemaTag}
+
+
+
+
+ {@render children()}
+
+
+
+
diff --git a/apps/lapikit.dev/src/routes/+layout.ts b/src/routes/+layout.ts
similarity index 100%
rename from apps/lapikit.dev/src/routes/+layout.ts
rename to src/routes/+layout.ts
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
new file mode 100644
index 00000000..cd2cdb1d
--- /dev/null
+++ b/src/routes/+page.svelte
@@ -0,0 +1,1346 @@
+
+
+
+
+
+
+
+
+
+ Documentation
+
+
+
+ {#snippet prepend()}
+
+ {@html githubIcon}
+
+ {/snippet}
+
+ GitHub
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#snippet prepend()}
+ New π
+ {/snippet}
+ Lapikit v0.5 is up!
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+
+
+ Simple, optimized components for
+ Svelte
+
+
+
+ A library of accessible, high-performance, versatile components that let you develop
+ fast, fully customizable interfaces.
+
+
+
+
+
+
+ Get Started
+
+
+ Browse Components
+
+
+
copyToClipboard('npm install -D lapikit')}
+ >
+ {#snippet prepend()}
+ ~
+ {/snippet}
+ npm install -D lapikit
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+
+
+
+
+
+
+
+
+
Build faster, write cleaner code
+
+ With Lapikit, you can easily create and manage your components, making your development
+ process more efficient
+
+
+
+
+ Why waste time developing the same UI components on each project? With raw
+ TailwindCSS, every button, card, and modal becomes a collection of repeating class
+ blocks that clutter your codebase and complicate maintenance. Lapikit allows you to
+ focus on what matters most: developing exceptional user experiences by delivering
+ ready-to-use, customisable, and type-safe Svelte components
+
+
With Lapikit, you write less but build more:
+
+
+ Your code will be cleaner, with simpler and more legible
+ syntax
+
+
+ Faster, thanks to reuse components and uniform styling
+
+
+ More consistently, with pre-optimized Svelte + TypeScript
+ integration
+
+
+ Stop copying and duplicating CSS classes and start shipping
+ better user interfaces
+
+
+
+ Instead of struggling with redundancy, you focus on the experience you want to offer
+
+
+ (stepCode = 0)}
+ active={stepCode === 0}
+ rounded="full"
+ background={stepCode === 0 ? 'accent-primary' : 'label-secondary'}
+ color="white"
+ size={{ base: 'sm', md: 'md' }}
+ >
+ View Button
+
+ (stepCode = 1)}
+ active={stepCode === 1}
+ rounded="full"
+ background={stepCode === 1 ? 'accent-primary' : 'label-secondary'}
+ color="white"
+ size={{ base: 'sm', md: 'md' }}
+ >
+ Discover Card
+
+ (stepCode = 2)}
+ active={stepCode === 2}
+ rounded="full"
+ background={stepCode === 2 ? 'accent-primary' : 'label-secondary'}
+ color="white"
+ size={{ base: 'sm', md: 'md' }}
+ >
+ Explore Modal
+
+
+
+
+ {#if stepCode === 0}
+ import('../content/examples/home/btn-lapikit.svelte?raw'),
+ lang: 'svelte'
+ },
+ Tailwind: {
+ code: () => import('../content/examples/home/btn-tailwind.svelte?raw'),
+ lang: 'svelte'
+ },
+ Native: {
+ code: () => import('../content/examples/home/btn.svelte?raw'),
+ lang: 'svelte'
+ }
+ }}
+ />
+ {:else if stepCode === 1}
+ import('../content/examples/home/card-lapikit.svelte?raw'),
+ lang: 'svelte'
+ },
+ Tailwind: {
+ code: () => import('../content/examples/home/card-tailwind.svelte?raw'),
+ lang: 'svelte'
+ },
+ Native: {
+ code: () => import('../content/examples/home/card.svelte?raw'),
+ lang: 'svelte'
+ }
+ }}
+ />
+ {:else if stepCode === 2}
+ import('../content/examples/home/modal-lapikit.svelte?raw'),
+ lang: 'svelte'
+ },
+ Tailwind: {
+ code: () => import('../content/examples/home/modal-tailwind.svelte?raw'),
+ lang: 'svelte'
+ },
+ Native: {
+ code: () => import('../content/examples/home/modal.svelte?raw'),
+ lang: 'svelte'
+ }
+ }}
+ />
+ {/if}
+
+
+
+
+
+ There are an infinite amount of themes with just one configuration
+
+
+ Lapikit supports several themes out of the box, allowing you to quickly swap between
+ theming options with minimal setup.Light and dark modes are also supported. Switching
+ themes or changing your design system takes seconds rather than hours
+
+
+
+
+
+
+
+
+
+
+
+ One library for your entire Svelte project
+
+
+
+
+
+ {#if stepTimeline === 0}
+
+ {/if}
+ {#if stepTimeline === 1}
+
+ {/if}
+ {#if stepTimeline === 2}
+
+ {/if}
+
+
+
+
+ {#each stepperToUseComponent as step, index (step)}
+ {@const StepIcon = step.icon}
+ (stepTimeline = index)}
+ aria-label={`Display ${step.title}`}
+ background={stepTimeline === index ? 'accent-primary' : 'label-secondary'}
+ color="white"
+ icon
+ >
+
+
+ {/each}
+
+
+
+
+
+
+
+
+
+ Start Building with Lapikit
+
+ {#snippet append()}
+
+ {counter || 0} components
+
+ {/snippet}
+
+
+
+
+
+
+
+
+
+
+
+ Discover what functionalities are available for your application
+
+
+ Lapikit is a component library with a variety of features to help you create beautiful
+ and functional web applications. Here are some of the features you can make use of:
+
+
+
+
+ {#each enableFeatures as { title, description, icon } (title)}
+
+
+
+ {#if typeof icon === 'string'}
+ {@html icon}
+ {:else}
+ {@const FeatureIcon = icon}
+
+
+ {/if}
+
+
+
{title['en']}
+
{description['en']}
+
+
+
+ {/each}
+
+
+
+
+
+ {capitalize(`It's not over yet!`)}
+
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lapikit is designed to simplify and streamline the work of front-end developers by
+ limiting code redundancy, leaving more time for the development of advanced and complex
+ features.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {@html npmIcon}
+
+
+
{npmState.downloads || '---'}
+
Monthly downloads
+
+
+
+
+
+
+
+ {@html githubIcon}
+
+
+
+
+
+
+
+
+
+
+
+ Open Source and built by developers, for developers
+
+
+ Lapikit is 100% open source, created and maintained by Nycolaide and a growing
+ community of frontend developers. You can contribute on GitHub, report issues, or
+ suggest new components.
+
+
+ Every contribution helps improve the developer experience for the entire Svelte
+ community.
+
+
+ Contribute to Lapikit on GitHub
+ {#snippet append()}
+ {@html githubIcon}
+ {/snippet}
+
+
+
+
+
+
+
+
+
+
+
+ {@html instagramIcon}
+
+
+
+
+
+
+
+
+
+
+
+ {@html discordIcon}
+
+
+
+
+
+
+
+
+
+
+
+
+
Go further with Lapikit
+
+ Explore our documentation and resources to get the most out of Lapikit:
+
+
+
+
+
+
+
Documentations
+
Learn how to install and use Lapikit in your project
+
+
+
+
+
+
+
+
Contribute
+
+ Do you want to contribute to Lapikit? We provide a Contributor Guide to assist you
+ in getting started
+
+
+
+
+
+
+
+
+
Sponsor
+
Become a sponsor to help Lapikit create a strong community
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ It's not magic, it's Lapikit
+
+
+
+
+
+
+
+
+
Start exploring Lapikit
+
Design system, themes, components, all in one lib
+
+ Discover the components
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+
+
+
+
+
+
+
+
+
+ {#each Object.entries(footer_links) as [sectionKey, sectionValue] (sectionKey)}
+
+ {capitalize(`${sectionValue.title}`)}
+ {#if Array.isArray(sectionValue.items)}
+ {#each sectionValue.items as { key, title, slug, custom, external } (key)}
+ {#if !custom}
+
+
+ {capitalize(`${title}`)}
+
+
+ {:else if custom === 'cookie-consent'}
+
+
+ {capitalize(`${title}`)}
+
+
+ {/if}
+ {/each}
+ {:else}
+ {#each Object.entries(sectionValue.items as Record) as [key, { title, slug, external }] (key)}
+
+
+ {capitalize(`${title}`)}
+
+
+ {/each}
+ {/if}
+
+ {/each}
+
+
+
+ Join our community on Discord
+ News, updates, and discussions await you!
+
+
+ Chat with us
+ {#snippet append()}
+
+ {/snippet}
+
+
+
+
+
+
+
+ Copyright Β© {year === 2025 ? year : `2025 - ${year}`} Lapikit -
+
+ MIT License
+
+
+
Developed by
+
+
+ Nycolaide
+
+
+
+
+
+
+
+
diff --git a/src/routes/docs/+layout.svelte b/src/routes/docs/+layout.svelte
new file mode 100644
index 00000000..d1b2c4a3
--- /dev/null
+++ b/src/routes/docs/+layout.svelte
@@ -0,0 +1,116 @@
+
+
+
+
+
+ Lapikit
+
+
+
+
+
+
+
+ {#snippet activator({ open, toggle }: ModelDropdownProps)}
+ toggle(e.currentTarget as HTMLElement)}
+ icon
+ size="lg"
+ >
+ {#if mode === 'light'}
+
+
+
+ {:else if mode === 'dark'}
+
+
+
+ {:else}
+
+
+
+ {/if}
+
+ {/snippet}
+
+
+ (mode = 'light')} active={mode === 'light'}>
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+ Light
+
+ (mode = 'dark')} active={mode === 'dark'}>
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+ Dark
+
+ (mode = 'system')} active={mode === 'system'}>
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+ System
+
+
+
+
+ {@html githubIcon}
+
+
+
+
+{@render children()}
diff --git a/src/routes/docs/+page.md b/src/routes/docs/+page.md
new file mode 100644
index 00000000..6720a7af
--- /dev/null
+++ b/src/routes/docs/+page.md
@@ -0,0 +1,22 @@
+---
+title: Documentation
+description: Browse Lapikit documentation, including components, hooks and theming resources.
+---
+
+# Lapikit documentation
+
+Lapikit documentation is organized as simple HTML pages so search engines and users can discover the project quickly.
+
+## Documentation sections
+
+- [Components](/docs/components)
+- [Hooks](/docs/hooks)
+
+## Start here
+
+Use this section to understand what Lapikit offers:
+
+- Reusable Svelte components for common interface patterns.
+- Hooks for state and behavior.
+- Theme tokens and CSS export tools.
+- Legal and project information available in the [legal notices](/terms).
diff --git a/src/routes/docs/[...slug]/+page.svelte b/src/routes/docs/[...slug]/+page.svelte
new file mode 100644
index 00000000..1a5b9220
--- /dev/null
+++ b/src/routes/docs/[...slug]/+page.svelte
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/routes/docs/[...slug]/+page.ts b/src/routes/docs/[...slug]/+page.ts
new file mode 100644
index 00000000..cb75c915
--- /dev/null
+++ b/src/routes/docs/[...slug]/+page.ts
@@ -0,0 +1,33 @@
+import { error } from '@sveltejs/kit';
+import { docsNavigation, docs, docsByPath, docsBySlug } from '$lib';
+
+export const prerender = true;
+
+const navPaths = docsNavigation.flatMap((section) => section.pages.map((page) => page.url));
+
+export function entries() {
+ return docs.map((doc) => ({ slug: doc.slug }));
+}
+
+export function load({ params }) {
+ const doc = docsBySlug.get(params.slug ?? '');
+
+ if (!doc) {
+ throw error(404, 'Documentation page not found');
+ }
+
+ const index = navPaths.indexOf(doc.path);
+ const prevPath = index > 0 ? navPaths[index - 1] : null;
+ const nextPath = index !== -1 && index < navPaths.length - 1 ? navPaths[index + 1] : null;
+
+ const prevDoc = prevPath ? toDocLink(prevPath) : null;
+ const nextDoc = nextPath ? toDocLink(nextPath) : null;
+
+ return { doc, prevDoc, nextDoc };
+}
+
+function toDocLink(path: string) {
+ const doc = docsByPath.get(path);
+ if (!doc) return null;
+ return { slug: doc.slug, title: doc.metadata.title, path: doc.path };
+}
diff --git a/src/routes/layout.css b/src/routes/layout.css
new file mode 100644
index 00000000..dd757f9f
--- /dev/null
+++ b/src/routes/layout.css
@@ -0,0 +1,20 @@
+@import 'tailwindcss';
+@import '@fontsource-variable/outfit';
+@import '@fontsource-variable/jetbrains-mono';
+@import './md.css';
+@import './theme.css';
+@plugin '@tailwindcss/forms';
+@plugin '@tailwindcss/typography';
+
+@theme {
+ --font-sans: 'Outfit Variable', sans-serif;
+ --font-mono: 'JetBrains Mono Variable', monospace;
+}
+
+@layer base {
+ body {
+ font-family: var(--font-sans);
+ background-color: var(--kit-bg);
+ color: var(--kit-fg);
+ }
+}
diff --git a/src/routes/md.css b/src/routes/md.css
new file mode 100644
index 00000000..9e9825de
--- /dev/null
+++ b/src/routes/md.css
@@ -0,0 +1,598 @@
+/* ββ Variables βββββββββββββββββββββββββββββββββββββββββββββββ */
+:root {
+ --md-font-sans: system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
+ --md-font-mono: ui-monospace, 'Cascadia Code', 'Fira Code', Consolas, monospace;
+ --md-font-size: 16px;
+ --md-line-height: 1.75;
+ --md-max-width: 720px;
+
+ /* Couleurs */
+ /* --md-color-text: #1a1a1a;
+ --md-color-muted: #555;
+ --md-color-link: #0969da;
+ --md-color-link-hover: #0550ae;
+ --md-color-border: #d0d7de;
+ --md-color-bg: #ffffff;
+ --md-color-surface: #f6f8fa;
+ --md-color-code-bg: #f0f2f5;
+ --md-color-code-text: #c7254e;
+ --md-color-blockquote: #57606a;
+ --md-color-blockquote-border: #0969da;
+ --md-color-mark: #fff3b0;
+ --md-color-ins: #d4f8d4;
+ --md-color-del: #ffd7d7; */
+
+ /* Espacements */
+ --md-space-xs: 0.25rem;
+ --md-space-sm: 0.5rem;
+ --md-space-md: 1rem;
+ --md-space-lg: 1.5rem;
+ --md-space-xl: 2rem;
+ --md-space-2xl: 2.5rem;
+
+ /* Tableaux */
+ --md-table-head-bg: #f6f8fa;
+ --md-table-stripe-bg: #fafafa;
+}
+
+/* Dark mode */
+/* @media (prefers-color-scheme: dark) {
+ :root {
+ --md-color-text: #e6edf3;
+ --md-color-muted: #8b949e;
+ --md-color-link: #58a6ff;
+ --md-color-link-hover: #79c0ff;
+ --md-color-border: #30363d;
+ --md-color-bg: #0d1117;
+ --md-color-surface: #161b22;
+ --md-color-code-bg: #161b22;
+ --md-color-code-text: #ff7b72;
+ --md-color-blockquote: #8b949e;
+ --md-color-blockquote-border: #388bfd;
+ --md-color-mark: #4a3c00;
+ --md-color-ins: #0f3d0f;
+ --md-color-del: #4a0f0f;
+ --md-table-head-bg: #161b22;
+ --md-table-stripe-bg: #0d1117;
+ }
+} */
+
+@layer kit-prose {
+ /* ββ Container ββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose {
+ font-family: var(--md-font-sans);
+ font-size: var(--md-font-size);
+ line-height: var(--md-line-height);
+ color: var(--md-color-text);
+ background: var(--md-color-bg);
+ max-width: var(--md-max-width);
+ margin: 0 auto;
+ padding: var(--md-space-xl) var(--md-space-lg);
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ }
+
+ /* ββ Reset ββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose * {
+ box-sizing: border-box;
+ }
+
+ .kit-prose > *:first-child {
+ margin-top: 0;
+ }
+ .kit-prose > *:last-child {
+ margin-bottom: 0;
+ }
+
+ /* ββ Title h1 β h6 βββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose h1,
+ .kit-prose h2,
+ .kit-prose h3,
+ .kit-prose h4,
+ .kit-prose h5,
+ .kit-prose h6 {
+ font-weight: 700;
+ line-height: 1.25;
+ color: var(--md-color-text);
+ margin-top: var(--md-space-xl);
+ margin-bottom: var(--md-space-sm);
+ /* appbar (4rem) + small buffer */
+ scroll-margin-top: 5rem;
+ }
+
+ /* appbar (4rem) + toolbar (3rem) + small buffer */
+ @media (max-width: 1023px) {
+ .kit-prose h1,
+ .kit-prose h2,
+ .kit-prose h3,
+ .kit-prose h4,
+ .kit-prose h5,
+ .kit-prose h6 {
+ scroll-margin-top: 8rem;
+ }
+ }
+
+ .kit-prose h1 {
+ font-size: 2rem;
+ border-bottom: 2px solid var(--md-color-border);
+ padding-bottom: var(--md-space-sm);
+ }
+ .kit-prose h2 {
+ font-size: 1.5rem;
+ border-bottom: 1px solid var(--md-color-border);
+ padding-bottom: var(--md-space-xs);
+ }
+ .kit-prose h3 {
+ font-size: 1.25rem;
+ }
+ .kit-prose h4 {
+ font-size: 1rem;
+ font-weight: 600;
+ }
+ .kit-prose h5 {
+ font-size: 0.875rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ }
+ .kit-prose h6 {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: var(--md-color-muted);
+ }
+
+ /* Anchor and Heading (optional) */
+ .kit-prose h1 .anchor,
+ .kit-prose h2 .anchor,
+ .kit-prose h3 .anchor,
+ .kit-prose h4 .anchor {
+ opacity: 0;
+ transition: opacity 0.15s;
+ margin-left: 0.4em;
+ font-weight: 400;
+ text-decoration: none;
+ color: var(--md-color-muted);
+ }
+ .kit-prose h1:hover .anchor,
+ .kit-prose h2:hover .anchor,
+ .kit-prose h3:hover .anchor,
+ .kit-prose h4:hover .anchor {
+ opacity: 1;
+ }
+
+ /* ββ Paragraphes βββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose p {
+ margin-top: 0;
+ margin-bottom: var(--md-space-md);
+ }
+
+ /* ββ Links ββββββββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose a {
+ color: var(--md-color-link);
+ text-decoration: underline;
+ text-underline-offset: 2px;
+ transition: color 0.15s;
+ }
+
+ .kit-prose a:hover {
+ color: var(--md-color-link-hover);
+ text-decoration-thickness: 2px;
+ }
+
+ .kit-prose a:visited {
+ color: #6f42c1;
+ }
+
+ /* ββ List βββββββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose ul,
+ .kit-prose ol {
+ margin-top: 0;
+ margin-bottom: var(--md-space-md);
+ padding-left: var(--md-space-xl);
+ }
+
+ .kit-prose ul {
+ list-style-type: disc;
+ }
+ .kit-prose ol {
+ list-style-type: decimal;
+ }
+
+ /* Levels */
+ .kit-prose ul ul {
+ list-style-type: circle;
+ }
+ .kit-prose ul ul ul {
+ list-style-type: square;
+ }
+ .kit-prose ol ol {
+ list-style-type: lower-alpha;
+ }
+ .kit-prose ol ol ol {
+ list-style-type: lower-roman;
+ }
+
+ .kit-prose li {
+ margin-bottom: var(--md-space-xs);
+ line-height: var(--md-line-height);
+ }
+
+ .kit-prose li > p {
+ margin-bottom: var(--md-space-xs);
+ }
+
+ /* Lists advanced */
+ .kit-prose li > ul,
+ .kit-prose li > ol {
+ margin-top: var(--md-space-xs);
+ margin-bottom: 0;
+ }
+
+ /* ββ Code inline βββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose code {
+ font-family: var(--md-font-mono);
+ font-size: 0.875em;
+ color: var(--md-color-code-text);
+ background-color: var(--md-color-code-bg);
+ border: 1px solid var(--md-color-border);
+ border-radius: 4px;
+ padding: 0.1em 0.35em;
+ white-space: nowrap;
+ }
+
+ /* ββ Block of code (pre > code) βββββββββββββββββββββββββββββββ */
+ .kit-prose pre {
+ font-family: var(--md-font-mono);
+ font-size: 0.875rem;
+ line-height: 1.6;
+ background-color: var(--md-color-surface);
+ border: 1px solid var(--md-color-border);
+ border-radius: 8px;
+ padding: var(--md-space-md) var(--md-space-lg);
+ overflow-x: auto;
+ margin-top: 0;
+ margin-bottom: var(--md-space-md);
+ -webkit-overflow-scrolling: touch;
+ }
+
+ /* Reset code inside pre */
+ .kit-prose pre code {
+ font-family: inherit;
+ font-size: inherit;
+ color: var(--md-color-text);
+ background: none;
+ border: none;
+ border-radius: 0;
+ padding: 0;
+ white-space: pre;
+ }
+
+ /* ββ Blockquote βββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose blockquote {
+ margin: 0 0 var(--md-space-md) 0;
+ padding: var(--md-space-sm) var(--md-space-md);
+ border-left: 4px solid var(--md-color-blockquote-border);
+ background: var(--md-color-surface);
+ border-radius: 0 4px 4px 0;
+ color: var(--md-color-blockquote);
+ }
+
+ .kit-prose blockquote > p:last-child {
+ margin-bottom: 0;
+ }
+
+ /* Nested blockquotes */
+ .kit-prose blockquote blockquote {
+ margin-top: var(--md-space-sm);
+ border-left-color: var(--md-color-border);
+ }
+
+ /* ββ Divider horizontal ββββββββββββββββββββββββββββββββββββ */
+ .kit-prose hr {
+ border: none;
+ border-top: 2px solid var(--md-color-border);
+ margin: var(--md-space-xl) 0;
+ }
+
+ /* ββ Table βββββββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose table {
+ width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-bottom: var(--md-space-md);
+ font-size: 0.9em;
+ overflow-x: auto;
+ display: block;
+ max-width: 100%;
+ }
+
+ .kit-prose thead {
+ background-color: var(--md-table-head-bg);
+ }
+
+ .kit-prose th,
+ .kit-prose td {
+ border: 1px solid var(--md-color-border);
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+ line-height: 1.5;
+ }
+
+ .kit-prose th {
+ font-weight: 600;
+ }
+
+ /* Lines (zebra striping) */
+ .kit-prose tbody tr:nth-child(even) {
+ background-color: var(--md-table-stripe-bg);
+ }
+
+ .kit-prose tbody tr:hover {
+ background-color: var(--md-color-surface);
+ }
+
+ /* ββ Pictures βββββββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose img {
+ max-width: 100%;
+ height: auto;
+ border-radius: 4px;
+ border: 1px solid var(--md-color-border);
+ display: block;
+ margin: var(--md-space-sm) 0;
+ }
+
+ .kit-prose .kit-aspect-ratio img,
+ .kit-prose .kit-repl img {
+ margin: 0;
+ }
+
+ /* Figure & figcaption */
+ .kit-prose figure {
+ margin: 0 0 var(--md-space-md) 0;
+ }
+
+ .kit-prose figcaption {
+ font-size: 0.85em;
+ color: var(--md-color-muted);
+ text-align: center;
+ margin-top: var(--md-space-xs);
+ font-style: italic;
+ }
+
+ /* ββ Typography inline βββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose strong {
+ font-weight: 700;
+ }
+ .kit-prose em {
+ font-style: italic;
+ }
+ .kit-prose s,
+ .kit-prose del {
+ text-decoration: line-through;
+ color: var(--md-color-muted);
+ }
+ .kit-prose ins {
+ text-decoration: underline;
+ background-color: var(--md-color-ins);
+ padding: 0 2px;
+ }
+ .kit-prose mark {
+ background-color: var(--md-color-mark);
+ border-radius: 2px;
+ padding: 0 2px;
+ }
+ .kit-prose sub {
+ font-size: 0.75em;
+ vertical-align: sub;
+ }
+ .kit-prose sup {
+ font-size: 0.75em;
+ vertical-align: super;
+ }
+ .kit-prose abbr {
+ text-decoration: underline dotted;
+ cursor: help;
+ }
+ .kit-prose :not(.kit-repl) kbd {
+ font-family: var(--md-font-mono);
+ font-size: 0.8em;
+ background: var(--md-color-surface);
+ border: 1px solid var(--md-color-border);
+ border-bottom: 2px solid var(--md-color-border);
+ border-radius: 4px;
+ padding: 0.1em 0.4em;
+ }
+
+ /* ββ Details / Summary ββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose details {
+ border: 1px solid var(--md-color-border);
+ border-radius: 6px;
+ padding: var(--md-space-sm) var(--md-space-md);
+ margin-bottom: var(--md-space-md);
+ background: var(--md-color-surface);
+ }
+
+ .kit-prose summary {
+ font-weight: 600;
+ cursor: pointer;
+ user-select: none;
+ padding: var(--md-space-xs) 0;
+ }
+
+ .kit-prose details[open] summary {
+ margin-bottom: var(--md-space-sm);
+ border-bottom: 1px solid var(--md-color-border);
+ padding-bottom: var(--md-space-sm);
+ }
+
+ /* ββ Task list (GFM) βββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose input[type='checkbox'] {
+ margin-right: 0.4em;
+ vertical-align: middle;
+ accent-color: var(--md-color-link);
+ }
+
+ .kit-prose .task-list-item {
+ list-style-type: none;
+ margin-left: -1.5em;
+ padding-left: 1.5em;
+ }
+
+ /* ββ Footnotes ββββββββββββββββββββββββββββββββββββββββββββββββ */
+ .kit-prose .footnotes {
+ border-top: 1px solid var(--md-color-border);
+ margin-top: var(--md-space-xl);
+ padding-top: var(--md-space-md);
+ font-size: 0.875em;
+ color: var(--md-color-muted);
+ }
+
+ /* ββ Margins within blocks βββββββββββββββββββββ */
+ .kit-prose h1 + p,
+ .kit-prose h2 + p,
+ .kit-prose h3 + p {
+ margin-top: var(--md-space-xs);
+ }
+
+ .kit-prose p + ul,
+ .kit-prose p + ol {
+ margin-top: calc(-1 * var(--md-space-xs));
+ }
+
+ .lazy-repl {
+ margin-bottom: var(--md-space-md);
+ }
+
+ /* ββ Union type wrapper (mixed types + enum chip) ββββββββββββ */
+ .kit-prose .type-union {
+ display: inline-flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.2em;
+ }
+
+ .kit-prose .type-sep {
+ font-family: var(--md-font-mono);
+ font-size: 0.875em;
+ color: var(--md-color-muted);
+ user-select: none;
+ }
+
+ /* ββ Enum chip (union types in tables) βββββββββββββββββββββββ */
+ .kit-prose .enum-chip {
+ position: relative;
+ display: inline-flex;
+ vertical-align: middle;
+ }
+
+ .kit-prose .enum-chip__trigger {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.3em;
+ font-family: var(--md-font-mono);
+ font-size: 0.875em;
+ color: var(--md-color-code-text);
+ background-color: var(--md-color-code-bg);
+ border: 1px solid var(--md-color-border);
+ border-radius: 4px;
+ padding: 0.1em 0.35em;
+ cursor: default;
+ white-space: nowrap;
+ user-select: none;
+ outline-offset: 2px;
+ }
+
+ .kit-prose .enum-chip__trigger:focus-visible {
+ outline: 2px solid var(--md-color-link);
+ }
+
+ .kit-prose .enum-chip__count {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--md-color-code-text);
+ color: var(--md-color-bg);
+ border-radius: 10px;
+ font-size: 0.7em;
+ line-height: 1;
+ padding: 0.15em 0.45em;
+ min-width: 1.4em;
+ font-style: normal;
+ }
+
+ .kit-prose .enum-chip__popover {
+ visibility: hidden;
+ opacity: 0;
+ pointer-events: none;
+ position: absolute;
+ bottom: calc(100% + 6px);
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 100;
+ background: var(--md-color-bg);
+ border: 1px solid var(--md-color-border);
+ border-radius: 8px;
+ padding: 0.4rem 0.5rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+ min-width: max-content;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+ transition:
+ opacity 0.15s ease,
+ visibility 0.15s ease;
+ }
+
+ .kit-prose .enum-chip:hover .enum-chip__popover,
+ .kit-prose .enum-chip:focus-within .enum-chip__popover {
+ visibility: visible;
+ opacity: 1;
+ pointer-events: auto;
+ }
+
+ .kit-prose .enum-chip__popover code {
+ display: block;
+ font-size: 0.8rem;
+ background-color: transparent;
+ border: none;
+ padding: 0;
+ white-space: nowrap;
+ }
+
+ /* Popover content rendered by EnumChip.svelte (kit:popover) */
+ .kit-prose .enum-chip__list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+ }
+
+ .kit-prose .enum-chip__list li {
+ margin: 0;
+ }
+
+ .kit-prose .enum-chip__list code {
+ font-size: 0.8rem;
+ white-space: nowrap;
+ }
+
+ /* ββ Print ββββββββββββββββββββββββββββββββββββββββββββββββββββ */
+ @media print {
+ .kit-prose {
+ max-width: 100%;
+ font-size: 12pt;
+ color: #000;
+ background: #fff;
+ }
+ .kit-prose a {
+ color: #000;
+ text-decoration: underline;
+ }
+ .kit-prose pre,
+ .kit-prose code {
+ border: 1px solid #ccc;
+ }
+ }
+} /* end @layer kit-prose */
diff --git a/src/routes/sitemap.xml/+server.ts b/src/routes/sitemap.xml/+server.ts
new file mode 100644
index 00000000..c9d7f2e5
--- /dev/null
+++ b/src/routes/sitemap.xml/+server.ts
@@ -0,0 +1,44 @@
+import { docsPaths } from '$lib';
+
+export const prerender = true;
+
+const pageModules = import.meta.glob('/src/routes/**/+page.svelte');
+const markdownModules = import.meta.glob('/src/routes/**/+page.md');
+
+function toUrl(path: string) {
+ const route = path
+ .replace('/src/routes', '')
+ .replace(/\/\+page\.(svelte|md)$/, '')
+ .replace(/\/$/, '');
+
+ return route || '/';
+}
+
+export async function GET({ request }) {
+ const baseUrl = new URL(request.url).origin;
+
+ const routes = [...Object.keys(pageModules), ...Object.keys(markdownModules)]
+ .map(toUrl)
+ .filter((route) => !route.includes('['))
+ .filter((route) => !route.includes('('))
+ .concat(docsPaths);
+
+ const uniqueRoutes = [...new Set(routes)].sort();
+
+ const body = `
+
+${uniqueRoutes
+ .map(
+ (route) => `
+ ${baseUrl}${route}
+ `
+ )
+ .join('\n')}
+ `;
+
+ return new Response(body, {
+ headers: {
+ 'Content-Type': 'application/xml; charset=utf-8'
+ }
+ });
+}
diff --git a/src/routes/terms/+page.md b/src/routes/terms/+page.md
new file mode 100644
index 00000000..9cd28254
--- /dev/null
+++ b/src/routes/terms/+page.md
@@ -0,0 +1,64 @@
+# Legal notices Lapikit
+
+Updated to 31/03/2026
+
+## Website publisher
+
+The **lapikit.dev** website is published by:
+
+**Nycolaide**
+
+Avenue de Paris, 91300 Massy, France
+
+Email: [contact@lapikit.dev](mailto:contact@lapikit.dev)
+
+## Hosting
+
+The website is hosted on a server at:
+
+**OVHcloud**
+
+2 rue Kellermann
+
+59100 Roubaix, France
+
+Website: [https://www.ovhcloud.com](https://www.ovhcloud.com)
+
+## Intellectual property
+
+The Lapikit project is distributed under an [MIT license](https://github.com/lapikit/lapikit/blob/main/LICENSE),which means that its source code can be freely used, modified, and redistributed under the terms of this license.
+
+However:
+
+- The name β**Lapikit**,β the **logo**, **the visual identity**, and the **lapikit.dev** website remain the exclusive property of their author, **Nycolaide**.
+- Any reproduction, use, or distribution of these elements without express authorization is prohibited.
+
+## Personal data & GDPR
+
+The lapikit.dev website may collect certain personal data (for example, via a contact form).
+This data is used solely for communication between the publisher and the user, and is not transferred to third parties under any circumstances.
+
+In accordance with the General Data Protection Regulation (GDPR), you have the right to access, rectify, delete, and object to the use of your personal data.
+
+To exercise these rights, you can write to: [contact@lapikit.dev](mailto:contact@lapikit.dev)
+
+### Cookies & audience measurement
+
+The site uses:
+
+- **Necessary cookies**, required for the proper functioning of the site and for saving your privacy choices.
+- **Audience measurement cookies**, used to understand site traffic and improve the documentation experience.
+
+In particular:
+
+- The site uses **Google Tag Manager** to manage certain tracking services.
+- The site uses **Google Analytics**, a service provided by Google Inc., to analyze site traffic and usage.
+
+These cookies are only placed after your explicit consent, collected via the information banner displayed on your first visit.
+
+You can at any time:
+
+- Accept or refuse the use of these cookies.
+- Change your preferences via the `Cookie settings` button on the site or via your browser settings.
+
+Certain data (including your IP address and browsing information) may be transferred and stored by Google on servers located outside the European Union.
diff --git a/src/routes/theme.css b/src/routes/theme.css
new file mode 100644
index 00000000..fb7cd591
--- /dev/null
+++ b/src/routes/theme.css
@@ -0,0 +1,110 @@
+html[data-theme='light'] {
+ color-scheme: light;
+ --kit-bg: hsl(0 0% 100%);
+ --kit-fg: hsl(222 20% 10%);
+ --kit-muted: hsl(220 10% 45%);
+
+ --kit-surface-1: hsl(0 0% 100%);
+ --kit-surface-2: hsl(220 20% 98%);
+ --kit-surface-3: hsl(220 18% 94%);
+
+ --kit-border: hsl(220 16% 88%);
+
+ --kit-accent: hsl(220 90% 56%);
+
+ --kit-focus: hsl(35, 90%, 56%);
+
+ /** markdown theme variables */
+ --md-color-text: #1a1a1a;
+ --md-color-muted: #555;
+ --md-color-link: #0969da;
+ --md-color-link-hover: #0550ae;
+ --md-color-border: #d0d7de;
+ --md-color-bg: #ffffff;
+ --md-color-surface: #f6f8fa;
+ --md-color-code-bg: #f0f2f5;
+ --md-color-code-text: #c7254e;
+ --md-color-blockquote: #57606a;
+ --md-color-blockquote-border: #0969da;
+ --md-color-mark: #fff3b0;
+ --md-color-ins: #d4f8d4;
+ --md-color-del: #ffd7d7;
+}
+
+@media (prefers-color-scheme: dark) {
+ html:not([data-theme='light']) {
+ color-scheme: dark;
+ --md-color-text: #e6edf3;
+ --md-color-muted: #8b949e;
+ --md-color-link: #58a6ff;
+ --md-color-link-hover: #79b8ff;
+ --md-color-border: #30363d;
+ --md-color-bg: hsl(222 20% 9%);
+ --md-color-surface: hsl(222 18% 15%);
+ --md-color-code-bg: hsl(222 16% 14%);
+ --md-color-code-text: #ff7b72;
+ --md-color-blockquote: #8b949e;
+ --md-color-blockquote-border: #58a6ff;
+ --md-color-mark: #3d3200;
+ --md-color-ins: #122b14;
+ --md-color-del: #3d0c10;
+ --md-table-head-bg: hsl(222 18% 15%);
+ --md-table-stripe-bg: hsl(222 20% 12%);
+ }
+
+ html:not([data-theme='light']),
+ html:not([data-theme='light']) div#kit-app {
+ color-scheme: dark;
+ --kit-bg: hsl(222 20% 9%);
+ --kit-fg: hsl(220 15% 93%);
+ --kit-muted: hsl(220 10% 60%);
+
+ --kit-surface-1: hsl(222 20% 11%);
+ --kit-surface-2: hsl(222 18% 15%);
+ --kit-surface-3: hsl(222 16% 20%);
+
+ --kit-border: hsl(220 15% 26%);
+
+ --kit-accent: hsl(220 90% 65%);
+
+ --kit-focus: hsl(35 90% 62%);
+ }
+}
+
+html[data-theme='dark'],
+html[data-theme='dark'] div#kit-app {
+ color-scheme: dark;
+ --kit-bg: hsl(222 20% 9%);
+ --kit-fg: hsl(220 15% 93%);
+ --kit-muted: hsl(220 10% 60%);
+
+ --kit-surface-1: hsl(222 20% 11%);
+ --kit-surface-2: hsl(222 18% 15%);
+ --kit-surface-3: hsl(222 16% 20%);
+
+ --kit-border: hsl(220 15% 26%);
+
+ --kit-accent: hsl(220 90% 65%);
+
+ --kit-focus: hsl(35 90% 62%);
+}
+
+html[data-theme='dark'] {
+ color-scheme: dark;
+ --md-color-text: #e6edf3;
+ --md-color-muted: #8b949e;
+ --md-color-link: #58a6ff;
+ --md-color-link-hover: #79b8ff;
+ --md-color-border: #30363d;
+ --md-color-bg: hsl(222 20% 9%);
+ --md-color-surface: hsl(222 18% 15%);
+ --md-color-code-bg: hsl(222 16% 14%);
+ --md-color-code-text: #ff7b72;
+ --md-color-blockquote: #8b949e;
+ --md-color-blockquote-border: #58a6ff;
+ --md-color-mark: #3d3200;
+ --md-color-ins: #122b14;
+ --md-color-del: #3d0c10;
+ --md-table-head-bg: hsl(222 18% 15%);
+ --md-table-stripe-bg: hsl(222 20% 12%);
+}
diff --git a/src/templates/doc.svelte b/src/templates/doc.svelte
new file mode 100644
index 00000000..7dbfec69
--- /dev/null
+++ b/src/templates/doc.svelte
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+ {#each docsNavigation as { label, icon, pages } (label)}
+
+
+ {#snippet prepend()}
+
+ {#if typeof icon === 'string'}
+ {@html icon}
+ {:else}
+ {@const Icon = icon}
+
+ {/if}
+
+ {/snippet}
+ {label}
+
+
+ {#each pages as page (page.label)}
+ (navOpen = false)}
+ active={normalizedPath === page.url}
+ >
+ {page.label}
+
+ {/each}
+
+ {/each}
+
+
+
+
+
+ (navOpen = true)} aria-label="open navigation">
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+
+ Menu
+
+
+
+
+
+ {#snippet activator({ toggle, open }: ModelDropdownProps)}
+ toggle(e.currentTarget as HTMLElement)}>
+ On this page
+
+ {#snippet append()}
+
+ {#if open}
+
+ {:else}
+
+ {/if}
+
+ {/snippet}
+
+ {/snippet}
+
+
+
+
+
+
+
+
+ {@render children?.()}
+
+
+
+ {#if data.prevDoc}
+
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+ {capitalize(data.prevDoc.title)}
+
+ {/if}
+
+ {#if data.nextDoc}
+
+ {#snippet append()}
+
+
+
+ {/snippet}
+ {capitalize(data.nextDoc.title)}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/templates/legacy.svelte b/src/templates/legacy.svelte
new file mode 100644
index 00000000..c7fa47df
--- /dev/null
+++ b/src/templates/legacy.svelte
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+ {#each docsNavigation as { label, icon, pages } (label)}
+
+
+ {#snippet prepend()}
+
+ {#if typeof icon === 'string'}
+ {@html icon}
+ {:else}
+ {@const Icon = icon}
+
+ {/if}
+
+ {/snippet}
+ {label}
+
+
+ {#each pages as page (page.label)}
+ (navOpen = false)}
+ active={normalizedPath === page.url}
+ >
+ {page.label}
+
+ {/each}
+
+ {/each}
+
+
+
+
+
+ (navOpen = true)} aria-label="open navigation">
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+
+ Menu
+
+
+
+
+
+
+
+
+
+
+ This feature is deprecated and is no longer supported. Check out the new features and
+ improvements in the documentation.
+
+
+ {@render children?.()}
+
+
+
+
diff --git a/src/templates/page.svelte b/src/templates/page.svelte
new file mode 100644
index 00000000..072692bf
--- /dev/null
+++ b/src/templates/page.svelte
@@ -0,0 +1,119 @@
+
+
+
+
+
+ Lapikit
+
+
+
+
+
+
+ Documentation
+
+ {@html githubIcon}
+
+
+
+
+
+
+
+
+
+
+ {#snippet activator({ toggle, open }: ModelDropdownProps)}
+ toggle(e.currentTarget as HTMLElement)}>
+ On this page
+
+ {#snippet append()}
+
+ {#if open}
+
+ {:else}
+
+ {/if}
+
+ {/snippet}
+
+ {/snippet}
+
+
+
+
+
+
+
+
+ {@render children?.()}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/templates/section.svelte b/src/templates/section.svelte
new file mode 100644
index 00000000..e8c2a96a
--- /dev/null
+++ b/src/templates/section.svelte
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+ {#each docsNavigation as { label, icon, pages } (label)}
+
+
+ {#snippet prepend()}
+
+ {#if typeof icon === 'string'}
+ {@html icon}
+ {:else}
+ {@const Icon = icon}
+
+ {/if}
+
+ {/snippet}
+ {label}
+
+
+ {#each pages as page (page.label)}
+ (navOpen = false)}
+ active={normalizedPath === page.url}
+ >
+ {page.label}
+
+ {/each}
+
+ {/each}
+
+
+
+
+
+ (navOpen = true)} aria-label="open navigation">
+ {#snippet prepend()}
+
+
+
+ {/snippet}
+
+ Menu
+
+
+
+
+
+
+
+
+
+ {@render children?.()}
+
+
+
+
+
+
+
+
diff --git a/apps/website/static/prod.robots.txt b/static/robots.txt
similarity index 94%
rename from apps/website/static/prod.robots.txt
rename to static/robots.txt
index df8a7993..77f856c7 100644
--- a/apps/website/static/prod.robots.txt
+++ b/static/robots.txt
@@ -17,6 +17,4 @@ Disallow: /app/*
Disallow: /private/*
Disallow: /config/*
Disallow: /tmp/*
-Disallow: /__MACOSX/*
-
-
+Disallow: /__MACOSX/*
\ No newline at end of file
diff --git a/svelte.config.js b/svelte.config.js
new file mode 100644
index 00000000..3539ff36
--- /dev/null
+++ b/svelte.config.js
@@ -0,0 +1,23 @@
+import { mdsvex } from 'mdsvex';
+import adapter from '@sveltejs/adapter-node';
+import { mdsvexOptions } from './mdsvex.config.js';
+import { lapikitPreprocess } from 'lapikit/labs/preprocess';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ kit: {
+ adapter: adapter({
+ out: 'build',
+ precompress: true,
+ envPrefix: ''
+ }),
+ alias: {
+ $components: 'src/components',
+ $examples: 'src/content/examples'
+ }
+ },
+ preprocess: [mdsvex(mdsvexOptions), lapikitPreprocess({ plugins: ['repl'] })],
+ extensions: ['.svelte', '.svx', '.md']
+};
+
+export default config;
diff --git a/tests/renders.test.ts b/tests/renders.test.ts
new file mode 100644
index 00000000..0f677cfa
--- /dev/null
+++ b/tests/renders.test.ts
@@ -0,0 +1,21 @@
+import { test, expect } from '@playwright/test';
+
+const pages = [
+ '/',
+ '/docs',
+ '/docs/introduction',
+ '/docs/getting-started',
+ '/docs/components/application'
+];
+
+for (const path of pages) {
+ test(`${path} loads without errors`, async ({ page }) => {
+ const errors: string[] = [];
+ page.on('pageerror', (err) => errors.push(err.message));
+
+ const response = await page.goto(path);
+
+ expect(response?.status()).toBeLessThan(400);
+ expect(errors).toHaveLength(0);
+ });
+}
diff --git a/tsconfig.json b/tsconfig.json
index 3298e48c..709cb832 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,35 +1,21 @@
{
- "compilerOptions": {
- // Environment setup & latest features
- "lib": ["ESNext"],
- "target": "ESNext",
- "module": "ESNext",
- "moduleDetection": "force",
- "jsx": "react-jsx",
- "allowJs": true,
-
- // Bundler mode
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "noEmit": true,
-
- // Best practices
- "strict": true,
- "skipLibCheck": true,
- "noFallthroughCasesInSwitch": true,
- "noUncheckedIndexedAccess": true,
-
- // Some stricter flags (disabled by default)
- "noUnusedLocals": false,
- "noUnusedParameters": false,
- "noPropertyAccessFromIndexSignature": false
- },
- "references": [
- { "path": "./packages/site-kit/tsconfig.build.json" },
- { "path": "./packages/lapikit/tsconfig.build.json" },
- { "path": "./apps/website/tsconfig.build.json" },
- { "path": "./apps/lapikit.dev/tsconfig.build.json" }
- ],
- "files": []
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "rewriteRelativeImportExtensions": true,
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "moduleResolution": "bundler",
+ "types": ["node"]
+ }
+ // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
+ // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+ //
+ // To make changes to top-level options such as include and exclude, we recommend extending
+ // the generated config; see https://svelte.dev/docs/kit/configuration#typescript
}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 00000000..8461553d
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,18 @@
+import devtoolsJson from 'vite-plugin-devtools-json';
+import tailwindcss from '@tailwindcss/vite';
+import { sveltekit } from '@sveltejs/kit/vite';
+import { enhancedImages } from '@sveltejs/enhanced-img';
+import { defineConfig } from 'vite';
+
+// legacy
+import { lapikit } from 'lapikit/vite';
+
+export default defineConfig(({ command }) => ({
+ plugins: [
+ tailwindcss(),
+ enhancedImages(),
+ sveltekit(),
+ lapikit({ config: 'src/plugins/lapikit.ts' }), //legacy
+ ...(command === 'serve' ? [devtoolsJson()] : [])
+ ]
+}));