@rimelight/ui 0.0.5 → 0.0.7

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 (315) hide show
  1. package/LICENSE +21 -21
  2. package/package.json +22 -14
  3. package/src/components/BlogPost.astro +195 -0
  4. package/src/components/DynamicShowcase.astro +681 -0
  5. package/src/components/ExtendedCarousel.astro +107 -0
  6. package/src/components/FormattedDate.astro +6 -2
  7. package/src/components/Head.astro +153 -0
  8. package/src/components/ProjectPost.astro +197 -0
  9. package/src/components/RLHead.astro +3 -0
  10. package/src/components/ThemeToggle.astro +30 -42
  11. package/src/components/astro/RLAButton.astro +32 -42
  12. package/src/components/astro/RLAHeader.astro +75 -0
  13. package/src/components/nuxt/index.ts +1 -0
  14. package/src/components/vue/RLVButton.vue +50 -37
  15. package/src/components/vue/RLVHeader.vue +78 -0
  16. package/src/composables/index.ts +1 -1
  17. package/src/composables/{useComponentUI.ts → useUi.ts} +3 -3
  18. package/src/config/index.ts +0 -2
  19. package/src/config/site.config.ts +1 -1
  20. package/src/env.d.ts +13 -16
  21. package/src/integrations/ui.ts +106 -81
  22. package/src/integrations/vue-entrypoint.ts +6 -0
  23. package/src/middleware/sri.ts +2 -2
  24. package/src/styles/index.css +2 -0
  25. package/src/themes/button.theme.ts +350 -34
  26. package/src/themes/header.theme.ts +33 -0
  27. package/src/themes/index.ts +3 -1
  28. package/src/utils/index.ts +1 -2
  29. package/i18n-data.json +0 -186
  30. package/src/components/MissingTranslationBanner.astro +0 -39
  31. package/src/components/accordion/Accordion.astro +0 -257
  32. package/src/components/accordion/AccordionContent.astro +0 -34
  33. package/src/components/accordion/AccordionItem.astro +0 -29
  34. package/src/components/accordion/AccordionTrigger.astro +0 -33
  35. package/src/components/alert/Alert.astro +0 -34
  36. package/src/components/alert/AlertDescription.astro +0 -15
  37. package/src/components/alert/AlertTitle.astro +0 -17
  38. package/src/components/alert-dialog/AlertDialog.astro +0 -275
  39. package/src/components/alert-dialog/AlertDialogAction.astro +0 -46
  40. package/src/components/alert-dialog/AlertDialogCancel.astro +0 -46
  41. package/src/components/alert-dialog/AlertDialogContent.astro +0 -52
  42. package/src/components/alert-dialog/AlertDialogDescription.astro +0 -18
  43. package/src/components/alert-dialog/AlertDialogFooter.astro +0 -16
  44. package/src/components/alert-dialog/AlertDialogHeader.astro +0 -14
  45. package/src/components/alert-dialog/AlertDialogTitle.astro +0 -20
  46. package/src/components/alert-dialog/AlertDialogTrigger.astro +0 -47
  47. package/src/components/aspect-ratio/AspectRatio.astro +0 -32
  48. package/src/components/avatar/Avatar.astro +0 -29
  49. package/src/components/avatar/AvatarFallback.astro +0 -18
  50. package/src/components/avatar/AvatarImage.astro +0 -66
  51. package/src/components/badge/Badge.astro +0 -57
  52. package/src/components/breadcrumb/Breadcrumb.astro +0 -12
  53. package/src/components/breadcrumb/BreadcrumbEllipsis.astro +0 -29
  54. package/src/components/breadcrumb/BreadcrumbItem.astro +0 -15
  55. package/src/components/breadcrumb/BreadcrumbLink.astro +0 -24
  56. package/src/components/breadcrumb/BreadcrumbList.astro +0 -17
  57. package/src/components/breadcrumb/BreadcrumbPage.astro +0 -22
  58. package/src/components/breadcrumb/BreadcrumbSeparator.astro +0 -24
  59. package/src/components/button/Button.astro +0 -58
  60. package/src/components/button-group/ButtonGroup.astro +0 -64
  61. package/src/components/button-group/ButtonGroupSeparator.astro +0 -20
  62. package/src/components/button-group/ButtonGroupText.astro +0 -19
  63. package/src/components/card/Card.astro +0 -36
  64. package/src/components/card/CardAction.astro +0 -16
  65. package/src/components/card/CardContent.astro +0 -16
  66. package/src/components/card/CardDescription.astro +0 -16
  67. package/src/components/card/CardFooter.astro +0 -16
  68. package/src/components/card/CardHeader.astro +0 -19
  69. package/src/components/card/CardTitle.astro +0 -16
  70. package/src/components/carousel/Carousel.astro +0 -55
  71. package/src/components/carousel/CarouselContent.astro +0 -26
  72. package/src/components/carousel/CarouselItem.astro +0 -26
  73. package/src/components/carousel/CarouselNext.astro +0 -39
  74. package/src/components/carousel/CarouselPrevious.astro +0 -41
  75. package/src/components/carousel/carousel-script.ts +0 -188
  76. package/src/components/carousel/index.ts +0 -1
  77. package/src/components/checkbox/Checkbox.astro +0 -133
  78. package/src/components/collapsible/Collapsible.astro +0 -161
  79. package/src/components/collapsible/CollapsibleContent.astro +0 -22
  80. package/src/components/collapsible/CollapsibleTrigger.astro +0 -44
  81. package/src/components/dialog/Dialog.astro +0 -389
  82. package/src/components/dialog/DialogClose.astro +0 -35
  83. package/src/components/dialog/DialogContent.astro +0 -78
  84. package/src/components/dialog/DialogDescription.astro +0 -14
  85. package/src/components/dialog/DialogFooter.astro +0 -14
  86. package/src/components/dialog/DialogHeader.astro +0 -14
  87. package/src/components/dialog/DialogTitle.astro +0 -18
  88. package/src/components/dialog/DialogTrigger.astro +0 -47
  89. package/src/components/dropdown/Dropdown.astro +0 -604
  90. package/src/components/dropdown/DropdownContent.astro +0 -118
  91. package/src/components/dropdown/DropdownItem.astro +0 -48
  92. package/src/components/dropdown/DropdownLabel.astro +0 -29
  93. package/src/components/dropdown/DropdownSeparator.astro +0 -21
  94. package/src/components/dropdown/DropdownShortcut.astro +0 -17
  95. package/src/components/dropdown/DropdownSub.astro +0 -15
  96. package/src/components/dropdown/DropdownSubContent.astro +0 -39
  97. package/src/components/dropdown/DropdownSubTrigger.astro +0 -34
  98. package/src/components/dropdown/DropdownTrigger.astro +0 -52
  99. package/src/components/dropzone/Dropzone.astro +0 -236
  100. package/src/components/dropzone/DropzoneFilesList.astro +0 -26
  101. package/src/components/dropzone/DropzoneLoadingIndicator.astro +0 -10
  102. package/src/components/dropzone/DropzoneUploadIndicator.astro +0 -10
  103. package/src/components/embeds/YoutubeEmbed.astro +0 -94
  104. package/src/components/hero/Hero.astro +0 -166
  105. package/src/components/icons/Flag.astro +0 -62
  106. package/src/components/image/ExtendedImage.astro +0 -46
  107. package/src/components/image/Image.astro +0 -25
  108. package/src/components/input/Input.astro +0 -27
  109. package/src/components/input-group/InputGroup.astro +0 -28
  110. package/src/components/input-group/InputGroupAddon.astro +0 -76
  111. package/src/components/input-group/InputGroupButton.astro +0 -36
  112. package/src/components/input-group/InputGroupInput.astro +0 -18
  113. package/src/components/input-group/InputGroupText.astro +0 -17
  114. package/src/components/input-group/InputGroupTextarea.astro +0 -22
  115. package/src/components/input-otp/InputOtp.astro +0 -352
  116. package/src/components/input-otp/InputOtpGroup.astro +0 -16
  117. package/src/components/input-otp/InputOtpSeparator.astro +0 -25
  118. package/src/components/input-otp/InputOtpSlot.astro +0 -50
  119. package/src/components/input-otp/InputOtpTypes.ts +0 -6
  120. package/src/components/item/Item.astro +0 -52
  121. package/src/components/item/ItemActions.astro +0 -16
  122. package/src/components/item/ItemContent.astro +0 -16
  123. package/src/components/item/ItemDescription.astro +0 -19
  124. package/src/components/item/ItemFooter.astro +0 -16
  125. package/src/components/item/ItemGroup.astro +0 -16
  126. package/src/components/item/ItemHeader.astro +0 -16
  127. package/src/components/item/ItemMedia.astro +0 -40
  128. package/src/components/item/ItemSeparator.astro +0 -23
  129. package/src/components/item/ItemTitle.astro +0 -16
  130. package/src/components/kbd/Kbd.astro +0 -21
  131. package/src/components/kbd/KbdGroup.astro +0 -16
  132. package/src/components/label/Label.astro +0 -24
  133. package/src/components/marquee/Marquee.astro +0 -73
  134. package/src/components/native-select/NativeSelect.astro +0 -68
  135. package/src/components/native-select/NativeSelectOptGroup.astro +0 -15
  136. package/src/components/native-select/NativeSelectOption.astro +0 -15
  137. package/src/components/pagination/Pagination.astro +0 -20
  138. package/src/components/pagination/PaginationContent.astro +0 -16
  139. package/src/components/pagination/PaginationEllipsis.astro +0 -37
  140. package/src/components/pagination/PaginationItem.astro +0 -16
  141. package/src/components/pagination/PaginationLink.astro +0 -27
  142. package/src/components/pagination/PaginationNext.astro +0 -33
  143. package/src/components/pagination/PaginationPrevious.astro +0 -33
  144. package/src/components/popover/Popover.astro +0 -717
  145. package/src/components/popover/PopoverContent.astro +0 -102
  146. package/src/components/popover/PopoverDescription.astro +0 -14
  147. package/src/components/popover/PopoverHeader.astro +0 -14
  148. package/src/components/popover/PopoverTitle.astro +0 -14
  149. package/src/components/popover/PopoverTrigger.astro +0 -51
  150. package/src/components/progress/Progress.astro +0 -154
  151. package/src/components/prose/Prose.astro +0 -619
  152. package/src/components/radio-group/RadioGroup.astro +0 -162
  153. package/src/components/radio-group/RadioGroupItem.astro +0 -133
  154. package/src/components/radio-group/RadioGroupTypes.ts +0 -6
  155. package/src/components/section/Section.astro +0 -167
  156. package/src/components/select/Select.astro +0 -752
  157. package/src/components/select/SelectContent.astro +0 -94
  158. package/src/components/select/SelectGroup.astro +0 -9
  159. package/src/components/select/SelectItem.astro +0 -51
  160. package/src/components/select/SelectLabel.astro +0 -14
  161. package/src/components/select/SelectSearch.astro +0 -49
  162. package/src/components/select/SelectSeparator.astro +0 -12
  163. package/src/components/select/SelectTrigger.astro +0 -56
  164. package/src/components/select/SelectTypes.ts +0 -13
  165. package/src/components/select/SelectValue.astro +0 -19
  166. package/src/components/separator/Separator.astro +0 -36
  167. package/src/components/sheet/Sheet.astro +0 -15
  168. package/src/components/sheet/SheetClose.astro +0 -15
  169. package/src/components/sheet/SheetContent.astro +0 -89
  170. package/src/components/sheet/SheetDescription.astro +0 -16
  171. package/src/components/sheet/SheetFooter.astro +0 -16
  172. package/src/components/sheet/SheetHeader.astro +0 -16
  173. package/src/components/sheet/SheetTitle.astro +0 -16
  174. package/src/components/sheet/SheetTrigger.astro +0 -15
  175. package/src/components/sidebar/Sidebar.astro +0 -231
  176. package/src/components/sidebar/SidebarContent.astro +0 -25
  177. package/src/components/sidebar/SidebarFooter.astro +0 -22
  178. package/src/components/sidebar/SidebarGroup.astro +0 -22
  179. package/src/components/sidebar/SidebarGroupContent.astro +0 -22
  180. package/src/components/sidebar/SidebarGroupLabel.astro +0 -53
  181. package/src/components/sidebar/SidebarHeader.astro +0 -22
  182. package/src/components/sidebar/SidebarInput.astro +0 -24
  183. package/src/components/sidebar/SidebarInset.astro +0 -22
  184. package/src/components/sidebar/SidebarMenu.astro +0 -22
  185. package/src/components/sidebar/SidebarMenuAction.astro +0 -63
  186. package/src/components/sidebar/SidebarMenuBadge.astro +0 -31
  187. package/src/components/sidebar/SidebarMenuButton.astro +0 -124
  188. package/src/components/sidebar/SidebarMenuItem.astro +0 -22
  189. package/src/components/sidebar/SidebarMenuSkeleton.astro +0 -43
  190. package/src/components/sidebar/SidebarMenuSub.astro +0 -25
  191. package/src/components/sidebar/SidebarMenuSubButton.astro +0 -52
  192. package/src/components/sidebar/SidebarMenuSubItem.astro +0 -17
  193. package/src/components/sidebar/SidebarProvider.astro +0 -215
  194. package/src/components/sidebar/SidebarRail.astro +0 -72
  195. package/src/components/sidebar/SidebarSeparator.astro +0 -25
  196. package/src/components/sidebar/SidebarTrigger.astro +0 -69
  197. package/src/components/skeleton/Skeleton.astro +0 -14
  198. package/src/components/slider/Slider.astro +0 -425
  199. package/src/components/spinner/Spinner.astro +0 -23
  200. package/src/components/switch/Switch.astro +0 -192
  201. package/src/components/switch/SwitchTypes.ts +0 -6
  202. package/src/components/table/Table.astro +0 -20
  203. package/src/components/table/TableBody.astro +0 -18
  204. package/src/components/table/TableCaption.astro +0 -18
  205. package/src/components/table/TableCell.astro +0 -18
  206. package/src/components/table/TableFoot.astro +0 -18
  207. package/src/components/table/TableHead.astro +0 -18
  208. package/src/components/table/TableHeader.astro +0 -18
  209. package/src/components/table/TableRow.astro +0 -17
  210. package/src/components/tabs/Tabs.astro +0 -270
  211. package/src/components/tabs/TabsContent.astro +0 -28
  212. package/src/components/tabs/TabsList.astro +0 -23
  213. package/src/components/tabs/TabsTrigger.astro +0 -34
  214. package/src/components/textarea/Textarea.astro +0 -31
  215. package/src/components/toast/ToastDescription.astro +0 -22
  216. package/src/components/toast/ToastItem.astro +0 -56
  217. package/src/components/toast/ToastTemplate.astro +0 -27
  218. package/src/components/toast/ToastTitle.astro +0 -59
  219. package/src/components/toast/Toaster.astro +0 -981
  220. package/src/components/toast/index.ts +0 -1
  221. package/src/components/toast/toast-manager.ts +0 -234
  222. package/src/components/toggle/Toggle.astro +0 -174
  223. package/src/components/toggle/ToggleTypes.ts +0 -14
  224. package/src/components/tooltip/Tooltip.astro +0 -422
  225. package/src/components/tooltip/TooltipContent.astro +0 -83
  226. package/src/components/tooltip/TooltipTrigger.astro +0 -13
  227. package/src/components/video/Video.astro +0 -121
  228. package/src/config/cookies.ts +0 -5
  229. package/src/config/links.ts +0 -4
  230. package/src/domain/cms/index.ts +0 -1
  231. package/src/domain/cms/types.ts +0 -20
  232. package/src/domain/i18n/constants.ts +0 -21
  233. package/src/domain/i18n/cookie-storage.ts +0 -13
  234. package/src/domain/i18n/country-to-locale-map.ts +0 -67
  235. package/src/domain/i18n/fallbacks.generated.ts +0 -230
  236. package/src/domain/i18n/fetcher.ts +0 -278
  237. package/src/domain/i18n/flags.ts +0 -16
  238. package/src/domain/i18n/format.ts +0 -90
  239. package/src/domain/i18n/index.ts +0 -10
  240. package/src/domain/i18n/middleware/i18n.ts +0 -161
  241. package/src/domain/i18n/resolve-locale.ts +0 -55
  242. package/src/domain/i18n/runtime-constants.ts +0 -14
  243. package/src/domain/i18n/schema.ts +0 -29
  244. package/src/domain/index.ts +0 -4
  245. package/src/domain/seo/constants.ts +0 -6
  246. package/src/domain/seo/index.ts +0 -3
  247. package/src/domain/seo/services/index.ts +0 -3
  248. package/src/domain/seo/services/llms.ts +0 -56
  249. package/src/domain/seo/services/robots.ts +0 -12
  250. package/src/domain/seo/services/sitemap.ts +0 -56
  251. package/src/domain/seo/utils.ts +0 -36
  252. package/src/domain/theme/constants.ts +0 -6
  253. package/src/domain/theme/index.ts +0 -2
  254. package/src/domain/theme/schema.ts +0 -10
  255. package/src/i18n.generated.d.ts +0 -202
  256. package/src/lib/component-preview.ts +0 -73
  257. package/src/lib/index.ts +0 -6
  258. package/src/lib/remark/remark-modified-time.ts +0 -13
  259. package/src/lib/showcase-preview-elements.ts +0 -408
  260. package/src/lib/showcase-renderer.ts +0 -218
  261. package/src/lib/showcase-utils.ts +0 -189
  262. package/src/lib/turnstile.ts +0 -35
  263. package/src/lib/utils/starwind/positioning.ts +0 -318
  264. package/src/locales/de/blog.json +0 -9
  265. package/src/locales/de/common.json +0 -19
  266. package/src/locales/de/errors.json +0 -6
  267. package/src/locales/de/home.json +0 -20
  268. package/src/locales/de/messages.json +0 -8
  269. package/src/locales/de/nav.json +0 -13
  270. package/src/locales/de/projects.json +0 -9
  271. package/src/locales/de/services.json +0 -43
  272. package/src/locales/en/blog.json +0 -9
  273. package/src/locales/en/chat.json +0 -29
  274. package/src/locales/en/common.json +0 -19
  275. package/src/locales/en/cookie_notice.json +0 -11
  276. package/src/locales/en/editor.json +0 -24
  277. package/src/locales/en/errors.json +0 -6
  278. package/src/locales/en/home.json +0 -20
  279. package/src/locales/en/messages.json +0 -8
  280. package/src/locales/en/nav.json +0 -13
  281. package/src/locales/en/projects.json +0 -9
  282. package/src/locales/en/services.json +0 -43
  283. package/src/locales/es/blog.json +0 -9
  284. package/src/locales/es/common.json +0 -19
  285. package/src/locales/es/errors.json +0 -6
  286. package/src/locales/es/home.json +0 -20
  287. package/src/locales/es/messages.json +0 -8
  288. package/src/locales/es/nav.json +0 -13
  289. package/src/locales/es/projects.json +0 -9
  290. package/src/locales/es/services.json +0 -43
  291. package/src/locales/ja/blog.json +0 -9
  292. package/src/locales/ja/common.json +0 -19
  293. package/src/locales/ja/errors.json +0 -6
  294. package/src/locales/ja/home.json +0 -20
  295. package/src/locales/ja/messages.json +0 -8
  296. package/src/locales/ja/nav.json +0 -13
  297. package/src/locales/ja/projects.json +0 -9
  298. package/src/locales/ja/services.json +0 -43
  299. package/src/locales/pt/blog.json +0 -9
  300. package/src/locales/pt/chat.json +0 -29
  301. package/src/locales/pt/common.json +0 -19
  302. package/src/locales/pt/cookie_notice.json +0 -11
  303. package/src/locales/pt/editor.json +0 -24
  304. package/src/locales/pt/errors.json +0 -6
  305. package/src/locales/pt/home.json +0 -20
  306. package/src/locales/pt/messages.json +0 -8
  307. package/src/locales/pt/nav.json +0 -13
  308. package/src/locales/pt/projects.json +0 -9
  309. package/src/locales/pt/services.json +0 -43
  310. package/src/utils/server/cookies.ts +0 -98
  311. package/src/utils/server/index.ts +0 -1
  312. package/src/utils/shared/deep-merge.ts +0 -36
  313. package/src/utils/shared/index.ts +0 -3
  314. package/src/utils/shared/parse-boolean.ts +0 -14
  315. /package/src/utils/{shared/embed.ts → embed.ts} +0 -0
@@ -1,13 +0,0 @@
1
- import { type AstroCookies } from "astro"
2
-
3
- import { type Locale, LocaleSchema } from "./schema"
4
- import { setCookie, getCookieWithSchema } from "../../utils/server/cookies"
5
- import { LANG_COOKIE_NAME } from "./constants"
6
-
7
- export function setCookieLang(cookies: AstroCookies, locale: Locale) {
8
- setCookie(cookies, LANG_COOKIE_NAME, locale)
9
- }
10
-
11
- export function getCookieLang(cookies: AstroCookies): Locale | null {
12
- return getCookieWithSchema(cookies, LANG_COOKIE_NAME, LocaleSchema)
13
- }
@@ -1,67 +0,0 @@
1
- import type { Locale } from "./schema.ts"
2
-
3
- // Key: ISO 3166-1 Alpha-2 Country Code (from request.cf.country)
4
- // Value: The optimal language to serve
5
- const GEO_MAP: Record<string, Locale> = {
6
- // --- ANGLOSPHERE (Explicitly set to EN) ---
7
- US: "en", // United States
8
- GB: "en", // United Kingdom
9
- AU: "en", // Australia
10
- NZ: "en", // New Zealand
11
- IE: "en", // Ireland
12
- CA: "en", // Canada (Majority EN, fallbacks handle FR better via Accept-Language headers)
13
-
14
- // --- DACH (German) ---
15
- DE: "de",
16
- AT: "de",
17
- CH: "de",
18
- LI: "de",
19
-
20
- // --- LATAM + SPAIN ---
21
- ES: "es",
22
- MX: "es",
23
- AR: "es",
24
- CO: "es",
25
- CL: "es",
26
- PE: "es",
27
- VE: "es",
28
- GT: "es",
29
- EC: "es",
30
-
31
- // Asia
32
- JP: "ja",
33
-
34
- // --- LUSOPHONE (Portuguese) ---
35
- PT: "pt",
36
- BR: "pt",
37
- AO: "pt",
38
- MZ: "pt"
39
-
40
- // --- FRANCOPHONE ---
41
- // FR: 'fr',
42
- // BE: 'fr',
43
- // MC: 'fr',
44
- // SN: 'fr',
45
-
46
- // --- SLAVIC / POST-SOVIET ---
47
- // UA: 'uk',
48
- // RU: 'ru',
49
- // KZ: 'ru',
50
- // BY: 'ru',
51
-
52
- // Add other mappings as needed...
53
- }
54
-
55
- /**
56
- * Maps a Cloudflare Country Code to a supported App Locale. Returns undefined if no direct mapping
57
- * exists (falling back to default strategy).
58
- */
59
- export function mapCountryToLocale(country: unknown): string | undefined {
60
- // Safety: In dev mode (localhost), 'country' might be null or undefined.
61
- if (typeof country !== "string") return undefined
62
-
63
- // Cloudflare always sends uppercase (e.g., 'US', 'DE'), but safety first.
64
- const code = country.toUpperCase()
65
-
66
- return GEO_MAP[code]
67
- }
@@ -1,230 +0,0 @@
1
- // Auto-generated by scripts/bundle-translations.ts
2
- // Do not edit manually.
3
-
4
- export const FALLBACK_LOCALE = "en" as const
5
-
6
- export const FALLBACK_BLOG = {
7
- meta_title: "Blog | Daniel Marchi",
8
- hero_title: "Blog",
9
- hero_description: "My insights throughout my journey as a developer.",
10
- latest_article: "Latest Article",
11
- latest: "Latest",
12
- read_article: "Read Article",
13
- all_posts: "All Posts"
14
- } as const
15
-
16
- export const FALLBACK_CHAT = {
17
- title: "Join a Chat Room",
18
- description: "Enter a room name to start chatting",
19
- heading: "Real-time Chat",
20
- intro:
21
- "Enter a room name below to join a conversation. Each room is a unique Durable Object instance!",
22
- label: "Room Name",
23
- placeholder: "e.g. general, help, coffee-break",
24
- button: "Join Room",
25
- room: {
26
- title: "Chat Room",
27
- connecting: "Connecting…",
28
- connected: "Connected",
29
- disconnected: "Disconnected",
30
- placeholder: "Type a message…",
31
- send: "Send",
32
- system: {
33
- joining: "Joining room…",
34
- error: "Connection error",
35
- joined: "joined the room",
36
- left: "left the room",
37
- reconnecting: "Reconnecting in {delay} seconds... (attempt {attempt}/{max})",
38
- fail_reconnect: "Failed to reconnect. Please refresh the page.",
39
- no_connect: "Cannot send message: not connected",
40
- prompt_user: "Enter your username:",
41
- you: "(You)",
42
- online_users: "Online Users:"
43
- }
44
- }
45
- } as const
46
-
47
- export const FALLBACK_COMMON = {
48
- seo: {
49
- title: "Zero-JS i18n Astro Starter for Cloudflare Workers",
50
- description:
51
- "Ship multilingual apps faster without hydration bloat. Full integration with Cloudflare Workers & KV, automated TypeScript generation, and edge caching out of the box."
52
- },
53
- nav: {
54
- home: "Astro components & islands",
55
- blog: "Markdown i18n examples",
56
- mobileButton: "Menu"
57
- },
58
- footer: {
59
- license: "Under the MIT license."
60
- },
61
- notFound: {
62
- title: "404 — Page not found",
63
- message: "The page you are looking for does not exist or has been moved.",
64
- backToHome: "Go back to homepage"
65
- }
66
- } as const
67
-
68
- export const FALLBACK_COOKIE_NOTICE = {
69
- title: "Cookie Policy",
70
- description:
71
- "This website does not use cookies, this is a sample of how it could work in your website as per your",
72
- privacy_policy: "Privacy Policy",
73
- reject_all: "Reject All",
74
- accept_all: "Accept All",
75
- accepted_toast: "Cookies Accepted",
76
- accepted_description: "You have accepted all cookies.",
77
- rejected_toast: "Cookies Rejected",
78
- rejected_description: "You have rejected all cookies."
79
- } as const
80
-
81
- export const FALLBACK_EDITOR = {
82
- title: "Editor",
83
- description: "Collaborative real-time document editor",
84
- collaborative_editor: "Collaborative Editor",
85
- status: {
86
- connecting: "Connecting…",
87
- connected: "Connected",
88
- disconnected: "Disconnected"
89
- },
90
- history: "History",
91
- version_history: "Version History",
92
- no_versions: "No versions yet.",
93
- placeholder: "Start typing… your changes are synced in real-time.",
94
- word_count: {
95
- word: "word",
96
- words: "words",
97
- character: "character",
98
- characters: "characters"
99
- },
100
- save: {
101
- saved: "Saved"
102
- },
103
- restore_confirm: "Restore this version? Current content will be replaced."
104
- } as const
105
-
106
- export const FALLBACK_ERRORS = {
107
- "404_title": "Page Not Found",
108
- "404_description": "The page you are looking for does not exist.",
109
- "500_title": "Internal Server Error",
110
- "500_description": "Something went wrong on our end. Please try again later."
111
- } as const
112
-
113
- export const FALLBACK_HOME = {
114
- meta_title: "Daniel Marchi | Web Developer",
115
- meta_description: "I'm a web developer specialized in Astro and high-performance websites.",
116
- hero_title: "Hey, I'm Daniel Marchi",
117
- hero_description: "I'm a web developer specialized in Astro and high-performance websites.",
118
- hero_view_components: "View Components",
119
- hero_contact_me: "Contact Me",
120
- stack_title: "Modern Web, Modern Stack",
121
- stack_description:
122
- "I help individuals and companies build high-performance web applications deployed on the edge. From architecture to deployment, I ensure your project is built for scale.",
123
- stack_view_services: "View Services",
124
- stack_resume: "Resume",
125
- marquee_title: "Built and deployed with these amazing technologies:",
126
- projects_title: "Recent Projects",
127
- projects_description: "A selection of my latest technical work and open source projects.",
128
- projects_view_all: "View All Projects",
129
- cta_title: "Ready to Build Something Amazing?",
130
- cta_description:
131
- "I'm currently available for new projects and consulting. Let's work together to bring your vision to life.",
132
- cta_contact: "Get in Touch",
133
- cta_resume: "Download Resume"
134
- } as const
135
-
136
- export const FALLBACK_MESSAGES = {
137
- errors: {
138
- ui: {
139
- MISSING_TRANSLATED_UI:
140
- "Sorry, this page is not yet fully available in your selected language.",
141
- MISSING_TRANSLATED_CONTENT:
142
- "Sorry, this article is not yet available in your selected language."
143
- }
144
- }
145
- } as const
146
-
147
- export const FALLBACK_NAV = {
148
- home: "Home",
149
- projects: "Projects",
150
- blog: "Blog",
151
- about: "About",
152
- services: "Services",
153
- resume: "Resume",
154
- contact: "Contact",
155
- components: "Components",
156
- privacy_policy: "Privacy Policy",
157
- terms_of_service: "Terms of Service",
158
- cookie_policy: "Cookie Policy"
159
- } as const
160
-
161
- export const FALLBACK_PROJECTS = {
162
- meta_title: "Projects | Daniel Marchi",
163
- hero_title: "Projects",
164
- hero_description: "A showcase of my work and open source contributions.",
165
- latest: "Latest Project",
166
- latest_badge: "Latest",
167
- view_project: "View Project",
168
- all: "All Projects"
169
- } as const
170
-
171
- export const FALLBACK_SERVICES = {
172
- meta_title: "Services | Daniel Marchi",
173
- hero_title: "Premium Services",
174
- hero_description:
175
- "I provide high-quality development and design services to help your business grow and stand out in the digital landscape.",
176
- capabilities_title: "Capabilities",
177
- capabilities_description: "An overview of the core services I provide to my clients.",
178
- web_dev_title: "Web Development",
179
- web_dev_description:
180
- "Crafting high-performance, accessible, and scalable web applications using modern technologies like Astro, Vue, and Nuxt.",
181
- ui_ux_title: "UI/UX Design",
182
- ui_ux_description:
183
- "Creating intuitive and visually stunning user interfaces focusing on user experience and brand identity.",
184
- perf_title: "Performance Optimization",
185
- perf_description:
186
- "Audit and optimize your website for speed, SEO, and accessibility to achieve perfect Lighthouse scores.",
187
- perf_security_title: "Performance & Security",
188
- perf_security_description:
189
- "Your users deserve a fast and secure experience. I build websites that load instantly and perform flawlessly across all devices.",
190
- testimonials_title: "What Our Users Say",
191
- testimonials_description:
192
- "Join thousands of developers building the next generation of the web with Astronaut.",
193
- faq_title: "Frequently Asked Questions",
194
- faq_description:
195
- "Everything you need to know about Astronaut and how to build amazing things with it.",
196
- cta_title: "Ready to Start?",
197
- cta_description:
198
- "Let's collaborate on your next big project. I'm currently available for freelance work and consulting.",
199
- cta_contact: "Get in Touch",
200
- cta_portfolio: "View Portfolio",
201
- badge_ceo: "CEO",
202
- badge_founder: "Founder",
203
- badge_cto: "CTO",
204
- badge_senior_ui: "Senior UI Engineer",
205
- badge_chef: "Chef",
206
- badge_product_designer: "Product Designer",
207
- testimonial_1:
208
- "Astronaut is hands down the best boilerplate I've ever used. The speed and clean architecture matching perfectly with how I want to build.",
209
- testimonial_2:
210
- "The component library and the way it handles Tailwind 4 is a game changer. I was able to launch my project in record time.",
211
- testimonial_3:
212
- "Finally a boilerplate that doesn't feel bloated but gives me all the tools I need. The SSR support on Cloudflare is flawless.",
213
- testimonial_4:
214
- "The best starting point for any modern web project. The developer experience is world-class and the performance is unbeatable.",
215
- testimonial_5:
216
- "Incredible attention to detail in the structure. It follows all the best practices without adding unnecessary complexity.",
217
- testimonial_6:
218
- "Everything is so smooth! Transitions, components, logic - it all just clicks. Best decision for my latest startup.",
219
- faq_category_general: "General",
220
- faq_q1: "What is Astronaut?",
221
- faq_a1:
222
- "Astronaut is a production-ready boilerplate for Astro, designed with speed, performance, and best practices in mind. It uses Tailwind CSS 4, Nuxt UI patterns, and a clean architecture.",
223
- faq_q2: "How do I get started?",
224
- faq_a2:
225
- "You can simply clone the repository, install dependencies with pnpm, and run the dev server. The project structure is standard Astro, so you'll feel right at home.",
226
- faq_category_technical: "Technical",
227
- faq_q3: "Does it support Server-Side Rendering (SSR)?",
228
- faq_a3:
229
- "Yes, Astronaut fully supports SSR and is configured for deployment on Cloudflare Workers by default, giving you the best of both worlds: static speed and dynamic power."
230
- } as const
@@ -1,278 +0,0 @@
1
- import { TRANSLATIONS_VERSION } from "./runtime-constants"
2
- let env: any = {}
3
- try {
4
- // @ts-ignore
5
- const workers = await import(/* @vite-ignore */ "cloudflare:workers")
6
- env = workers.env
7
- } catch {
8
- // Safe fallback for Node.js environments (Astro config, local scripts)
9
- env = {}
10
- }
11
- import type { Locale, Namespace, PickSchema } from "./schema"
12
- import { deepMerge } from "../../utils/shared/deep-merge"
13
- import { parseBooleanFlag } from "../../utils/shared/parse-boolean"
14
-
15
- /**
16
- * Minimal environment interface for i18n operations. Usually provided by Cloudflare Workers.
17
- */
18
- interface Env {
19
- TRANSLATIONS: {
20
- get: (keys: string[], options: { type: "json"; cacheTtl?: number }) => Promise<Map<string, any>>
21
- }
22
- I18N_CACHE?: string
23
- DEBUG_I18N?: string
24
- }
25
-
26
- // Optional fallbacks (auto-loaded if generated)
27
- let FALLBACKS: Record<string, unknown> | null = null
28
-
29
- try {
30
- FALLBACKS = await import("./fallbacks.generated.ts")
31
- } catch {
32
- FALLBACKS = null
33
- }
34
-
35
- const KV_JSON_OPTIONS = { type: "json" as const, cacheTtl: 3600 }
36
-
37
- function assertRecord(obj: unknown): asserts obj is Record<string, unknown> {
38
- if (!obj || typeof obj !== "object") throw new Error("Expected record")
39
- }
40
-
41
- function assertDefaultCache(obj: unknown): asserts obj is {
42
- match: (r: Request) => Promise<Response | undefined>
43
- put: (r: Request, res: Response) => Promise<void>
44
- } {
45
- if (!obj || typeof obj !== "object") throw new Error("Expected cache")
46
- }
47
-
48
- function assertSchema<N extends Namespace>(obj: unknown): asserts obj is PickSchema<N> {
49
- if (!obj) throw new Error("Expected schema")
50
- }
51
-
52
- function assertA<N extends Namespace>(obj: unknown): asserts obj is PickSchema<N> {
53
- if (!obj) throw new Error("Expected result")
54
- }
55
-
56
- /**
57
- * Runtime object provided by Astro via Astro.locals.
58
- */
59
- export interface Runtime {
60
- cf?: unknown
61
- cfContext: { waitUntil: (p: Promise<unknown>) => void }
62
- }
63
-
64
- /**
65
- * Fetch translations from KV for a given locale and list of namespaces.
66
- *
67
- * Responsibilities:
68
- *
69
- * - Build KV keys using namespace and locale (isolated by KV namespace binding)
70
- * - Optionally use edge cache (controlled by env flag I18N_CACHE)
71
- * - On cache miss, read from KV and merge with optional FALLBACK_* dictionaries
72
- * - Persist the merged payload back to the edge cache
73
- * - If KV is unavailable, fall back to static FALLBACK_* dictionaries only
74
- */
75
- export async function fetchTranslations<N extends Namespace>(
76
- runtime: Runtime,
77
- lang: Locale,
78
- namespaces: readonly N[]
79
- ): Promise<PickSchema<N>> {
80
- const useCache = isCacheEnabled(env)
81
-
82
- if (!useCache) {
83
- debug(env, "i18n cache DISABLED, using KV only", { lang, namespaces })
84
- }
85
-
86
- const { cache, waitUntil } = useCache ? getEdgeCache(runtime) : { cache: null, waitUntil: null }
87
-
88
- const keys = namespaces.map((ns) => `${ns}:${lang}`)
89
-
90
- const { cacheRequest } = buildCacheKey(lang, namespaces)
91
-
92
- // 1. Try to serve from edge cache if available and enabled
93
- if (useCache && cache) {
94
- try {
95
- const cached = await cache.match(cacheRequest)
96
-
97
- if (cached) {
98
- const json = await cached.json()
99
- assertSchema<N>(json)
100
- debug(env, "i18n cache HIT", { lang, namespaces })
101
- return json
102
- }
103
- debug(env, "i18n cache MISS (no entry)", { lang, namespaces })
104
- } catch (error) {
105
- debug(env, "i18n cache READ error, falling back to KV", error)
106
- }
107
- }
108
-
109
- // 2. Cache is missing, disabled, or unavailable → read from KV
110
- try {
111
- const data = await loadTranslationsFromKV(env, keys, namespaces)
112
- debug(env, "i18n KV OK", { lang, namespaces })
113
-
114
- // 3. Store the resulting payload in the edge cache asynchronously (if enabled)
115
- if (useCache && cache && waitUntil) {
116
- try {
117
- const response = new Response(JSON.stringify(data), {
118
- headers: {
119
- "Content-Type": "application/json; charset=utf-8",
120
- "Cache-Control": "public, s-maxage=3600, stale-while-revalidate=86400"
121
- }
122
- })
123
-
124
- const putPromise = cache.put(cacheRequest, response.clone())
125
-
126
- // In real Workers: schedule as a background task.
127
- // In dev / non-Workers: just await so cache is actually written.
128
- if (waitUntil) {
129
- waitUntil(putPromise)
130
- } else {
131
- await putPromise
132
- }
133
-
134
- debug(env, "i18n cache PUT completed", { lang, namespaces })
135
- } catch (error) {
136
- debug(env, "i18n cache WRITE error", error)
137
- }
138
- }
139
-
140
- return data
141
- } catch (error) {
142
- debug(env, "i18n KV ERROR, using FALLBACK_* only", error)
143
-
144
- // 4. Hard fallback to static FALLBACK_* constants if KV is unavailable
145
- return buildFallbackOnly(namespaces)
146
- }
147
- }
148
-
149
- /**
150
- * Narrow runtime.caches and runtime.ctx to the minimal shape needed for using the Cache API and
151
- * waitUntil in this module.
152
- */
153
- function getEdgeCache(runtime: Runtime): {
154
- cache: {
155
- match: (r: Request) => Promise<Response | undefined>
156
- put: (r: Request, res: Response) => Promise<void>
157
- } | null
158
- waitUntil: ((p: Promise<unknown>) => void) | null
159
- } {
160
- return {
161
- cache: getCacheFromStorage(),
162
- waitUntil: runtime.cfContext?.waitUntil ?? null
163
- }
164
- }
165
-
166
- function getCacheFromStorage(): {
167
- match: (r: Request) => Promise<Response | undefined>
168
- put: (r: Request, res: Response) => Promise<void>
169
- } | null {
170
- const c = Reflect.get(Object(caches), "default")
171
- try {
172
- assertDefaultCache(c)
173
- return c
174
- } catch {
175
- return null
176
- }
177
- }
178
-
179
- /**
180
- * Build a stable cache key and synthetic Request object used with the Cache API. The URL origin is
181
- * irrelevant; only the string identity matters.
182
- */
183
- function buildCacheKey<N extends Namespace>(
184
- lang: Locale,
185
- namespaces: readonly N[]
186
- ): { cacheId: string; cacheRequest: Request } {
187
- const cacheId = `i18n:v${TRANSLATIONS_VERSION}:${lang}:${namespaces.join(",")}`
188
-
189
- const cacheRequest = new Request(`https://i18n-cache/${encodeURIComponent(cacheId)}`)
190
-
191
- return { cacheId, cacheRequest }
192
- }
193
-
194
- /**
195
- * Read bulk translations from KV and merge with optional FALLBACK_* dictionaries. This is the main
196
- * "happy-path" loader.
197
- */
198
- async function loadTranslationsFromKV<N extends Namespace>(
199
- environment: Env,
200
- keys: string[],
201
- namespaces: readonly N[]
202
- ): Promise<PickSchema<N>> {
203
- const resultMap = await environment.TRANSLATIONS.get(keys, KV_JSON_OPTIONS)
204
-
205
- const data: Partial<PickSchema<N>> = {}
206
-
207
- for (let i = 0; i < namespaces.length; i++) {
208
- const ns = namespaces[i]!
209
- const key = keys[i]!
210
- const value = resultMap.get(key) ?? {}
211
- assertRecord(value)
212
-
213
- const fallbackConstName = `FALLBACK_${String(ns).toUpperCase()}`
214
- const fallback = FALLBACKS?.[fallbackConstName]
215
-
216
- if (fallback) {
217
- assertRecord(fallback)
218
- Reflect.set(data, ns, deepMerge(fallback, value))
219
- } else {
220
- Reflect.set(data, ns, value)
221
- }
222
- }
223
-
224
- assertA<N>(data)
225
- return data
226
- }
227
-
228
- /**
229
- * Build a payload using only FALLBACK_* dictionaries. Used when KV is unavailable or throws
230
- * unexpectedly.
231
- */
232
- function buildFallbackOnly<N extends Namespace>(namespaces: readonly N[]): PickSchema<N> {
233
- const empty: Partial<PickSchema<N>> = {}
234
-
235
- for (let i = 0; i < namespaces.length; i++) {
236
- const ns = namespaces[i]!
237
- const fallbackConstName = `FALLBACK_${String(ns).toUpperCase()}`
238
- const fallback = FALLBACKS?.[fallbackConstName]
239
-
240
- ;(empty as Record<string, unknown>)[ns] = fallback ?? {}
241
- }
242
-
243
- assertSchema<N>(empty)
244
- return empty
245
- }
246
-
247
- /**
248
- * Determine whether edge caching is enabled.
249
- *
250
- * Wrangler var: I18N_CACHE = "on" | "off" | "true" | "false" | "1" | "0"
251
- *
252
- * After adding the variable:
253
- *
254
- * - Update wrangler.jsonc / wrangler.toml or .dev.vars
255
- * - Run: npm run typegen
256
- */
257
- function isCacheEnabled(environment: Env): boolean {
258
- // env.I18N_CACHE is generated by `wrangler types`
259
- return parseBooleanFlag(environment.I18N_CACHE, /* defaultValue */ true)
260
- }
261
-
262
- /**
263
- * Debug logger controlled by a Wrangler variable.
264
- *
265
- * Wrangler var: DEBUG_I18N = "on" | "off" | "true" | "false" | "1" | "0"
266
- *
267
- * After adding the variable:
268
- *
269
- * - Update wrangler.jsonc / wrangler.toml or .dev.vars
270
- * - Run: npm run typegen
271
- */
272
- function debug(environment: Env, ...args: unknown[]) {
273
- const enabled = parseBooleanFlag(environment.DEBUG_I18N, /* defaultValue */ false)
274
- if (!enabled) return
275
-
276
- // eslint-disable-next-line no-console
277
- console.log(...args)
278
- }
@@ -1,16 +0,0 @@
1
- import type { Locale } from "./schema"
2
-
3
- // Explicit locale → flag mapping
4
- export const FLAG_CODES = {
5
- en: "us-4x3",
6
- ja: "jp-4x3",
7
- de: "de-4x3",
8
- es: "es-4x3",
9
- pt: "br-4x3"
10
- } as const
11
-
12
- export type FlagCode = (typeof FLAG_CODES)[keyof typeof FLAG_CODES]
13
-
14
- export const localeToFlagCode = (locale: Locale): FlagCode | null => {
15
- return locale in FLAG_CODES ? FLAG_CODES[locale] : null
16
- }
@@ -1,90 +0,0 @@
1
- // Sanitizer: Turns <script> into &lt;script&gt;
2
- function escapeHtml(unsafe: string | number): string {
3
- return String(unsafe)
4
- .replace(/&/g, "&amp;")
5
- .replace(/</g, "&lt;")
6
- .replace(/>/g, "&gt;")
7
- .replace(/"/g, "&quot;")
8
- .replace(/'/g, "&#039;")
9
- }
10
-
11
- type TemplateValues = Record<string, string | number>
12
-
13
- /**
14
- * Interpolates {placeholders} in a template string and escapes values. - If `template` is
15
- * undefined/null, returns an empty string (and logs in dev). - If `values` is undefined, returns
16
- * the template unchanged.
17
- */
18
- export function fmt(template: string | null | undefined, values?: TemplateValues): string {
19
- if (template == null) {
20
- if (!import.meta.env.PROD) {
21
- console.warn("[i18n] fmt() called with null/undefined template")
22
- }
23
- return ""
24
- }
25
-
26
- if (!values) return template
27
-
28
- return template.replace(/\{([^}]+)\}/g, (match, key) => {
29
- const replacement = values[key]
30
-
31
- if (replacement === undefined || replacement === null) {
32
- return match
33
- }
34
-
35
- return escapeHtml(replacement)
36
- })
37
- }
38
-
39
- /**
40
- * Simple two-form plural helper. Good for English-like languages where "1" vs "other" is enough.
41
- */
42
- export function plural(count: number, singular: string, pluralForm: string): string {
43
- return count === 1 ? singular : fmt(pluralForm, { count })
44
- }
45
-
46
- /**
47
- * ICU-style plural categories used by Intl.PluralRules.
48
- */
49
- export type PluralCategory = "zero" | "one" | "two" | "few" | "many" | "other"
50
-
51
- export type PluralPatterns = Partial<Record<PluralCategory, string>>
52
-
53
- /**
54
- * Advanced plural helper using Intl.PluralRules + fmt().
55
- *
56
- * - `locale` controls plural categories (en, de, es, ja, ...).
57
- * - `patterns` comes from KV (e.g. { zero, one, other }).
58
- * - Missing categories fall back to `other`.
59
- *
60
- * Example: pluralIcu(5, 'en', { zero: 'No items', one: '{count} item', other: '{count} items' })
61
- */
62
- export function pluralIcu(count: number, locale: string, patterns: PluralPatterns): string {
63
- const rules = new Intl.PluralRules(locale)
64
- const cat = rules.select(count) as PluralCategory
65
-
66
- const template =
67
- patterns[cat] ??
68
- patterns.other ??
69
- (import.meta.env.PROD ? "" : (console.warn('[i18n] pluralIcu(): missing "other" pattern'), ""))
70
-
71
- return fmt(template, { count })
72
- }
73
-
74
- // Used in the LanguageSwitcher and SeoHreflangs components
75
- export function replaceLocaleInPath(
76
- currentPath: string,
77
- currentLocale: string,
78
- newLocale: string
79
- ): string {
80
- const prefixRegex = new RegExp(`^/${currentLocale}/`)
81
- return currentPath.replace(prefixRegex, `/${newLocale}/`)
82
- }
83
-
84
- // Used in the LanguageSwitcher component
85
- export function getLangFromUrl(pathname: string) {
86
- // Remove leading/trailing slashes: '/en/about/' -> 'en/about'
87
- const cleaned = pathname.replace(/^\/+|\/+$/g, "")
88
- const [lang] = cleaned.split("/")
89
- return lang
90
- }