From 546e8d56f2fed06ce84451f033a90f0ffc1487bd Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 23 Jul 2026 20:25:41 +0700 Subject: [PATCH] refactor: convert typescript sources to javascript with jsdoc - rewrite lib, routes, and vite config as js with jsdoc type annotations - replace tsconfig with jsconfig and point svelte-check at it - drop typescript-eslint from eslint config and dev dependencies - resolve nav hrefs in template to satisfy svelte navigation lint rule - add gitattributes forcing lf so prettier and autocrlf stop conflicting --- .gitattributes | 4 + README.md | 2 +- eslint.config.js | 19 +- tsconfig.json => jsconfig.json | 1 - package.json | 5 +- pnpm-lock.yaml | 184 +----------------- src/lib/i18n/{en.ts => en.js} | 10 +- src/lib/i18n/index.js | 39 ++++ src/lib/i18n/index.ts | 21 -- .../i18n/{preferences.ts => preferences.js} | 44 +++-- src/lib/i18n/types.js | 84 ++++++++ src/lib/i18n/types.ts | 80 -------- src/lib/i18n/{vi.ts => vi.js} | 10 +- src/lib/{index.ts => index.js} | 0 src/routes/{+layout.ts => +layout.js} | 0 src/routes/+layout.svelte | 24 +-- src/routes/+page.svelte | 2 +- src/routes/cv/+page.svelte | 2 +- src/routes/jd/+page.svelte | 2 +- vite.config.ts => vite.config.js | 5 +- 20 files changed, 193 insertions(+), 345 deletions(-) create mode 100644 .gitattributes rename tsconfig.json => jsconfig.json (93%) rename src/lib/i18n/{en.ts => en.js} (96%) create mode 100644 src/lib/i18n/index.js delete mode 100644 src/lib/i18n/index.ts rename src/lib/i18n/{preferences.ts => preferences.js} (62%) create mode 100644 src/lib/i18n/types.js delete mode 100644 src/lib/i18n/types.ts rename src/lib/i18n/{vi.ts => vi.js} (97%) rename src/lib/{index.ts => index.js} (100%) rename src/routes/{+layout.ts => +layout.js} (100%) rename vite.config.ts => vite.config.js (87%) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..28b6f13 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf +*.png binary +*.webp binary +*.ico binary diff --git a/README.md b/README.md index b2e96ef..4860576 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Warm-witty dating JD and CV site for Tiến Nguyễn Minh. - SvelteKit 2 - Svelte 5 -- TypeScript +- JavaScript with JSDoc type checking - `@sveltejs/adapter-static` - GitHub Pages diff --git a/eslint.config.js b/eslint.config.js index ed35999..4f14b1c 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,34 +4,17 @@ import js from '@eslint/js'; import svelte from 'eslint-plugin-svelte'; import { defineConfig, includeIgnoreFile } from 'eslint/config'; import globals from 'globals'; -import ts from 'typescript-eslint'; const gitignorePath = path.resolve(import.meta.dirname, '.gitignore'); export default defineConfig( includeIgnoreFile(gitignorePath), js.configs.recommended, - ts.configs.recommended, svelte.configs.recommended, prettier, svelte.configs.prettier, { - languageOptions: { globals: { ...globals.browser, ...globals.node } }, - rules: { - // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. - // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors - 'no-undef': 'off' - } - }, - { - files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], - languageOptions: { - parserOptions: { - projectService: true, - extraFileExtensions: ['.svelte'], - parser: ts.parser - } - } + languageOptions: { globals: { ...globals.browser, ...globals.node } } }, { // Override or add rule settings here, such as: diff --git a/tsconfig.json b/jsconfig.json similarity index 93% rename from tsconfig.json rename to jsconfig.json index 2c2ed3c..a5567ee 100644 --- a/tsconfig.json +++ b/jsconfig.json @@ -1,7 +1,6 @@ { "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { - "rewriteRelativeImportExtensions": true, "allowJs": true, "checkJs": true, "esModuleInterop": true, diff --git a/package.json b/package.json index 00e89e2..c6a53d8 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "build:gh": "BUILD_PROFILE=gh vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", "lint": "prettier --check . && eslint .", "format": "prettier --write ." }, @@ -30,7 +30,6 @@ "svelte": "^5.56.1", "svelte-check": "^4.6.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.60.1", "vite": "^8.0.16" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ff5210..e4b4d47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,9 +53,6 @@ importers: typescript: specifier: ^6.0.3 version: 6.0.3 - typescript-eslint: - specifier: ^8.60.1 - version: 8.61.1(eslint@10.5.0)(typescript@6.0.3) vite: specifier: ^8.0.16 version: 8.0.16(@types/node@24.13.2) @@ -317,65 +314,10 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.61.1': - resolution: {integrity: sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.61.1 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.61.1': - resolution: {integrity: sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.61.1': - resolution: {integrity: sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.61.1': - resolution: {integrity: sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.61.1': - resolution: {integrity: sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.61.1': - resolution: {integrity: sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.61.1': resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.61.1': - resolution: {integrity: sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.61.1': - resolution: {integrity: sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.61.1': - resolution: {integrity: sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -588,10 +530,6 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -893,12 +831,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -906,13 +838,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.61.1: - resolution: {integrity: sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} @@ -1207,96 +1132,8 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.61.1 - '@typescript-eslint/type-utils': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.61.1 - eslint: 10.5.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@6.0.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.61.1 - '@typescript-eslint/types': 8.61.1 - '@typescript-eslint/typescript-estree': 8.61.1(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.61.1 - debug: 4.4.3 - eslint: 10.5.0 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.61.1(typescript@6.0.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@6.0.3) - '@typescript-eslint/types': 8.61.1 - debug: 4.4.3 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.61.1': - dependencies: - '@typescript-eslint/types': 8.61.1 - '@typescript-eslint/visitor-keys': 8.61.1 - - '@typescript-eslint/tsconfig-utils@8.61.1(typescript@6.0.3)': - dependencies: - typescript: 6.0.3 - - '@typescript-eslint/type-utils@8.61.1(eslint@10.5.0)(typescript@6.0.3)': - dependencies: - '@typescript-eslint/types': 8.61.1 - '@typescript-eslint/typescript-estree': 8.61.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - debug: 4.4.3 - eslint: 10.5.0 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.61.1': {} - - '@typescript-eslint/typescript-estree@8.61.1(typescript@6.0.3)': - dependencies: - '@typescript-eslint/project-service': 8.61.1(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@6.0.3) - '@typescript-eslint/types': 8.61.1 - '@typescript-eslint/visitor-keys': 8.61.1 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.8.5 - tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@6.0.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) - '@typescript-eslint/scope-manager': 8.61.1 - '@typescript-eslint/types': 8.61.1 - '@typescript-eslint/typescript-estree': 8.61.1(typescript@6.0.3) - eslint: 10.5.0 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.61.1': - dependencies: - '@typescript-eslint/types': 8.61.1 - eslint-visitor-keys: 5.0.1 + '@typescript-eslint/types@8.61.1': + optional: true acorn-jsx@5.3.2(acorn@8.17.0): dependencies: @@ -1497,8 +1334,6 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.5: {} - imurmurhash@0.1.4: {} is-extglob@2.1.1: {} @@ -1769,10 +1604,6 @@ snapshots: totalist@3.0.1: {} - ts-api-utils@2.5.0(typescript@6.0.3): - dependencies: - typescript: 6.0.3 - tslib@2.8.1: optional: true @@ -1780,17 +1611,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.61.1(eslint@10.5.0)(typescript@6.0.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.61.1(@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.61.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@6.0.3) - eslint: 10.5.0 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - typescript@6.0.3: {} undici-types@7.18.2: {} diff --git a/src/lib/i18n/en.ts b/src/lib/i18n/en.js similarity index 96% rename from src/lib/i18n/en.ts rename to src/lib/i18n/en.js index 4358173..6a79611 100644 --- a/src/lib/i18n/en.ts +++ b/src/lib/i18n/en.js @@ -1,6 +1,5 @@ -import type { SiteCopy } from './types'; - -export const en: SiteCopy = { +/** @type {import('./types.js').SiteCopy} */ +export const en = { layout: { skipLink: 'Skip to content', brand: 'Dating JD & CV', @@ -119,7 +118,10 @@ export const en: SiteCopy = { ['Favorite team', 'T1 — Keria is the bias'], ['Lifestyle', 'Homebody, computer enthusiast, and careful spender'], ['Pets', 'Not really a pet person'], - ['Spiritual side', 'Year of the Cat 🐱; compatible with Monkey 🐒, Tiger 🐯, Snake 🐍, Horse 🐴, Pig 🐷, Dragon 🐉, and Dog 🐶'], + [ + 'Spiritual side', + 'Year of the Cat 🐱; compatible with Monkey 🐒, Tiger 🐯, Snake 🐍, Horse 🐴, Pig 🐷, Dragon 🐉, and Dog 🐶' + ], ['Private note', 'A little naughty, with a particular fondness for beautiful feet'] ], closingEyebrow: 'Closing statement', diff --git a/src/lib/i18n/index.js b/src/lib/i18n/index.js new file mode 100644 index 0000000..638fcf2 --- /dev/null +++ b/src/lib/i18n/index.js @@ -0,0 +1,39 @@ +import { en } from './en.js'; +import { vi } from './vi.js'; +import { localeOptions, themeOptions } from './types.js'; + +export * from './types.js'; + +/** @typedef {import('./types.js').Locale} Locale */ +/** @typedef {import('./types.js').Theme} Theme */ +/** @typedef {import('./types.js').CopyFact} CopyFact */ +/** @typedef {import('./types.js').CopyStrength} CopyStrength */ +/** @typedef {import('./types.js').SiteCopy} SiteCopy */ + +/** @type {Locale} */ +export const defaultLocale = 'vi'; + +/** @type {Theme} */ +export const defaultTheme = 'light'; + +/** @satisfies {Record} */ +export const messages = { + en, + vi +}; + +/** + * @param {string | null} value + * @returns {value is Locale} + */ +export function isLocale(value) { + return localeOptions.includes(/** @type {Locale} */ (value)); +} + +/** + * @param {string | null} value + * @returns {value is Theme} + */ +export function isTheme(value) { + return themeOptions.includes(/** @type {Theme} */ (value)); +} diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts deleted file mode 100644 index ca0c6fc..0000000 --- a/src/lib/i18n/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { en } from './en'; -import { vi } from './vi'; -import { localeOptions, themeOptions, type Locale, type SiteCopy, type Theme } from './types'; - -export * from './types'; - -export const defaultLocale: Locale = 'vi'; -export const defaultTheme: Theme = 'light'; - -export const messages = { - en, - vi -} satisfies Record; - -export function isLocale(value: string | null): value is Locale { - return localeOptions.includes(value as Locale); -} - -export function isTheme(value: string | null): value is Theme { - return themeOptions.includes(value as Theme); -} diff --git a/src/lib/i18n/preferences.ts b/src/lib/i18n/preferences.js similarity index 62% rename from src/lib/i18n/preferences.ts rename to src/lib/i18n/preferences.js index b0f1608..cad758a 100644 --- a/src/lib/i18n/preferences.ts +++ b/src/lib/i18n/preferences.js @@ -7,23 +7,29 @@ import { isTheme, localeOptions, messages, - themeOptions, - type Locale, - type Theme -} from './index'; + themeOptions +} from './index.js'; + +/** @typedef {import('./types.js').Locale} Locale */ +/** @typedef {import('./types.js').Theme} Theme */ const localeStorageKey = 'dating-locale'; const themeStorageKey = 'dating-theme'; export { localeOptions, themeOptions }; -export const locale = writable(defaultLocale); -export const theme = writable(defaultTheme); +/** @type {import('svelte/store').Writable} */ +export const locale = writable(defaultLocale); + +/** @type {import('svelte/store').Writable} */ +export const theme = writable(defaultTheme); + export const copy = derived(locale, ($locale) => messages[$locale]); let preferencesStarted = false; -function readStoredLocale(): Locale { +/** @returns {Locale} */ +function readStoredLocale() { if (!browser) return defaultLocale; const storedLocale = readStorage(localeStorageKey); @@ -32,14 +38,16 @@ function readStoredLocale(): Locale { return defaultLocale; } -function readStoredTheme(): Theme { +/** @returns {Theme} */ +function readStoredTheme() { if (!browser) return defaultTheme; const storedTheme = readStorage(themeStorageKey); return isTheme(storedTheme) ? storedTheme : defaultTheme; } -function readStorage(key: string) { +/** @param {string} key */ +function readStorage(key) { try { return localStorage.getItem(key); } catch { @@ -47,7 +55,11 @@ function readStorage(key: string) { } } -function writeStorage(key: string, value: string) { +/** + * @param {string} key + * @param {string} value + */ +function writeStorage(key, value) { try { localStorage.setItem(key, value); } catch { @@ -55,12 +67,14 @@ function writeStorage(key: string, value: string) { } } -function applyLocale(nextLocale: Locale) { +/** @param {Locale} nextLocale */ +function applyLocale(nextLocale) { document.documentElement.lang = nextLocale; writeStorage(localeStorageKey, nextLocale); } -function applyTheme(nextTheme: Theme) { +/** @param {Theme} nextTheme */ +function applyTheme(nextTheme) { document.documentElement.dataset.theme = nextTheme; document.documentElement.style.colorScheme = nextTheme; writeStorage(themeStorageKey, nextTheme); @@ -77,10 +91,12 @@ export function initializePreferences() { theme.subscribe(applyTheme); } -export function setLocale(nextLocale: Locale) { +/** @param {Locale} nextLocale */ +export function setLocale(nextLocale) { locale.set(nextLocale); } -export function setTheme(nextTheme: Theme) { +/** @param {Theme} nextTheme */ +export function setTheme(nextTheme) { theme.set(nextTheme); } diff --git a/src/lib/i18n/types.js b/src/lib/i18n/types.js new file mode 100644 index 0000000..98bf455 --- /dev/null +++ b/src/lib/i18n/types.js @@ -0,0 +1,84 @@ +export const localeOptions = /** @type {const} */ (['vi', 'en']); +/** @typedef {(typeof localeOptions)[number]} Locale */ + +export const themeOptions = /** @type {const} */ (['light', 'dark']); +/** @typedef {(typeof themeOptions)[number]} Theme */ + +/** @typedef {readonly [label: string, value: string]} CopyFact */ + +/** + * @typedef {object} CopyStrength + * @property {string} title + * @property {string} body + */ + +/** + * @typedef {object} SiteCopy + * @property {{ + * skipLink: string, + * brand: string, + * homeAria: string, + * primaryNavAria: string + * }} layout + * @property {Record<'home' | 'jd' | 'cv', string>} nav + * @property {{ + * themeGroup: string, + * languageGroup: string, + * themeActions: Record, + * languageActions: Record + * }} controls + * @property {{ + * metaTitle: string, + * metaDescription: string, + * heroEyebrow: string, + * title: string, + * lead: string, + * primaryCta: string, + * secondaryCta: string, + * packetEyebrow: string, + * packetTitle: string, + * futureLoverTitle: string, + * futureLoverBody: string, + * committeeTitle: string, + * committeeBody: string + * }} home + * @property {{ + * metaTitle: string, + * metaDescription: string, + * heroEyebrow: string, + * title: string, + * lead: string, + * summaryAria: string, + * summary: CopyFact[], + * benefitsEyebrow: string, + * benefitsTitle: string, + * benefits: string[], + * responsibilitiesEyebrow: string, + * responsibilitiesTitle: string, + * responsibilities: string[], + * niceEyebrow: string, + * processTitle: string, + * niceToHave: string[], + * selectionTitle: string, + * selectionBody: string + * }} jd + * @property {{ + * metaTitle: string, + * metaDescription: string, + * heroEyebrow: string, + * title: string, + * lead: string, + * summaryAria: string, + * strengthsEyebrow: string, + * strengthsTitle: string, + * strengths: CopyStrength[], + * factsEyebrow: string, + * factsTitle: string, + * facts: CopyFact[], + * closingEyebrow: string, + * closingTitle: string, + * closingBody: string + * }} cv + */ + +export {}; diff --git a/src/lib/i18n/types.ts b/src/lib/i18n/types.ts deleted file mode 100644 index 92fc321..0000000 --- a/src/lib/i18n/types.ts +++ /dev/null @@ -1,80 +0,0 @@ -export const localeOptions = ['vi', 'en'] as const; -export type Locale = (typeof localeOptions)[number]; - -export const themeOptions = ['light', 'dark'] as const; -export type Theme = (typeof themeOptions)[number]; - -export type CopyFact = readonly [label: string, value: string]; - -export type CopyStrength = { - title: string; - body: string; -}; - -export type SiteCopy = { - layout: { - skipLink: string; - brand: string; - homeAria: string; - primaryNavAria: string; - }; - nav: Record<'home' | 'jd' | 'cv', string>; - controls: { - themeGroup: string; - languageGroup: string; - themeActions: Record; - languageActions: Record; - }; - home: { - metaTitle: string; - metaDescription: string; - heroEyebrow: string; - title: string; - lead: string; - primaryCta: string; - secondaryCta: string; - packetEyebrow: string; - packetTitle: string; - futureLoverTitle: string; - futureLoverBody: string; - committeeTitle: string; - committeeBody: string; - }; - jd: { - metaTitle: string; - metaDescription: string; - heroEyebrow: string; - title: string; - lead: string; - summaryAria: string; - summary: CopyFact[]; - benefitsEyebrow: string; - benefitsTitle: string; - benefits: string[]; - responsibilitiesEyebrow: string; - responsibilitiesTitle: string; - responsibilities: string[]; - niceEyebrow: string; - processTitle: string; - niceToHave: string[]; - selectionTitle: string; - selectionBody: string; - }; - cv: { - metaTitle: string; - metaDescription: string; - heroEyebrow: string; - title: string; - lead: string; - summaryAria: string; - strengthsEyebrow: string; - strengthsTitle: string; - strengths: CopyStrength[]; - factsEyebrow: string; - factsTitle: string; - facts: CopyFact[]; - closingEyebrow: string; - closingTitle: string; - closingBody: string; - }; -}; diff --git a/src/lib/i18n/vi.ts b/src/lib/i18n/vi.js similarity index 97% rename from src/lib/i18n/vi.ts rename to src/lib/i18n/vi.js index e17f9a5..86ff2a6 100644 --- a/src/lib/i18n/vi.ts +++ b/src/lib/i18n/vi.js @@ -1,6 +1,5 @@ -import type { SiteCopy } from './types'; - -export const vi: SiteCopy = { +/** @type {import('./types.js').SiteCopy} */ +export const vi = { layout: { skipLink: 'Bỏ qua đến nội dung', brand: 'Mô tả & hồ sơ hẹn hò', @@ -118,7 +117,10 @@ export const vi: SiteCopy = { ['Đội tuyển yêu thích', 'T1 — bias Keria'], ['Lối sống', 'Ở nhà, mê máy tính và chi tiêu tiết kiệm'], ['Thú cưng', 'Không hợp lắm'], - ['Tâm linh', 'Tuổi Mão 🐱; hợp tuổi Thân 🐒, Dần 🐯, Tỵ 🐍, Ngọ 🐴, Hợi 🐷, Thìn 🐉 và Tuất 🐶'], + [ + 'Tâm linh', + 'Tuổi Mão 🐱; hợp tuổi Thân 🐒, Dần 🐯, Tỵ 🐍, Ngọ 🐴, Hợi 🐷, Thìn 🐉 và Tuất 🐶' + ], ['Góc riêng tư', 'Hơi tà răm; có thiện cảm đặc biệt với đôi chân đẹp'] ], closingEyebrow: 'Lời kết', diff --git a/src/lib/index.ts b/src/lib/index.js similarity index 100% rename from src/lib/index.ts rename to src/lib/index.js diff --git a/src/routes/+layout.ts b/src/routes/+layout.js similarity index 100% rename from src/routes/+layout.ts rename to src/routes/+layout.js diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d135a66..885e5bc 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,4 +1,4 @@ - @@ -64,9 +64,9 @@