@ciderpress/ui 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/0~142.js +2 -0
  4. package/dist/0~164.js +2 -0
  5. package/dist/0~2.js +2 -0
  6. package/dist/0~225.js +2 -0
  7. package/dist/0~288.js +2 -0
  8. package/dist/0~299.js +2 -0
  9. package/dist/0~3.js +2 -0
  10. package/dist/0~301.js +2 -0
  11. package/dist/0~311.js +2 -0
  12. package/dist/0~326.js +2 -0
  13. package/dist/0~40.js +2 -0
  14. package/dist/0~43.js +2 -0
  15. package/dist/0~433.js +2 -0
  16. package/dist/0~453.js +2 -0
  17. package/dist/0~457.js +2 -0
  18. package/dist/0~497.js +2 -0
  19. package/dist/0~511.js +2 -0
  20. package/dist/0~603.js +2 -0
  21. package/dist/0~616.js +2 -0
  22. package/dist/0~659.js +2 -0
  23. package/dist/0~670.js +2 -0
  24. package/dist/0~687.js +2 -0
  25. package/dist/0~706.js +2 -0
  26. package/dist/0~729.js +2 -0
  27. package/dist/0~768.js +2 -0
  28. package/dist/0~819.js +2 -0
  29. package/dist/0~830.js +2 -0
  30. package/dist/0~854.js +2 -0
  31. package/dist/0~863.js +2 -0
  32. package/dist/0~879.js +2 -0
  33. package/dist/0~96.js +2 -0
  34. package/dist/0~97.js +2 -0
  35. package/dist/components/FileTree/FileTree.css +90 -0
  36. package/dist/components/FileTree/FileTree.d.ts +7 -0
  37. package/dist/components/FileTree/FileTree.js +531 -0
  38. package/dist/components/FileTree/FileTreeItem.d.ts +8 -0
  39. package/dist/components/FileTree/RemoteSvgIcon.d.ts +11 -0
  40. package/dist/components/FileTree/index.d.ts +4 -0
  41. package/dist/components/folder-icons.d.ts +32 -0
  42. package/dist/components/languages.d.ts +7 -0
  43. package/dist/components/tree-parser/tree-parser.d.ts +12 -0
  44. package/dist/components/tree-parser/types.d.ts +11 -0
  45. package/dist/head/css/loader-apple.css +1 -0
  46. package/dist/head/css/loader-backdrop.css +1 -0
  47. package/dist/head/css/loader-dots.css +1 -0
  48. package/dist/head/css/themes/amber.css +1 -0
  49. package/dist/head/css/themes/arcade.css +1 -0
  50. package/dist/head/css/themes/grannysmith.css +1 -0
  51. package/dist/head/css/themes/honeycrisp.css +1 -0
  52. package/dist/head/css/themes/midnight.css +1 -0
  53. package/dist/head/css/themes/mulled.css +1 -0
  54. package/dist/head/js/loader-dots.js +1 -0
  55. package/dist/head/js/vscode-nav.js +1 -0
  56. package/dist/index.d.ts +43 -0
  57. package/dist/index.mjs +40 -0
  58. package/dist/node.d.ts +81 -0
  59. package/dist/node.mjs +17762 -0
  60. package/dist/plugins/mermaid/MermaidRenderer.tsx +480 -0
  61. package/dist/plugins/mermaid/mermaid.css +199 -0
  62. package/dist/theme/components/announcement/announcement-bar.css +103 -0
  63. package/dist/theme/components/announcement/announcement-bar.tsx +173 -0
  64. package/dist/theme/components/ask-ai/ask-ai-button.css +52 -0
  65. package/dist/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  66. package/dist/theme/components/content-footer/content-footer-portal.tsx +70 -0
  67. package/dist/theme/components/content-footer/feedback.css +47 -0
  68. package/dist/theme/components/content-footer/feedback.tsx +96 -0
  69. package/dist/theme/components/content-footer/meta-actions.css +25 -0
  70. package/dist/theme/components/content-footer/meta-actions.tsx +57 -0
  71. package/dist/theme/components/content-footer/page-pager.css +61 -0
  72. package/dist/theme/components/content-footer/page-pager.tsx +110 -0
  73. package/dist/theme/components/edit-source-button.tsx +97 -0
  74. package/dist/theme/components/footer/site-footer.css +179 -0
  75. package/dist/theme/components/footer/site-footer.tsx +115 -0
  76. package/dist/theme/components/home/cta.css +67 -0
  77. package/dist/theme/components/home/cta.tsx +77 -0
  78. package/dist/theme/components/home/feature-card.css +52 -0
  79. package/dist/theme/components/home/feature-card.tsx +131 -0
  80. package/dist/theme/components/home/feature.tsx +79 -0
  81. package/dist/theme/components/home/hero-demo.css +66 -0
  82. package/dist/theme/components/home/hero-demo.tsx +46 -0
  83. package/dist/theme/components/home/hero.css +96 -0
  84. package/dist/theme/components/home/hero.tsx +111 -0
  85. package/dist/theme/components/home/layout.tsx +183 -0
  86. package/dist/theme/components/home/page-rail.css +21 -0
  87. package/dist/theme/components/home/page-rail.tsx +19 -0
  88. package/dist/theme/components/home/split.css +148 -0
  89. package/dist/theme/components/home/split.tsx +120 -0
  90. package/dist/theme/components/home/trust-strip.css +33 -0
  91. package/dist/theme/components/home/trust-strip.tsx +43 -0
  92. package/dist/theme/components/home/workspaces.tsx +71 -0
  93. package/dist/theme/components/nav/branch-tag.css +54 -0
  94. package/dist/theme/components/nav/branch-tag.tsx +101 -0
  95. package/dist/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  96. package/dist/theme/components/nav/ciderpress-docs-bar.css +505 -0
  97. package/dist/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  98. package/dist/theme/components/nav/ciderpress-header.css +172 -0
  99. package/dist/theme/components/nav/ciderpress-header.tsx +113 -0
  100. package/dist/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  101. package/dist/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  102. package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  103. package/dist/theme/components/nav/ciderpress-nav-menu.css +130 -0
  104. package/dist/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  105. package/dist/theme/components/nav/ciderpress-nav-search.css +73 -0
  106. package/dist/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  107. package/dist/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  108. package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  109. package/dist/theme/components/nav/floating-branch-indicator.css +106 -0
  110. package/dist/theme/components/nav/floating-branch-indicator.tsx +109 -0
  111. package/dist/theme/components/nav/layout.tsx +268 -0
  112. package/dist/theme/components/nav/mobile-nav-cta.tsx +79 -0
  113. package/dist/theme/components/nav/nav-divider.css +15 -0
  114. package/dist/theme/components/nav/nav-divider.tsx +19 -0
  115. package/dist/theme/components/nav/nav-logo.css +42 -0
  116. package/dist/theme/components/nav/nav-logo.tsx +262 -0
  117. package/dist/theme/components/nav/theme-switcher.css +92 -0
  118. package/dist/theme/components/nav/theme-switcher.tsx +298 -0
  119. package/dist/theme/components/nav/topbar-cta.css +45 -0
  120. package/dist/theme/components/nav/topbar-cta.tsx +39 -0
  121. package/dist/theme/components/nav/variant-toggle.css +70 -0
  122. package/dist/theme/components/nav/variant-toggle.tsx +83 -0
  123. package/dist/theme/components/nav/version-chip.css +31 -0
  124. package/dist/theme/components/nav/version-chip.tsx +45 -0
  125. package/dist/theme/components/nav/vscode-tag.css +32 -0
  126. package/dist/theme/components/nav/vscode-tag.tsx +20 -0
  127. package/dist/theme/components/openapi/code-sample.tsx +341 -0
  128. package/dist/theme/components/openapi/copy-markdown-button.tsx +41 -0
  129. package/dist/theme/components/openapi/icons.tsx +45 -0
  130. package/dist/theme/components/openapi/index.ts +6 -0
  131. package/dist/theme/components/openapi/method-badge.tsx +24 -0
  132. package/dist/theme/components/openapi/openapi.css +665 -0
  133. package/dist/theme/components/openapi/operation.tsx +200 -0
  134. package/dist/theme/components/openapi/overview.tsx +207 -0
  135. package/dist/theme/components/openapi/parameters-table.tsx +149 -0
  136. package/dist/theme/components/openapi/request-body.tsx +90 -0
  137. package/dist/theme/components/openapi/response-list.tsx +112 -0
  138. package/dist/theme/components/openapi/schema-viewer.tsx +277 -0
  139. package/dist/theme/components/openapi/security-badges.tsx +63 -0
  140. package/dist/theme/components/openapi/spec-utils.ts +122 -0
  141. package/dist/theme/components/shared/accordion.css +118 -0
  142. package/dist/theme/components/shared/accordion.stories.tsx +96 -0
  143. package/dist/theme/components/shared/accordion.tsx +191 -0
  144. package/dist/theme/components/shared/brand-logo.stories.tsx +49 -0
  145. package/dist/theme/components/shared/brand-mark.stories.tsx +53 -0
  146. package/dist/theme/components/shared/browser-window.css +1 -0
  147. package/dist/theme/components/shared/browser-window.stories.tsx +100 -0
  148. package/dist/theme/components/shared/browser-window.tsx +2 -0
  149. package/dist/theme/components/shared/card.stories.tsx +50 -0
  150. package/dist/theme/components/shared/card.tsx +35 -0
  151. package/dist/theme/components/shared/ciderpress-logo.tsx +93 -0
  152. package/dist/theme/components/shared/ciderpress-mark.tsx +77 -0
  153. package/dist/theme/components/shared/color.css +56 -0
  154. package/dist/theme/components/shared/color.stories.tsx +47 -0
  155. package/dist/theme/components/shared/color.tsx +69 -0
  156. package/dist/theme/components/shared/columns.css +37 -0
  157. package/dist/theme/components/shared/columns.stories.tsx +91 -0
  158. package/dist/theme/components/shared/columns.tsx +50 -0
  159. package/dist/theme/components/shared/desktop-window.css +339 -0
  160. package/dist/theme/components/shared/desktop-window.tsx +535 -0
  161. package/dist/theme/components/shared/field.css +158 -0
  162. package/dist/theme/components/shared/field.stories.tsx +100 -0
  163. package/dist/theme/components/shared/field.tsx +186 -0
  164. package/dist/theme/components/shared/frame.css +39 -0
  165. package/dist/theme/components/shared/frame.stories.tsx +49 -0
  166. package/dist/theme/components/shared/frame.tsx +76 -0
  167. package/dist/theme/components/shared/icon.stories.tsx +90 -0
  168. package/dist/theme/components/shared/icon.tsx +41 -0
  169. package/dist/theme/components/shared/prompt.css +178 -0
  170. package/dist/theme/components/shared/prompt.stories.tsx +57 -0
  171. package/dist/theme/components/shared/prompt.tsx +369 -0
  172. package/dist/theme/components/shared/resolve-card-icon.ts +28 -0
  173. package/dist/theme/components/shared/section-card.stories.tsx +51 -0
  174. package/dist/theme/components/shared/section-card.tsx +44 -0
  175. package/dist/theme/components/shared/section-grid.stories.tsx +46 -0
  176. package/dist/theme/components/shared/section-grid.tsx +15 -0
  177. package/dist/theme/components/shared/status-badge.css +37 -0
  178. package/dist/theme/components/shared/status-badge.stories.tsx +61 -0
  179. package/dist/theme/components/shared/status-badge.tsx +74 -0
  180. package/dist/theme/components/shared/steps.css +88 -0
  181. package/dist/theme/components/shared/steps.stories.tsx +68 -0
  182. package/dist/theme/components/shared/steps.tsx +100 -0
  183. package/dist/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  184. package/dist/theme/components/shared/tech-icon-table.tsx +71 -0
  185. package/dist/theme/components/shared/tech-tag.stories.tsx +40 -0
  186. package/dist/theme/components/shared/tech-tag.tsx +31 -0
  187. package/dist/theme/components/shared/theme-color-palette.css +80 -0
  188. package/dist/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  189. package/dist/theme/components/shared/theme-color-palette.tsx +275 -0
  190. package/dist/theme/components/shared/tooltip.css +69 -0
  191. package/dist/theme/components/shared/tooltip.stories.tsx +72 -0
  192. package/dist/theme/components/shared/tooltip.tsx +77 -0
  193. package/dist/theme/components/sidebar/framework-picker.css +77 -0
  194. package/dist/theme/components/sidebar/framework-picker.tsx +78 -0
  195. package/dist/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  196. package/dist/theme/components/sidebar/sidebar-filter.ts +79 -0
  197. package/dist/theme/components/sidebar/sidebar-links.css +102 -0
  198. package/dist/theme/components/sidebar/sidebar-links.tsx +122 -0
  199. package/dist/theme/components/sidebar/sidebar-promo.css +42 -0
  200. package/dist/theme/components/sidebar/sidebar-promo.tsx +52 -0
  201. package/dist/theme/components/sidebar/sidebar-scope.tsx +151 -0
  202. package/dist/theme/components/sidebar/sidebar-toggle.css +181 -0
  203. package/dist/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  204. package/dist/theme/components/theme-provider.tsx +637 -0
  205. package/dist/theme/components/workspaces/card.css +151 -0
  206. package/dist/theme/components/workspaces/card.tsx +166 -0
  207. package/dist/theme/components/workspaces/grid.tsx +62 -0
  208. package/dist/theme/css.d.ts +1 -0
  209. package/dist/theme/env.d.ts +12 -0
  210. package/dist/theme/fonts/GeistMono-Variable.woff2 +0 -0
  211. package/dist/theme/fonts/GeistPixel-Square.woff2 +0 -0
  212. package/dist/theme/fonts/GeistSans-Variable.woff2 +0 -0
  213. package/dist/theme/hooks/use-ciderpress.ts +61 -0
  214. package/dist/theme/hooks/use-nav-items.ts +76 -0
  215. package/dist/theme/icons/index.ts +2 -0
  216. package/dist/theme/icons/tech-map.ts +228 -0
  217. package/dist/theme/index.tsx +180 -0
  218. package/dist/theme/lib/read-social-links.ts +27 -0
  219. package/dist/theme/lib/route-link.tsx +126 -0
  220. package/dist/theme/lib/safe-url.test.ts +0 -0
  221. package/dist/theme/lib/safe-url.ts +68 -0
  222. package/dist/theme/lib/theme-favicon.ts +125 -0
  223. package/dist/theme/lib/user-config-stub.ts +12 -0
  224. package/dist/theme/styles/layers.css +32 -0
  225. package/dist/theme/styles/overrides/badge.css +26 -0
  226. package/dist/theme/styles/overrides/content-footer.css +80 -0
  227. package/dist/theme/styles/overrides/details.css +61 -0
  228. package/dist/theme/styles/overrides/fonts.css +32 -0
  229. package/dist/theme/styles/overrides/home-card.css +133 -0
  230. package/dist/theme/styles/overrides/home.css +243 -0
  231. package/dist/theme/styles/overrides/rail.css +337 -0
  232. package/dist/theme/styles/overrides/rspress.css +62 -0
  233. package/dist/theme/styles/overrides/scrollbar.css +25 -0
  234. package/dist/theme/styles/overrides/section-card.css +114 -0
  235. package/dist/theme/styles/overrides/sidebar.css +144 -0
  236. package/dist/theme/styles/overrides/tokens.css +288 -0
  237. package/dist/theme/styles/overrides/vscode.css +88 -0
  238. package/dist/theme/styles/themes/amber.css +545 -0
  239. package/dist/theme/styles/themes/arcade-fx.css +366 -0
  240. package/dist/theme/styles/themes/arcade.css +273 -0
  241. package/dist/theme/styles/themes/grannysmith.css +545 -0
  242. package/dist/theme/styles/themes/honeycrisp.css +545 -0
  243. package/dist/theme/styles/themes/midnight.css +273 -0
  244. package/dist/theme/styles/themes/mulled.css +817 -0
  245. package/package.json +103 -0
  246. package/src/theme/components/announcement/announcement-bar.css +103 -0
  247. package/src/theme/components/announcement/announcement-bar.tsx +173 -0
  248. package/src/theme/components/ask-ai/ask-ai-button.css +52 -0
  249. package/src/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  250. package/src/theme/components/content-footer/content-footer-portal.tsx +70 -0
  251. package/src/theme/components/content-footer/feedback.css +47 -0
  252. package/src/theme/components/content-footer/feedback.tsx +96 -0
  253. package/src/theme/components/content-footer/meta-actions.css +25 -0
  254. package/src/theme/components/content-footer/meta-actions.tsx +57 -0
  255. package/src/theme/components/content-footer/page-pager.css +61 -0
  256. package/src/theme/components/content-footer/page-pager.tsx +110 -0
  257. package/src/theme/components/edit-source-button.tsx +97 -0
  258. package/src/theme/components/footer/site-footer.css +179 -0
  259. package/src/theme/components/footer/site-footer.tsx +115 -0
  260. package/src/theme/components/home/cta.css +67 -0
  261. package/src/theme/components/home/cta.tsx +77 -0
  262. package/src/theme/components/home/feature-card.css +52 -0
  263. package/src/theme/components/home/feature-card.tsx +131 -0
  264. package/src/theme/components/home/feature.tsx +79 -0
  265. package/src/theme/components/home/hero-demo.css +66 -0
  266. package/src/theme/components/home/hero-demo.tsx +46 -0
  267. package/src/theme/components/home/hero.css +96 -0
  268. package/src/theme/components/home/hero.tsx +111 -0
  269. package/src/theme/components/home/layout.tsx +183 -0
  270. package/src/theme/components/home/page-rail.css +21 -0
  271. package/src/theme/components/home/page-rail.tsx +19 -0
  272. package/src/theme/components/home/split.css +148 -0
  273. package/src/theme/components/home/split.tsx +120 -0
  274. package/src/theme/components/home/trust-strip.css +33 -0
  275. package/src/theme/components/home/trust-strip.tsx +43 -0
  276. package/src/theme/components/home/workspaces.tsx +71 -0
  277. package/src/theme/components/nav/branch-tag.css +54 -0
  278. package/src/theme/components/nav/branch-tag.tsx +101 -0
  279. package/src/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  280. package/src/theme/components/nav/ciderpress-docs-bar.css +505 -0
  281. package/src/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  282. package/src/theme/components/nav/ciderpress-header.css +172 -0
  283. package/src/theme/components/nav/ciderpress-header.tsx +113 -0
  284. package/src/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  285. package/src/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  286. package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  287. package/src/theme/components/nav/ciderpress-nav-menu.css +130 -0
  288. package/src/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  289. package/src/theme/components/nav/ciderpress-nav-search.css +73 -0
  290. package/src/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  291. package/src/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  292. package/src/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  293. package/src/theme/components/nav/floating-branch-indicator.css +106 -0
  294. package/src/theme/components/nav/floating-branch-indicator.tsx +109 -0
  295. package/src/theme/components/nav/layout.tsx +268 -0
  296. package/src/theme/components/nav/mobile-nav-cta.tsx +79 -0
  297. package/src/theme/components/nav/nav-divider.css +15 -0
  298. package/src/theme/components/nav/nav-divider.tsx +19 -0
  299. package/src/theme/components/nav/nav-logo.css +42 -0
  300. package/src/theme/components/nav/nav-logo.tsx +262 -0
  301. package/src/theme/components/nav/theme-switcher.css +92 -0
  302. package/src/theme/components/nav/theme-switcher.tsx +298 -0
  303. package/src/theme/components/nav/topbar-cta.css +45 -0
  304. package/src/theme/components/nav/topbar-cta.tsx +39 -0
  305. package/src/theme/components/nav/variant-toggle.css +70 -0
  306. package/src/theme/components/nav/variant-toggle.tsx +83 -0
  307. package/src/theme/components/nav/version-chip.css +31 -0
  308. package/src/theme/components/nav/version-chip.tsx +45 -0
  309. package/src/theme/components/nav/vscode-tag.css +32 -0
  310. package/src/theme/components/nav/vscode-tag.tsx +20 -0
  311. package/src/theme/components/openapi/code-sample.tsx +341 -0
  312. package/src/theme/components/openapi/copy-markdown-button.tsx +41 -0
  313. package/src/theme/components/openapi/icons.tsx +45 -0
  314. package/src/theme/components/openapi/index.ts +6 -0
  315. package/src/theme/components/openapi/method-badge.tsx +24 -0
  316. package/src/theme/components/openapi/openapi.css +665 -0
  317. package/src/theme/components/openapi/operation.tsx +200 -0
  318. package/src/theme/components/openapi/overview.tsx +207 -0
  319. package/src/theme/components/openapi/parameters-table.tsx +149 -0
  320. package/src/theme/components/openapi/request-body.tsx +90 -0
  321. package/src/theme/components/openapi/response-list.tsx +112 -0
  322. package/src/theme/components/openapi/schema-viewer.tsx +277 -0
  323. package/src/theme/components/openapi/security-badges.tsx +63 -0
  324. package/src/theme/components/openapi/spec-utils.ts +122 -0
  325. package/src/theme/components/shared/accordion.css +118 -0
  326. package/src/theme/components/shared/accordion.stories.tsx +96 -0
  327. package/src/theme/components/shared/accordion.tsx +191 -0
  328. package/src/theme/components/shared/brand-logo.stories.tsx +49 -0
  329. package/src/theme/components/shared/brand-mark.stories.tsx +53 -0
  330. package/src/theme/components/shared/browser-window.css +1 -0
  331. package/src/theme/components/shared/browser-window.stories.tsx +100 -0
  332. package/src/theme/components/shared/browser-window.tsx +2 -0
  333. package/src/theme/components/shared/card.stories.tsx +50 -0
  334. package/src/theme/components/shared/card.tsx +35 -0
  335. package/src/theme/components/shared/ciderpress-logo.tsx +93 -0
  336. package/src/theme/components/shared/ciderpress-mark.tsx +77 -0
  337. package/src/theme/components/shared/color.css +56 -0
  338. package/src/theme/components/shared/color.stories.tsx +47 -0
  339. package/src/theme/components/shared/color.tsx +69 -0
  340. package/src/theme/components/shared/columns.css +37 -0
  341. package/src/theme/components/shared/columns.stories.tsx +91 -0
  342. package/src/theme/components/shared/columns.tsx +50 -0
  343. package/src/theme/components/shared/desktop-window.css +339 -0
  344. package/src/theme/components/shared/desktop-window.tsx +535 -0
  345. package/src/theme/components/shared/field.css +158 -0
  346. package/src/theme/components/shared/field.stories.tsx +100 -0
  347. package/src/theme/components/shared/field.tsx +186 -0
  348. package/src/theme/components/shared/frame.css +39 -0
  349. package/src/theme/components/shared/frame.stories.tsx +49 -0
  350. package/src/theme/components/shared/frame.tsx +76 -0
  351. package/src/theme/components/shared/icon.stories.tsx +90 -0
  352. package/src/theme/components/shared/icon.tsx +41 -0
  353. package/src/theme/components/shared/prompt.css +178 -0
  354. package/src/theme/components/shared/prompt.stories.tsx +57 -0
  355. package/src/theme/components/shared/prompt.tsx +369 -0
  356. package/src/theme/components/shared/resolve-card-icon.ts +28 -0
  357. package/src/theme/components/shared/section-card.stories.tsx +51 -0
  358. package/src/theme/components/shared/section-card.tsx +44 -0
  359. package/src/theme/components/shared/section-grid.stories.tsx +46 -0
  360. package/src/theme/components/shared/section-grid.tsx +15 -0
  361. package/src/theme/components/shared/status-badge.css +37 -0
  362. package/src/theme/components/shared/status-badge.stories.tsx +61 -0
  363. package/src/theme/components/shared/status-badge.tsx +74 -0
  364. package/src/theme/components/shared/steps.css +88 -0
  365. package/src/theme/components/shared/steps.stories.tsx +68 -0
  366. package/src/theme/components/shared/steps.tsx +100 -0
  367. package/src/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  368. package/src/theme/components/shared/tech-icon-table.tsx +71 -0
  369. package/src/theme/components/shared/tech-tag.stories.tsx +40 -0
  370. package/src/theme/components/shared/tech-tag.tsx +31 -0
  371. package/src/theme/components/shared/theme-color-palette.css +80 -0
  372. package/src/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  373. package/src/theme/components/shared/theme-color-palette.tsx +275 -0
  374. package/src/theme/components/shared/tooltip.css +69 -0
  375. package/src/theme/components/shared/tooltip.stories.tsx +72 -0
  376. package/src/theme/components/shared/tooltip.tsx +77 -0
  377. package/src/theme/components/sidebar/framework-picker.css +77 -0
  378. package/src/theme/components/sidebar/framework-picker.tsx +78 -0
  379. package/src/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  380. package/src/theme/components/sidebar/sidebar-filter.ts +79 -0
  381. package/src/theme/components/sidebar/sidebar-links.css +102 -0
  382. package/src/theme/components/sidebar/sidebar-links.tsx +122 -0
  383. package/src/theme/components/sidebar/sidebar-promo.css +42 -0
  384. package/src/theme/components/sidebar/sidebar-promo.tsx +52 -0
  385. package/src/theme/components/sidebar/sidebar-scope.tsx +151 -0
  386. package/src/theme/components/sidebar/sidebar-toggle.css +181 -0
  387. package/src/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  388. package/src/theme/components/theme-provider.tsx +637 -0
  389. package/src/theme/components/workspaces/card.css +151 -0
  390. package/src/theme/components/workspaces/card.tsx +166 -0
  391. package/src/theme/components/workspaces/grid.tsx +62 -0
  392. package/src/theme/css.d.ts +1 -0
  393. package/src/theme/env.d.ts +12 -0
  394. package/src/theme/fonts/GeistMono-Variable.woff2 +0 -0
  395. package/src/theme/fonts/GeistPixel-Square.woff2 +0 -0
  396. package/src/theme/fonts/GeistSans-Variable.woff2 +0 -0
  397. package/src/theme/hooks/use-ciderpress.ts +61 -0
  398. package/src/theme/hooks/use-nav-items.ts +76 -0
  399. package/src/theme/icons/index.ts +2 -0
  400. package/src/theme/icons/tech-map.ts +228 -0
  401. package/src/theme/index.tsx +180 -0
  402. package/src/theme/lib/read-social-links.ts +27 -0
  403. package/src/theme/lib/route-link.tsx +126 -0
  404. package/src/theme/lib/safe-url.test.ts +0 -0
  405. package/src/theme/lib/safe-url.ts +68 -0
  406. package/src/theme/lib/theme-favicon.ts +125 -0
  407. package/src/theme/lib/user-config-stub.ts +12 -0
  408. package/src/theme/styles/layers.css +32 -0
  409. package/src/theme/styles/overrides/badge.css +26 -0
  410. package/src/theme/styles/overrides/content-footer.css +80 -0
  411. package/src/theme/styles/overrides/details.css +61 -0
  412. package/src/theme/styles/overrides/fonts.css +32 -0
  413. package/src/theme/styles/overrides/home-card.css +133 -0
  414. package/src/theme/styles/overrides/home.css +243 -0
  415. package/src/theme/styles/overrides/rail.css +337 -0
  416. package/src/theme/styles/overrides/rspress.css +62 -0
  417. package/src/theme/styles/overrides/scrollbar.css +25 -0
  418. package/src/theme/styles/overrides/section-card.css +114 -0
  419. package/src/theme/styles/overrides/sidebar.css +144 -0
  420. package/src/theme/styles/overrides/tokens.css +288 -0
  421. package/src/theme/styles/overrides/vscode.css +88 -0
  422. package/src/theme/styles/themes/amber.css +545 -0
  423. package/src/theme/styles/themes/arcade-fx.css +366 -0
  424. package/src/theme/styles/themes/arcade.css +273 -0
  425. package/src/theme/styles/themes/grannysmith.css +545 -0
  426. package/src/theme/styles/themes/honeycrisp.css +545 -0
  427. package/src/theme/styles/themes/midnight.css +273 -0
  428. package/src/theme/styles/themes/mulled.css +817 -0
@@ -0,0 +1,96 @@
1
+ import type { Story } from '@ladle/react'
2
+
3
+ import { Accordion, AccordionGroup } from './accordion.tsx'
4
+
5
+ const meta = {
6
+ title: 'Disclosure / Accordion',
7
+ }
8
+
9
+ export default meta
10
+
11
+ /**
12
+ * Single accordion — collapsed by default.
13
+ *
14
+ * @returns Accordion with title and body
15
+ */
16
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
17
+ export const Default: Story = () => (
18
+ <Accordion title="What is Ciderpress?">
19
+ <p>
20
+ Ciderpress is a documentation framework for monorepos. Point it at your existing markdown and
21
+ get a full site without forcing a layout on the repo.
22
+ </p>
23
+ </Accordion>
24
+ )
25
+
26
+ /**
27
+ * Accordion with icon and description shown alongside the title.
28
+ *
29
+ * @returns Accordion with icon and subtitle
30
+ */
31
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
32
+ export const WithIconAndDescription: Story = () => (
33
+ <Accordion
34
+ title="Theme cascade"
35
+ description="How --cp-* tokens win over Rspress's --rp-* defaults"
36
+ icon="pixelarticons:layers"
37
+ >
38
+ <p>
39
+ Each theme palette declares a layer (`mulled`, `honeycrisp`, …) ordered after Rspress's base
40
+ layer, so brand vars always win.
41
+ </p>
42
+ </Accordion>
43
+ )
44
+
45
+ /**
46
+ * Accordion that starts expanded.
47
+ *
48
+ * @returns Accordion with initial open state
49
+ */
50
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
51
+ export const InitiallyOpen: Story = () => (
52
+ <Accordion title="Open by default" icon="pixelarticons:check" defaultOpen>
53
+ <p>This panel renders expanded on first mount.</p>
54
+ </Accordion>
55
+ )
56
+
57
+ /**
58
+ * Multiple accordions inside a Group — each is independent (multiple
59
+ * may be open at once).
60
+ *
61
+ * @returns Group of independent accordions
62
+ */
63
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
64
+ export const Group: Story = () => (
65
+ <AccordionGroup>
66
+ <Accordion title="First section" icon="pixelarticons:flag">
67
+ <p>Plain content.</p>
68
+ </Accordion>
69
+ <Accordion title="Second section" icon="pixelarticons:bulb">
70
+ <p>More plain content.</p>
71
+ </Accordion>
72
+ <Accordion title="Third section" icon="pixelarticons:bookmark">
73
+ <p>Yet more.</p>
74
+ </Accordion>
75
+ </AccordionGroup>
76
+ )
77
+
78
+ /**
79
+ * Exclusive group — only one accordion may be open at a time.
80
+ *
81
+ * @returns Group with mutex behaviour
82
+ */
83
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
84
+ export const ExclusiveGroup: Story = () => (
85
+ <AccordionGroup exclusive>
86
+ <Accordion title="Step 1 — Install" icon="pixelarticons:download">
87
+ <p>Run `pnpm add ciderpress` in your repo root.</p>
88
+ </Accordion>
89
+ <Accordion title="Step 2 — Configure" icon="pixelarticons:sliders">
90
+ <p>Create `ciderpress.config.ts` and point it at your docs directory.</p>
91
+ </Accordion>
92
+ <Accordion title="Step 3 — Run" icon="pixelarticons:play">
93
+ <p>Run `pnpm cider dev` and open localhost:3000.</p>
94
+ </Accordion>
95
+ </AccordionGroup>
96
+ )
@@ -0,0 +1,191 @@
1
+ import { match, P } from 'massaman/match'
2
+ import type React from 'react'
3
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
4
+ import { Button, Disclosure, DisclosurePanel } from 'react-aria-components'
5
+
6
+ import { Icon } from './icon'
7
+
8
+ export interface AccordionGroupProps {
9
+ /**
10
+ * When true, only one accordion in the group can be open at a time.
11
+ */
12
+ readonly exclusive?: boolean
13
+ /**
14
+ * Accordion children to coordinate.
15
+ */
16
+ readonly children: React.ReactNode
17
+ }
18
+
19
+ interface AccordionGroupContextValue {
20
+ readonly exclusive: boolean
21
+ readonly openId: string | null
22
+ readonly setOpenId: (id: string | null) => void
23
+ }
24
+
25
+ const AccordionGroupContext = createContext<AccordionGroupContextValue | null>(null)
26
+
27
+ /**
28
+ * Group container that coordinates multiple Accordion components.
29
+ * When `exclusive` is true, only one accordion can be open at a time.
30
+ *
31
+ * @param props - Group configuration with optional exclusive mode
32
+ * @returns React element wrapping coordinated accordions
33
+ */
34
+ export function AccordionGroup({
35
+ exclusive = false,
36
+ children,
37
+ }: AccordionGroupProps): React.ReactElement {
38
+ const [openId, setOpenId] = useState<string | null>(null)
39
+
40
+ return (
41
+ <AccordionGroupContext.Provider value={{ exclusive, openId, setOpenId }}>
42
+ <div className="cp-accordion-group">{children}</div>
43
+ </AccordionGroupContext.Provider>
44
+ )
45
+ }
46
+
47
+ export interface AccordionProps {
48
+ /**
49
+ * Title displayed in the accordion trigger.
50
+ */
51
+ readonly title: string
52
+ /**
53
+ * Optional description displayed below the title.
54
+ */
55
+ readonly description?: string
56
+ /**
57
+ * Optional Iconify icon ID rendered before the title.
58
+ */
59
+ readonly icon?: string
60
+ /**
61
+ * Whether the accordion starts in the expanded state.
62
+ */
63
+ readonly defaultOpen?: boolean
64
+ /**
65
+ * Custom anchor ID for deep linking. Defaults to a slug of the title.
66
+ */
67
+ readonly id?: string
68
+ /**
69
+ * Content revealed when the accordion is expanded.
70
+ */
71
+ readonly children: React.ReactNode
72
+ }
73
+
74
+ /**
75
+ * Expandable section with title, optional description and icon,
76
+ * URL-hash deep linking, and keyboard-accessible expand/collapse.
77
+ *
78
+ * Built on react-aria-components Disclosure for full ARIA support.
79
+ *
80
+ * @param props - Accordion configuration
81
+ * @returns React element with expandable disclosure
82
+ */
83
+ export function Accordion({
84
+ title,
85
+ description,
86
+ icon,
87
+ defaultOpen = false,
88
+ id,
89
+ children,
90
+ }: AccordionProps): React.ReactElement {
91
+ const anchorId = id ?? slugify(title)
92
+ const group = useContext(AccordionGroupContext)
93
+ const isFirstRender = useRef(true)
94
+
95
+ // Determine if this accordion should start open:
96
+ // 1. URL hash match takes priority
97
+ // 2. Then defaultOpen prop
98
+ // 3. Then group exclusive state
99
+ const hashMatch = globalThis.location !== undefined && globalThis.location.hash === `#${anchorId}`
100
+ const initialOpen = hashMatch || defaultOpen
101
+
102
+ const [isExpanded, setIsExpanded] = useState(initialOpen)
103
+
104
+ useEffect(() => {
105
+ if (group !== null && group.exclusive && group.openId === null && initialOpen) {
106
+ group.setOpenId(anchorId)
107
+ }
108
+ }, []) // eslint-disable-line react-hooks/exhaustive-deps -- seed once on mount
109
+
110
+ const expanded = match(group)
111
+ .with(
112
+ P.when((g): g is AccordionGroupContextValue => g !== null && g.exclusive),
113
+ (g) => g.openId === anchorId
114
+ )
115
+ .otherwise(() => isExpanded)
116
+
117
+ const handleExpandedChange = useCallback(
118
+ (open: boolean) => {
119
+ match({ group, exclusive: group !== null && group.exclusive })
120
+ .with({ group: P.nonNullable, exclusive: true }, ({ group: g }) => {
121
+ g.setOpenId(
122
+ match(open)
123
+ .with(true, () => anchorId)
124
+ .otherwise(() => null)
125
+ )
126
+ })
127
+ .otherwise(() => {
128
+ setIsExpanded(open)
129
+ })
130
+
131
+ if (open && globalThis.history !== undefined) {
132
+ globalThis.history.replaceState(null, '', `#${anchorId}`)
133
+ }
134
+ },
135
+ [group, anchorId]
136
+ )
137
+
138
+ useEffect(() => {
139
+ if (isFirstRender.current && hashMatch) {
140
+ isFirstRender.current = false
141
+ handleExpandedChange(true)
142
+ }
143
+ }, [hashMatch, handleExpandedChange])
144
+
145
+ const iconEl = match(icon)
146
+ .with(P.nonNullable, (i) => (
147
+ <span className="cp-accordion__icon">
148
+ <Icon icon={i} />
149
+ </span>
150
+ ))
151
+ .otherwise(() => null)
152
+
153
+ const descEl = match(description)
154
+ .with(P.nonNullable, (d) => <span className="cp-accordion__description">{d}</span>)
155
+ .otherwise(() => null)
156
+
157
+ return (
158
+ <Disclosure
159
+ id={anchorId}
160
+ isExpanded={expanded}
161
+ onExpandedChange={handleExpandedChange}
162
+ className="cp-accordion"
163
+ >
164
+ <Button slot="trigger" className="cp-accordion__trigger">
165
+ {iconEl}
166
+ <span className="cp-accordion__header">
167
+ <span className="cp-accordion__title">{title}</span>
168
+ {descEl}
169
+ </span>
170
+ <span className="cp-accordion__chevron">
171
+ <Icon icon="pixelarticons:chevron-right" />
172
+ </span>
173
+ </Button>
174
+ <DisclosurePanel className="cp-accordion__panel">{children}</DisclosurePanel>
175
+ </Disclosure>
176
+ )
177
+ }
178
+
179
+ /**
180
+ * Convert a title string to a URL-safe slug.
181
+ *
182
+ * @private
183
+ * @param text - Title text to slugify
184
+ * @returns Lowercase hyphenated slug
185
+ */
186
+ function slugify(text: string): string {
187
+ return text
188
+ .toLowerCase()
189
+ .replaceAll(/[^a-z0-9]+/g, '-')
190
+ .replaceAll(/^-|-$/g, '')
191
+ }
@@ -0,0 +1,49 @@
1
+ import type { Story } from '@ladle/react'
2
+
3
+ import { CiderpressLogo } from './ciderpress-logo.tsx'
4
+
5
+ const meta = {
6
+ title: 'Brand / Logo',
7
+ }
8
+
9
+ export default meta
10
+
11
+ /**
12
+ * Wordmark inheriting the active palette's `--rp-c-brand`.
13
+ *
14
+ * @returns Inline SVG wordmark
15
+ */
16
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
17
+ export const Default: Story = () => (
18
+ <div style={{ width: 'min(640px, 100%)' }}>
19
+ <CiderpressLogo />
20
+ </div>
21
+ )
22
+
23
+ /**
24
+ * Explicit-size variant — useful for visual diffs against the favicon
25
+ * mark and footer mark at fixed pixel dimensions.
26
+ *
27
+ * @returns SVG wordmark at three explicit sizes
28
+ */
29
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
30
+ export const Sizes: Story = () => (
31
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
32
+ <CiderpressLogo width={480} />
33
+ <CiderpressLogo width={320} />
34
+ <CiderpressLogo width={200} />
35
+ </div>
36
+ )
37
+
38
+ /**
39
+ * Custom accessible title — replaces the default `"ciderpress"` label
40
+ * announced to screen readers.
41
+ *
42
+ * @returns Wordmark with custom title
43
+ */
44
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
45
+ export const CustomTitle: Story = () => (
46
+ <div style={{ width: 480 }}>
47
+ <CiderpressLogo title="ciderpress — documentation framework" />
48
+ </div>
49
+ )
@@ -0,0 +1,53 @@
1
+ import type { Story } from '@ladle/react'
2
+
3
+ import { CiderpressMark } from './ciderpress-mark.tsx'
4
+
5
+ const meta = {
6
+ title: 'Brand / Mark',
7
+ }
8
+
9
+ export default meta
10
+
11
+ /**
12
+ * Default brand mark — rounded-square chip with `cp` monogram in
13
+ * the active palette's brand colour.
14
+ *
15
+ * @returns SVG mark at 64px
16
+ */
17
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
18
+ export const Default: Story = () => <CiderpressMark size={64} />
19
+
20
+ /**
21
+ * Size scale used across nav, footer, and favicon contexts.
22
+ *
23
+ * @returns Marks at 16/24/32/48/64/96/128 px
24
+ */
25
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
26
+ export const Sizes: Story = () => (
27
+ <div style={{ display: 'flex', alignItems: 'flex-end', gap: 16, flexWrap: 'wrap' }}>
28
+ {[16, 24, 32, 48, 64, 96, 128].map((s) => (
29
+ <div key={s} style={{ textAlign: 'center' }}>
30
+ <CiderpressMark size={s} />
31
+ <div
32
+ style={{
33
+ marginTop: 6,
34
+ fontSize: 11,
35
+ color: 'var(--cp-c-text-3)',
36
+ fontFamily: 'ui-monospace, monospace',
37
+ }}
38
+ >
39
+ {s}px
40
+ </div>
41
+ </div>
42
+ ))}
43
+ </div>
44
+ )
45
+
46
+ /**
47
+ * Decorative mark — empty title sets `aria-hidden` so screen readers
48
+ * skip it. Use this when the surrounding text already conveys meaning.
49
+ *
50
+ * @returns Mark hidden from a11y tree
51
+ */
52
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
53
+ export const Decorative: Story = () => <CiderpressMark size={64} title="" />
@@ -0,0 +1 @@
1
+ /* Styles moved to desktop-window.css */
@@ -0,0 +1,100 @@
1
+ import type { Story } from '@ladle/react'
2
+
3
+ import {
4
+ BrowserWindow,
5
+ Command,
6
+ IDEWindow,
7
+ Line,
8
+ Output,
9
+ TerminalWindow,
10
+ } from './desktop-window.tsx'
11
+
12
+ const meta = {
13
+ title: 'Windows',
14
+ }
15
+
16
+ export default meta
17
+
18
+ /**
19
+ * BrowserWindow with a URL bar and inline body content.
20
+ *
21
+ * @returns Rendered browser chrome
22
+ */
23
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
24
+ export const Browser: Story = () => (
25
+ <BrowserWindow url="https://ciderpress.dev/guides/themes" tab={{ title: 'Ciderpress · Themes' }}>
26
+ <div style={{ padding: 24 }}>
27
+ <h1 style={{ marginTop: 0 }}>Theme palettes</h1>
28
+ <p>Switch the palette in the toolbar above to preview the cascade.</p>
29
+ </div>
30
+ </BrowserWindow>
31
+ )
32
+
33
+ /**
34
+ * BrowserWindow rendering an image as its body — common pattern in docs
35
+ * for screenshots / hero captures.
36
+ *
37
+ * @returns Browser chrome wrapping an image
38
+ */
39
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
40
+ export const BrowserWithImage: Story = () => (
41
+ <BrowserWindow
42
+ url="https://ciderpress.dev"
43
+ tab={{ title: 'Ciderpress' }}
44
+ image="https://picsum.photos/seed/ciderpress/1200/600"
45
+ />
46
+ )
47
+
48
+ /**
49
+ * TerminalWindow with composed command/output children including coloured
50
+ * inline `<Line>` runs.
51
+ *
52
+ * @returns Terminal chrome
53
+ */
54
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
55
+ export const Terminal: Story = () => (
56
+ <TerminalWindow title="zsh">
57
+ <Command>pnpm install ciderpress</Command>
58
+ <Output>
59
+ <Line color="muted">resolved 142 packages in 1.4s</Line>
60
+ </Output>
61
+ <Output>
62
+ <Line color="success" bold>
63
+ +
64
+ </Line>{' '}
65
+ <Line color="muted">ciderpress 1.0.0-rc.0</Line>
66
+ </Output>
67
+ <Command>pnpm cider dev</Command>
68
+ <Output>
69
+ <Line color="info">→</Line> <Line>http://localhost:3000</Line>
70
+ </Output>
71
+ </TerminalWindow>
72
+ )
73
+
74
+ const IDE_SAMPLE_CODE = `import { defineConfig } from 'ciderpress'
75
+
76
+ export default defineConfig({
77
+ title: 'My Docs',
78
+ theme: 'mulled',
79
+ base: '/',
80
+ })
81
+ `
82
+
83
+ /**
84
+ * IDE-style window with file tabs and a syntax-highlighted code block
85
+ * rendered via the stubbed `CodeBlockRuntime`.
86
+ *
87
+ * @returns IDE chrome with sample TypeScript code
88
+ */
89
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
90
+ export const IDE: Story = () => (
91
+ <IDEWindow
92
+ files={[
93
+ { name: 'ciderpress.config.ts', active: true },
94
+ { name: 'package.json' },
95
+ { name: 'README.md' },
96
+ ]}
97
+ code={IDE_SAMPLE_CODE}
98
+ lang="ts"
99
+ />
100
+ )
@@ -0,0 +1,2 @@
1
+ export { BrowserWindow } from './desktop-window'
2
+ export type { BrowserWindowProps, BrowserTab } from './desktop-window'
@@ -0,0 +1,50 @@
1
+ import type { Story } from '@ladle/react'
2
+
3
+ import { Card } from './card.tsx'
4
+
5
+ const meta = {
6
+ title: 'Surface / Card',
7
+ }
8
+
9
+ export default meta
10
+
11
+ /**
12
+ * Plain card without a link target — renders as `<div>`.
13
+ *
14
+ * @returns Static card
15
+ */
16
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
17
+ export const Static: Story = () => (
18
+ <Card>
19
+ <h3 style={{ marginTop: 0 }}>Static card</h3>
20
+ <p>No href supplied — the surface renders as a plain div.</p>
21
+ </Card>
22
+ )
23
+
24
+ /**
25
+ * Card with a safe URL — renders as the stubbed Rspress `<Link>`.
26
+ *
27
+ * @returns Clickable card
28
+ */
29
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
30
+ export const Clickable: Story = () => (
31
+ <Card href="/guides/getting-started">
32
+ <h3 style={{ marginTop: 0 }}>Clickable card</h3>
33
+ <p>href passes safeUrl validation, so the card becomes an anchor.</p>
34
+ </Card>
35
+ )
36
+
37
+ /**
38
+ * Card with an unsafe `javascript:` href — `safeUrl()` rejects it and the
39
+ * card falls back to `<div>`. Visually identical to `Static`.
40
+ *
41
+ * @returns Card with stripped href
42
+ */
43
+ // oxlint-disable-next-line func-style -- Ladle stories use `export const`
44
+ export const RejectedHref: Story = () => (
45
+ // oxlint-disable-next-line no-script-url -- testing safeUrl() rejection
46
+ <Card href={'javascript:alert(1)'}>
47
+ <h3 style={{ marginTop: 0 }}>Rejected href</h3>
48
+ <p>Falls back to a div — XSS sink defused.</p>
49
+ </Card>
50
+ )
@@ -0,0 +1,35 @@
1
+ import { Link } from '@rspress/core/runtime'
2
+ import { match, P } from 'massaman/match'
3
+ import type React from 'react'
4
+
5
+ import { safeUrl } from '../../lib/safe-url.ts'
6
+
7
+ export interface CardProps {
8
+ readonly href?: string
9
+ readonly className?: string
10
+ readonly children: React.ReactNode
11
+ }
12
+
13
+ /**
14
+ * Shared base card handling link-vs-div rendering.
15
+ *
16
+ * Renders `<a>` with `cp-card--clickable` when `href` is provided AND
17
+ * passes `safeUrl()` validation. When `href` is omitted or fails
18
+ * validation, falls back to a plain `<div>` so the card surface stays
19
+ * visible without becoming a script-execution sink.
20
+ *
21
+ * @param props - Props with optional href, optional className, and children
22
+ * @returns React element rendered as an anchor or div
23
+ */
24
+ export function Card({ href, className, children }: CardProps): React.ReactElement {
25
+ const safeHref = match(href)
26
+ .with(P.nullish, () => null)
27
+ .otherwise((h) => safeUrl(h))
28
+ return match(safeHref)
29
+ .with(P.nonNullable, (h) => (
30
+ <Link className={`cp-card cp-card--clickable ${className ?? ''}`} to={h}>
31
+ {children}
32
+ </Link>
33
+ ))
34
+ .otherwise(() => <div className={`cp-card ${className ?? ''}`}>{children}</div>)
35
+ }
@@ -0,0 +1,93 @@
1
+ import { BRAND_COLORS, DEFAULT_THEME_NAME } from '@ciderpress/theme'
2
+ import type React from 'react'
3
+
4
+ const FONT_STACK = "'SF Mono', 'Fira Code', 'JetBrains Mono', Consolas, monospace"
5
+ /**
6
+ * ViewBox cropped to the measured glyph bounding box plus a 1px border
7
+ * on every side. With `translate(0, 14)` below, the first line's
8
+ * ascender sits at y≈0 and the sixth line's descender bottoms out at
9
+ * y≈99, so the whole wordmark fills the box edge-to-edge instead of
10
+ * floating in extra empty space.
11
+ */
12
+ const LOGO_VIEWBOX = '-1 -1 588 101'
13
+ const LOGO_FALLBACK_COLOR = BRAND_COLORS[DEFAULT_THEME_NAME].primary
14
+ const FONT_SIZE = 13
15
+ const LINE_HEIGHT = 16
16
+ const X_OFFSET = 0
17
+ const Y_OFFSET = 14
18
+
19
+ const CIDERPRESS_ART: readonly string[] = Object.freeze([
20
+ ' ██████╗██╗██████╗ ███████╗██████╗ ██████╗ ██████╗ ███████╗███████╗███████╗',
21
+ '██╔════╝██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔════╝',
22
+ '██║ ██║██║ ██║█████╗ ██████╔╝██████╔╝██████╔╝█████╗ ███████╗███████╗',
23
+ '██║ ██║██║ ██║██╔══╝ ██╔══██╗██╔═══╝ ██╔══██╗██╔══╝ ╚════██║╚════██║',
24
+ '╚██████╗██║██████╔╝███████╗██║ ██║██║ ██║ ██║███████╗███████║███████║',
25
+ ' ╚═════╝╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝',
26
+ ])
27
+
28
+ export interface CiderpressLogoProps {
29
+ /**
30
+ * Optional className applied to the root `<svg>` element.
31
+ */
32
+ readonly className?: string
33
+ /**
34
+ * Accessible label rendered into an SVG `<title>` element. Defaults to
35
+ * `"ciderpress"` so the logo is always announced by screen readers.
36
+ */
37
+ readonly title?: string
38
+ /**
39
+ * Explicit `width` attribute. Omit to let CSS / containing element
40
+ * control sizing via the SVG's `viewBox`.
41
+ */
42
+ readonly width?: number | string
43
+ /**
44
+ * Explicit `height` attribute. Omit to let CSS / containing element
45
+ * control sizing via the SVG's `viewBox`.
46
+ */
47
+ readonly height?: number | string
48
+ }
49
+
50
+ /**
51
+ * Inline `<svg>` ciderpress wordmark logo that auto-themes to the active theme.
52
+ *
53
+ * Renders the FIGlet "ciderpress" wordmark using `fill="currentColor"` so the
54
+ * glyphs inherit color from the wrapping `<svg>`. The wrapper sets `color`
55
+ * to `var(--rp-c-brand)` — the canonical brand variable maintained by
56
+ * `ThemeProvider` — so the logo tints to whichever theme (and variant) is
57
+ * active without any JS re-renders or theme subscriptions.
58
+ *
59
+ * Falls back to the default theme's primary brand color when
60
+ * `--rp-c-brand` is not defined (e.g. when rendered outside the
61
+ * ciderpress theme context).
62
+ *
63
+ * @param props - Optional className, title, and explicit size overrides
64
+ * @returns Inline SVG element
65
+ */
66
+ export function CiderpressLogo(props: CiderpressLogoProps): React.ReactElement {
67
+ const title = props.title ?? 'ciderpress'
68
+
69
+ return (
70
+ <svg
71
+ xmlns="http://www.w3.org/2000/svg"
72
+ viewBox={LOGO_VIEWBOX}
73
+ className={props.className}
74
+ width={props.width}
75
+ height={props.height}
76
+ style={{ color: `var(--rp-c-brand, ${LOGO_FALLBACK_COLOR})` }}
77
+ role="img"
78
+ >
79
+ <title>{title}</title>
80
+ <g
81
+ transform={`translate(${X_OFFSET}, ${Y_OFFSET})`}
82
+ fontFamily={FONT_STACK}
83
+ fill="currentColor"
84
+ >
85
+ {CIDERPRESS_ART.map((line, i) => (
86
+ <text key={line} fontSize={FONT_SIZE} y={i * LINE_HEIGHT} xmlSpace="preserve">
87
+ {line}
88
+ </text>
89
+ ))}
90
+ </g>
91
+ </svg>
92
+ )
93
+ }