diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index 7d0f73959..11284832d 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -19,7 +19,7 @@ module.exports = { "**/dist/**", "**/__generated__/**", "**/coverage/**", - "!.storybook", + "!.storybook/locales.ts", "*/gql/*.ts", ], overrides: [ diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts new file mode 100644 index 000000000..9d51f3e6e --- /dev/null +++ b/frontend/.storybook/locales.ts @@ -0,0 +1,102 @@ +export type LocalazyLanguage = { + language: string; + region: string; + script: string; + isRtl: boolean; + localizedName: string; + name: string; + pluralType: (n: number) => "zero" | "one" | "two" | "many" | "few" | "other"; +}; +export type LocalazyFile = { + cdnHash: string; + file: string; + path: string; + library: string; + module: string; + buildType: string; + productFlavors: string[]; + cdnFiles: { [lang:string]: string }; +}; +export type LocalazyMetadata = { + projectUrl: string; + baseLocale: string; + languages: LocalazyLanguage[]; + files: LocalazyFile[]; +}; + +const localazyMetadata: LocalazyMetadata = { + projectUrl: "https://localazy.com/p/matrix-authentication-service", + baseLocale: "en", + languages: [ + { + language: "de", + region: "", + script: "", + isRtl: false, + name: "German", + localizedName: "Deutsch", + pluralType: (n) => { return (n===1) ? "one" : "other"; } + }, + { + language: "en", + region: "", + script: "", + isRtl: false, + name: "English", + localizedName: "English", + pluralType: (n) => { return (n===1) ? "one" : "other"; } + }, + { + language: "fr", + region: "", + script: "", + isRtl: false, + name: "French", + localizedName: "Français", + pluralType: (n) => { return (n===0 || n===1) ? "one" : "other"; } + }, + { + language: "zh", + region: "", + script: "Hans", + isRtl: false, + name: "Simplified Chinese", + localizedName: "简体中文", + pluralType: (n) => { return "other"; } + } + ], + files: [ + { + cdnHash: "7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2", + file: "frontend.json", + path: "", + library: "", + module: "", + buildType: "", + productFlavors: [], + cdnFiles: { + "de#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", + "en#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", + "fr#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" + } + }, + { + cdnHash: "5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e", + file: "file.json", + path: "", + library: "", + module: "", + buildType: "", + productFlavors: [], + cdnFiles: { + "de#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", + "en#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", + "fr#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" + } + } + ] +}; + +export default localazyMetadata; \ No newline at end of file diff --git a/frontend/.storybook/preview-head.html b/frontend/.storybook/preview-head.html index 05da1e9df..66d2626e7 100644 --- a/frontend/.storybook/preview-head.html +++ b/frontend/.storybook/preview-head.html @@ -1,3 +1,9 @@ \ No newline at end of file + + + diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx index f77e7cc8b..7e2106107 100644 --- a/frontend/.storybook/preview.tsx +++ b/frontend/.storybook/preview.tsx @@ -19,6 +19,8 @@ import { useLayoutEffect } from "react"; import "../src/main.css"; import i18n from "../src/i18n"; +import localazyMetadata from "./locales"; + export const parameters: Parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { @@ -29,39 +31,38 @@ export const parameters: Parameters = { }, }; -export const globalTypes: ArgTypes = { +export const globalTypes = { theme: { name: "Theme", + defaultValue: "system", description: "Global theme for components", - defaultValue: "light", toolbar: { icon: "circlehollow", title: "Theme", items: [ - { - title: "Light", - value: "light", - icon: "sun", - }, - { - title: "Dark", - value: "dark", - icon: "moon", - }, + { title: "System", value: "system", icon: "browser" }, + { title: "Light", value: "light", icon: "sun" }, + { title: "Light (high contrast)", value: "light-hc", icon: "sun" }, + { title: "Dark", value: "dark", icon: "moon" }, + { title: "Dark (high contrast)", value: "darkhc", icon: "moon" }, ], }, }, -}; +} satisfies ArgTypes; -const ThemeSwitcher: React.FC<{ theme?: "light" | "dark" }> = ({ theme }) => { +const allThemesClasses = globalTypes.theme.toolbar.items.map( + ({ value }) => `cpd-theme-${value}`, +); + +const ThemeSwitcher: React.FC<{ + theme: string; +}> = ({ theme }) => { useLayoutEffect(() => { - if (theme === "dark") { - document.documentElement.classList.add("cpd-theme-dark"); - } else { - document.documentElement.classList.remove("cpd-theme-dark"); + document.documentElement.classList.remove(...allThemesClasses); + if (theme !== "system") { + document.documentElement.classList.add(`cpd-theme-${theme}`); } - - return () => document.documentElement.classList.remove("cpd-theme-dark"); + return () => document.documentElement.classList.remove(...allThemesClasses); }, [theme]); return null; @@ -80,13 +81,17 @@ const withThemeProvider: Decorator = (Story, context) => { export const decorators: Decorator[] = [withThemeProvider]; +const locales = Object.fromEntries( + localazyMetadata.languages.map(({ language, name, localizedName }) => [ + language, + `${localizedName} (${name})`, + ]), +); + const preview: Preview = { globals: { - locale: "en", - locales: { - en: "English", - fr: "Français", - }, + locale: localazyMetadata.baseLocale, + locales, }, parameters: { i18n, diff --git a/localazy.json b/localazy.json index a9d46b293..a32c6fe85 100644 --- a/localazy.json +++ b/localazy.json @@ -17,6 +17,7 @@ }] }, "download": { + "metadataFileTs": "frontend/.storybook/locales.ts", "files": [{ "conditions": "equals: ${file}, file.json", "output": "translations/${lang}.json"