@rimelight/ui 0.0.4 → 0.0.6

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 (310) hide show
  1. package/package.json +36 -6
  2. package/src/components/BlogPost.astro +181 -0
  3. package/src/components/DynamicShowcase.astro +681 -0
  4. package/src/components/ExtendedCarousel.astro +107 -0
  5. package/src/components/Head.astro +150 -0
  6. package/src/components/LanguageSwitcher.astro +128 -0
  7. package/src/components/ProjectPost.astro +183 -0
  8. package/src/components/RLHead.astro +3 -0
  9. package/src/components/ThemeToggle.astro +30 -42
  10. package/src/components/astro/RLAButton.astro +85 -0
  11. package/src/components/astro/RLAHeader.astro +75 -0
  12. package/src/components/vue/RLVButton.vue +90 -0
  13. package/src/components/vue/RLVHeader.vue +78 -0
  14. package/src/composables/index.ts +1 -0
  15. package/src/composables/useUi.ts +27 -0
  16. package/src/config/index.ts +0 -2
  17. package/src/config/site.config.ts +1 -1
  18. package/src/env.d.ts +9 -42
  19. package/src/integrations/index.ts +2 -0
  20. package/src/integrations/ui.ts +87 -0
  21. package/src/themes/button.theme.ts +361 -0
  22. package/src/themes/header.theme.ts +33 -0
  23. package/src/themes/index.ts +13 -0
  24. package/src/utils/index.ts +3 -2
  25. package/i18n-data.json +0 -186
  26. package/src/components/accordion/Accordion.astro +0 -257
  27. package/src/components/accordion/AccordionContent.astro +0 -34
  28. package/src/components/accordion/AccordionItem.astro +0 -29
  29. package/src/components/accordion/AccordionTrigger.astro +0 -33
  30. package/src/components/alert/Alert.astro +0 -34
  31. package/src/components/alert/AlertDescription.astro +0 -15
  32. package/src/components/alert/AlertTitle.astro +0 -17
  33. package/src/components/alert-dialog/AlertDialog.astro +0 -275
  34. package/src/components/alert-dialog/AlertDialogAction.astro +0 -46
  35. package/src/components/alert-dialog/AlertDialogCancel.astro +0 -46
  36. package/src/components/alert-dialog/AlertDialogContent.astro +0 -52
  37. package/src/components/alert-dialog/AlertDialogDescription.astro +0 -18
  38. package/src/components/alert-dialog/AlertDialogFooter.astro +0 -16
  39. package/src/components/alert-dialog/AlertDialogHeader.astro +0 -14
  40. package/src/components/alert-dialog/AlertDialogTitle.astro +0 -20
  41. package/src/components/alert-dialog/AlertDialogTrigger.astro +0 -47
  42. package/src/components/aspect-ratio/AspectRatio.astro +0 -32
  43. package/src/components/avatar/Avatar.astro +0 -29
  44. package/src/components/avatar/AvatarFallback.astro +0 -18
  45. package/src/components/avatar/AvatarImage.astro +0 -66
  46. package/src/components/badge/Badge.astro +0 -57
  47. package/src/components/breadcrumb/Breadcrumb.astro +0 -12
  48. package/src/components/breadcrumb/BreadcrumbEllipsis.astro +0 -29
  49. package/src/components/breadcrumb/BreadcrumbItem.astro +0 -15
  50. package/src/components/breadcrumb/BreadcrumbLink.astro +0 -24
  51. package/src/components/breadcrumb/BreadcrumbList.astro +0 -17
  52. package/src/components/breadcrumb/BreadcrumbPage.astro +0 -22
  53. package/src/components/breadcrumb/BreadcrumbSeparator.astro +0 -24
  54. package/src/components/button/Button.astro +0 -58
  55. package/src/components/button-group/ButtonGroup.astro +0 -64
  56. package/src/components/button-group/ButtonGroupSeparator.astro +0 -20
  57. package/src/components/button-group/ButtonGroupText.astro +0 -19
  58. package/src/components/card/Card.astro +0 -36
  59. package/src/components/card/CardAction.astro +0 -16
  60. package/src/components/card/CardContent.astro +0 -16
  61. package/src/components/card/CardDescription.astro +0 -16
  62. package/src/components/card/CardFooter.astro +0 -16
  63. package/src/components/card/CardHeader.astro +0 -19
  64. package/src/components/card/CardTitle.astro +0 -16
  65. package/src/components/carousel/Carousel.astro +0 -55
  66. package/src/components/carousel/CarouselContent.astro +0 -26
  67. package/src/components/carousel/CarouselItem.astro +0 -26
  68. package/src/components/carousel/CarouselNext.astro +0 -39
  69. package/src/components/carousel/CarouselPrevious.astro +0 -41
  70. package/src/components/carousel/carousel-script.ts +0 -188
  71. package/src/components/carousel/index.ts +0 -1
  72. package/src/components/checkbox/Checkbox.astro +0 -133
  73. package/src/components/collapsible/Collapsible.astro +0 -161
  74. package/src/components/collapsible/CollapsibleContent.astro +0 -22
  75. package/src/components/collapsible/CollapsibleTrigger.astro +0 -44
  76. package/src/components/dialog/Dialog.astro +0 -389
  77. package/src/components/dialog/DialogClose.astro +0 -35
  78. package/src/components/dialog/DialogContent.astro +0 -78
  79. package/src/components/dialog/DialogDescription.astro +0 -14
  80. package/src/components/dialog/DialogFooter.astro +0 -14
  81. package/src/components/dialog/DialogHeader.astro +0 -14
  82. package/src/components/dialog/DialogTitle.astro +0 -18
  83. package/src/components/dialog/DialogTrigger.astro +0 -47
  84. package/src/components/dropdown/Dropdown.astro +0 -604
  85. package/src/components/dropdown/DropdownContent.astro +0 -118
  86. package/src/components/dropdown/DropdownItem.astro +0 -48
  87. package/src/components/dropdown/DropdownLabel.astro +0 -29
  88. package/src/components/dropdown/DropdownSeparator.astro +0 -21
  89. package/src/components/dropdown/DropdownShortcut.astro +0 -17
  90. package/src/components/dropdown/DropdownSub.astro +0 -15
  91. package/src/components/dropdown/DropdownSubContent.astro +0 -39
  92. package/src/components/dropdown/DropdownSubTrigger.astro +0 -34
  93. package/src/components/dropdown/DropdownTrigger.astro +0 -52
  94. package/src/components/dropzone/Dropzone.astro +0 -236
  95. package/src/components/dropzone/DropzoneFilesList.astro +0 -26
  96. package/src/components/dropzone/DropzoneLoadingIndicator.astro +0 -10
  97. package/src/components/dropzone/DropzoneUploadIndicator.astro +0 -10
  98. package/src/components/embeds/YoutubeEmbed.astro +0 -94
  99. package/src/components/hero/Hero.astro +0 -166
  100. package/src/components/icons/Flag.astro +0 -62
  101. package/src/components/image/ExtendedImage.astro +0 -46
  102. package/src/components/image/Image.astro +0 -25
  103. package/src/components/input/Input.astro +0 -27
  104. package/src/components/input-group/InputGroup.astro +0 -28
  105. package/src/components/input-group/InputGroupAddon.astro +0 -76
  106. package/src/components/input-group/InputGroupButton.astro +0 -36
  107. package/src/components/input-group/InputGroupInput.astro +0 -18
  108. package/src/components/input-group/InputGroupText.astro +0 -17
  109. package/src/components/input-group/InputGroupTextarea.astro +0 -22
  110. package/src/components/input-otp/InputOtp.astro +0 -352
  111. package/src/components/input-otp/InputOtpGroup.astro +0 -16
  112. package/src/components/input-otp/InputOtpSeparator.astro +0 -25
  113. package/src/components/input-otp/InputOtpSlot.astro +0 -50
  114. package/src/components/input-otp/InputOtpTypes.ts +0 -6
  115. package/src/components/item/Item.astro +0 -52
  116. package/src/components/item/ItemActions.astro +0 -16
  117. package/src/components/item/ItemContent.astro +0 -16
  118. package/src/components/item/ItemDescription.astro +0 -19
  119. package/src/components/item/ItemFooter.astro +0 -16
  120. package/src/components/item/ItemGroup.astro +0 -16
  121. package/src/components/item/ItemHeader.astro +0 -16
  122. package/src/components/item/ItemMedia.astro +0 -40
  123. package/src/components/item/ItemSeparator.astro +0 -23
  124. package/src/components/item/ItemTitle.astro +0 -16
  125. package/src/components/kbd/Kbd.astro +0 -21
  126. package/src/components/kbd/KbdGroup.astro +0 -16
  127. package/src/components/label/Label.astro +0 -24
  128. package/src/components/marquee/Marquee.astro +0 -73
  129. package/src/components/native-select/NativeSelect.astro +0 -68
  130. package/src/components/native-select/NativeSelectOptGroup.astro +0 -15
  131. package/src/components/native-select/NativeSelectOption.astro +0 -15
  132. package/src/components/pagination/Pagination.astro +0 -20
  133. package/src/components/pagination/PaginationContent.astro +0 -16
  134. package/src/components/pagination/PaginationEllipsis.astro +0 -37
  135. package/src/components/pagination/PaginationItem.astro +0 -16
  136. package/src/components/pagination/PaginationLink.astro +0 -27
  137. package/src/components/pagination/PaginationNext.astro +0 -33
  138. package/src/components/pagination/PaginationPrevious.astro +0 -33
  139. package/src/components/popover/Popover.astro +0 -717
  140. package/src/components/popover/PopoverContent.astro +0 -102
  141. package/src/components/popover/PopoverDescription.astro +0 -14
  142. package/src/components/popover/PopoverHeader.astro +0 -14
  143. package/src/components/popover/PopoverTitle.astro +0 -14
  144. package/src/components/popover/PopoverTrigger.astro +0 -51
  145. package/src/components/progress/Progress.astro +0 -154
  146. package/src/components/prose/Prose.astro +0 -619
  147. package/src/components/radio-group/RadioGroup.astro +0 -162
  148. package/src/components/radio-group/RadioGroupItem.astro +0 -133
  149. package/src/components/radio-group/RadioGroupTypes.ts +0 -6
  150. package/src/components/section/Section.astro +0 -167
  151. package/src/components/select/Select.astro +0 -752
  152. package/src/components/select/SelectContent.astro +0 -94
  153. package/src/components/select/SelectGroup.astro +0 -9
  154. package/src/components/select/SelectItem.astro +0 -51
  155. package/src/components/select/SelectLabel.astro +0 -14
  156. package/src/components/select/SelectSearch.astro +0 -49
  157. package/src/components/select/SelectSeparator.astro +0 -12
  158. package/src/components/select/SelectTrigger.astro +0 -56
  159. package/src/components/select/SelectTypes.ts +0 -13
  160. package/src/components/select/SelectValue.astro +0 -19
  161. package/src/components/separator/Separator.astro +0 -36
  162. package/src/components/sheet/Sheet.astro +0 -15
  163. package/src/components/sheet/SheetClose.astro +0 -15
  164. package/src/components/sheet/SheetContent.astro +0 -89
  165. package/src/components/sheet/SheetDescription.astro +0 -16
  166. package/src/components/sheet/SheetFooter.astro +0 -16
  167. package/src/components/sheet/SheetHeader.astro +0 -16
  168. package/src/components/sheet/SheetTitle.astro +0 -16
  169. package/src/components/sheet/SheetTrigger.astro +0 -15
  170. package/src/components/sidebar/Sidebar.astro +0 -231
  171. package/src/components/sidebar/SidebarContent.astro +0 -25
  172. package/src/components/sidebar/SidebarFooter.astro +0 -22
  173. package/src/components/sidebar/SidebarGroup.astro +0 -22
  174. package/src/components/sidebar/SidebarGroupContent.astro +0 -22
  175. package/src/components/sidebar/SidebarGroupLabel.astro +0 -53
  176. package/src/components/sidebar/SidebarHeader.astro +0 -22
  177. package/src/components/sidebar/SidebarInput.astro +0 -24
  178. package/src/components/sidebar/SidebarInset.astro +0 -22
  179. package/src/components/sidebar/SidebarMenu.astro +0 -22
  180. package/src/components/sidebar/SidebarMenuAction.astro +0 -63
  181. package/src/components/sidebar/SidebarMenuBadge.astro +0 -31
  182. package/src/components/sidebar/SidebarMenuButton.astro +0 -124
  183. package/src/components/sidebar/SidebarMenuItem.astro +0 -22
  184. package/src/components/sidebar/SidebarMenuSkeleton.astro +0 -43
  185. package/src/components/sidebar/SidebarMenuSub.astro +0 -25
  186. package/src/components/sidebar/SidebarMenuSubButton.astro +0 -52
  187. package/src/components/sidebar/SidebarMenuSubItem.astro +0 -17
  188. package/src/components/sidebar/SidebarProvider.astro +0 -215
  189. package/src/components/sidebar/SidebarRail.astro +0 -72
  190. package/src/components/sidebar/SidebarSeparator.astro +0 -25
  191. package/src/components/sidebar/SidebarTrigger.astro +0 -69
  192. package/src/components/skeleton/Skeleton.astro +0 -14
  193. package/src/components/slider/Slider.astro +0 -425
  194. package/src/components/spinner/Spinner.astro +0 -23
  195. package/src/components/switch/Switch.astro +0 -192
  196. package/src/components/switch/SwitchTypes.ts +0 -6
  197. package/src/components/table/Table.astro +0 -20
  198. package/src/components/table/TableBody.astro +0 -18
  199. package/src/components/table/TableCaption.astro +0 -18
  200. package/src/components/table/TableCell.astro +0 -18
  201. package/src/components/table/TableFoot.astro +0 -18
  202. package/src/components/table/TableHead.astro +0 -18
  203. package/src/components/table/TableHeader.astro +0 -18
  204. package/src/components/table/TableRow.astro +0 -17
  205. package/src/components/tabs/Tabs.astro +0 -270
  206. package/src/components/tabs/TabsContent.astro +0 -28
  207. package/src/components/tabs/TabsList.astro +0 -23
  208. package/src/components/tabs/TabsTrigger.astro +0 -34
  209. package/src/components/textarea/Textarea.astro +0 -31
  210. package/src/components/toast/ToastDescription.astro +0 -22
  211. package/src/components/toast/ToastItem.astro +0 -56
  212. package/src/components/toast/ToastTemplate.astro +0 -27
  213. package/src/components/toast/ToastTitle.astro +0 -59
  214. package/src/components/toast/Toaster.astro +0 -981
  215. package/src/components/toast/index.ts +0 -1
  216. package/src/components/toast/toast-manager.ts +0 -234
  217. package/src/components/toggle/Toggle.astro +0 -174
  218. package/src/components/toggle/ToggleTypes.ts +0 -14
  219. package/src/components/tooltip/Tooltip.astro +0 -422
  220. package/src/components/tooltip/TooltipContent.astro +0 -83
  221. package/src/components/tooltip/TooltipTrigger.astro +0 -13
  222. package/src/components/video/Video.astro +0 -121
  223. package/src/config/cookies.ts +0 -5
  224. package/src/config/links.ts +0 -4
  225. package/src/domain/cms/index.ts +0 -1
  226. package/src/domain/cms/types.ts +0 -20
  227. package/src/domain/i18n/constants.ts +0 -21
  228. package/src/domain/i18n/cookie-storage.ts +0 -13
  229. package/src/domain/i18n/country-to-locale-map.ts +0 -67
  230. package/src/domain/i18n/fallbacks.generated.ts +0 -230
  231. package/src/domain/i18n/fetcher.ts +0 -278
  232. package/src/domain/i18n/flags.ts +0 -16
  233. package/src/domain/i18n/format.ts +0 -90
  234. package/src/domain/i18n/index.ts +0 -10
  235. package/src/domain/i18n/middleware/i18n.ts +0 -161
  236. package/src/domain/i18n/resolve-locale.ts +0 -55
  237. package/src/domain/i18n/runtime-constants.ts +0 -14
  238. package/src/domain/i18n/schema.ts +0 -29
  239. package/src/domain/index.ts +0 -4
  240. package/src/domain/seo/constants.ts +0 -6
  241. package/src/domain/seo/index.ts +0 -3
  242. package/src/domain/seo/services/index.ts +0 -3
  243. package/src/domain/seo/services/llms.ts +0 -56
  244. package/src/domain/seo/services/robots.ts +0 -12
  245. package/src/domain/seo/services/sitemap.ts +0 -56
  246. package/src/domain/seo/utils.ts +0 -36
  247. package/src/domain/theme/constants.ts +0 -6
  248. package/src/domain/theme/index.ts +0 -2
  249. package/src/domain/theme/schema.ts +0 -10
  250. package/src/i18n.generated.d.ts +0 -202
  251. package/src/lib/component-preview.ts +0 -73
  252. package/src/lib/index.ts +0 -6
  253. package/src/lib/remark/remark-modified-time.ts +0 -13
  254. package/src/lib/showcase-preview-elements.ts +0 -408
  255. package/src/lib/showcase-renderer.ts +0 -218
  256. package/src/lib/showcase-utils.ts +0 -189
  257. package/src/lib/turnstile.ts +0 -35
  258. package/src/lib/utils/starwind/positioning.ts +0 -318
  259. package/src/locales/de/blog.json +0 -9
  260. package/src/locales/de/common.json +0 -19
  261. package/src/locales/de/errors.json +0 -6
  262. package/src/locales/de/home.json +0 -20
  263. package/src/locales/de/messages.json +0 -8
  264. package/src/locales/de/nav.json +0 -13
  265. package/src/locales/de/projects.json +0 -9
  266. package/src/locales/de/services.json +0 -43
  267. package/src/locales/en/blog.json +0 -9
  268. package/src/locales/en/chat.json +0 -29
  269. package/src/locales/en/common.json +0 -19
  270. package/src/locales/en/cookie_notice.json +0 -11
  271. package/src/locales/en/editor.json +0 -24
  272. package/src/locales/en/errors.json +0 -6
  273. package/src/locales/en/home.json +0 -20
  274. package/src/locales/en/messages.json +0 -8
  275. package/src/locales/en/nav.json +0 -13
  276. package/src/locales/en/projects.json +0 -9
  277. package/src/locales/en/services.json +0 -43
  278. package/src/locales/es/blog.json +0 -9
  279. package/src/locales/es/common.json +0 -19
  280. package/src/locales/es/errors.json +0 -6
  281. package/src/locales/es/home.json +0 -20
  282. package/src/locales/es/messages.json +0 -8
  283. package/src/locales/es/nav.json +0 -13
  284. package/src/locales/es/projects.json +0 -9
  285. package/src/locales/es/services.json +0 -43
  286. package/src/locales/ja/blog.json +0 -9
  287. package/src/locales/ja/common.json +0 -19
  288. package/src/locales/ja/errors.json +0 -6
  289. package/src/locales/ja/home.json +0 -20
  290. package/src/locales/ja/messages.json +0 -8
  291. package/src/locales/ja/nav.json +0 -13
  292. package/src/locales/ja/projects.json +0 -9
  293. package/src/locales/ja/services.json +0 -43
  294. package/src/locales/pt/blog.json +0 -9
  295. package/src/locales/pt/chat.json +0 -29
  296. package/src/locales/pt/common.json +0 -19
  297. package/src/locales/pt/cookie_notice.json +0 -11
  298. package/src/locales/pt/editor.json +0 -24
  299. package/src/locales/pt/errors.json +0 -6
  300. package/src/locales/pt/home.json +0 -20
  301. package/src/locales/pt/messages.json +0 -8
  302. package/src/locales/pt/nav.json +0 -13
  303. package/src/locales/pt/projects.json +0 -9
  304. package/src/locales/pt/services.json +0 -43
  305. package/src/utils/server/cookies.ts +0 -98
  306. package/src/utils/server/index.ts +0 -1
  307. package/src/utils/shared/index.ts +0 -3
  308. /package/src/utils/{shared/deep-merge.ts → deep-merge.ts} +0 -0
  309. /package/src/utils/{shared/embed.ts → embed.ts} +0 -0
  310. /package/src/utils/{shared/parse-boolean.ts → parse-boolean.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
- }