[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D2GPZ71X605APW9GRKTFBN":3,"skill-same:01M6D2GPZ71X605APW9GRKTFBN":77},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":59,"ownerHtmlUrl":60,"ownerBlogUrl":59,"ownerDescription":61,"updatedAt":62,"install":63,"resources":76},"01M6D2GPZ71X605APW9GRKTFBN","ui-stack-svelte",null,"Building interfaces in Svelte 5 and SvelteKit: project layout, runes ($state, $state.raw, $derived, $effect only for side effects, typed $props, $bindable, $props.id), snippets and render tags, event attributes, keyed each blocks, class and style directives, attachments, shared state in .svelte.ts modules and context, boundaries, transitions, SvelteKit routes, server and universal load functions, form actions with use:enhance, hooks for auth, env modules, Superforms, Bits UI and Melt UI, testing, svelte-check, and the traps. Read when the project uses Svelte or SvelteKit.","enowdev\u002Fenowxcli","enowdev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F179420349?v=4","01M6D1MVX2KC0X3Z9NESE7P22K","Enow Dev.","01M6D1MW1FMZGBDKWAJY4GQX81",67,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-stack-svelte\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"ui stack svelte","ui","svelte","stack","hooks","layout","project","shared","snippets","svelte 5","enhance","modules","testing","only","context","read","effect","actions","server","auth","2026-11-10 10:12:30",false,"---\nname: ui-stack-svelte\ndescription: \"Building interfaces in Svelte 5 and SvelteKit: project layout, runes ($state, $state.raw, $derived, $effect only for side effects, typed $props, $bindable, $props.id), snippets and render tags, event attributes, keyed each blocks, class and style directives, attachments, shared state in .svelte.ts modules and context, boundaries, transitions, SvelteKit routes, server and universal load functions, form actions with use:enhance, hooks for auth, env modules, Superforms, Bits UI and Melt UI, testing, svelte-check, and the traps. Read when the project uses Svelte or SvelteKit.\"\n---\n\n# Svelte 5 and SvelteKit\n\nGenerated Svelte mixes versions (`export let` beside `$props`, `on:click`\nbeside `onclick`), computes values in `$effect`, forgets keys in `{#each}`,\nkeeps per-user state in a module the server shares between requests, and\nimports database code into a load function that also runs in the browser.\nThis is Svelte 5 (5.57 in September 2026) with SvelteKit 2 as written now:\nrunes, snippets, server-only data, and forms that work before JavaScript\nloads. SvelteKit 3 is in release candidate: follow the project's version.\n\n## 1. Version and layout\n\nMatch the project's Svelte version: these are Svelte 5's runes; a Svelte 4\nproject uses `export let` props and `$:` statements instead, and one\ncomponent never mixes the two.\n\n```text\nsrc\u002Fapp.html  src\u002Fapp.css  src\u002Fapp.d.ts  src\u002Fhooks.server.ts\nsrc\u002Flib\u002Fcomponents\u002Fui\u002F        primitives: Button, Field, Dialog\nsrc\u002Flib\u002Fcomponents\u002Forders\u002F    the parts of one feature\nsrc\u002Flib\u002Fserver\u002F               database and secrets: server imports only\nsrc\u002Flib\u002Fstate\u002Fcart.svelte.ts  shared state written with runes\nsrc\u002Froutes\u002Forders\u002F            +page.svelte, +page.server.ts, +error.svelte\nsrc\u002Froutes\u002Fapi\u002Forders\u002F        +server.ts for other clients\n```\n\nA new project starts with `npx sv create`, then `npx sv add` for Tailwind,\nVitest, Playwright and ESLint rather than wiring them by hand.\n\n## 2. Components\n\n- One component per `.svelte` file. Props with `let { title, variant =\n  \"primary\", ...rest } = $props()`, typed, and `rest` spread onto the native\n  element a primitive wraps.\n- Content through snippets (`{@render children()}`) rather than a prop per\n  variation; snippets with parameters for rows and items.\n\n```svelte\n\u003C!-- src\u002Flib\u002Fcomponents\u002Fui\u002FButton.svelte -->\n\u003Cscript lang=\"ts\">\n  import type { Snippet } from \"svelte\";\n  import type { HTMLButtonAttributes } from \"svelte\u002Felements\";\n  type Props = HTMLButtonAttributes & { variant?: \"primary\" | \"quiet\"; children: Snippet };\n  let { variant = \"primary\", type = \"button\", class: className, children, ...rest }: Props = $props();\n\u003C\u002Fscript>\n\n\u003Cbutton {type} class={[\"btn\", `btn--${variant}`, className]} {...rest}>\n  {@render children()}\n\u003C\u002Fbutton>\n```\n\n```svelte\n\u003C!-- a list that renders rows its caller defines -->\n\u003Cscript lang=\"ts\" generics=\"T extends { id: string }\">\n  import type { Snippet } from \"svelte\";\n  let { items, row, empty }: { items: T[]; row: Snippet\u003C[T]>; empty: Snippet } = $props();\n\u003C\u002Fscript>\n\n{#each items as item (item.id)}{@render row(item)}{:else}{@render empty()}{\u002Feach}\n```\n\n- `class` takes arrays and objects like `clsx` (5.16+); `class:active={on}`\n  and `style:--progress=\"{pct}%\"` for single toggles and values.\n- Events are attributes (`onclick={...}`), with no modifiers: call\n  `event.preventDefault()` in the handler. A component reports up through\n  callback props (`onselect`), not `createEventDispatcher`.\n- `$bindable` only for a value the parent really shares both ways (a\n  field's `value`, a dialog's `open`); otherwise callbacks.\n- `$props.id()` (5.20+) gives an id that matches on server and client, for\n  `for`, `aria-describedby` and `aria-controls`.\n- Attachments, `{@attach tooltip}` (5.29+), replace `use:` actions for DOM\n  behaviour: a function of the element that returns its cleanup.\n- Styles in the component's `\u003Cstyle>` (scoped by default) or the project's\n  Tailwind; tokens as CSS variables in one global place (`app.css`).\n\n## 3. State\n\n- `$state` for what changes, `$derived` for what follows from it; `$effect`\n  only for work outside Svelte (a subscription, the canvas, a chart\n  library), with cleanup.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let { orders }: { orders: Order[] } = $props();\n  let query = $state(\"\");\n  const visible = $derived(orders.filter((o) => o.customer.toLowerCase().includes(query.toLowerCase())));\n  const total = $derived.by(() => visible.reduce((sum, o) => sum + o.amount, 0));\n\u003C\u002Fscript>\n```\n\n- `$state.raw` for large data replaced whole (an API response), reassigned\n  to update; `$state.snapshot(value)` before handing state to other code.\n- A `$derived` can be assigned for an optimistic value (5.25+); it returns\n  to the computed value when its inputs change.\n- Destructuring `$state` copies the current values: read `cart.count`, not\n  `const { count } = cart`.\n- Shared state lives in a `.svelte.ts` module as a class, and reaches\n  components through context:\n\n```ts\n\u002F\u002F src\u002Flib\u002Fstate\u002Fcart.svelte.ts\nimport { createContext } from \"svelte\";\nexport class Cart {\n  items = $state\u003CCartItem[]>([]);\n  count = $derived(this.items.reduce((n, item) => n + item.quantity, 0));\n  add(item: CartItem) { this.items.push(item); }\n}\nexport const [getCart, setCart] = createContext\u003CCart>(); \u002F\u002F 5.40+; setContext and getContext before\n```\n\n`setCart(new Cart())` in the root layout, `const cart = getCart()` below. A\nmodule-level instance is shared by every request on the server, one user's\ncart shown to the next: module state only for what never differs per user.\n\n- Loading, error and empty as branches: `{#await}` for a promise, explicit\n  states otherwise, `{:else}` for an empty `{#each}`. `\u003Csvelte:boundary>`\n  with a `failed` snippet (and its `reset`) around a part that can throw.\n\n## 4. Lists and motion\n\n- `{#each items as item (item.id)}`: keyed by a stable id, for every list\n  that changes.\n- `svelte\u002Ftransition` (`fade`, `fly`, `slide`) for purposeful motion and\n  `animate:flip` in keyed lists, with duration 0 when reduced motion is on\n  (`prefersReducedMotion.current` from `svelte\u002Fmotion`; `motion-stacks`).\n\n## 5. SvelteKit: data\n\n- `+page.server.ts` loads anything touching the database, secrets or\n  cookies; `+page.ts` (universal) runs on the server and in the browser, so\n  it calls public APIs only. `$lib\u002Fserver` never reaches a browser bundle.\n\n```ts\n\u002F\u002F src\u002Froutes\u002Forders\u002F+page.server.ts\nimport { redirect } from \"@sveltejs\u002Fkit\";\nimport { listOrders, listActivity } from \"$lib\u002Fserver\u002Forders\";\nimport type { PageServerLoad } from \".\u002F$types\";\n\nexport const load: PageServerLoad = async ({ locals, url }) => {\n  if (!locals.user) redirect(303, `\u002Flogin?next=${encodeURIComponent(url.pathname)}`);\n  return {\n    orders: await listOrders(locals.user, url.searchParams.get(\"status\") ?? \"open\"),\n    activity: listActivity(locals.user), \u002F\u002F not awaited: streams in after the page\n  };\n};\n```\n\n- The page reads `let { data }: PageProps = $props()` (2.16+) and streams\n  the slow part with `{#await data.activity}` and a skeleton.\n- `redirect()`, `error(404, \"Order not found\")` and `fail()` come from\n  `@sveltejs\u002Fkit`; in SvelteKit 2 they throw on their own.\n- `+error.svelte` per section for failures, `+layout.svelte` for the shared\n  frame, `\u003Csvelte:head>` for the title and description.\n- Auth in `hooks.server.ts`: `handle` puts the session's user in\n  `event.locals.user`. A layout's load does not guard form actions or\n  `+server.ts` routes: check the user in each (`backend-auth`).\n- `$env\u002Fstatic\u002Fprivate` and `$env\u002Fdynamic\u002Fprivate` in server files only;\n  browser code reads `$env\u002Fstatic\u002Fpublic` (names starting `PUBLIC_`).\n- `page` from `$app\u002Fstate` (2.12+) in new code, not the `$page` store.\n- Remote functions (`query`, `form`, `command` in `.remote.ts`) are still\n  experimental (2.27+, two flags): only where the project has them on.\n\n## 6. Forms\n\nForm actions in `+page.server.ts`, a real `\u003Cform method=\"POST\">`, and\n`use:enhance` from `$app\u002Fforms`: it works without JavaScript and upgrades\nwith it.\n\n```ts\n\u002F\u002F src\u002Froutes\u002Forders\u002Fnew\u002F+page.server.ts\nimport { fail, redirect } from \"@sveltejs\u002Fkit\";\nimport { createOrder } from \"$lib\u002Fserver\u002Forders\";\nimport type { Actions } from \".\u002F$types\";\n\nexport const actions = {\n  default: async ({ request, locals }) => {\n    if (!locals.user) redirect(303, \"\u002Flogin\");\n    const title = String((await request.formData()).get(\"title\") ?? \"\").trim();\n    if (!title) return fail(400, { title, errors: { title: \"Give the order a title.\" } });\n    const order = await createOrder(locals.user, { title });\n    redirect(303, `\u002Forders\u002F${order.id}`);\n  },\n} satisfies Actions;\n```\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { enhance } from \"$app\u002Fforms\";\n  import type { PageProps } from \".\u002F$types\";\n  let { form }: PageProps = $props();\n  let saving = $state(false);\n\u003C\u002Fscript>\n\n\u003Cform method=\"POST\" use:enhance={() => {\n  saving = true;\n  return async ({ update }) => { await update(); saving = false; };\n}}>\n  \u003Clabel for=\"title\">Title\u003C\u002Flabel>\n  \u003Cinput id=\"title\" name=\"title\" value={form?.title ?? \"\"}\n    aria-invalid={!!form?.errors?.title} aria-describedby=\"title-error\" \u002F>\n  \u003Cp id=\"title-error\">{form?.errors?.title}\u003C\u002Fp>\n  \u003Cbutton disabled={saving}>{saving ? \"Creating...\" : \"Create order\"}\u003C\u002Fbutton>\n\u003C\u002Fform>\n```\n\n- Superforms for larger forms: `superValidate(request, zod4(schema))` on the\n  server (`zod4` from `sveltekit-superforms\u002Fadapters`, `zod` for Zod 3),\n  `superForm(data.form)` in the page for errors, constraints and a\n  `$submitting` flag (`frontend-forms`).\n\n## 7. Accessible widgets\n\n- Menus, dialogs, selects, comboboxes and popovers from Bits UI (headless,\n  what shadcn-svelte is built on) or Melt UI's builders, themed with the\n  tokens, not hand-rolled; `\u003Cdialog>` and `popover` for simple cases.\n- `svelte-check` reports the compiler's accessibility warnings (a click\n  handler on a `div`, a missing label): fix them rather than silence them.\n\n## 8. Testing\n\nVitest with `@testing-library\u002Fsvelte`, or Vitest browser mode with\n`vitest-browser-svelte`, querying by role and name; Playwright for flows\nacross pages (`frontend-testing`).\n\n## 9. Traps\n\n- `$effect` computing a value (`$effect(() => { total = ... })`): use\n  `$derived`. An effect that writes state it reads loops.\n- Mutating a prop the parent owns: callbacks, or `$bindable`.\n- Missing keys: after a delete, the next row inherits the removed row's\n  input and focus.\n- Server-only code in a universal load (`+page.ts`) or a component.\n- A reassigned `$state` primitive exported from a module: export an object\n  or a class and change its properties.\n- `window` or `localStorage` read at a component's top level, which also\n  runs on the server: read it in `$effect`, or behind `browser` from\n  `$app\u002Fenvironment`.\n- `{@html}` with anything but sanitised content: it bypasses escaping.\n\n## Check it\n\n- `npm run check` (`svelte-kit sync` and `svelte-check`): types and\n  accessibility warnings. `npm run build`, and `npx vitest run`.\n- Look at it with the `preview` tool: `url` `http:\u002F\u002Flocalhost:5173\u002F` and\n  `start` `npm run dev -- --port 5173 --strictPort`.\n- With JavaScript off, pages still render and forms still post.\n\n## Avoid\n\nSvelte 4 and 5 syntax in one component; `$effect` for derived values;\nstores for new state; module-level state holding user data; unkeyed lists\nthat change; database or secret imports in `+page.ts` or components; a\nlayout load as the only auth check; `createEventDispatcher` in new code;\n`{@html}` with user input; forms that only work with JavaScript.\n","# Svelte 5 and SvelteKit\n\nGenerated Svelte mixes versions (`export let` beside `$props`, `on:click`\nbeside `onclick`), computes values in `$effect`, forgets keys in `{#each}`,\nkeeps per-user state in a module the server shares between requests, and\nimports database code into a load function that also runs in the browser.\nThis is Svelte 5 (5.57 in September 2026) with SvelteKit 2 as written now:\nrunes, snippets, server-only data, and forms that work before JavaScript\nloads. SvelteKit 3 is in release candidate: follow the project's version.\n\n## 1. Version and layout\n\nMatch the project's Svelte version: these are Svelte 5's runes; a Svelte 4\nproject uses `export let` props and `$:` statements instead, and one\ncomponent never mixes the two.\n\n```text\nsrc\u002Fapp.html  src\u002Fapp.css  src\u002Fapp.d.ts  src\u002Fhooks.server.ts\nsrc\u002Flib\u002Fcomponents\u002Fui\u002F        primitives: Button, Field, Dialog\nsrc\u002Flib\u002Fcomponents\u002Forders\u002F    the parts of one feature\nsrc\u002Flib\u002Fserver\u002F               database and secrets: server imports only\nsrc\u002Flib\u002Fstate\u002Fcart.svelte.ts  shared state written with runes\nsrc\u002Froutes\u002Forders\u002F            +page.svelte, +page.server.ts, +error.svelte\nsrc\u002Froutes\u002Fapi\u002Forders\u002F        +server.ts for other clients\n```\n\nA new project starts with `npx sv create`, then `npx sv add` for Tailwind,\nVitest, Playwright and ESLint rather than wiring them by hand.\n\n## 2. Components\n\n- One component per `.svelte` file. Props with `let { title, variant =\n  \"primary\", ...rest } = $props()`, typed, and `rest` spread onto the native\n  element a primitive wraps.\n- Content through snippets (`{@render children()}`) rather than a prop per\n  variation; snippets with parameters for rows and items.\n\n```svelte\n\u003C!-- src\u002Flib\u002Fcomponents\u002Fui\u002FButton.svelte -->\n\u003Cscript lang=\"ts\">\n  import type { Snippet } from \"svelte\";\n  import type { HTMLButtonAttributes } from \"svelte\u002Felements\";\n  type Props = HTMLButtonAttributes & { variant?: \"primary\" | \"quiet\"; children: Snippet };\n  let { variant = \"primary\", type = \"button\", class: className, children, ...rest }: Props = $props();\n\u003C\u002Fscript>\n\n\u003Cbutton {type} class={[\"btn\", `btn--${variant}`, className]} {...rest}>\n  {@render children()}\n\u003C\u002Fbutton>\n```\n\n```svelte\n\u003C!-- a list that renders rows its caller defines -->\n\u003Cscript lang=\"ts\" generics=\"T extends { id: string }\">\n  import type { Snippet } from \"svelte\";\n  let { items, row, empty }: { items: T[]; row: Snippet\u003C[T]>; empty: Snippet } = $props();\n\u003C\u002Fscript>\n\n{#each items as item (item.id)}{@render row(item)}{:else}{@render empty()}{\u002Feach}\n```\n\n- `class` takes arrays and objects like `clsx` (5.16+); `class:active={on}`\n  and `style:--progress=\"{pct}%\"` for single toggles and values.\n- Events are attributes (`onclick={...}`), with no modifiers: call\n  `event.preventDefault()` in the handler. A component reports up through\n  callback props (`onselect`), not `createEventDispatcher`.\n- `$bindable` only for a value the parent really shares both ways (a\n  field's `value`, a dialog's `open`); otherwise callbacks.\n- `$props.id()` (5.20+) gives an id that matches on server and client, for\n  `for`, `aria-describedby` and `aria-controls`.\n- Attachments, `{@attach tooltip}` (5.29+), replace `use:` actions for DOM\n  behaviour: a function of the element that returns its cleanup.\n- Styles in the component's `\u003Cstyle>` (scoped by default) or the project's\n  Tailwind; tokens as CSS variables in one global place (`app.css`).\n\n## 3. State\n\n- `$state` for what changes, `$derived` for what follows from it; `$effect`\n  only for work outside Svelte (a subscription, the canvas, a chart\n  library), with cleanup.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let { orders }: { orders: Order[] } = $props();\n  let query = $state(\"\");\n  const visible = $derived(orders.filter((o) => o.customer.toLowerCase().includes(query.toLowerCase())));\n  const total = $derived.by(() => visible.reduce((sum, o) => sum + o.amount, 0));\n\u003C\u002Fscript>\n```\n\n- `$state.raw` for large data replaced whole (an API response), reassigned\n  to update; `$state.snapshot(value)` before handing state to other code.\n- A `$derived` can be assigned for an optimistic value (5.25+); it returns\n  to the computed value when its inputs change.\n- Destructuring `$state` copies the current values: read `cart.count`, not\n  `const { count } = cart`.\n- Shared state lives in a `.svelte.ts` module as a class, and reaches\n  components through context:\n\n```ts\n\u002F\u002F src\u002Flib\u002Fstate\u002Fcart.svelte.ts\nimport { createContext } from \"svelte\";\nexport class Cart {\n  items = $state\u003CCartItem[]>([]);\n  count = $derived(this.items.reduce((n, item) => n + item.quantity, 0));\n  add(item: CartItem) { this.items.push(item); }\n}\nexport const [getCart, setCart] = createContext\u003CCart>(); \u002F\u002F 5.40+; setContext and getContext before\n```\n\n`setCart(new Cart())` in the root layout, `const cart = getCart()` below. A\nmodule-level instance is shared by every request on the server, one user's\ncart shown to the next: module state only for what never differs per user.\n\n- Loading, error and empty as branches: `{#await}` for a promise, explicit\n  states otherwise, `{:else}` for an empty `{#each}`. `\u003Csvelte:boundary>`\n  with a `failed` snippet (and its `reset`) around a part that can throw.\n\n## 4. Lists and motion\n\n- `{#each items as item (item.id)}`: keyed by a stable id, for every list\n  that changes.\n- `svelte\u002Ftransition` (`fade`, `fly`, `slide`) for purposeful motion and\n  `animate:flip` in keyed lists, with duration 0 when reduced motion is on\n  (`prefersReducedMotion.current` from `svelte\u002Fmotion`; `motion-stacks`).\n\n## 5. SvelteKit: data\n\n- `+page.server.ts` loads anything touching the database, secrets or\n  cookies; `+page.ts` (universal) runs on the server and in the browser, so\n  it calls public APIs only. `$lib\u002Fserver` never reaches a browser bundle.\n\n```ts\n\u002F\u002F src\u002Froutes\u002Forders\u002F+page.server.ts\nimport { redirect } from \"@sveltejs\u002Fkit\";\nimport { listOrders, listActivity } from \"$lib\u002Fserver\u002Forders\";\nimport type { PageServerLoad } from \".\u002F$types\";\n\nexport const load: PageServerLoad = async ({ locals, url }) => {\n  if (!locals.user) redirect(303, `\u002Flogin?next=${encodeURIComponent(url.pathname)}`);\n  return {\n    orders: await listOrders(locals.user, url.searchParams.get(\"status\") ?? \"open\"),\n    activity: listActivity(locals.user), \u002F\u002F not awaited: streams in after the page\n  };\n};\n```\n\n- The page reads `let { data }: PageProps = $props()` (2.16+) and streams\n  the slow part with `{#await data.activity}` and a skeleton.\n- `redirect()`, `error(404, \"Order not found\")` and `fail()` come from\n  `@sveltejs\u002Fkit`; in SvelteKit 2 they throw on their own.\n- `+error.svelte` per section for failures, `+layout.svelte` for the shared\n  frame, `\u003Csvelte:head>` for the title and description.\n- Auth in `hooks.server.ts`: `handle` puts the session's user in\n  `event.locals.user`. A layout's load does not guard form actions or\n  `+server.ts` routes: check the user in each (`backend-auth`).\n- `$env\u002Fstatic\u002Fprivate` and `$env\u002Fdynamic\u002Fprivate` in server files only;\n  browser code reads `$env\u002Fstatic\u002Fpublic` (names starting `PUBLIC_`).\n- `page` from `$app\u002Fstate` (2.12+) in new code, not the `$page` store.\n- Remote functions (`query`, `form`, `command` in `.remote.ts`) are still\n  experimental (2.27+, two flags): only where the project has them on.\n\n## 6. Forms\n\nForm actions in `+page.server.ts`, a real `\u003Cform method=\"POST\">`, and\n`use:enhance` from `$app\u002Fforms`: it works without JavaScript and upgrades\nwith it.\n\n```ts\n\u002F\u002F src\u002Froutes\u002Forders\u002Fnew\u002F+page.server.ts\nimport { fail, redirect } from \"@sveltejs\u002Fkit\";\nimport { createOrder } from \"$lib\u002Fserver\u002Forders\";\nimport type { Actions } from \".\u002F$types\";\n\nexport const actions = {\n  default: async ({ request, locals }) => {\n    if (!locals.user) redirect(303, \"\u002Flogin\");\n    const title = String((await request.formData()).get(\"title\") ?? \"\").trim();\n    if (!title) return fail(400, { title, errors: { title: \"Give the order a title.\" } });\n    const order = await createOrder(locals.user, { title });\n    redirect(303, `\u002Forders\u002F${order.id}`);\n  },\n} satisfies Actions;\n```\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { enhance } from \"$app\u002Fforms\";\n  import type { PageProps } from \".\u002F$types\";\n  let { form }: PageProps = $props();\n  let saving = $state(false);\n\u003C\u002Fscript>\n\n\u003Cform method=\"POST\" use:enhance={() => {\n  saving = true;\n  return async ({ update }) => { await update(); saving = false; };\n}}>\n  \u003Clabel for=\"title\">Title\u003C\u002Flabel>\n  \u003Cinput id=\"title\" name=\"title\" value={form?.title ?? \"\"}\n    aria-invalid={!!form?.errors?.title} aria-describedby=\"title-error\" \u002F>\n  \u003Cp id=\"title-error\">{form?.errors?.title}\u003C\u002Fp>\n  \u003Cbutton disabled={saving}>{saving ? \"Creating...\" : \"Create order\"}\u003C\u002Fbutton>\n\u003C\u002Fform>\n```\n\n- Superforms for larger forms: `superValidate(request, zod4(schema))` on the\n  server (`zod4` from `sveltekit-superforms\u002Fadapters`, `zod` for Zod 3),\n  `superForm(data.form)` in the page for errors, constraints and a\n  `$submitting` flag (`frontend-forms`).\n\n## 7. Accessible widgets\n\n- Menus, dialogs, selects, comboboxes and popovers from Bits UI (headless,\n  what shadcn-svelte is built on) or Melt UI's builders, themed with the\n  tokens, not hand-rolled; `\u003Cdialog>` and `popover` for simple cases.\n- `svelte-check` reports the compiler's accessibility warnings (a click\n  handler on a `div`, a missing label): fix them rather than silence them.\n\n## 8. Testing\n\nVitest with `@testing-library\u002Fsvelte`, or Vitest browser mode with\n`vitest-browser-svelte`, querying by role and name; Playwright for flows\nacross pages (`frontend-testing`).\n\n## 9. Traps\n\n- `$effect` computing a value (`$effect(() => { total = ... })`): use\n  `$derived`. An effect that writes state it reads loops.\n- Mutating a prop the parent owns: callbacks, or `$bindable`.\n- Missing keys: after a delete, the next row inherits the removed row's\n  input and focus.\n- Server-only code in a universal load (`+page.ts`) or a component.\n- A reassigned `$state` primitive exported from a module: export an object\n  or a class and change its properties.\n- `window` or `localStorage` read at a component's top level, which also\n  runs on the server: read it in `$effect`, or behind `browser` from\n  `$app\u002Fenvironment`.\n- `{@html}` with anything but sanitised content: it bypasses escaping.\n\n## Check it\n\n- `npm run check` (`svelte-kit sync` and `svelte-check`): types and\n  accessibility warnings. `npm run build`, and `npx vitest run`.\n- Look at it with the `preview` tool: `url` `http:\u002F\u002Flocalhost:5173\u002F` and\n  `start` `npm run dev -- --port 5173 --strictPort`.\n- With JavaScript off, pages still render and forms still post.\n\n## Avoid\n\nSvelte 4 and 5 syntax in one component; `$effect` for derived values;\nstores for new state; module-level state holding user data; unkeyed lists\nthat change; database or secret imports in `+page.ts` or components; a\nlayout load as the only auth check; `createEventDispatcher` in new code;\n`{@html}` with user input; forms that only work with JavaScript.\n",{"name":5,"description":7},"main","38293fe1b096e6bf3646c7344c38786ed688f464","crates\u002Fenowx-core\u002Fskills\u002Fui-stack-svelte",21,"https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli","https:\u002F\u002Fenowx.ai","https:\u002F\u002Fgithub.com\u002Fenowdev","Pretending to be a Developer","2026-10-06 02:05:35",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add enowdev\u002Fenowxcli --skill ui-stack-svelte",{"tool":69,"command":70},"bunx","bunx skills add enowdev\u002Fenowxcli --skill ui-stack-svelte",{"tool":72,"command":73},"pnpm","pnpm dlx skills add enowdev\u002Fenowxcli --skill ui-stack-svelte","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-stack-svelte\u002FSKILL.md",true,[],[78,91,114,126,153,175],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":87,"publishedAt":49},"01M6D2HQYSQD9N7MTNDT4A7CBM","demo-skill","Project-scope demo skill for tests.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fworkspace\u002F.agents\u002Fskills\u002Fdemo-skill\u002FSKILL.md",[84],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[88,89,90,35,44],"demo skill","demo","tests",{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":103,"publishedAt":49},"01M6D2HM0GCPM0TM2HPG9HHR2R","writing","Writing words people read: the specific thing instead of claims, words to drop, sentences, interface copy (buttons, labels, errors, empty states, confirmations), page copy, notifications and emails, alt text and link text, numbers and dates, words that translate well, documentation and voice. Read before writing a page's copy, an interface's text or a document.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fwriting\u002FSKILL.md",[97,100],{"categoryNo":98,"categoryName":99,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":101,"categoryName":102,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000036","内容创作者",[93,104,105,106,107,108,44,109,110,111,112,113],"text","emails","empty","drop","document","page","voice","notifications","documentation","translate",{"skillNo":115,"name":30,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":120,"publishedAt":49},"01M6D2HG07YS49NM196Q0R3AZ8","Designing or restyling an interface: direction, layout, type, colour, icons, components, states, responsive behaviour. Read before building a page, a screen or a set of components.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui\u002FSKILL.md",[119],{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[30,121,122,123,124,109,34,44,125],"icons","components","SET","responsive","before building",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":138,"publishedAt":49},"01M6D2HB59HZHWG1RYZDV4SJ91","ui-themes","Light and dark themes, and colour that holds in both: tokens with a value per theme, and what each kind of content needs to stay visible (icons, SVG drawings and line art, logos, photos, screenshots, charts, code, maps, borders, shadows, focus, form controls), switching without a flash, and checking both. Read before building a second theme or a theme toggle, and before any drawing, logo or chart on a page that has two themes.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-themes\u002FSKILL.md",[132,135],{"categoryNo":133,"categoryName":134,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":136,"categoryName":137,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师",[30,139,140,141,142,143,144,145,146,44,125,147,109,148,149,150,121,151,152],"ui themes","switching","photos","tokens","drawing","focus","maps","Art","flash","code","Charts","content","screenshots","logo",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":162,"publishedAt":49},"01M6D2H5R5KRAE524C8QX0T7Q0","ui-structure","Structure before styling: the blueprint written before any interface code (the screen's job, the regions its kind of page needs, their order and why, the layout skeleton in numbers, the components and their states), the anatomy and order of a homepage, a dashboard, a list, a detail page, settings, a form, sign-in, pricing, docs, an article and a checkout, and how to turn the blueprint into code (tokens, layout primitives, components, sections, page). Read first, before building or rebuilding any page or screen.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-structure\u002FSKILL.md",[159,160,161],{"categoryNo":98,"categoryName":99,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":136,"categoryName":137,"taxonomyType":26,"taxonomyTypeDesc":27},{"categoryNo":101,"categoryName":102,"taxonomyType":26,"taxonomyTypeDesc":27},[163,30,164,122,165,166,148,167,168,169,34,142,170,171,172,44,125,109,173,174],"structure","ui structure","pricing","dashboard","Blueprint","article","anatomy","styling","primitives","list","why","how",{"skillNo":176,"name":177,"nameZh":6,"description":178,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":179,"categories":180,"keywords":186,"publishedAt":49},"01M6D2H0ZZBJG77MBGPZHA6MWD","ui-stack-vue","Building interfaces in Vue 3 and Nuxt: project layout, script setup with typed defineProps, defineEmits and defineModel, attribute fallthrough, slots and scoped slots, template refs, ref, reactive and computed, watch versus watchEffect, composables and VueUse, provide and inject, Pinia, keyed v-for, transitions, Nuxt 4 (app directory, pages, layouts, useFetch and useAsyncData keys, $fetch in handlers, server routes, runtime config, useSeoMeta, NuxtImg, middleware), VeeValidate forms, Reka UI and Nuxt UI, testing, vue-tsc, and the traps. Read when the project uses Vue or Nuxt.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-stack-vue\u002FSKILL.md",[181,182,185],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":183,"categoryName":184,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[30,187,32,188,189,190,191,192,34,35,193,194,44,195,196,197,47,198,199,41],"vue","ui stack vue","forms","pages","watch","runtime","transitions","fetch","pinia","nuxt","template","config","directory"]