[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D2ECTBHNYMH2MSDZT249FZ":3,"skill-same:01M6D2ECTBHNYMH2MSDZT249FZ":63},{"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":35,"linkOnly":36,"markdownContent":37,"markdownBody":38,"frontMatter":39,"refName":40,"commitSha":41,"skillDirectory":42,"forksCount":43,"repositoryHtmlUrl":44,"repositoryHomepageUrl":45,"ownerHtmlUrl":46,"ownerBlogUrl":45,"ownerDescription":47,"updatedAt":48,"install":49,"resources":62},"01M6D2ECTBHNYMH2MSDZT249FZ","ui-part-pagination",null,"Pagination and loading more: numbered pages, Previous and Next over cursors, Show more and infinite scroll, paging on the server in a stable order, the range and total, page size, the page in the URL, focus and scroll after a change, phones, and public paged pages. Read before building any list that can grow past one screen.","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-pagination\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"ui","pagination","ui part pagination","change","server","page","public","before building","read","list","show","next","focus","scroll","grow","pages","2026-11-10 10:12:30",false,"---\nname: ui-part-pagination\ndescription: \"Pagination and loading more: numbered pages, Previous and Next over cursors, Show more and infinite scroll, paging on the server in a stable order, the range and total, page size, the page in the URL, focus and scroll after a change, phones, and public paged pages. Read before building any list that can grow past one screen.\"\n---\n\n# Pagination and loading more\n\nThe generated version: every row fetched and sliced in the browser, ten\npage numbers that run off a phone, page 3 that resets to page 1 on back,\nan infinite scroll that makes the footer unreachable, and a total that\nchanges as you page. Pagination is a promise about position: where the\nreader is, how much there is, and that going back returns them to the same\nplace. The principles are in the `ui` skill, the measures in `ui-layout`,\nthe API side in `backend-api` (section 5).\n\n## 1. Choose by the task\n\n| Pattern | For | Needs |\n|---|---|---|\n| Numbered pages | lists people navigate and come back to: search results, records, admin tables | a total, the page in the URL |\n| Previous and Next | cursor-based APIs; very large or growing lists | the cursor in the URL |\n| A \"Show more\" button | feeds and catalogues read from the top | the depth kept on back |\n| Infinite scroll | endless feeds (activity, social) where nothing needs the footer | the position kept on back, a reachable footer |\n\n- Numbered pages when position matters (search results, records); a \"Show\n  more\" button for feeds; infinite scroll only when nothing needs the\n  footer, and never without keeping the scroll position on return.\n- No controls when everything fits on one page.\n\n## 2. On the server\n\n- On the server, always, once a list can pass a couple of hundred rows:\n  the page, the sort and the filters go into the query (`LIMIT` with a\n  cursor or an offset, backed by an index), and the response carries the\n  rows and either the total or whether there is more.\n- Cursor pagination (`?after=\u003Ccursor>`) for long or growing lists, where an\n  offset gets slow and skips rows as new ones arrive; page numbers with a\n  total (\"1 to 25 of 1,284\") when the reader jumps around.\n- The order is stable: the sort column, then the id, so no row repeats or\n  goes missing between pages. The cursor is opaque: the last row's sort key\n  and id, encoded.\n- Ask for one row more than the page to learn whether there is a next page\n  without counting.\n- A total over a very large table is costly: count once per filter and\n  cache it, or say \"More than 10,000\", rather than a page count that jumps\n  as you page.\n\n```sql\n-- PostgreSQL keyset page; the cursor carries the last row's created_at and id.\nSELECT id, number, total, created_at\nFROM invoices\nWHERE status = $1\n  AND (created_at, id) \u003C ($2, $3)\nORDER BY created_at DESC, id DESC\nLIMIT 26; -- 25 to show, one more to know there is a next page\n-- Backed by: CREATE INDEX ON invoices (status, created_at DESC, id DESC);\n```\n\n## 3. Numbered pages\n\n- `\u003Cnav aria-label=\"Pagination\">` around a list: Previous, the numbers,\n  Next.\n- The first, the last, the current page and one on each side, an ellipsis\n  for each gap: Previous 1 … 4 5 6 … 20 Next. Seven numbers at most; fewer\n  on phones.\n- Every page a real link to its URL (`?page=5`): it works without\n  JavaScript, opens in a new tab and can be shared. Page 1 is the plain URL,\n  with no `?page=1`.\n- The current page carries `aria-current=\"page\"` and is filled or outlined\n  and bold, not marked by colour alone.\n- The ends: on page 1 there is no Previous link, but a `span` with\n  `aria-disabled=\"true\"` keeps its place so nothing shifts; the same for\n  Next on the last page.\n- Previous and Next are words, with a chevron if you like, never chevrons\n  alone; numbers may carry `aria-label=\"Page 5\"`.\n- 36 to 40px squares on desktop, 44px on touch, 4px apart, in\n  `tabular-nums` so the row does not twitch as the numbers change.\n- In a table, the range and total at the start of the footer and the\n  controls at its end (`ui-part-tables`): \"51 to 100 of 1,240\", formatted\n  for the locale (`Intl.NumberFormat`).\n- A page size of 25 by default, with 50 and 100 to choose from in tables\n  (\"Rows per page\"); changing it returns to page 1.\n- The page, the size, the sort and the filters in the URL, so back and\n  reload return to the same page; changing a filter goes back to page one.\n- A page past the end (`?page=99` of 20): the last page, or a line saying\n  there is no page 99 with a link to page 1; never an empty table with no\n  explanation.\n\n## 4. Changing page\n\n- While the next page loads, the current one stays on screen, dimmed, and\n  the controls show the wait (`ui-part-loading`).\n- Then the top of the list is in view (scroll to the list, not to the top of\n  the page when the list sits lower), and focus moves to the list's heading\n  or its count (`tabindex=\"-1\"`), so the next Tab starts in the new page.\n- Back keeps the scroll position: the browser does it for full page loads;\n  a single-page app keeps the pages in its query cache so the list renders\n  at once, then restores the scroll.\n\n## 5. Show more and infinite scroll\n\n- \"Show more\" at the end of the list says what it does (\"Show 24 more\")\n  beside the count so far (\"Showing 48 of 312\"). On a press the next page\n  is appended, focus moves to the first new item (its link, or a heading\n  with `tabindex=\"-1\"`), and a `role=\"status\"` line says \"24 more products\n  loaded\".\n- The depth goes in the URL (`?page=3`, with `history.replaceState`), and\n  back renders pages 1 to 3 and restores the scroll.\n- Infinite scroll: an IntersectionObserver on a sentinel 600 to 1000px\n  before the end loads the next page; after two or three automatic loads a\n  \"Show more\" button takes over, so the footer can be reached. Or the screen\n  has no footer at all.\n- A screen that is only an endless feed can follow the APG feed pattern:\n  `role=\"feed\"`, `article`s with `aria-setsize` and `aria-posinset`,\n  `aria-busy` while more load.\n- Very long results are virtualised (`ui-part-lists`, section 5).\n\n## 6. Phones\n\n- Fewer numbers: \"Previous · Page 5 of 20 · Next\" with 44px targets, or the\n  label with a select to jump.\n- A table's footer stacks: the count above, the controls below at full\n  width.\n- For catalogues on a phone \"Show more\" is often better: one large target\n  at the end of the list.\n\n## 7. Themes, motion, search engines\n\n- The current page's fill and border from tokens, 3:1 in both themes\n  (`ui-themes`).\n- No animation beyond the dimming; new items arrive without a stagger;\n  scrolling is instant under reduced motion (`motion-interface`).\n- Public paged lists (a blog, a catalogue): each page has its own canonical\n  URL (not canonical to page 1), crawlable `\u003Ca href>` links and a distinct\n  title (\"Articles, page 2\"). `rel=\"next\"` and `rel=\"prev\"` do no harm but\n  Google no longer reads them (`frontend-seo`).\n\n## 8. A sketch\n\n```ts\n\u002F** The page numbers to show: the first, the last, the current one and its\n * neighbours, with \"…\" for each gap. pageItems(5, 20) gives\n * [1, \"…\", 4, 5, 6, \"…\", 20]. *\u002F\nexport function pageItems(current: number, total: number, siblings = 1): (number | \"…\")[] {\n  if (total \u003C= 1) return [];\n  const pages = new Set([1, total]);\n  for (let p = current - siblings; p \u003C= current + siblings; p++) {\n    if (p > 1 && p \u003C total) pages.add(p);\n  }\n  const sorted = [...pages].sort((a, b) => a - b);\n  const items: (number | \"…\")[] = [];\n  sorted.forEach((page, i) => {\n    const gap = i > 0 ? page - sorted[i - 1] : 1;\n    if (gap === 2) items.push(page - 1); \u002F\u002F a gap of one page shows that page\n    else if (gap > 2) items.push(\"…\");\n    items.push(page);\n  });\n  return items;\n}\n```\n\n```html\n\u003Cnav aria-label=\"Pagination\">\n  \u003Cul class=\"pages\" role=\"list\">\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=4\" rel=\"prev\">Previous\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles\" aria-label=\"Page 1\">1\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Cspan aria-hidden=\"true\">…\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=4\" aria-label=\"Page 4\">4\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=5\" aria-current=\"page\" aria-label=\"Page 5\">5\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=6\" aria-label=\"Page 6\">6\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Cspan aria-hidden=\"true\">…\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=20\" aria-label=\"Page 20\">20\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=6\" rel=\"next\">Next\u003C\u002Fa>\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Fnav>\n```\n\n## Check it\n\n- Go to page 3, open a row, press back: page 3 at the same scroll. Reload:\n  page 3. Change a filter: page 1.\n- `preview` at 360px: the control fits without overflow, targets reach 44px,\n  and no link goes nowhere.\n- Keyboard: Previous, the numbers and Next in order, the current page\n  announced; after \"Show more\", focus is on the first new item and the\n  count is announced.\n- `EXPLAIN` the list's query: the index serves the filter and the sort; no\n  request fetches every row.\n\n## Avoid\n\nFetching every row to paginate in the browser; a page count that jumps as\nyou page; pages that lose the filters; ten numbers on a phone; chevrons\nwithout words; the current page marked by colour alone; infinite scroll in\nfront of a footer; a \"Show more\" that forgets its depth on back; offset\npaging on a feed that grows while people read it; a page change that\nleaves focus at the bottom of the old page.\n","# Pagination and loading more\n\nThe generated version: every row fetched and sliced in the browser, ten\npage numbers that run off a phone, page 3 that resets to page 1 on back,\nan infinite scroll that makes the footer unreachable, and a total that\nchanges as you page. Pagination is a promise about position: where the\nreader is, how much there is, and that going back returns them to the same\nplace. The principles are in the `ui` skill, the measures in `ui-layout`,\nthe API side in `backend-api` (section 5).\n\n## 1. Choose by the task\n\n| Pattern | For | Needs |\n|---|---|---|\n| Numbered pages | lists people navigate and come back to: search results, records, admin tables | a total, the page in the URL |\n| Previous and Next | cursor-based APIs; very large or growing lists | the cursor in the URL |\n| A \"Show more\" button | feeds and catalogues read from the top | the depth kept on back |\n| Infinite scroll | endless feeds (activity, social) where nothing needs the footer | the position kept on back, a reachable footer |\n\n- Numbered pages when position matters (search results, records); a \"Show\n  more\" button for feeds; infinite scroll only when nothing needs the\n  footer, and never without keeping the scroll position on return.\n- No controls when everything fits on one page.\n\n## 2. On the server\n\n- On the server, always, once a list can pass a couple of hundred rows:\n  the page, the sort and the filters go into the query (`LIMIT` with a\n  cursor or an offset, backed by an index), and the response carries the\n  rows and either the total or whether there is more.\n- Cursor pagination (`?after=\u003Ccursor>`) for long or growing lists, where an\n  offset gets slow and skips rows as new ones arrive; page numbers with a\n  total (\"1 to 25 of 1,284\") when the reader jumps around.\n- The order is stable: the sort column, then the id, so no row repeats or\n  goes missing between pages. The cursor is opaque: the last row's sort key\n  and id, encoded.\n- Ask for one row more than the page to learn whether there is a next page\n  without counting.\n- A total over a very large table is costly: count once per filter and\n  cache it, or say \"More than 10,000\", rather than a page count that jumps\n  as you page.\n\n```sql\n-- PostgreSQL keyset page; the cursor carries the last row's created_at and id.\nSELECT id, number, total, created_at\nFROM invoices\nWHERE status = $1\n  AND (created_at, id) \u003C ($2, $3)\nORDER BY created_at DESC, id DESC\nLIMIT 26; -- 25 to show, one more to know there is a next page\n-- Backed by: CREATE INDEX ON invoices (status, created_at DESC, id DESC);\n```\n\n## 3. Numbered pages\n\n- `\u003Cnav aria-label=\"Pagination\">` around a list: Previous, the numbers,\n  Next.\n- The first, the last, the current page and one on each side, an ellipsis\n  for each gap: Previous 1 … 4 5 6 … 20 Next. Seven numbers at most; fewer\n  on phones.\n- Every page a real link to its URL (`?page=5`): it works without\n  JavaScript, opens in a new tab and can be shared. Page 1 is the plain URL,\n  with no `?page=1`.\n- The current page carries `aria-current=\"page\"` and is filled or outlined\n  and bold, not marked by colour alone.\n- The ends: on page 1 there is no Previous link, but a `span` with\n  `aria-disabled=\"true\"` keeps its place so nothing shifts; the same for\n  Next on the last page.\n- Previous and Next are words, with a chevron if you like, never chevrons\n  alone; numbers may carry `aria-label=\"Page 5\"`.\n- 36 to 40px squares on desktop, 44px on touch, 4px apart, in\n  `tabular-nums` so the row does not twitch as the numbers change.\n- In a table, the range and total at the start of the footer and the\n  controls at its end (`ui-part-tables`): \"51 to 100 of 1,240\", formatted\n  for the locale (`Intl.NumberFormat`).\n- A page size of 25 by default, with 50 and 100 to choose from in tables\n  (\"Rows per page\"); changing it returns to page 1.\n- The page, the size, the sort and the filters in the URL, so back and\n  reload return to the same page; changing a filter goes back to page one.\n- A page past the end (`?page=99` of 20): the last page, or a line saying\n  there is no page 99 with a link to page 1; never an empty table with no\n  explanation.\n\n## 4. Changing page\n\n- While the next page loads, the current one stays on screen, dimmed, and\n  the controls show the wait (`ui-part-loading`).\n- Then the top of the list is in view (scroll to the list, not to the top of\n  the page when the list sits lower), and focus moves to the list's heading\n  or its count (`tabindex=\"-1\"`), so the next Tab starts in the new page.\n- Back keeps the scroll position: the browser does it for full page loads;\n  a single-page app keeps the pages in its query cache so the list renders\n  at once, then restores the scroll.\n\n## 5. Show more and infinite scroll\n\n- \"Show more\" at the end of the list says what it does (\"Show 24 more\")\n  beside the count so far (\"Showing 48 of 312\"). On a press the next page\n  is appended, focus moves to the first new item (its link, or a heading\n  with `tabindex=\"-1\"`), and a `role=\"status\"` line says \"24 more products\n  loaded\".\n- The depth goes in the URL (`?page=3`, with `history.replaceState`), and\n  back renders pages 1 to 3 and restores the scroll.\n- Infinite scroll: an IntersectionObserver on a sentinel 600 to 1000px\n  before the end loads the next page; after two or three automatic loads a\n  \"Show more\" button takes over, so the footer can be reached. Or the screen\n  has no footer at all.\n- A screen that is only an endless feed can follow the APG feed pattern:\n  `role=\"feed\"`, `article`s with `aria-setsize` and `aria-posinset`,\n  `aria-busy` while more load.\n- Very long results are virtualised (`ui-part-lists`, section 5).\n\n## 6. Phones\n\n- Fewer numbers: \"Previous · Page 5 of 20 · Next\" with 44px targets, or the\n  label with a select to jump.\n- A table's footer stacks: the count above, the controls below at full\n  width.\n- For catalogues on a phone \"Show more\" is often better: one large target\n  at the end of the list.\n\n## 7. Themes, motion, search engines\n\n- The current page's fill and border from tokens, 3:1 in both themes\n  (`ui-themes`).\n- No animation beyond the dimming; new items arrive without a stagger;\n  scrolling is instant under reduced motion (`motion-interface`).\n- Public paged lists (a blog, a catalogue): each page has its own canonical\n  URL (not canonical to page 1), crawlable `\u003Ca href>` links and a distinct\n  title (\"Articles, page 2\"). `rel=\"next\"` and `rel=\"prev\"` do no harm but\n  Google no longer reads them (`frontend-seo`).\n\n## 8. A sketch\n\n```ts\n\u002F** The page numbers to show: the first, the last, the current one and its\n * neighbours, with \"…\" for each gap. pageItems(5, 20) gives\n * [1, \"…\", 4, 5, 6, \"…\", 20]. *\u002F\nexport function pageItems(current: number, total: number, siblings = 1): (number | \"…\")[] {\n  if (total \u003C= 1) return [];\n  const pages = new Set([1, total]);\n  for (let p = current - siblings; p \u003C= current + siblings; p++) {\n    if (p > 1 && p \u003C total) pages.add(p);\n  }\n  const sorted = [...pages].sort((a, b) => a - b);\n  const items: (number | \"…\")[] = [];\n  sorted.forEach((page, i) => {\n    const gap = i > 0 ? page - sorted[i - 1] : 1;\n    if (gap === 2) items.push(page - 1); \u002F\u002F a gap of one page shows that page\n    else if (gap > 2) items.push(\"…\");\n    items.push(page);\n  });\n  return items;\n}\n```\n\n```html\n\u003Cnav aria-label=\"Pagination\">\n  \u003Cul class=\"pages\" role=\"list\">\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=4\" rel=\"prev\">Previous\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles\" aria-label=\"Page 1\">1\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Cspan aria-hidden=\"true\">…\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=4\" aria-label=\"Page 4\">4\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=5\" aria-current=\"page\" aria-label=\"Page 5\">5\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=6\" aria-label=\"Page 6\">6\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Cspan aria-hidden=\"true\">…\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=20\" aria-label=\"Page 20\">20\u003C\u002Fa>\u003C\u002Fli>\n    \u003Cli>\u003Ca href=\"\u002Farticles?page=6\" rel=\"next\">Next\u003C\u002Fa>\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Fnav>\n```\n\n## Check it\n\n- Go to page 3, open a row, press back: page 3 at the same scroll. Reload:\n  page 3. Change a filter: page 1.\n- `preview` at 360px: the control fits without overflow, targets reach 44px,\n  and no link goes nowhere.\n- Keyboard: Previous, the numbers and Next in order, the current page\n  announced; after \"Show more\", focus is on the first new item and the\n  count is announced.\n- `EXPLAIN` the list's query: the index serves the filter and the sort; no\n  request fetches every row.\n\n## Avoid\n\nFetching every row to paginate in the browser; a page count that jumps as\nyou page; pages that lose the filters; ten numbers on a phone; chevrons\nwithout words; the current page marked by colour alone; infinite scroll in\nfront of a footer; a \"Show more\" that forgets its depth on back; offset\npaging on a feed that grows while people read it; a page change that\nleaves focus at the bottom of the old page.\n",{"name":5,"description":7},"main","38293fe1b096e6bf3646c7344c38786ed688f464","crates\u002Fenowx-core\u002Fskills\u002Fui-part-pagination",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":50,"prompt":60,"zipAvailable":61},[51,54,57],{"tool":52,"command":53},"npx","npx skills add enowdev\u002Fenowxcli --skill ui-part-pagination",{"tool":55,"command":56},"bunx","bunx skills add enowdev\u002Fenowxcli --skill ui-part-pagination",{"tool":58,"command":59},"pnpm","pnpm dlx skills add enowdev\u002Fenowxcli --skill ui-part-pagination","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-part-pagination\u002FSKILL.md",true,[],[64,80,104,118,144,165],{"skillNo":65,"name":66,"nameZh":6,"description":67,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":75,"publishedAt":35},"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",[70],{"categoryNo":71,"categoryName":72,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[76,77,78,79,27],"demo skill","demo","tests","project",{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":94,"publishedAt":35},"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",[86,89],{"categoryNo":87,"categoryName":88,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[82,95,96,97,98,99,27,24,100,101,102,103],"text","emails","empty","drop","document","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":35},"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":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000032","设计师",[19,113,114,115,116,24,117,27,26],"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":35},"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":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":128,"categoryName":129,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000030","开发工程师",[19,131,132,133,134,135,31,136,137,27,26,138,24,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":35},"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":87,"categoryName":88,"taxonomyType":73,"taxonomyTypeDesc":74},{"categoryNo":128,"categoryName":129,"taxonomyType":92,"taxonomyTypeDesc":93},{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},[154,19,155,114,156,157,139,158,159,160,117,134,161,162,28,27,26,24,163,164],"structure","ui structure","pricing","dashboard","Blueprint","article","anatomy","styling","primitives","why","how",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":178,"publishedAt":35},"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",[171,174,177],{"categoryNo":172,"categoryName":173,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":175,"categoryName":176,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":110,"categoryName":111,"taxonomyType":92,"taxonomyTypeDesc":93},[19,179,180,181,182,34,183,184,117,79,185,186,27,187,188,189,23,190,191,192],"vue","stack","ui stack vue","forms","watch","runtime","transitions","fetch","pinia","nuxt","template","config","directory","testing"]