[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6H483K2C0GR5YVMB6B9DYDP":3,"skill-same:01M6H483K2C0GR5YVMB6B9DYDP":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":23,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":49,"ownerHtmlUrl":50,"ownerBlogUrl":51,"ownerDescription":6,"updatedAt":52,"install":53,"resources":66},"01M6H483K2C0GR5YVMB6B9DYDP","dev-ui",null,"UI development approach — component architecture, state management, accessibility, and user experience patterns.","eyelock\u002Fassistants","eyelock","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1277325?v=4","01M6H423MGYJ0P316VZ2MMH75N","David Collie","01M6H423RR18QA9N8S2F3J8S8X",1,"MIT","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fdev\u002Fskills\u002Fdev-ui\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"dev","ui","dev ui","accessibility","component","architecture","development","state management","component architecture","state","management","user","ui development","patterns","user experience","2026-11-10 10:12:30",false,"---\nname: dev-ui\ndescription: UI development approach — component architecture, state management, accessibility, and user experience patterns.\n---\n\n# UI Development\n\nYou apply these principles when building user interfaces, regardless of framework.\n\n## Component Architecture\n\n### Structure\n\n- Components should do one thing well — if a component has multiple responsibilities, split it\n- Separate presentation from logic: keep rendering pure and predictable, push side effects and data fetching to the edges\n- Name components by what they are, not what they do: `UserProfile` not `RenderUserData`\n- Prefer composition over configuration — small composable components beat large ones with many props\u002Fflags\n\n### Props and data flow\n\n- Data flows down, events flow up — parent passes data to children, children notify parent via callbacks or events\n- Keep the prop surface small — a component that takes 15 props probably needs to be split\n- Use sensible defaults for optional props — the component should be useful with minimal configuration\n- Don't pass data through intermediate components that don't use it (prop drilling) — use context, state management, or composition instead\n\n### Component hierarchy\n\n```\nPage \u002F Route\n  └── Layout (header, sidebar, content area)\n       └── Feature Container (data fetching, state)\n            └── Presentation Components (rendering, styling)\n                 └── Shared UI Primitives (button, input, card)\n```\n\n- Pages own routing and data loading\n- Containers handle state and side effects\n- Presentation components are pure: same props = same output\n- Primitives are the design system — reusable across features\n\n## State Management\n\n### Where state lives\n\n- **Local component state**: UI state that only this component cares about (open\u002Fclosed, hover, form field values before submit)\n- **Shared state**: Data multiple components need (current user, theme, feature flags) — lift to nearest common ancestor or use a state store\n- **Server state**: Data from APIs — use purpose-built tools (React Query, SWR, Apollo) that handle caching, revalidation, and loading states\n- **URL state**: Filters, pagination, search terms — put in the URL so it's shareable and survives refresh\n\n### Principles\n\n- Derive what you can — don't store `fullName` if you have `firstName` and `lastName`\n- Single source of truth — each piece of state lives in exactly one place\n- Keep state as close to where it's used as possible — don't hoist prematurely\n- Treat server data as a cache, not as state you own — it can change out from under you\n\n## Forms\n\n- Validate on blur (field level) and on submit (form level)\n- Show errors inline next to the relevant field, not in a banner at the top\n- Preserve user input on validation failure — never clear a form the user just filled in\n- Disable submit button while submitting, show a loading indicator\n- Handle the full lifecycle: idle, validating, submitting, success, error\n- For complex forms, use a form library — don't hand-roll state tracking for 20 fields\n\n## Loading and Error States\n\n### Every async operation has three states\n\n1. **Loading** — show a skeleton, spinner, or placeholder. Never show a blank screen.\n2. **Success** — render the data\n3. **Error** — show what went wrong and what the user can do about it\n\n### Patterns\n\n- Use skeleton screens instead of spinners where possible — they feel faster\n- Show stale data while revalidating in the background (stale-while-revalidate)\n- For errors: show a message, a retry button, and (if applicable) a way to report the issue\n- Empty states are not errors — design for them: \"No results found. Try adjusting your search.\"\n\n## Accessibility\n\n### Fundamentals\n\n- Use semantic HTML elements: `\u003Cbutton>` not `\u003Cdiv onClick>`, `\u003Cnav>` not `\u003Cdiv class=\"nav\">`\n- All images need `alt` text — decorative images get `alt=\"\"`\n- All form inputs need associated `\u003Clabel>` elements\n- Ensure sufficient colour contrast (WCAG AA: 4.5:1 for normal text, 3:1 for large text)\n- Don't rely on colour alone to convey meaning — add icons, text, or patterns\n\n### Keyboard navigation\n\n- All interactive elements must be reachable via Tab\n- Custom widgets need appropriate ARIA roles, states, and keyboard handlers\n- Focus management: when a modal opens, focus moves to it; when it closes, focus returns to the trigger\n- Visible focus indicators — never remove the outline without providing an alternative\n\n### Screen readers\n\n- Use heading hierarchy: `h1` → `h2` → `h3`, don't skip levels\n- Use `aria-live` regions for dynamic content updates (notifications, form errors)\n- Hide decorative elements from screen readers with `aria-hidden=\"true\"`\n- Test with a screen reader — VoiceOver on macOS, NVDA on Windows\n\n## Performance\n\n### Rendering\n\n- Don't render what's off-screen — use virtualisation for long lists\n- Memoize expensive computations and components that receive the same props\n- Debounce rapid user input (search-as-you-type, window resize)\n- Avoid layout thrashing — batch DOM reads and writes\n\n### Assets\n\n- Lazy-load images and heavy components below the fold\n- Optimise images: use modern formats (WebP, AVIF), serve appropriate sizes\n- Code-split by route — don't ship the entire app in one bundle\n- Set appropriate cache headers for static assets\n\n## Responsive Design\n\n- Design mobile-first, then enhance for larger screens\n- Use relative units (rem, %, vh\u002Fvw) over fixed pixels for layout\n- Test at real breakpoints, not just \"desktop and mobile\" — tablets and small laptops matter\n- Touch targets need minimum 44x44px for comfortable tapping\n- Consider content priority: what matters most on a small screen? Show that first.\n","# UI Development\n\nYou apply these principles when building user interfaces, regardless of framework.\n\n## Component Architecture\n\n### Structure\n\n- Components should do one thing well — if a component has multiple responsibilities, split it\n- Separate presentation from logic: keep rendering pure and predictable, push side effects and data fetching to the edges\n- Name components by what they are, not what they do: `UserProfile` not `RenderUserData`\n- Prefer composition over configuration — small composable components beat large ones with many props\u002Fflags\n\n### Props and data flow\n\n- Data flows down, events flow up — parent passes data to children, children notify parent via callbacks or events\n- Keep the prop surface small — a component that takes 15 props probably needs to be split\n- Use sensible defaults for optional props — the component should be useful with minimal configuration\n- Don't pass data through intermediate components that don't use it (prop drilling) — use context, state management, or composition instead\n\n### Component hierarchy\n\n```\nPage \u002F Route\n  └── Layout (header, sidebar, content area)\n       └── Feature Container (data fetching, state)\n            └── Presentation Components (rendering, styling)\n                 └── Shared UI Primitives (button, input, card)\n```\n\n- Pages own routing and data loading\n- Containers handle state and side effects\n- Presentation components are pure: same props = same output\n- Primitives are the design system — reusable across features\n\n## State Management\n\n### Where state lives\n\n- **Local component state**: UI state that only this component cares about (open\u002Fclosed, hover, form field values before submit)\n- **Shared state**: Data multiple components need (current user, theme, feature flags) — lift to nearest common ancestor or use a state store\n- **Server state**: Data from APIs — use purpose-built tools (React Query, SWR, Apollo) that handle caching, revalidation, and loading states\n- **URL state**: Filters, pagination, search terms — put in the URL so it's shareable and survives refresh\n\n### Principles\n\n- Derive what you can — don't store `fullName` if you have `firstName` and `lastName`\n- Single source of truth — each piece of state lives in exactly one place\n- Keep state as close to where it's used as possible — don't hoist prematurely\n- Treat server data as a cache, not as state you own — it can change out from under you\n\n## Forms\n\n- Validate on blur (field level) and on submit (form level)\n- Show errors inline next to the relevant field, not in a banner at the top\n- Preserve user input on validation failure — never clear a form the user just filled in\n- Disable submit button while submitting, show a loading indicator\n- Handle the full lifecycle: idle, validating, submitting, success, error\n- For complex forms, use a form library — don't hand-roll state tracking for 20 fields\n\n## Loading and Error States\n\n### Every async operation has three states\n\n1. **Loading** — show a skeleton, spinner, or placeholder. Never show a blank screen.\n2. **Success** — render the data\n3. **Error** — show what went wrong and what the user can do about it\n\n### Patterns\n\n- Use skeleton screens instead of spinners where possible — they feel faster\n- Show stale data while revalidating in the background (stale-while-revalidate)\n- For errors: show a message, a retry button, and (if applicable) a way to report the issue\n- Empty states are not errors — design for them: \"No results found. Try adjusting your search.\"\n\n## Accessibility\n\n### Fundamentals\n\n- Use semantic HTML elements: `\u003Cbutton>` not `\u003Cdiv onClick>`, `\u003Cnav>` not `\u003Cdiv class=\"nav\">`\n- All images need `alt` text — decorative images get `alt=\"\"`\n- All form inputs need associated `\u003Clabel>` elements\n- Ensure sufficient colour contrast (WCAG AA: 4.5:1 for normal text, 3:1 for large text)\n- Don't rely on colour alone to convey meaning — add icons, text, or patterns\n\n### Keyboard navigation\n\n- All interactive elements must be reachable via Tab\n- Custom widgets need appropriate ARIA roles, states, and keyboard handlers\n- Focus management: when a modal opens, focus moves to it; when it closes, focus returns to the trigger\n- Visible focus indicators — never remove the outline without providing an alternative\n\n### Screen readers\n\n- Use heading hierarchy: `h1` → `h2` → `h3`, don't skip levels\n- Use `aria-live` regions for dynamic content updates (notifications, form errors)\n- Hide decorative elements from screen readers with `aria-hidden=\"true\"`\n- Test with a screen reader — VoiceOver on macOS, NVDA on Windows\n\n## Performance\n\n### Rendering\n\n- Don't render what's off-screen — use virtualisation for long lists\n- Memoize expensive computations and components that receive the same props\n- Debounce rapid user input (search-as-you-type, window resize)\n- Avoid layout thrashing — batch DOM reads and writes\n\n### Assets\n\n- Lazy-load images and heavy components below the fold\n- Optimise images: use modern formats (WebP, AVIF), serve appropriate sizes\n- Code-split by route — don't ship the entire app in one bundle\n- Set appropriate cache headers for static assets\n\n## Responsive Design\n\n- Design mobile-first, then enhance for larger screens\n- Use relative units (rem, %, vh\u002Fvw) over fixed pixels for layout\n- Test at real breakpoints, not just \"desktop and mobile\" — tablets and small laptops matter\n- Touch targets need minimum 44x44px for comfortable tapping\n- Consider content priority: what matters most on a small screen? Show that first.\n",{"name":5,"description":7},"develop","5f79513fe27520bf03af784e8df568a04931c48d","skills\u002Fdev\u002Fskills\u002Fdev-ui",0,"https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants","https:\u002F\u002Feyelock.github.io\u002Fassistants\u002F","https:\u002F\u002Fgithub.com\u002Feyelock","http:\u002F\u002Fwww.eyelock.net\u002Fblog","2026-11-11 22:45:53",{"source":8,"skillName":5,"commands":54,"prompt":64,"zipAvailable":65},[55,58,61],{"tool":56,"command":57},"npx","npx skills add eyelock\u002Fassistants --skill dev-ui",{"tool":59,"command":60},"bunx","bunx skills add eyelock\u002Fassistants --skill dev-ui",{"tool":62,"command":63},"pnpm","pnpm dlx skills add eyelock\u002Fassistants --skill dev-ui","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fdev\u002Fskills\u002Fdev-ui\u002FSKILL.md",true,[67,73],{"path":68,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":71,"sourceHtmlUrl":72},"evals\u002Feval_queries.json","REFERENCE","参考文档",891,"https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fdev\u002Fskills\u002Fdev-ui\u002Fevals\u002Feval_queries.json",{"path":74,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":75,"sourceHtmlUrl":76},"evals\u002Fevals.json",4454,"https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fdev\u002Fskills\u002Fdev-ui\u002Fevals\u002Fevals.json",[78,84,111,128,141,154],{"skillNo":79,"name":80,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":39},"01M6H46CHAJFE20J3Q118P9PW9","doctor","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fplugins\u002Fwheelhouse\u002Fskills\u002Fdoctor\u002FSKILL.md",[],[80],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":39},"01M6H45X8QJZTQAPN56WZ8V111","add-seat","Add a named seat to a Wheelhouse - a crew member, a standing role (such as a dispatcher) or a worker - as a ynh harness with its charter, standing orders and only the tools its job needs, named from the Wheelhouse's roster. Use when asked to add, create or set up a seat, role, worker or agent in a Wheelhouse (a release manager, a PR watcher, a dispatcher, a designer, more workers), or to give a role a name, or to start on a Wheelhouse's team (its starter team), one role at a time. Also use to trial, make official or drop a seat.","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fplugins\u002Fwheelhouse\u002Fskills\u002Fadd-seat\u002FSKILL.md",[],[91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110],"add","add seat","harness","SET","roster","use","release manager","workers","team","with","create","watcher","starter","when","more","worker","up","only","pr","as",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":39},"01M6H4BWCVR2YJVP8RW878NYDP","voice","How voices work - what a voice skill contains, how to write a new one, and how several voices compose into one reply. Use whenever drafting a reply in a named voice, or when asked to create or change a voice.","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fvoice\u002Fskills\u002Fvoice\u002FSKILL.md",[],[113,101,118,119,120,121,96,122,123,124,125,126,104,127],"how to","work","change","voice skill","compose","how","write","reply","new","drafting",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":39},"01M6H4BRVA87C6T495HCFNDQ7Z","voice-warm","A friendly voice that acknowledges the person and their effort. Compose with direct for friendly but brief.","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fvoice\u002Fskills\u002Fvoice-warm\u002FSKILL.md",[],[135,113,136,100,137,122,138,139,140],"voice warm","person","brief","direct","for","but",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":39},"01M6H4BNFQ64X65YZDM9QMD61B","voice-formal","A careful, complete voice for people outside the team - customers, partners, senior stakeholders.","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fvoice\u002Fskills\u002Fvoice-formal\u002FSKILL.md",[],[148,113,99,149,150,151,152,153,139],"voice formal","complete","senior","careful","partners","people",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":39},"01M6H4BHXE6KSNBY92TBFZY7QD","voice-direct","A plain, brief voice that leads with the answer. The default when no voice is named.","https:\u002F\u002Fgithub.com\u002Feyelock\u002Fassistants\u002Fblob\u002Fdevelop\u002Fskills\u002Fvoice\u002Fskills\u002Fvoice-direct\u002FSKILL.md",[],[161,138,113,100,137,162,163,164,104,165],"voice direct","leads","answer","default","plain"]