a tool for shared writing and social publishing

add useLocalizedDate hook

+57
+18
package-lock.json
··· 48 48 "ioredis": "^5.6.1", 49 49 "katex": "^0.16.22", 50 50 "linkifyjs": "^4.2.0", 51 + "luxon": "^3.7.2", 51 52 "multiformats": "^13.3.2", 52 53 "next": "^15.5.3", 53 54 "pg": "^8.16.3", ··· 88 89 "@cloudflare/workers-types": "^4.20240512.0", 89 90 "@tailwindcss/postcss": "^4.1.13", 90 91 "@types/katex": "^0.16.7", 92 + "@types/luxon": "^3.7.1", 91 93 "@types/node": "^22.15.17", 92 94 "@types/react": "19.1.3", 93 95 "@types/react-dom": "19.1.3", ··· 6614 6616 "license": "MIT", 6615 6617 "peer": true 6616 6618 }, 6619 + "node_modules/@types/luxon": { 6620 + "version": "3.7.1", 6621 + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", 6622 + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", 6623 + "dev": true, 6624 + "license": "MIT" 6625 + }, 6617 6626 "node_modules/@types/markdown-it": { 6618 6627 "version": "14.1.2", 6619 6628 "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", ··· 12262 12271 "dev": true, 12263 12272 "dependencies": { 12264 12273 "es5-ext": "~0.10.2" 12274 + } 12275 + }, 12276 + "node_modules/luxon": { 12277 + "version": "3.7.2", 12278 + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", 12279 + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", 12280 + "license": "MIT", 12281 + "engines": { 12282 + "node": ">=12" 12265 12283 } 12266 12284 }, 12267 12285 "node_modules/magic-string": {
+2
package.json
··· 58 58 "ioredis": "^5.6.1", 59 59 "katex": "^0.16.22", 60 60 "linkifyjs": "^4.2.0", 61 + "luxon": "^3.7.2", 61 62 "multiformats": "^13.3.2", 62 63 "next": "^15.5.3", 63 64 "pg": "^8.16.3", ··· 98 99 "@cloudflare/workers-types": "^4.20240512.0", 99 100 "@tailwindcss/postcss": "^4.1.13", 100 101 "@types/katex": "^0.16.7", 102 + "@types/luxon": "^3.7.1", 101 103 "@types/node": "^22.15.17", 102 104 "@types/react": "19.1.3", 103 105 "@types/react-dom": "19.1.3",
+37
src/hooks/useLocalizedDate.ts
··· 1 + "use client"; 2 + import { useContext, useMemo } from "react"; 3 + import { DateTime } from "luxon"; 4 + import { RequestHeadersContext } from "components/Providers/RequestHeadersProvider"; 5 + 6 + /** 7 + * Hook that formats a date string using Luxon with timezone and locale from request headers. 8 + * 9 + * @param dateString - ISO date string to format 10 + * @param options - Intl.DateTimeFormatOptions for formatting 11 + * @returns Formatted date string 12 + * 13 + * @example 14 + * const formatted = useLocalizedDate("2024-01-15T10:30:00Z", { dateStyle: 'full', timeStyle: 'short' }); 15 + */ 16 + export function useLocalizedDate( 17 + dateString: string, 18 + options?: Intl.DateTimeFormatOptions, 19 + ): string { 20 + const { timezone, language } = useContext(RequestHeadersContext); 21 + 22 + return useMemo(() => { 23 + // Parse the date string to Luxon DateTime 24 + let dateTime = DateTime.fromISO(dateString); 25 + 26 + // Apply timezone if available 27 + if (timezone) { 28 + dateTime = dateTime.setZone(timezone); 29 + } 30 + 31 + // Parse locale from accept-language header (take first locale) 32 + // accept-language format: "en-US,en;q=0.9,es;q=0.8" 33 + const locale = language?.split(",")[0]?.split(";")[0]?.trim() || "en-US"; 34 + 35 + return dateTime.toLocaleString(options, { locale }); 36 + }, [dateString, options, timezone, language]); 37 + }