[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D2CMFPVNQFZVE5M7TE1AFP":3,"skill-same:01M6D2CMFPVNQFZVE5M7TE1AFP":62},{"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":18,"publishedAt":34,"linkOnly":35,"markdownContent":36,"markdownBody":37,"frontMatter":38,"refName":39,"commitSha":40,"skillDirectory":41,"forksCount":42,"repositoryHtmlUrl":43,"repositoryHomepageUrl":44,"ownerHtmlUrl":45,"ownerBlogUrl":44,"ownerDescription":46,"updatedAt":47,"install":48,"resources":61},"01M6D2CMFPVNQFZVE5M7TE1AFP","ui-part-drawers",null,"Drawers, side panels and bottom sheets: detail and editing beside a list, modal or not, the open record in the URL, structure and widths, focus and closing, sheets with a handle and snap points, filters on phones, unsaved changes and stacking order. Read before building a panel or a sheet that slides in.","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-part-drawers\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33],"ui","ui part drawers","modal","open","slides","editing","before building","read","list","filters","record","sheet","structure","focus","detail","2026-11-10 10:12:30",false,"---\nname: ui-part-drawers\ndescription: \"Drawers, side panels and bottom sheets: detail and editing beside a list, modal or not, the open record in the URL, structure and widths, focus and closing, sheets with a handle and snap points, filters on phones, unsaved changes and stacking order. Read before building a panel or a sheet that slides in.\"\n---\n\n# Drawers and sheets\n\nThe generated version: a drawer that covers the list the user was working\nthrough, a drawer opened from a drawer, a bottom sheet you can only close\nby dragging, a footer that scrolls away with the content, and a record\nthat vanishes on reload because it was never in the URL. A drawer keeps\nthe current view in place while a detail or a secondary task sits beside\nit; this is how to size it, wire it and close it. One part of an\ninterface: the principles (direction, spacing, type, colour, icons,\nstates, accessibility) are in the `ui` skill, the measures in `ui-layout`.\n\n## 1. Which one\n\n| Need | Use |\n|---|---|\n| Read or edit a record while the list stays visible | a side panel from the right, 400 to 560px |\n| Go through records one after another on a wide screen | a split view: the list and a detail pane |\n| Filters, sorting and short choices on a phone | a bottom sheet |\n| The application's navigation under 1024px | a drawer from the left (`ui-part-sidebar`) |\n| A decision that must be answered now | a dialog (`ui-part-dialogs`) |\n| A long task, or a record that needs the whole screen | its own page |\n\n- Use them for details or a secondary task beside the current view; not\n  for the screen's main task, and not for content that needs the full\n  width to be compared.\n\n## 2. Modal or not\n\n- Modal (a scrim, the page inert, focus kept inside): for editing, and\n  under about 1024px, where the panel covers most of the page anyway.\n- Non-modal (no scrim, the list narrows or the panel sits beside it, both\n  usable): for inspecting records one by one on a wide screen. It is a\n  region (`aside` with an `aria-label`), not a dialog: no focus trap, but\n  Escape still closes it and focus returns to the row.\n- The open record lives in the URL (`?invoice=INV-0042`, or a nested\n  route), so a reload, the back button and a shared link all open it\n  again. Opening adds a history entry; Back closes the panel before it\n  leaves the page.\n\n## 3. Structure and measures\n\n- Side panel: full height, from the right, 400 to 560px wide (`inline-size:\n  min(480px, 100vw)`), 640 to 720px for a wide editor, full screen on a\n  phone: a width that leaves the page visible on wide screens.\n- Header, 56 to 64px: the title (an `h2`, the record's name) and the close\n  button at the right (40px, 44px on touch, `aria-label=\"Close\"`); for\n  records, previous and next buttons beside it.\n- Body: scrolls on its own (`overflow-y: auto`) with\n  `overscroll-behavior: contain`, so reaching its end does not scroll the\n  page behind; padding 16 to 24px.\n- Footer: fixed to the panel's bottom, with the actions (primary at the\n  right, Cancel beside it), a hairline above and the safe area below\n  (`env(safe-area-inset-bottom)`).\n- A hairline on the open edge; a shadow only on the modal kind.\n\n## 4. Bottom sheets\n\n- For filters, sorting and short choices on phones: from the bottom edge,\n  12 to 16px radius on the top corners, at most 90% of the screen's height\n  (`max-block-size: 90dvh`).\n- A drag handle 32 to 40px wide and 4 to 5px tall, centred, 8px from the\n  top, to drag it closed; never the only way: a close or \"Done\" button and\n  Escape do it too. A drag starts from the handle or the header, so\n  scrolling the content does not close the sheet.\n- Snap points (half and nearly full) only when the content gains from\n  them: a map with results, a long list. A short sheet is as tall as its\n  content.\n- A filter sheet: the filters, then a footer with \"Clear all\" and a\n  primary that says what it will show (\"Show 24 results\", counted live);\n  the filters apply when it is pressed. The button that opened it shows\n  how many are active (\"Filters · 2\", `ui-layout` 9).\n\n## 5. Behaviour and keyboard\n\n- The same focus and closing rules as a dialog: focus moves in on open\n  (the title with `tabindex=\"-1\"`, or the first field when editing), stays\n  inside a modal drawer, and returns to the trigger or the row on close;\n  Escape, the close button and the scrim close it.\n- Do not open a drawer from a drawer. A related record replaces the\n  panel's content, with a back button in its header, or opens its own\n  page.\n- Unsaved changes: closing an edited form (Escape, scrim, close, Back) asks\n  in place, in the footer: \"Discard changes?\" with \"Discard\" and \"Keep\n  editing\". Or it saves as the user types (`frontend-forms`).\n- The navigation drawer closes when a link is chosen, and focus goes to\n  the new page's heading (`ui-part-sidebar`).\n- Libraries: a side panel is a dialog placed at an edge: Radix Dialog\n  (shadcn's Sheet), React Aria `Modal`, Headless UI `Dialog`, Ark UI, Bits\n  UI; the native `dialog` in plain HTML. Sheets with dragging and snap\n  points: shadcn's Drawer (Vaul underneath) or react-modal-sheet.\n- One stacking order, as tokens: the sticky header, then drawers, then\n  dialogs, then toasts, so a confirmation never opens under a drawer. The\n  native `dialog` and `popover` sit in the top layer and need none.\n\n## 6. Themes and motion\n\n- The panel is a surface step with a hairline; the scrim has a value per\n  theme (`ui-themes`).\n- It slides from its edge with a transform, 320ms in and 200ms out; a\n  sheet follows the finger one to one and settles by distance and speed;\n  under reduced motion a short fade or nothing. Never animate `left` or\n  `width` (`motion-interface` 5).\n\n## 7. A sketch\n\nReact with Radix Dialog as a panel, its open record in the URL (React\nRouter):\n\n```tsx\nimport * as Dialog from \"@radix-ui\u002Freact-dialog\";\nimport { useSearchParams } from \"react-router\";\n\nexport function InvoicePanel() {\n  const [params, setParams] = useSearchParams();\n  const id = params.get(\"invoice\");\n  const close = () => setParams((p) => { p.delete(\"invoice\"); return p; });\n  return (\n    \u003CDialog.Root open={id !== null} onOpenChange={(open) => { if (!open) close(); }}>\n      \u003CDialog.Portal>\n        \u003CDialog.Overlay className=\"scrim\" \u002F>\n        \u003CDialog.Content className=\"panel\" aria-describedby={undefined}>\n          \u003Cdiv className=\"panel__head\">\n            \u003CDialog.Title>Invoice {id}\u003C\u002FDialog.Title>\n            \u003CDialog.Close className=\"icon-btn\" aria-label=\"Close\">\n              \u003CXIcon aria-hidden=\"true\" \u002F>\n            \u003C\u002FDialog.Close>\n          \u003C\u002Fdiv>\n          \u003Cdiv className=\"panel__body\">{id && \u003CInvoiceDetail id={id} \u002F>}\u003C\u002Fdiv>\n          \u003Cdiv className=\"panel__foot\">{\u002F* Cancel, then Save *\u002F}\u003C\u002Fdiv>\n        \u003C\u002FDialog.Content>\n      \u003C\u002FDialog.Portal>\n    \u003C\u002FDialog.Root>\n  );\n}\n```\n\n```css\n.panel {\n  position: fixed; inset-block: 0; inset-inline-end: 0;\n  inline-size: min(480px, 100vw);\n  display: flex; flex-direction: column;\n  background: var(--surface); border-inline-start: 1px solid var(--border);\n}\n.panel__head {\n  display: flex; align-items: center; justify-content: space-between; gap: 12px;\n  min-block-size: 56px; padding-inline: 24px;\n}\n.panel__body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 24px; }\n.panel__foot {\n  display: flex; justify-content: flex-end; gap: 8px;\n  padding: 16px 24px calc(16px + env(safe-area-inset-bottom));\n  border-block-start: 1px solid var(--border);\n}\n```\n\n## Check it\n\n- Open a record and reload: it is still open. Press Back: the panel\n  closes, the list is where it was, focus is on the row.\n- Keyboard only: focus lands in the panel; Tab stays inside the modal\n  kind; Escape closes it; focus returns to the trigger.\n- Scroll the panel to its end: the page behind does not move, and the\n  footer stays in view.\n- At 360px (`preview`): the panel is full screen, nothing overflows, the\n  close button is 44px and named, a sheet's actions sit above the safe\n  area.\n- Edit something, then press Escape: the discard question appears.\n\n## Avoid\n\nA drawer from a drawer; a drawer covering the list the user works through\non a wide screen; a sheet closed only by dragging; a footer that scrolls\naway; an open record that is not in the URL; a page that scrolls under the\npanel; animating `left` or `width`; the screen's main task in a drawer; a\nfilter sheet whose button does not say what it will show.\n","# Drawers and sheets\n\nThe generated version: a drawer that covers the list the user was working\nthrough, a drawer opened from a drawer, a bottom sheet you can only close\nby dragging, a footer that scrolls away with the content, and a record\nthat vanishes on reload because it was never in the URL. A drawer keeps\nthe current view in place while a detail or a secondary task sits beside\nit; this is how to size it, wire it and close it. One part of an\ninterface: the principles (direction, spacing, type, colour, icons,\nstates, accessibility) are in the `ui` skill, the measures in `ui-layout`.\n\n## 1. Which one\n\n| Need | Use |\n|---|---|\n| Read or edit a record while the list stays visible | a side panel from the right, 400 to 560px |\n| Go through records one after another on a wide screen | a split view: the list and a detail pane |\n| Filters, sorting and short choices on a phone | a bottom sheet |\n| The application's navigation under 1024px | a drawer from the left (`ui-part-sidebar`) |\n| A decision that must be answered now | a dialog (`ui-part-dialogs`) |\n| A long task, or a record that needs the whole screen | its own page |\n\n- Use them for details or a secondary task beside the current view; not\n  for the screen's main task, and not for content that needs the full\n  width to be compared.\n\n## 2. Modal or not\n\n- Modal (a scrim, the page inert, focus kept inside): for editing, and\n  under about 1024px, where the panel covers most of the page anyway.\n- Non-modal (no scrim, the list narrows or the panel sits beside it, both\n  usable): for inspecting records one by one on a wide screen. It is a\n  region (`aside` with an `aria-label`), not a dialog: no focus trap, but\n  Escape still closes it and focus returns to the row.\n- The open record lives in the URL (`?invoice=INV-0042`, or a nested\n  route), so a reload, the back button and a shared link all open it\n  again. Opening adds a history entry; Back closes the panel before it\n  leaves the page.\n\n## 3. Structure and measures\n\n- Side panel: full height, from the right, 400 to 560px wide (`inline-size:\n  min(480px, 100vw)`), 640 to 720px for a wide editor, full screen on a\n  phone: a width that leaves the page visible on wide screens.\n- Header, 56 to 64px: the title (an `h2`, the record's name) and the close\n  button at the right (40px, 44px on touch, `aria-label=\"Close\"`); for\n  records, previous and next buttons beside it.\n- Body: scrolls on its own (`overflow-y: auto`) with\n  `overscroll-behavior: contain`, so reaching its end does not scroll the\n  page behind; padding 16 to 24px.\n- Footer: fixed to the panel's bottom, with the actions (primary at the\n  right, Cancel beside it), a hairline above and the safe area below\n  (`env(safe-area-inset-bottom)`).\n- A hairline on the open edge; a shadow only on the modal kind.\n\n## 4. Bottom sheets\n\n- For filters, sorting and short choices on phones: from the bottom edge,\n  12 to 16px radius on the top corners, at most 90% of the screen's height\n  (`max-block-size: 90dvh`).\n- A drag handle 32 to 40px wide and 4 to 5px tall, centred, 8px from the\n  top, to drag it closed; never the only way: a close or \"Done\" button and\n  Escape do it too. A drag starts from the handle or the header, so\n  scrolling the content does not close the sheet.\n- Snap points (half and nearly full) only when the content gains from\n  them: a map with results, a long list. A short sheet is as tall as its\n  content.\n- A filter sheet: the filters, then a footer with \"Clear all\" and a\n  primary that says what it will show (\"Show 24 results\", counted live);\n  the filters apply when it is pressed. The button that opened it shows\n  how many are active (\"Filters · 2\", `ui-layout` 9).\n\n## 5. Behaviour and keyboard\n\n- The same focus and closing rules as a dialog: focus moves in on open\n  (the title with `tabindex=\"-1\"`, or the first field when editing), stays\n  inside a modal drawer, and returns to the trigger or the row on close;\n  Escape, the close button and the scrim close it.\n- Do not open a drawer from a drawer. A related record replaces the\n  panel's content, with a back button in its header, or opens its own\n  page.\n- Unsaved changes: closing an edited form (Escape, scrim, close, Back) asks\n  in place, in the footer: \"Discard changes?\" with \"Discard\" and \"Keep\n  editing\". Or it saves as the user types (`frontend-forms`).\n- The navigation drawer closes when a link is chosen, and focus goes to\n  the new page's heading (`ui-part-sidebar`).\n- Libraries: a side panel is a dialog placed at an edge: Radix Dialog\n  (shadcn's Sheet), React Aria `Modal`, Headless UI `Dialog`, Ark UI, Bits\n  UI; the native `dialog` in plain HTML. Sheets with dragging and snap\n  points: shadcn's Drawer (Vaul underneath) or react-modal-sheet.\n- One stacking order, as tokens: the sticky header, then drawers, then\n  dialogs, then toasts, so a confirmation never opens under a drawer. The\n  native `dialog` and `popover` sit in the top layer and need none.\n\n## 6. Themes and motion\n\n- The panel is a surface step with a hairline; the scrim has a value per\n  theme (`ui-themes`).\n- It slides from its edge with a transform, 320ms in and 200ms out; a\n  sheet follows the finger one to one and settles by distance and speed;\n  under reduced motion a short fade or nothing. Never animate `left` or\n  `width` (`motion-interface` 5).\n\n## 7. A sketch\n\nReact with Radix Dialog as a panel, its open record in the URL (React\nRouter):\n\n```tsx\nimport * as Dialog from \"@radix-ui\u002Freact-dialog\";\nimport { useSearchParams } from \"react-router\";\n\nexport function InvoicePanel() {\n  const [params, setParams] = useSearchParams();\n  const id = params.get(\"invoice\");\n  const close = () => setParams((p) => { p.delete(\"invoice\"); return p; });\n  return (\n    \u003CDialog.Root open={id !== null} onOpenChange={(open) => { if (!open) close(); }}>\n      \u003CDialog.Portal>\n        \u003CDialog.Overlay className=\"scrim\" \u002F>\n        \u003CDialog.Content className=\"panel\" aria-describedby={undefined}>\n          \u003Cdiv className=\"panel__head\">\n            \u003CDialog.Title>Invoice {id}\u003C\u002FDialog.Title>\n            \u003CDialog.Close className=\"icon-btn\" aria-label=\"Close\">\n              \u003CXIcon aria-hidden=\"true\" \u002F>\n            \u003C\u002FDialog.Close>\n          \u003C\u002Fdiv>\n          \u003Cdiv className=\"panel__body\">{id && \u003CInvoiceDetail id={id} \u002F>}\u003C\u002Fdiv>\n          \u003Cdiv className=\"panel__foot\">{\u002F* Cancel, then Save *\u002F}\u003C\u002Fdiv>\n        \u003C\u002FDialog.Content>\n      \u003C\u002FDialog.Portal>\n    \u003C\u002FDialog.Root>\n  );\n}\n```\n\n```css\n.panel {\n  position: fixed; inset-block: 0; inset-inline-end: 0;\n  inline-size: min(480px, 100vw);\n  display: flex; flex-direction: column;\n  background: var(--surface); border-inline-start: 1px solid var(--border);\n}\n.panel__head {\n  display: flex; align-items: center; justify-content: space-between; gap: 12px;\n  min-block-size: 56px; padding-inline: 24px;\n}\n.panel__body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 24px; }\n.panel__foot {\n  display: flex; justify-content: flex-end; gap: 8px;\n  padding: 16px 24px calc(16px + env(safe-area-inset-bottom));\n  border-block-start: 1px solid var(--border);\n}\n```\n\n## Check it\n\n- Open a record and reload: it is still open. Press Back: the panel\n  closes, the list is where it was, focus is on the row.\n- Keyboard only: focus lands in the panel; Tab stays inside the modal\n  kind; Escape closes it; focus returns to the trigger.\n- Scroll the panel to its end: the page behind does not move, and the\n  footer stays in view.\n- At 360px (`preview`): the panel is full screen, nothing overflows, the\n  close button is 44px and named, a sheet's actions sit above the safe\n  area.\n- Edit something, then press Escape: the discard question appears.\n\n## Avoid\n\nA drawer from a drawer; a drawer covering the list the user works through\non a wide screen; a sheet closed only by dragging; a footer that scrolls\naway; an open record that is not in the URL; a page that scrolls under the\npanel; animating `left` or `width`; the screen's main task in a drawer; a\nfilter sheet whose button does not say what it will show.\n",{"name":5,"description":7},"main","38293fe1b096e6bf3646c7344c38786ed688f464","crates\u002Fenowx-core\u002Fskills\u002Fui-part-drawers",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":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add enowdev\u002Fenowxcli --skill ui-part-drawers",{"tool":54,"command":55},"bunx","bunx skills add enowdev\u002Fenowxcli --skill ui-part-drawers",{"tool":57,"command":58},"pnpm","pnpm dlx skills add enowdev\u002Fenowxcli --skill ui-part-drawers","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-part-drawers\u002FSKILL.md",true,[],[63,79,104,118,144,164],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":74,"publishedAt":34},"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",[69],{"categoryNo":70,"categoryName":71,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[75,76,77,78,26],"demo skill","demo","tests","project",{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":93,"publishedAt":34},"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",[85,88],{"categoryNo":86,"categoryName":87,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":89,"categoryName":90,"taxonomyType":91,"taxonomyTypeDesc":92},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[81,94,95,96,97,98,26,99,100,101,102,103],"text","emails","empty","drop","document","page","voice","notifications","documentation","translate",{"skillNo":105,"name":19,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":112,"publishedAt":34},"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",[109],{"categoryNo":110,"categoryName":111,"taxonomyType":91,"taxonomyTypeDesc":92},"01JBSEEDCAT000000000000032","设计师",[19,113,114,115,116,99,117,26,25],"icons","components","SET","responsive","layout",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":130,"publishedAt":34},"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",[124,127],{"categoryNo":125,"categoryName":126,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":128,"categoryName":129,"taxonomyType":91,"taxonomyTypeDesc":92},"01JBSEEDCAT000000000000030","开发工程师",[19,131,132,133,134,135,32,136,137,26,25,138,99,139,140,141,113,142,143],"ui themes","switching","photos","tokens","drawing","maps","Art","flash","code","Charts","content","screenshots","logo",{"skillNo":145,"name":146,"nameZh":6,"description":147,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":148,"categories":149,"keywords":153,"publishedAt":34},"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",[150,151,152],{"categoryNo":86,"categoryName":87,"taxonomyType":72,"taxonomyTypeDesc":73},{"categoryNo":128,"categoryName":129,"taxonomyType":91,"taxonomyTypeDesc":92},{"categoryNo":89,"categoryName":90,"taxonomyType":91,"taxonomyTypeDesc":92},[31,19,154,114,155,156,139,157,158,159,117,134,160,161,27,26,25,99,162,163],"ui structure","pricing","dashboard","Blueprint","article","anatomy","styling","primitives","why","how",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":177,"publishedAt":34},"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",[170,173,176],{"categoryNo":171,"categoryName":172,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":174,"categoryName":175,"taxonomyType":72,"taxonomyTypeDesc":73},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":110,"categoryName":111,"taxonomyType":91,"taxonomyTypeDesc":92},[19,178,179,180,181,182,183,184,117,78,185,186,26,187,188,189,190,191,192,193],"vue","stack","ui stack vue","forms","pages","watch","runtime","transitions","fetch","pinia","nuxt","template","server","config","directory","testing"]