@beehexa/design-rules 0.0.0-stage → 2611.3.2

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 (290) hide show
  1. package/README.md +56 -2
  2. package/dist/AGENTS.md +24 -0
  3. package/dist/catalog.json +1814 -0
  4. package/dist/docs/public/_redirects +7 -0
  5. package/dist/docs/public/apple-touch-icon.png +0 -0
  6. package/dist/docs/public/brand/logos/app/apple-touch-icon.png +0 -0
  7. package/dist/docs/public/brand/logos/app/avatar-800.png +0 -0
  8. package/dist/docs/public/brand/logos/app/icon-192.png +0 -0
  9. package/dist/docs/public/brand/logos/app/icon-512.png +0 -0
  10. package/dist/docs/public/brand/logos/app/icon-maskable-512.png +0 -0
  11. package/dist/docs/public/brand/logos/archive/d-550/beehexa-horizontal-1-light.svg +1 -0
  12. package/dist/docs/public/brand/logos/archive/d-550/beehexa-horizontal-2-dark.svg +1 -0
  13. package/dist/docs/public/brand/logos/archive/d-550/beehexa-horizontal-3-white.svg +1 -0
  14. package/dist/docs/public/brand/logos/archive/d-550/beehexa-horizontal-4-graphite.svg +1 -0
  15. package/dist/docs/public/brand/logos/archive/d-550/hexasync-horizontal-1-light.svg +1 -0
  16. package/dist/docs/public/brand/logos/archive/d-550/hexasync-horizontal-2-dark.svg +1 -0
  17. package/dist/docs/public/brand/logos/archive/d-550/hexasync-horizontal-3-white.svg +1 -0
  18. package/dist/docs/public/brand/logos/archive/d-550/hexasync-horizontal-4-graphite.svg +1 -0
  19. package/dist/docs/public/brand/logos/archive/d-550/ui/beehexa-d-550-dark.svg +1 -0
  20. package/dist/docs/public/brand/logos/archive/d-550/ui/beehexa-d-550-light.svg +1 -0
  21. package/dist/docs/public/brand/logos/archive/d-550/ui/beehexa-design-d-550-dark.svg +1 -0
  22. package/dist/docs/public/brand/logos/archive/d-550/ui/beehexa-design-d-550-light.svg +1 -0
  23. package/dist/docs/public/brand/logos/archive/d-550/ui/hexasync-d-550-dark.svg +1 -0
  24. package/dist/docs/public/brand/logos/archive/d-550/ui/hexasync-d-550-light.svg +1 -0
  25. package/dist/docs/public/brand/logos/archive/d-550/ui/png/beehexa-design-d-550-dark@3x.png +0 -0
  26. package/dist/docs/public/brand/logos/archive/d-550/ui/png/beehexa-design-d-550-light@3x.png +0 -0
  27. package/dist/docs/public/brand/logos/beehexa-logo.zip +0 -0
  28. package/dist/docs/public/brand/logos/fig/anatomy-en.png +0 -0
  29. package/dist/docs/public/brand/logos/fig/anatomy-vi.png +0 -0
  30. package/dist/docs/public/brand/logos/fig/beehexa-dark-12.png +0 -0
  31. package/dist/docs/public/brand/logos/fig/beehexa-dark-14.png +0 -0
  32. package/dist/docs/public/brand/logos/fig/beehexa-dark-28.png +0 -0
  33. package/dist/docs/public/brand/logos/fig/beehexa-dark-32.png +0 -0
  34. package/dist/docs/public/brand/logos/fig/beehexa-dark-56.png +0 -0
  35. package/dist/docs/public/brand/logos/fig/beehexa-graphite-28.png +0 -0
  36. package/dist/docs/public/brand/logos/fig/beehexa-graphite-32.png +0 -0
  37. package/dist/docs/public/brand/logos/fig/beehexa-light-14.png +0 -0
  38. package/dist/docs/public/brand/logos/fig/beehexa-light-21.png +0 -0
  39. package/dist/docs/public/brand/logos/fig/beehexa-light-22.png +0 -0
  40. package/dist/docs/public/brand/logos/fig/beehexa-light-24.png +0 -0
  41. package/dist/docs/public/brand/logos/fig/beehexa-light-28.png +0 -0
  42. package/dist/docs/public/brand/logos/fig/beehexa-light-32.png +0 -0
  43. package/dist/docs/public/brand/logos/fig/beehexa-light-36-7c3aed7c3aed.png +0 -0
  44. package/dist/docs/public/brand/logos/fig/beehexa-light-36-swap.png +0 -0
  45. package/dist/docs/public/brand/logos/fig/beehexa-light-36.png +0 -0
  46. package/dist/docs/public/brand/logos/fig/beehexa-light-56.png +0 -0
  47. package/dist/docs/public/brand/logos/fig/beehexa-white-20.png +0 -0
  48. package/dist/docs/public/brand/logos/fig/beehexa-white-32.png +0 -0
  49. package/dist/docs/public/brand/logos/fig/clearspace.png +0 -0
  50. package/dist/docs/public/brand/logos/fig/construction-en.png +0 -0
  51. package/dist/docs/public/brand/logos/fig/construction-vi.png +0 -0
  52. package/dist/docs/public/brand/logos/fig/container-en.png +0 -0
  53. package/dist/docs/public/brand/logos/fig/container-vi.png +0 -0
  54. package/dist/docs/public/brand/logos/fig/hexasync-dark-20.png +0 -0
  55. package/dist/docs/public/brand/logos/fig/hexasync-dark-28.png +0 -0
  56. package/dist/docs/public/brand/logos/fig/hexasync-dark-48.png +0 -0
  57. package/dist/docs/public/brand/logos/fig/hexasync-light-19.png +0 -0
  58. package/dist/docs/public/brand/logos/fig/hexasync-light-28.png +0 -0
  59. package/dist/docs/public/brand/logos/fig/hexasync-light-48.png +0 -0
  60. package/dist/docs/public/brand/logos/fig/icon-graphite-14.png +0 -0
  61. package/dist/docs/public/brand/logos/fig/icon-graphite-16.png +0 -0
  62. package/dist/docs/public/brand/logos/fig/icon-light-16.png +0 -0
  63. package/dist/docs/public/brand/logos/fig/icon-light-24.png +0 -0
  64. package/dist/docs/public/brand/logos/fig/icon-light-48.png +0 -0
  65. package/dist/docs/public/brand/logos/fig/icon-light-92.png +0 -0
  66. package/dist/docs/public/brand/logos/fig/meaning-bee-en.png +0 -0
  67. package/dist/docs/public/brand/logos/fig/meaning-bee-vi.png +0 -0
  68. package/dist/docs/public/brand/logos/fig/meaning-outline-en.png +0 -0
  69. package/dist/docs/public/brand/logos/fig/meaning-outline-vi.png +0 -0
  70. package/dist/docs/public/brand/logos/fig/meaning-stack-en.png +0 -0
  71. package/dist/docs/public/brand/logos/fig/meaning-stack-vi.png +0 -0
  72. package/dist/docs/public/brand/logos/fig/misuse-serif.png +0 -0
  73. package/dist/docs/public/brand/logos/icon/beehexa-icon-graphite.svg +1 -0
  74. package/dist/docs/public/brand/logos/icon/beehexa-icon-white.svg +1 -0
  75. package/dist/docs/public/brand/logos/icon/beehexa-icon-yellow.svg +1 -0
  76. package/dist/docs/public/brand/logos/lockups/beehexa-horizontal-1-light.svg +1 -0
  77. package/dist/docs/public/brand/logos/lockups/beehexa-horizontal-2-dark.svg +1 -0
  78. package/dist/docs/public/brand/logos/lockups/beehexa-horizontal-3-white.svg +1 -0
  79. package/dist/docs/public/brand/logos/lockups/beehexa-horizontal-4-graphite.svg +1 -0
  80. package/dist/docs/public/brand/logos/lockups/hexasync-horizontal-1-light.svg +1 -0
  81. package/dist/docs/public/brand/logos/lockups/hexasync-horizontal-2-dark.svg +1 -0
  82. package/dist/docs/public/brand/logos/lockups/hexasync-horizontal-3-white.svg +1 -0
  83. package/dist/docs/public/brand/logos/lockups/hexasync-horizontal-4-graphite.svg +1 -0
  84. package/dist/docs/public/brand/logos/ui/beehexa-dark.svg +1 -0
  85. package/dist/docs/public/brand/logos/ui/beehexa-design-dark.svg +1 -0
  86. package/dist/docs/public/brand/logos/ui/beehexa-design-light.svg +1 -0
  87. package/dist/docs/public/brand/logos/ui/beehexa-icon-yellow.svg +1 -0
  88. package/dist/docs/public/brand/logos/ui/beehexa-light.svg +1 -0
  89. package/dist/docs/public/brand/logos/ui/hexasync-dark.svg +1 -0
  90. package/dist/docs/public/brand/logos/ui/hexasync-light.svg +1 -0
  91. package/dist/docs/public/brand/logos/ui/png/beehexa-design-dark@3x.png +0 -0
  92. package/dist/docs/public/brand/logos/ui/png/beehexa-design-light@3x.png +0 -0
  93. package/dist/docs/public/favicon.ico +0 -0
  94. package/dist/docs/public/favicon.svg +1 -0
  95. package/dist/docs/public/fonts/LICENSE-Inter.txt +93 -0
  96. package/dist/docs/public/fonts/LICENSE-JetBrainsMono.txt +93 -0
  97. package/dist/docs/public/fonts/inter-latin-ext-opsz-wght-italic.woff2 +0 -0
  98. package/dist/docs/public/fonts/inter-latin-ext-opsz-wght-normal.woff2 +0 -0
  99. package/dist/docs/public/fonts/inter-latin-opsz-wght-italic.woff2 +0 -0
  100. package/dist/docs/public/fonts/inter-latin-opsz-wght-normal.woff2 +0 -0
  101. package/dist/docs/public/fonts/inter-vietnamese-opsz-wght-italic.woff2 +0 -0
  102. package/dist/docs/public/fonts/inter-vietnamese-opsz-wght-normal.woff2 +0 -0
  103. package/dist/docs/public/fonts/jetbrains-mono-latin-ext-wght-normal.woff2 +0 -0
  104. package/dist/docs/public/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  105. package/dist/docs/public/fonts/jetbrains-mono-vietnamese-wght-normal.woff2 +0 -0
  106. package/dist/docs/public/icon-192.png +0 -0
  107. package/dist/docs/public/icon-512.png +0 -0
  108. package/dist/docs/public/icon-maskable-512.png +0 -0
  109. package/dist/docs/public/robots.txt +4 -0
  110. package/dist/docs/public/site.webmanifest +21 -0
  111. package/dist/docs/scripts/color-pairs.mjs +46 -0
  112. package/dist/docs/scripts/contrast-exceptions.mjs +6 -0
  113. package/dist/docs/scripts/token-utils.d.mts +26 -0
  114. package/dist/docs/scripts/token-utils.mjs +114 -0
  115. package/dist/docs/src/brand/Beehexa-brandguide-full-mar12.pdf +0 -0
  116. package/dist/docs/src/brand/color+typoDirections.pdf +0 -0
  117. package/dist/docs/src/brand/structure-proposal.md +227 -0
  118. package/dist/docs/src/components/ChildPages.astro +25 -0
  119. package/dist/docs/src/components/CodeExample.astro +18 -0
  120. package/dist/docs/src/components/ColorDemo.astro +794 -0
  121. package/dist/docs/src/components/ColorExample.astro +32 -0
  122. package/dist/docs/src/components/ColorSwatch.astro +20 -0
  123. package/dist/docs/src/components/ComponentTabs.astro +21 -0
  124. package/dist/docs/src/components/DocsFooter.astro +25 -0
  125. package/dist/docs/src/components/HelpOptions.astro +20 -0
  126. package/dist/docs/src/components/IconBrowser.astro +257 -0
  127. package/dist/docs/src/components/IconDemo.astro +185 -0
  128. package/dist/docs/src/components/InDevelopment.astro +29 -0
  129. package/dist/docs/src/components/LayoutDemo.astro +384 -0
  130. package/dist/docs/src/components/Logo.astro +25 -0
  131. package/dist/docs/src/components/PhaseTable.astro +22 -0
  132. package/dist/docs/src/components/RoleGuides.astro +48 -0
  133. package/dist/docs/src/components/ShapeDemo.astro +239 -0
  134. package/dist/docs/src/components/ShapePin.astro +22 -0
  135. package/dist/docs/src/components/Sidebar.astro +206 -0
  136. package/dist/docs/src/components/SiteHeader.astro +211 -0
  137. package/dist/docs/src/components/SpacingDemo.astro +172 -0
  138. package/dist/docs/src/components/StatusBadge.astro +22 -0
  139. package/dist/docs/src/components/SystemAreas.astro +29 -0
  140. package/dist/docs/src/components/TableOfContents.astro +47 -0
  141. package/dist/docs/src/components/TokenTable.astro +40 -0
  142. package/dist/docs/src/components/TypeDemo.astro +249 -0
  143. package/dist/docs/src/components/logos/Fig.astro +28 -0
  144. package/dist/docs/src/components/logos/LogoAnatomy.astro +101 -0
  145. package/dist/docs/src/components/logos/LogoClearSpace.astro +81 -0
  146. package/dist/docs/src/components/logos/LogoColourVersions.astro +45 -0
  147. package/dist/docs/src/components/logos/LogoConstruction.astro +84 -0
  148. package/dist/docs/src/components/logos/LogoContainer.astro +84 -0
  149. package/dist/docs/src/components/logos/LogoHero.astro +42 -0
  150. package/dist/docs/src/components/logos/LogoInUse.astro +197 -0
  151. package/dist/docs/src/components/logos/LogoMeanings.astro +75 -0
  152. package/dist/docs/src/components/logos/LogoMinSize.astro +55 -0
  153. package/dist/docs/src/components/logos/LogoMistakes.astro +109 -0
  154. package/dist/docs/src/components/logos/LogoMisuse.astro +96 -0
  155. package/dist/docs/src/components/logos/LogoPair.astro +26 -0
  156. package/dist/docs/src/components/logos/LogoSvg.astro +68 -0
  157. package/dist/docs/src/content/components/button/accessibility.mdx +18 -0
  158. package/dist/docs/src/content/components/button/changelog.mdx +6 -0
  159. package/dist/docs/src/content/components/button/code.mdx +27 -0
  160. package/dist/docs/src/content/components/button/examples.mdx +21 -0
  161. package/dist/docs/src/content/components/button/meta.json +5 -0
  162. package/dist/docs/src/content/components/button/usage.mdx +18 -0
  163. package/dist/docs/src/content/foundations/guidelines/accessibility.mdx +19 -0
  164. package/dist/docs/src/content/foundations/guidelines/content.mdx +25 -0
  165. package/dist/docs/src/content/foundations/index.mdx +9 -0
  166. package/dist/docs/src/content/foundations/styles/border.mdx +89 -0
  167. package/dist/docs/src/content/foundations/styles/color/accessibility.mdx +32 -0
  168. package/dist/docs/src/content/foundations/styles/color/dark-mode.mdx +22 -0
  169. package/dist/docs/src/content/foundations/styles/color/index.mdx +65 -0
  170. package/dist/docs/src/content/foundations/styles/color/palette.mdx +57 -0
  171. package/dist/docs/src/content/foundations/styles/color/tokens.mdx +55 -0
  172. package/dist/docs/src/content/foundations/styles/color/usage.mdx +111 -0
  173. package/dist/docs/src/content/foundations/styles/data-visualization.mdx +11 -0
  174. package/dist/docs/src/content/foundations/styles/elevation.mdx +12 -0
  175. package/dist/docs/src/content/foundations/styles/icons/accessibility.mdx +72 -0
  176. package/dist/docs/src/content/foundations/styles/icons/code.mdx +171 -0
  177. package/dist/docs/src/content/foundations/styles/icons/index.mdx +62 -0
  178. package/dist/docs/src/content/foundations/styles/icons/library.mdx +19 -0
  179. package/dist/docs/src/content/foundations/styles/icons/usage.mdx +100 -0
  180. package/dist/docs/src/content/foundations/styles/illustration.mdx +9 -0
  181. package/dist/docs/src/content/foundations/styles/interaction-states.mdx +49 -0
  182. package/dist/docs/src/content/foundations/styles/layout/app-frame.mdx +81 -0
  183. package/dist/docs/src/content/foundations/styles/layout/breakpoints.mdx +56 -0
  184. package/dist/docs/src/content/foundations/styles/layout/grid.mdx +87 -0
  185. package/dist/docs/src/content/foundations/styles/layout/index.mdx +24 -0
  186. package/dist/docs/src/content/foundations/styles/layout/overlays.mdx +45 -0
  187. package/dist/docs/src/content/foundations/styles/layout/page-widths.mdx +38 -0
  188. package/dist/docs/src/content/foundations/styles/logos/downloads-and-terms.mdx +65 -0
  189. package/dist/docs/src/content/foundations/styles/logos/index.mdx +64 -0
  190. package/dist/docs/src/content/foundations/styles/logos/placement-and-containers.mdx +96 -0
  191. package/dist/docs/src/content/foundations/styles/logos/product-logos.mdx +56 -0
  192. package/dist/docs/src/content/foundations/styles/logos/using-the-logo.mdx +70 -0
  193. package/dist/docs/src/content/foundations/styles/motion.mdx +11 -0
  194. package/dist/docs/src/content/foundations/styles/opacity.mdx +9 -0
  195. package/dist/docs/src/content/foundations/styles/radius.mdx +98 -0
  196. package/dist/docs/src/content/foundations/styles/size-and-density.mdx +41 -0
  197. package/dist/docs/src/content/foundations/styles/spacing.mdx +70 -0
  198. package/dist/docs/src/content/foundations/styles/typography/code.mdx +53 -0
  199. package/dist/docs/src/content/foundations/styles/typography/index.mdx +58 -0
  200. package/dist/docs/src/content/foundations/styles/typography/usage.mdx +144 -0
  201. package/dist/docs/src/content/foundations/styles/typography/vietnamese.mdx +46 -0
  202. package/dist/docs/src/content/foundations/styles/z-index.mdx +9 -0
  203. package/dist/docs/src/content/foundations/tokens/all-tokens.mdx +36 -0
  204. package/dist/docs/src/content/foundations/tokens/index.mdx +27 -0
  205. package/dist/docs/src/content/get-started/content.mdx +14 -0
  206. package/dist/docs/src/content/get-started/design.mdx +30 -0
  207. package/dist/docs/src/content/get-started/develop.mdx +59 -0
  208. package/dist/docs/src/content/get-started/get-help.mdx +19 -0
  209. package/dist/docs/src/content/get-started/index.mdx +50 -0
  210. package/dist/docs/src/content/news/2026-10-16-site-structure.md +15 -0
  211. package/dist/docs/src/content/news/2026-10-20-docs-site.md +13 -0
  212. package/dist/docs/src/content/release-phases/index.mdx +12 -0
  213. package/dist/docs/src/content/tools/ai-agents.mdx +49 -0
  214. package/dist/docs/src/content/tools/ant-design-vue-theme.mdx +138 -0
  215. package/dist/docs/src/content/tools/eslint.mdx +15 -0
  216. package/dist/docs/src/content/tools/index.mdx +7 -0
  217. package/dist/docs/src/content/tools/stylelint.mdx +19 -0
  218. package/dist/docs/src/content-vi/foundations/styles/border.mdx +89 -0
  219. package/dist/docs/src/content-vi/foundations/styles/color/accessibility.mdx +32 -0
  220. package/dist/docs/src/content-vi/foundations/styles/color/dark-mode.mdx +22 -0
  221. package/dist/docs/src/content-vi/foundations/styles/color/index.mdx +65 -0
  222. package/dist/docs/src/content-vi/foundations/styles/color/palette.mdx +57 -0
  223. package/dist/docs/src/content-vi/foundations/styles/color/tokens.mdx +55 -0
  224. package/dist/docs/src/content-vi/foundations/styles/color/usage.mdx +111 -0
  225. package/dist/docs/src/content-vi/foundations/styles/data-visualization.mdx +11 -0
  226. package/dist/docs/src/content-vi/foundations/styles/icons/accessibility.mdx +72 -0
  227. package/dist/docs/src/content-vi/foundations/styles/icons/code.mdx +170 -0
  228. package/dist/docs/src/content-vi/foundations/styles/icons/index.mdx +62 -0
  229. package/dist/docs/src/content-vi/foundations/styles/icons/library.mdx +19 -0
  230. package/dist/docs/src/content-vi/foundations/styles/icons/usage.mdx +100 -0
  231. package/dist/docs/src/content-vi/foundations/styles/illustration.mdx +9 -0
  232. package/dist/docs/src/content-vi/foundations/styles/interaction-states.mdx +49 -0
  233. package/dist/docs/src/content-vi/foundations/styles/layout/app-frame.mdx +77 -0
  234. package/dist/docs/src/content-vi/foundations/styles/layout/breakpoints.mdx +56 -0
  235. package/dist/docs/src/content-vi/foundations/styles/layout/grid.mdx +87 -0
  236. package/dist/docs/src/content-vi/foundations/styles/layout/index.mdx +24 -0
  237. package/dist/docs/src/content-vi/foundations/styles/layout/page-widths.mdx +34 -0
  238. package/dist/docs/src/content-vi/foundations/styles/logos/downloads-and-terms.mdx +65 -0
  239. package/dist/docs/src/content-vi/foundations/styles/logos/index.mdx +64 -0
  240. package/dist/docs/src/content-vi/foundations/styles/logos/placement-and-containers.mdx +96 -0
  241. package/dist/docs/src/content-vi/foundations/styles/logos/product-logos.mdx +56 -0
  242. package/dist/docs/src/content-vi/foundations/styles/logos/using-the-logo.mdx +70 -0
  243. package/dist/docs/src/content-vi/foundations/styles/opacity.mdx +9 -0
  244. package/dist/docs/src/content-vi/foundations/styles/radius.mdx +98 -0
  245. package/dist/docs/src/content-vi/foundations/styles/size-and-density.mdx +41 -0
  246. package/dist/docs/src/content-vi/foundations/styles/spacing.mdx +70 -0
  247. package/dist/docs/src/content-vi/foundations/styles/typography/code.mdx +53 -0
  248. package/dist/docs/src/content-vi/foundations/styles/typography/index.mdx +58 -0
  249. package/dist/docs/src/content-vi/foundations/styles/typography/usage.mdx +144 -0
  250. package/dist/docs/src/content-vi/foundations/styles/typography/vietnamese.mdx +46 -0
  251. package/dist/docs/src/content-vi/foundations/styles/z-index.mdx +9 -0
  252. package/dist/docs/src/content.config.ts +68 -0
  253. package/dist/docs/src/lib/brand.ts +57 -0
  254. package/dist/docs/src/lib/contrast.ts +34 -0
  255. package/dist/docs/src/lib/i18n.ts +152 -0
  256. package/dist/docs/src/lib/icons.ts +46 -0
  257. package/dist/docs/src/lib/logo-geometry.ts +30 -0
  258. package/dist/docs/src/lib/lucide-categories.json +1 -0
  259. package/dist/docs/src/lib/lucide-data.ts +40 -0
  260. package/dist/docs/src/lib/navigation.ts +222 -0
  261. package/dist/docs/src/lib/release-phases.ts +10 -0
  262. package/dist/docs/src/lib/routes.ts +40 -0
  263. package/dist/docs/src/lib/token-descriptions-vi.ts +40 -0
  264. package/dist/docs/src/lib/tokens.ts +67 -0
  265. package/dist/docs/src/lib/tri-grid.ts +28 -0
  266. package/dist/docs/src/styles/chrome.css +122 -0
  267. package/dist/docs/src/styles/color.css +270 -0
  268. package/dist/docs/src/styles/docs.css +323 -0
  269. package/dist/docs/src/styles/global.css +66 -0
  270. package/dist/docs/src/styles/icons.css +135 -0
  271. package/dist/docs/src/styles/layout.css +165 -0
  272. package/dist/docs/src/styles/logos.css +236 -0
  273. package/dist/docs/src/styles/shapes.css +139 -0
  274. package/dist/docs/src/styles/tokens.css +461 -0
  275. package/dist/docs/src/styles/tokens.js +425 -0
  276. package/dist/docs/src/styles/typography.css +91 -0
  277. package/dist/docs/tokens/border.json +26 -0
  278. package/dist/docs/tokens/breakpoints.json +8 -0
  279. package/dist/docs/tokens/color.json +1350 -0
  280. package/dist/docs/tokens/elevation.json +26 -0
  281. package/dist/docs/tokens/layout.json +29 -0
  282. package/dist/docs/tokens/motion.json +12 -0
  283. package/dist/docs/tokens/radius.json +44 -0
  284. package/dist/docs/tokens/size.json +13 -0
  285. package/dist/docs/tokens/spacing.json +18 -0
  286. package/dist/docs/tokens/states.json +12 -0
  287. package/dist/docs/tokens/typography.json +220 -0
  288. package/dist/index.d.ts +19 -0
  289. package/dist/index.js +1823 -0
  290. package/package.json +31 -4
@@ -0,0 +1,249 @@
1
+ ---
2
+ // Live typography examples for the Typography page, set in the site's own Inter and
3
+ // JetBrains Mono, so what you see is what the fonts do.
4
+ import '../styles/typography.css';
5
+ import { langOf } from '../lib/i18n';
6
+
7
+ interface Props {
8
+ kind: 'faces' | 'styles' | 'ui' | 'features' | 'numbers' | 'vietnamese' | 'leading';
9
+ }
10
+ const { kind } = Astro.props;
11
+ const vi = langOf(Astro.url.pathname) === 'vi';
12
+ const L = (en: string, viText: string) => (vi ? viText : en);
13
+
14
+ // Every text style, read from the tokens, with a sample in its role.
15
+ import { tokensByPrefix } from '../lib/tokens';
16
+ const groups: { name: string; styles: { id: string; sample: string; tnum?: boolean }[] }[] = [
17
+ { name: 'Display', styles: [
18
+ { id: 'display.large', sample: 'Sync everything' },
19
+ { id: 'display.medium', sample: 'Sync everything' },
20
+ { id: 'display.small', sample: 'Sync everything' },
21
+ ] },
22
+ { name: 'Heading', styles: [
23
+ { id: 'heading.xlarge', sample: 'Connect your first store' },
24
+ { id: 'heading.large', sample: 'Orders' },
25
+ { id: 'heading.medium', sample: 'Sync settings' },
26
+ { id: 'heading.small', sample: 'Online store → ERP' },
27
+ { id: 'heading.xsmall', sample: 'Inventory' },
28
+ ] },
29
+ { name: 'Body', styles: [
30
+ { id: 'body.large', sample: 'Orders from your online store are copied to the ERP every 5 minutes.' },
31
+ { id: 'body.default', sample: 'Last synced 2 minutes ago. 3 orders are waiting.' },
32
+ { id: 'body.small', sample: 'Updated by Linh · 24/10/2026 09:41' },
33
+ ] },
34
+ { name: 'Label', styles: [
35
+ { id: 'label.default', sample: 'Save changes' },
36
+ { id: 'label.small', sample: 'Synced' },
37
+ ] },
38
+ { name: 'Code', styles: [
39
+ { id: 'code.default', sample: 'order_id: SO-10421' },
40
+ ] },
41
+ ];
42
+ // What each style is for, in Vietnamese (the English text is the token's description).
43
+ const useVi: Record<string, string> = {
44
+ 'display.large': 'Hero của trang marketing. Dưới 768 px, dùng display.small.',
45
+ 'display.medium': 'Mở đầu một phần của trang marketing. Dưới 768 px, dùng display.small.',
46
+ 'display.small': 'Tiêu đề trang marketing. Dưới 768 px, dùng heading.xlarge.',
47
+ 'heading.xlarge': 'Tiêu đề lớn: màn hình trống, onboarding, các phần của tài liệu và landing page.',
48
+ 'heading.large': 'Tiêu đề trang, mỗi trang một tiêu đề.',
49
+ 'heading.medium': 'Tiêu đề phần và tiêu đề dialog.',
50
+ 'heading.small': 'Tiêu đề card, panel và drawer.',
51
+ 'heading.xsmall': 'Tiêu đề nhóm trong form, danh sách và menu; tiêu đề banner.',
52
+ 'body.large': 'Chữ để đọc: mô tả, hướng dẫn, tài liệu, email.',
53
+ 'body.default': 'Chữ giao diện mặc định: ô bảng, ô nhập, thông báo.',
54
+ 'body.small': 'Chữ phụ: helper text, metadata, mốc thời gian, tooltip.',
55
+ 'label.default': 'Nút, nhãn của form, tab, mục menu và mục điều hướng.',
56
+ 'label.small': 'Badge, tag, nút nhỏ, header của bảng.',
57
+ 'code.default': 'Khối code, ID, key, JSON. Cùng cỡ với body.default: JetBrains Mono và Inter có cùng x-height.',
58
+ };
59
+ const fontTokens = new Map(tokensByPrefix('font').map((t) => [t.name, t]));
60
+ const info = (id: string) => {
61
+ const t = fontTokens.get(`font.${id}`)!;
62
+ const [weight, rest] = t.resolved.split(' ');
63
+ const [size, lh] = rest.split('/');
64
+ const px = (v: string) => Math.round(parseFloat(v) * 16);
65
+ return { cssVar: t.cssVar, weight, size: px(size), lh: px(lh), use: vi && useVi[id] ? useVi[id] : t.description.replace(/^\d+\/\d+\. /, '') };
66
+ };
67
+ const features = [
68
+ { tag: 'cv05', what: L('Lowercase l with a tail', 'Chữ l thường có đuôi'), sample: 'Il1 · lI1' },
69
+ { tag: 'cv08', what: L('Uppercase I with serifs', 'Chữ I hoa có chân'), sample: 'Il1 · lI1' },
70
+ { tag: 'zero', what: L('Slashed zero', 'Số 0 có gạch chéo'), sample: 'O0 · 0O' },
71
+ ];
72
+ ---
73
+
74
+ {kind === 'faces' && (
75
+ <div class="type-faces">
76
+ <figure class="type-face">
77
+ <p class="type-face-sample">Aa</p>
78
+ <figcaption>
79
+ <b>Inter</b>
80
+ <span>{L('Interface and reading text. Weights 400, 500, 600; 700 for display.', 'Chữ giao diện và chữ để đọc. Độ đậm 400, 500, 600; 700 cho display.')}</span>
81
+ <span class="type-face-line">{L('Đồng bộ đơn hàng · Sync orders 0123456789', 'Đồng bộ đơn hàng · Ổn định 0123456789')}</span>
82
+ </figcaption>
83
+ </figure>
84
+ <figure class="type-face is-mono">
85
+ <p class="type-face-sample">Aa</p>
86
+ <figcaption>
87
+ <b>JetBrains Mono</b>
88
+ <span>{L('Code, IDs, API keys and token names. Weight 400.', 'Code, ID, API key và tên token. Độ đậm 400.')}</span>
89
+ <span class="type-face-line">order_id: SO-10421 · 0O Il1</span>
90
+ </figcaption>
91
+ </figure>
92
+ </div>
93
+ )}
94
+
95
+ {kind === 'styles' && (
96
+ <div class="type-styles" lang="en">
97
+ {groups.map((g) => (
98
+ <section class="type-group">
99
+ <p class="type-group-name">{g.name}</p>
100
+ {g.styles.map((st) => {
101
+ const i = info(st.id);
102
+ return (
103
+ <div class="type-row">
104
+ <div class="type-meta">
105
+ <code>font.{st.id}</code>
106
+ <span class="type-num">{i.size}/{i.lh} · {i.weight}</span>
107
+ </div>
108
+ <div class="type-specimen" style={`font:var(${i.cssVar});${st.tnum ? 'font-variant-numeric:tabular-nums;' : ''}`}>{st.sample}</div>
109
+ <p class="type-use">{i.use}</p>
110
+ </div>
111
+ );
112
+ })}
113
+ </section>
114
+ ))}
115
+ </div>
116
+ )}
117
+
118
+ {kind === 'ui' && (
119
+ <figure class="type-ui">
120
+ <div class="type-ui-scroll">
121
+ <div class="type-ui-screen">
122
+ <div class="ui-page-head">
123
+ <span class="ui-crumb" data-n="1" style="font:var(--bh-font-body-small)">{L('Integrations / Online store', 'Tích hợp / Cửa hàng online')}</span>
124
+ <span class="ui-title" data-n="2" style="font:var(--bh-font-heading-large)">{L('Orders', 'Đơn hàng')}</span>
125
+ </div>
126
+ <div class="ui-metrics">
127
+ <div class="ui-card">
128
+ <span data-n="3" style="font:var(--bh-font-body-small)">{L('Synced today', 'Đồng bộ hôm nay')}</span>
129
+ <span data-n="4" style="font:var(--bh-font-heading-large);font-variant-numeric:tabular-nums">{L('1,204', '1.204')}</span>
130
+ </div>
131
+ <div class="ui-card">
132
+ <span style="font:var(--bh-font-body-small)">{L('Failed', 'Lỗi')}</span>
133
+ <span style="font:var(--bh-font-heading-large);font-variant-numeric:tabular-nums">3</span>
134
+ </div>
135
+ </div>
136
+ <div class="ui-card ui-panel">
137
+ <div class="ui-panel-head">
138
+ <span data-n="5" style="font:var(--bh-font-heading-small)">{L('Recent orders', 'Đơn hàng gần đây')}</span>
139
+ <span class="ui-btn" data-n="6" style="font:var(--bh-font-label-default)">{L('Retry failed', 'Thử lại đơn lỗi')}</span>
140
+ </div>
141
+ <p class="ui-desc" data-n="7" style="font:var(--bh-font-body-default)">{L('Orders copied from the online store to the ERP in the last 24 hours.', 'Đơn hàng được chép từ cửa hàng online sang ERP trong 24 giờ qua.')}</p>
142
+ <table class="ui-table" data-no-stack>
143
+ <thead><tr><th data-n="8" style="font:var(--bh-font-label-small)">{L('Order', 'Đơn hàng')}</th><th style="font:var(--bh-font-label-small)">{L('Status', 'Trạng thái')}</th><th style="font:var(--bh-font-label-small);text-align:right">{L('Total', 'Tổng tiền')}</th></tr></thead>
144
+ <tbody>
145
+ <tr><td data-n="9" style="font:var(--bh-font-code-default)">SO-10421</td><td><span class="ui-badge" data-n="10" style="font:var(--bh-font-label-small)">{L('Synced', 'Đã đồng bộ')}</span></td><td style="font:var(--bh-font-body-default);font-variant-numeric:tabular-nums;text-align:right"><span data-n="11">{L('1,250,000 ₫', '1.250.000 ₫')}</span></td></tr>
146
+ <tr><td style="font:var(--bh-font-code-default)">SO-10420</td><td><span class="ui-badge is-error" style="font:var(--bh-font-label-small)">{L('Failed', 'Lỗi')}</span></td><td style="font:var(--bh-font-body-default);font-variant-numeric:tabular-nums;text-align:right">{L('480,000 ₫', '480.000 ₫')}</td></tr>
147
+ </tbody>
148
+ </table>
149
+ <span class="ui-meta" data-n="12" style="font:var(--bh-font-body-small)">{L('Updated 2 minutes ago', 'Cập nhật 2 phút trước')}</span>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ <ol class="type-ui-legend">
154
+ <li><b>Breadcrumb</b> <code>body.small</code></li>
155
+ <li><b>{L('Page title', 'Tiêu đề trang')}</b> <code>heading.large</code></li>
156
+ <li><b>{L('Card label', 'Nhãn trong card')}</b> <code>body.small</code></li>
157
+ <li><b>{L('Number in a card', 'Số trong card')}</b> <code>heading.large</code> + {L('tabular figures', 'số đều cột')}</li>
158
+ <li><b>{L('Card title', 'Tiêu đề card')}</b> <code>heading.small</code></li>
159
+ <li><b>{L('Button', 'Nút')}</b> <code>label.default</code></li>
160
+ <li><b>{L('Description', 'Mô tả')}</b> <code>body.default</code></li>
161
+ <li><b>{L('Table header', 'Header của bảng')}</b> <code>label.small</code></li>
162
+ <li><b>{L('Order ID', 'Mã đơn hàng')}</b> <code>code.default</code></li>
163
+ <li><b>{L('Badge', 'Badge')}</b> <code>label.small</code></li>
164
+ <li><b>{L('Table cell, amount', 'Ô bảng, số tiền')}</b> <code>body.default</code> + {L('tabular figures', 'số đều cột')}</li>
165
+ <li><b>{L('Timestamp', 'Mốc thời gian')}</b> <code>body.small</code></li>
166
+ </ol>
167
+ </figure>
168
+ )}
169
+
170
+ {kind === 'features' && (
171
+ <div class="table-wrap">
172
+ <table class="type-features">
173
+ <thead><tr><th scope="col">{L('Feature', 'Tính năng')}</th><th scope="col">{L('What it does', 'Tác dụng')}</th><th scope="col">{L('Off', 'Tắt')}</th><th scope="col">{L('On', 'Bật')}</th></tr></thead>
174
+ <tbody>
175
+ {features.map((f) => (
176
+ <tr>
177
+ <td><code>{f.tag}</code></td>
178
+ <td>{f.what}</td>
179
+ <td><span class="type-glyphs" style="--bh-font-features:normal">{f.sample}</span></td>
180
+ <td><span class="type-glyphs" style={`--bh-font-features:'${f.tag}'`}>{f.sample}</span></td>
181
+ </tr>
182
+ ))}
183
+ <tr>
184
+ <td><code>cv05 cv08 zero</code></td>
185
+ <td>{L('All three, for codes people read and type', 'Cả ba, cho mã mà người dùng đọc và gõ')}</td>
186
+ <td><span class="type-glyphs" style="--bh-font-features:normal">SKU-I01l0O</span></td>
187
+ <td><span class="type-glyphs" style="--bh-font-features:'cv05','cv08','zero'">SKU-I01l0O</span></td>
188
+ </tr>
189
+ </tbody>
190
+ </table>
191
+ </div>
192
+ )}
193
+
194
+ {kind === 'numbers' && (
195
+ <div class="type-numbers">
196
+ <figure>
197
+ <figcaption>{L('Proportional (default)', 'Số tỉ lệ (mặc định)')}</figcaption>
198
+ <p set:html={L('1,111.11<br />9,840.00<br />704.18', '1.111,11<br />9.840,00<br />704,18')} />
199
+ </figure>
200
+ <figure>
201
+ <figcaption><code>tabular-nums</code></figcaption>
202
+ <p class="is-tabular" set:html={L('1,111.11<br />9,840.00<br />704.18', '1.111,11<br />9.840,00<br />704,18')} />
203
+ </figure>
204
+ </div>
205
+ )}
206
+
207
+ {kind === 'vietnamese' && (
208
+ <div class="type-vi">
209
+ <div class="type-vi-head" aria-hidden="true"><span>{L('Style', 'Text style')}</span><span>{L('English line height', 'Line height tiếng Anh')}</span><span>{L('Vietnamese line height', 'Line height tiếng Việt')}</span></div>
210
+ {groups.flatMap((g) => g.styles).map((st) => {
211
+ const i = info(st.id);
212
+ const t = fontTokens.get(`font.${st.id}`)!;
213
+ const viLh = t.viResolved ? Math.round(parseFloat(t.viResolved.split('/')[1]) * 16) : i.lh;
214
+ const sample = st.id.startsWith('display') ? 'Ẫm · Ổn' : 'Ổn định · Ấn Độ · Ẫm · Ở đây';
215
+ return (
216
+ <div class="type-vi-row">
217
+ <div class="type-meta">
218
+ <code>font.{st.id}</code>
219
+ <span class="type-num">{i.size}/{i.lh} → {i.size}/{viLh}</span>
220
+ </div>
221
+ <span class="type-vi-box" lang="vi" style={`font:${t.resolved}`}>{sample}</span>
222
+ <span class="type-vi-box" lang="vi" style={`font:var(${i.cssVar})`}>{sample}</span>
223
+ </div>
224
+ );
225
+ })}
226
+ </div>
227
+ )}
228
+
229
+ {kind === 'leading' && (() => {
230
+ const body = fontTokens.get('font.body.default')!;
231
+ const viLh = body.viResolved ? Math.round(parseFloat(body.viResolved.split('/')[1]) * 16) : 24;
232
+ const en = ['Orders sync every 5 minutes.', 'Index, Item and Order lists.', 'Online store to the ERP.'];
233
+ const viText = ['Ổn định đơn hàng mỗi 5 phút.', 'Ấn Độ, Ẫm và Ở đây có ưu đãi.', 'Ổn định, Ấn Độ, Ẫm.'];
234
+ const cols = [
235
+ { lang: 'en', text: en, lh: 20, title: L('English, 14/20', 'Tiếng Anh, 14/20'), note: L('Fits.', 'Vừa.'), bad: false },
236
+ { lang: 'vi', text: viText, lh: 20, title: L('Vietnamese at the English line height, 14/20', 'Tiếng Việt với line height tiếng Anh, 14/20'), note: L('Marks on capitals touch the line above.', 'Dấu trên chữ hoa chạm vào dòng trên.'), bad: true },
237
+ { lang: 'vi', text: viText, lh: viLh, title: L(`Vietnamese, 14/${viLh}`, `Tiếng Việt, 14/${viLh}`), note: L('Every mark stays in its own line.', 'Mọi dấu nằm gọn trong dòng của nó.'), bad: false },
238
+ ];
239
+ return (
240
+ <div class="type-leading">
241
+ {cols.map((c) => (
242
+ <figure class={c.bad ? 'is-bad' : ''}>
243
+ <p class="type-leading-text" lang={c.lang} style={`font-family:var(--bh-font-family-sans);font-size:14px;font-weight:400;line-height:${c.lh}px;--lh:${c.lh}px`}>{c.text.map((line, i) => <>{i > 0 && <br />}{line}</>)}</p>
244
+ <figcaption><b>{c.title}</b><span>{c.note}</span></figcaption>
245
+ </figure>
246
+ ))}
247
+ </div>
248
+ );
249
+ })()}
@@ -0,0 +1,28 @@
1
+ ---
2
+ // A logo figure. The site shows a PNG drawn at 3× and displayed at 1×: shrinking a larger
3
+ // picture softens the 30° edges, so they don't show stair steps on 100% screens the way an
4
+ // SVG does. The PNGs are made from the same SVG by scripts/build-logo-figures.mjs, which
5
+ // builds the site with LOGO_SVG=1 (this component then draws the SVG and tags it with its id)
6
+ // and photographs every tagged figure at 3×.
7
+ interface Props {
8
+ id: string; // file name in /brand/logos/fig/, without .png
9
+ w: number; // size in CSS px, whole numbers
10
+ h: number;
11
+ viewBox: string;
12
+ class?: unknown;
13
+ style?: string;
14
+ label?: string; // accessible name; empty = decorative
15
+ }
16
+
17
+ const { id, w, h, viewBox, class: cls, style = '', label = '' } = Astro.props;
18
+ const capture = process.env.LOGO_SVG === '1';
19
+ const box = { width: w, height: h, style: `--w:${w}px;--h:${h}px;${style}` };
20
+ ---
21
+
22
+ {capture ? (
23
+ <svg data-fig={id} class:list={[cls]} xmlns="http://www.w3.org/2000/svg" viewBox={viewBox} {...box} aria-hidden="true">
24
+ <slot />
25
+ </svg>
26
+ ) : (
27
+ <img class:list={['fig', cls]} src={`/brand/logos/fig/${id}.png`} {...box} alt={label} decoding="async" />
28
+ )}
@@ -0,0 +1,101 @@
1
+ ---
2
+ // Anatomy of the lockup on its triangle grid. The grid is the icon's construction grid (28 bands
3
+ // across the icon), continued over the whole lockup and its clear space, so every measure reads
4
+ // in grid units. Every 7th line is darker: one hexagon side is two of those triangles.
5
+ import { BAND, COLORS, ICON_H, ICON_PATH, ICON_SCALE, ICON_TOP, ICON_W, WORDMARKS, X_HEIGHT } from '../../lib/logo-geometry';
6
+ import { triGrid } from '../../lib/tri-grid';
7
+ import Fig from './Fig.astro';
8
+ import { langOf } from '../../lib/i18n';
9
+ import '../../styles/logos.css';
10
+
11
+ const lang = langOf(Astro.url.pathname);
12
+ const L = {
13
+ en: {
14
+ alt: 'The beehexa lockup on a triangle grid. One side of the hexagon equals the x-height of the wordmark (x). The icon is 2x tall; the gap between icon and wordmark is 10 grid bands; the clear space is x on every side.',
15
+ legend: [
16
+ ['Icon', '2x tall. One hexagon side is the x-height of the wordmark, so icon and text share one unit.'],
17
+ ['Gap', '10 grid bands: half of the white top face, which is 20 bands wide. The two lengths marked 10 are equal.'],
18
+ ['Wordmark', '“beehexa” in Inter Display 500, lowercase, outlined.'],
19
+ ],
20
+ },
21
+ vi: {
22
+ alt: 'Lockup beehexa trên lưới tam giác. Một cạnh lục giác bằng x-height của wordmark (x). Icon cao 2x; khoảng cách giữa icon và wordmark là 10 dải lưới; vùng trống là x ở mọi phía.',
23
+ legend: [
24
+ ['Icon', 'Cao 2x. Một cạnh lục giác bằng x-height của wordmark, nên icon và chữ dùng chung một đơn vị.'],
25
+ ['Khoảng cách', '10 dải lưới: bằng nửa mặt trắng trên cùng, vốn rộng 20 dải. Hai đoạn ghi 10 dài bằng nhau.'],
26
+ ['Wordmark', 'Chữ “beehexa” bằng Inter Display 500, viết thường, đã chuyển thành nét vẽ.'],
27
+ ],
28
+ },
29
+ }[lang];
30
+
31
+ const iconPx = 112; // x = 56 px
32
+ const s = iconPx / ICON_H;
33
+ const X = X_HEIGHT;
34
+ const px = (n: number) => n / s; // screen px to drawing units
35
+ const fs = px(12);
36
+ const sw = px(1);
37
+ const tick = px(4);
38
+ const inkStart = ICON_W + 10 * BAND; // the wordmark's first stroke, 10 bands after the icon
39
+ const iconBottom = ICON_TOP + ICON_H;
40
+ // One hexagon edge, upper left: from the left vertex to the top vertex.
41
+ const edge = { x1: 0, y1: ICON_TOP + 75 * ICON_SCALE, x2: 129.9 * ICON_SCALE, y2: ICON_TOP };
42
+
43
+ const dimH = (x1: number, x2: number, y: number) => `M${x1} ${y - tick}V${y + tick}M${x1} ${y}H${x2}M${x2} ${y - tick}V${y + tick}`;
44
+ const dimV = (y1: number, y2: number, x: number) => `M${x - tick} ${y1}H${x + tick}M${x} ${y1}V${y2}M${x - tick} ${y2}H${x + tick}`;
45
+
46
+ // The figure fills its panel edge to edge (FIG_W is wider than the content column; the panel
47
+ // crops it), with the lockup centred on whole pixels and the grid running under everything.
48
+ const FIG_W = 1040;
49
+ const FIG_H = 288;
50
+ // The white top face: 20 bands wide, from (37.1, 85.7) to (222.7, 85.7) in icon units.
51
+ const faceY = ICON_TOP + 85.7 * ICON_SCALE;
52
+ const faceMid = 129.9 * ICON_SCALE;
53
+ const faceRight = 222.7 * ICON_SCALE;
54
+
55
+ const diagrams = [WORDMARKS.beehexa].map((word) => {
56
+ const left = Math.round((FIG_W - word.width * s) / 2);
57
+ const top = Math.round((FIG_H - iconPx) / 2);
58
+ const box = { x1: -left / s, y1: ICON_TOP - top / s, x2: (FIG_W - left) / s, y2: ICON_TOP + (FIG_H - top) / s };
59
+ // Fine grid: 1 band. Major grid: 7 bands, so one hexagon side (x) is two major triangle sides.
60
+ return { word, box, grid: triGrid(0, ICON_TOP, BAND, box), major: triGrid(0, ICON_TOP, 7 * BAND, box), viewBox: `${box.x1} ${box.y1} ${FIG_W / s} ${FIG_H / s}` };
61
+ });
62
+ ---
63
+
64
+ <figure class="logo-figure">
65
+ <div class="logo-stage bg-white anatomy-stage bleed-stage">
66
+ {diagrams.map((d) => (
67
+ <Fig id={`anatomy-${lang}`} class={['diagram px-center bleed']} viewBox={d.viewBox} w={FIG_W} h={FIG_H} label={L.alt}>
68
+ <path class="d-grid" d={d.grid} stroke-width={sw} style="opacity:.06" />
69
+ <path class="d-grid" d={d.major} stroke-width={sw} style="opacity:.18" />
70
+ <path fill={COLORS.yellow} fill-rule="evenodd" transform={`translate(0 ${ICON_TOP}) scale(${ICON_SCALE})`} d={ICON_PATH} />
71
+ <path fill={COLORS.graphite} transform={`translate(${d.word.x} 0)`} d={d.word.d} />
72
+
73
+ {/* x on the icon: one hexagon side */}
74
+ <line class="d-measure" x1={edge.x1} y1={edge.y1} x2={edge.x2} y2={edge.y2} stroke-width={px(2)} stroke-linecap="round" />
75
+ <text class="d-label" x={edge.x2 * 0.42 - px(6)} y={(edge.y1 + edge.y2) / 2 - px(6)} font-size={fs} text-anchor="end" stroke-width={px(4)}>x</text>
76
+
77
+ {/* x on the wordmark: baseline and x-height */}
78
+ <g class="d-guide" stroke-width={sw} stroke-dasharray={`${px(3)} ${px(3)}`}>
79
+ <line x1={inkStart} x2={d.word.width + px(28)} y1="0" y2="0" />
80
+ <line x1={inkStart} x2={d.word.width + px(28)} y1={-X} y2={-X} />
81
+ </g>
82
+ <path class="d-measure" d={dimV(-X, 0, d.word.width + px(20))} stroke-width={sw} />
83
+ <text class="d-label" x={d.word.width + px(28)} y={-X / 2 + fs * 0.35} font-size={fs} stroke-width={px(4)}>x</text>
84
+
85
+ {/* icon height */}
86
+ <path class="d-measure" d={dimV(ICON_TOP, iconBottom, -px(20))} stroke-width={sw} />
87
+ <text class="d-label" x={-px(28)} y={ICON_TOP + ICON_H / 2 + fs * 0.35} font-size={fs} text-anchor="end" stroke-width={px(4)}>2x</text>
88
+
89
+ {/* the gap is half the white top face: two equal lengths on one line */}
90
+ <path class="d-measure" d={dimH(faceMid, faceRight, faceY)} stroke-width={sw} />
91
+ <text class="d-label" x={(faceMid + faceRight) / 2} y={faceY - px(8)} font-size={fs} text-anchor="middle" stroke-width={px(4)}>10</text>
92
+ <path class="d-measure" d={dimH(ICON_W, inkStart, faceY)} stroke-width={sw} />
93
+ <text class="d-label" x={(ICON_W + inkStart) / 2} y={faceY - px(8)} font-size={fs} text-anchor="middle" stroke-width={px(4)}>10</text>
94
+ </Fig>
95
+ ))}
96
+ </div>
97
+ </figure>
98
+
99
+ <ul class="diagram-legend">
100
+ {L.legend.map(([title, text]) => <li><b>{title}</b>{text}</li>)}
101
+ </ul>
@@ -0,0 +1,81 @@
1
+ ---
2
+ // Clear space: x on every side, where x is the x-height of the wordmark, which is also one side of
3
+ // the hexagon. Drawn the way GitLab shows its own: a grid of quarter-x cells on which every edge of
4
+ // the logo and of the margin is a line; the margin is tinted; the wordmark's own "x", set in the
5
+ // corner, is the unit.
6
+ import { COLORS, ICON_H, ICON_PATH, ICON_SCALE, ICON_TOP, WORDMARKS, X_HEIGHT } from '../../lib/logo-geometry';
7
+ import { langOf } from '../../lib/i18n';
8
+ import Fig from './Fig.astro';
9
+ import '../../styles/logos.css';
10
+
11
+ const lang = langOf(Astro.url.pathname);
12
+ const L = {
13
+ en: {
14
+ alt: 'Clear space. x is the x-height of the wordmark, the height of its letter x. An empty margin of x surrounds the lockup on all four sides.',
15
+ caption: 'Clear space x = the x-height of the wordmark: the height of its “x”, the same as the lowercase “e” without its round overshoot. It is also one side of the hexagon and half the icon height.',
16
+ },
17
+ vi: {
18
+ alt: 'Vùng trống. x là x-height của wordmark, tức chiều cao chữ x trong wordmark. Lề trống rộng x bao quanh lockup ở cả bốn phía.',
19
+ caption: 'Vùng trống x = x-height của wordmark: chiều cao chữ “x”, cũng là chiều cao chữ “e” khi bỏ phần nét cong nhô ra. x còn bằng một cạnh lục giác và nửa chiều cao icon.',
20
+ },
21
+ }[lang];
22
+
23
+ const FIG_W = 1040;
24
+ const FIG_H = 272;
25
+ const iconPx = 80; // x = 40 px, one grid cell = 10 px
26
+ const s = iconPx / ICON_H;
27
+ const X = X_HEIGHT;
28
+ const cell = X / 4; // a quarter x: 10 px
29
+ const px = (n: number) => n / s;
30
+ // The wordmark's own "x": flat on the baseline and flat on top, so it is exactly x-height tall.
31
+ // Its subpath index in the wordmark (b, e, e, h, e, x, a) and its left and right edges.
32
+ // (Archived 550 option: x1 5686, x2 6713.)
33
+ const X_GLYPH = { x1: 5637, x2: 6648 } as const;
34
+
35
+ // Grid lines between two edges: the span is cut into equal cells as close as possible to a
36
+ // quarter x, so both edges fall exactly on a line.
37
+ const split = (a: number, b: number) => { const n = Math.max(1, Math.round((b - a) / cell)); return Array.from({ length: n + 1 }, (_, i) => a + ((b - a) * i) / n); };
38
+ // Lines outside the clear space: whole quarter-x cells, counted outwards from its edge.
39
+ const outward = (edge: number, limit: number, dir: 1 | -1) => { const out: number[] = []; for (let v = edge + dir * cell; dir > 0 ? v <= limit : v >= limit; v += dir * cell) out.push(v); return out; };
40
+
41
+ const diagrams = [WORDMARKS.beehexa].map((word) => {
42
+ const left = Math.round((FIG_W - word.width * s) / 2);
43
+ const top = Math.round((FIG_H - iconPx) / 2);
44
+ const box = { x1: -left / s, y1: ICON_TOP - top / s, x2: (FIG_W - left) / s, y2: ICON_TOP + (FIG_H - top) / s };
45
+ const ink = { x1: 0, y1: ICON_TOP, x2: word.width, y2: ICON_TOP + ICON_H };
46
+ const zone = { x1: -X, y1: ICON_TOP - X, x2: word.width + X, y2: ICON_TOP + ICON_H + X };
47
+
48
+ // Every edge of the logo and of the clear space is a grid line.
49
+ const xs = [...outward(zone.x1, box.x1, -1), ...split(zone.x1, ink.x1), ...split(ink.x1, ink.x2), ...split(ink.x2, zone.x2), ...outward(zone.x2, box.x2, 1)];
50
+ const ys = [...outward(zone.y1, box.y1, -1), ...split(zone.y1, ink.y1), ...split(ink.y1, ink.y2), ...split(ink.y2, zone.y2), ...outward(zone.y2, box.y2, 1)];
51
+ const grid = [...new Set(xs)].map((x) => `M${x} ${box.y1}V${box.y2}`).concat([...new Set(ys)].map((y) => `M${box.x1} ${y}H${box.x2}`)).join('');
52
+ // Guides along the edges of the logo and of the clear space, across the whole figure.
53
+ const guides = [
54
+ ...[zone.x1, ink.x1, ink.x2, zone.x2].map((x) => `M${x} ${box.y1}V${box.y2}`),
55
+ ...[zone.y1, ink.y1, ink.y2, zone.y2].map((y) => `M${box.x1} ${y}H${box.x2}`),
56
+ ].join('');
57
+ // The unit: the wordmark's "x" in the bottom right corner of the clear space, standing on its
58
+ // bottom edge, so it fills the margin from edge to edge and is centred in its x-by-x corner.
59
+ const g = X_GLYPH;
60
+ const gX = zone.x2 - X / 2 - (g.x1 + g.x2) / 2;
61
+ return { word, ink, zone, grid, guides, viewBox: `${box.x1} ${box.y1} ${FIG_W / s} ${FIG_H / s}`, glyph: word.d.split(/ (?=M)/)[5], gX, labelX: zone.x2 - X };
62
+ });
63
+ ---
64
+
65
+ <figure class="logo-figure">
66
+ <div class="logo-stage bg-white clear-stage bleed-stage">
67
+ {diagrams.map((d) => (
68
+ <Fig id="clearspace" class={['diagram px-center bleed']} viewBox={d.viewBox} w={FIG_W} h={FIG_H} label={L.alt}>
69
+ <path fill-rule="evenodd" fill="#2b2a28" fill-opacity=".06" d={`M${d.zone.x1} ${d.zone.y1}H${d.zone.x2}V${d.zone.y2}H${d.zone.x1}Z M${d.ink.x1} ${d.ink.y1}V${d.ink.y2}H${d.ink.x2}V${d.ink.y1}Z`} />
70
+ {/* lines centred on the edges; 2/3 px is two whole device pixels in the 3× picture */}
71
+ <path class="d-grid" d={d.grid} stroke-width={px(2 / 3)} style="opacity:.1" />
72
+ <path class="d-grid" d={d.guides} stroke-width={px(2 / 3)} style="opacity:.32" />
73
+ <path fill="#d5d4d3" transform={`translate(${d.gX} ${d.zone.y2})`} d={d.glyph} />
74
+ <text class="d-label" x={d.labelX - px(6)} y={d.zone.y2 - X / 2 + px(4)} font-size={px(12)} text-anchor="end">x =</text>
75
+ <path fill={COLORS.yellow} fill-rule="evenodd" transform={`translate(0 ${ICON_TOP}) scale(${ICON_SCALE})`} d={ICON_PATH} />
76
+ <path fill={COLORS.graphite} transform={`translate(${d.word.x} 0)`} d={d.word.d} />
77
+ </Fig>
78
+ ))}
79
+ </div>
80
+ <figcaption>{L.caption}</figcaption>
81
+ </figure>
@@ -0,0 +1,45 @@
1
+ ---
2
+ // The four colour versions, made from three colours: yellow, graphite and white. Each version is
3
+ // shown once, on a background of the same three colours.
4
+ import LogoSvg from './LogoSvg.astro';
5
+ import { langOf } from '../../lib/i18n';
6
+ import type { Version } from '../../lib/logo-geometry';
7
+ import '../../styles/logos.css';
8
+
9
+ const lang = langOf(Astro.url.pathname);
10
+ const Y = '#FCB017', G = '#2B2A28', W = '#FFFFFF';
11
+ type Card = { v: Version; bg: string; title: string; text: string; codes: string[] };
12
+ const cards: Card[] = lang === 'vi'
13
+ ? [
14
+ { v: 'light', bg: W, title: '1. Màu', text: 'Bản chính, cho nền sáng. Icon vàng, chữ xám ghi.', codes: [Y, G] },
15
+ { v: 'dark', bg: G, title: '2. Màu trên nền tối', text: 'Cho nền tối. Icon vàng, chữ trắng.', codes: [Y, W] },
16
+ { v: 'white', bg: G, title: '3. Trắng', text: 'Cho ảnh và nền màu đậm, nơi màu vàng bị chìm hoặc chọi màu.', codes: [W] },
17
+ { v: 'graphite', bg: Y, title: '4. Xám ghi', text: 'Cho nền vàng và khi chỉ in được một màu: in một màu, khắc, đóng dấu.', codes: [G] },
18
+ ]
19
+ : [
20
+ { v: 'light', bg: W, title: '1. Colour', text: 'The main version, for light backgrounds. Yellow icon, graphite text.', codes: [Y, G] },
21
+ { v: 'dark', bg: G, title: '2. Colour on dark', text: 'For dark backgrounds. Yellow icon, white text.', codes: [Y, W] },
22
+ { v: 'white', bg: G, title: '3. White', text: 'For photos and strong colours, where the yellow would sink or clash.', codes: [W] },
23
+ { v: 'graphite', bg: Y, title: '4. Graphite', text: 'For yellow backgrounds and one-colour work: one-colour print, engraving, stamps.', codes: [G] },
24
+ ];
25
+ const names: Record<string, string> = lang === 'vi'
26
+ ? { [Y]: 'Vàng', [G]: 'Xám ghi', [W]: 'Trắng' }
27
+ : { [Y]: 'Yellow', [G]: 'Graphite', [W]: 'White' };
28
+ ---
29
+
30
+ <div class="logo-cards versions">
31
+ {cards.map((c) => (
32
+ <div class="logo-card">
33
+ <div class="logo-stage version-stage" style={`background:${c.bg}`}>
34
+ <LogoSvg version={c.v} iconPx={32} class="px-center" label="" />
35
+ </div>
36
+ <div class="logo-card-body">
37
+ <p class="card-title">{c.title}</p>
38
+ <p>{c.text}</p>
39
+ <p class="card-codes">
40
+ {c.codes.map((hex) => <span><i style={`background:${hex}`} />{names[hex]} <code>{hex}</code></span>)}
41
+ </p>
42
+ </div>
43
+ </div>
44
+ ))}
45
+ </div>
@@ -0,0 +1,84 @@
1
+ ---
2
+ // The icon on its construction grid: an equilateral triangle grid, 28 bands across the icon.
3
+ // Drawn in the icon's own units (259.8 × 300).
4
+ import { COLORS, ICON_PATH } from '../../lib/logo-geometry';
5
+ import Fig from './Fig.astro';
6
+ import { langOf } from '../../lib/i18n';
7
+ import '../../styles/logos.css';
8
+
9
+ const lang = langOf(Astro.url.pathname);
10
+ const L = {
11
+ en: {
12
+ alt: 'The icon drawn on a triangle grid of 28 bands. Strokes and white gaps are each 3 bands; the top face is 20 bands wide.',
13
+ n28: '28 bands', n20: '20 bands', n3: '3 bands',
14
+ legend: [
15
+ ['Grid', 'Equilateral triangles. 1 band = icon width ÷ 28; 1 triangle side = 1.155 bands.'],
16
+ ['Hexagon', 'Regular, pointy top. Height = 28 triangle sides; every edge is at 30° or vertical.'],
17
+ ['Stroke and gap', 'Both 3 bands (1 : 1), so the layers stay apart at 16 px.'],
18
+ ['Top face', '20 bands wide, 71% of the icon. White areas are 40% of the icon.'],
19
+ ],
20
+ },
21
+ vi: {
22
+ alt: 'Icon dựng trên lưới tam giác 28 dải. Nét vàng và khe trắng đều 3 dải; mặt trên rộng 20 dải.',
23
+ n28: '28 dải', n20: '20 dải', n3: '3 dải',
24
+ legend: [
25
+ ['Lưới', 'Tam giác đều. 1 dải = bề rộng icon ÷ 28; 1 cạnh tam giác = 1.155 dải.'],
26
+ ['Lục giác', 'Lục giác đều, đỉnh nhọn. Cao = 28 cạnh tam giác; mọi cạnh nghiêng 30° hoặc thẳng đứng.'],
27
+ ['Nét và khe', 'Cùng 3 dải (1 : 1), nên ba lớp vẫn tách nhau ở 16 px.'],
28
+ ['Mặt trên', 'Rộng 20 dải, bằng 71% icon. Phần trắng chiếm 40% icon.'],
29
+ ],
30
+ },
31
+ }[lang];
32
+
33
+ const W = 259.8;
34
+ const H = 300;
35
+ const h = W / 28; // one band
36
+ const a = h / Math.cos(Math.PI / 6); // one triangle side
37
+ const t = Math.tan(Math.PI / 6);
38
+ const px = 300; // icon height on screen
39
+ const s = px / H;
40
+ const m = 44 / s; // margin for labels
41
+ const fs = 12 / s;
42
+ const sw = 1 / s;
43
+
44
+ // Grid lines, cut to the icon's box here rather than with a clip path.
45
+ const lines: string[] = [];
46
+ for (let k = 0; k <= 28; k++) lines.push(`M${k * h} 0V${H}`);
47
+ const cut = (slope: number, c: number) => {
48
+ // y = slope * x + c, inside 0 ≤ x ≤ W and 0 ≤ y ≤ H
49
+ const xs = [0, W, (0 - c) / slope, (H - c) / slope].filter((x) => x >= -1e-6 && x <= W + 1e-6);
50
+ const pts = xs.map((x) => [x, slope * x + c]).filter(([, y]) => y >= -1e-6 && y <= H + 1e-6).sort((p, q) => p[0] - q[0]);
51
+ if (pts.length < 2) return;
52
+ const [p1, p2] = [pts[0], pts[pts.length - 1]];
53
+ if (Math.hypot(p2[0] - p1[0], p2[1] - p1[1]) > 0.5) lines.push(`M${p1[0]} ${p1[1]}L${p2[0]} ${p2[1]}`);
54
+ };
55
+ for (let n = -14; n <= 28; n++) cut(t, n * a);
56
+ for (let n = 0; n <= 42; n++) cut(-t, n * a);
57
+
58
+ const w = Math.round((W + 2 * m) * s);
59
+ const hh = Math.round((H + 2 * m) * s);
60
+ // Measures: the top face is 20 bands wide; the outline stroke is 3 bands.
61
+ const face = { x1: 37.1, x2: 222.7, y: 85.7 };
62
+ ---
63
+
64
+ <figure class="logo-figure">
65
+ <div class="logo-stage bg-white construction-stage">
66
+ <Fig id={`construction-${lang}`} class="diagram px-center" viewBox={`${-m} ${-m} ${w / s} ${hh / s}`} w={w} h={hh} label={L.alt}>
67
+ <path fill={COLORS.yellow} fill-rule="evenodd" d={ICON_PATH} opacity=".9" />
68
+ <path class="d-grid" d={lines.join('')} stroke-width={sw} />
69
+ <rect class="d-guide" x="0" y="0" width={W} height={H} stroke-width={sw} stroke-dasharray={`${3 / s} ${3 / s}`} />
70
+ <g class="d-measure" stroke-width={1.5 * sw}>
71
+ <path d={`M${face.x1} ${face.y - 4 / s}V${face.y + 4 / s}M${face.x1} ${face.y}H${face.x2}M${face.x2} ${face.y - 4 / s}V${face.y + 4 / s}`} />
72
+ <path d={`M0 ${-16 / s}V${-8 / s}M0 ${-12 / s}H${W}M${W} ${-16 / s}V${-8 / s}`} />
73
+ <path d={`M${3 * h} ${H + 8 / s}V${H + 16 / s}M0 ${H + 12 / s}H${3 * h}M0 ${H + 8 / s}V${H + 16 / s}`} />
74
+ </g>
75
+ <text class="d-label" x={W / 2} y={-20 / s} font-size={fs} text-anchor="middle">{L.n28}</text>
76
+ <text class="d-label" x={W / 2} y={face.y - 8 / s} font-size={fs} text-anchor="middle">{L.n20}</text>
77
+ <text class="d-label" x={3 * h + 6 / s} y={H + 16 / s} font-size={fs}>{L.n3}</text>
78
+ </Fig>
79
+ </div>
80
+ </figure>
81
+
82
+ <ul class="diagram-legend" style="--cols:4">
83
+ {L.legend.map(([title, text]) => <li><b>{title}</b>{text}</li>)}
84
+ </ul>