diff --git a/src/app/global-error.tsx b/src/app/global-error.tsx index 911ceda8..6977c3da 100644 --- a/src/app/global-error.tsx +++ b/src/app/global-error.tsx @@ -22,7 +22,6 @@ export default function GlobalError({ diff --git a/src/features/common/assets/auth0-logo.component.tsx b/src/features/common/assets/auth0-logo.component.tsx new file mode 100644 index 00000000..22f18ce7 --- /dev/null +++ b/src/features/common/assets/auth0-logo.component.tsx @@ -0,0 +1,53 @@ +interface Auth0LogoComponentProps { + title: string; +} + +export const Auth0LogoComponent: React.FC = ({title}) => { + return ( + + {title} + + + + + + + + + + + ); +}; diff --git a/src/features/common/assets/auth0-logo.png b/src/features/common/assets/auth0-logo.png deleted file mode 100644 index 51ff6735..00000000 Binary files a/src/features/common/assets/auth0-logo.png and /dev/null differ diff --git a/src/features/common/assets/jwt-flower.png b/src/features/common/assets/jwt-flower.png deleted file mode 100644 index 96b2e512..00000000 Binary files a/src/features/common/assets/jwt-flower.png and /dev/null differ diff --git a/src/features/common/assets/jwt-logo.component.tsx b/src/features/common/assets/jwt-logo.component.tsx new file mode 100644 index 00000000..57db4704 --- /dev/null +++ b/src/features/common/assets/jwt-logo.component.tsx @@ -0,0 +1,82 @@ +export const JwtLogoComponent: React.FC = () => { + return ( + + + + + + + + + + + + + ); +}; \ No newline at end of file diff --git a/src/features/common/assets/jwt-wordmark.component.tsx b/src/features/common/assets/jwt-wordmark.component.tsx new file mode 100644 index 00000000..7cb4a514 --- /dev/null +++ b/src/features/common/assets/jwt-wordmark.component.tsx @@ -0,0 +1,30 @@ +export const JwtWordmarkComponent: React.FC = () => { + return ( + + + + + + ); +}; \ No newline at end of file diff --git a/src/features/common/components/errors/error-page/error-page.component.tsx b/src/features/common/components/errors/error-page/error-page.component.tsx index 35d32065..96f0f8c5 100644 --- a/src/features/common/components/errors/error-page/error-page.component.tsx +++ b/src/features/common/components/errors/error-page/error-page.component.tsx @@ -1,29 +1,24 @@ import React from "react"; import styles from "./error-page.module.scss"; import { ShellComponent } from "@/features/common/components/shell/shell.component"; -import { RibbonComponent } from "@/features/common/components/bars/ribbon/ribbon.component"; import { MobileHeaderComponent } from "@/features/common/components/headers/mobile-header/mobile-header.component"; import { HeaderComponent } from "@/features/common/components/headers/header/header.component"; import { FooterComponent } from "@/features/common/components/footer/footer.component"; -import { LayoutDictionaryModel } from "@/features/localization/models/layout-dictionary.model"; import { ThemeCookieValues } from "@/features/common/values/theme.values"; -import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; -import { SiteLogoComponent } from "@/features/common/components/site-logo/site-logo.component"; +import { getLayoutDictionary } from "@/features/localization/services/language-dictionary.service"; interface ErrorPageComponentProps { languageCode: string; themeCode: ThemeCookieValues; - dictionary: LayoutDictionaryModel; children: React.ReactNode; } export const ErrorPageComponent: React.FC = ({ languageCode, themeCode, - dictionary, children, }) => { - const images = getImageDictionary(languageCode); + const layoutDictionary = getLayoutDictionary(languageCode); return ( @@ -31,35 +26,19 @@ export const ErrorPageComponent: React.FC = ({ } - ribbon={ - - } + dictionary={layoutDictionary} + themeCode={themeCode} /> } - ribbon={ - - } + dictionary={layoutDictionary} + themeCode={themeCode} /> {children} } + dictionary={layoutDictionary.footer} /> diff --git a/src/features/common/components/footer/footer.component.tsx b/src/features/common/components/footer/footer.component.tsx index 42859a07..719ff3db 100644 --- a/src/features/common/components/footer/footer.component.tsx +++ b/src/features/common/components/footer/footer.component.tsx @@ -15,25 +15,23 @@ import { DEFAULT_LANGUAGE_CODE } from "@/features/localization/localization.conf import { sitePaths } from "@/features/seo/site-tree"; import { createUrlPath } from "@/libs/utils/path.utils"; import { SiteBrandComponent } from "@/features/common/components/site-brand/site-brand.component"; -import { StaticImageMetadataModel } from "@/features/common/models/static-image-metadata.model"; import { Button } from "react-aria-components"; +import { Auth0LogoComponent } from "../../assets/auth0-logo.component"; +import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; interface FooterComponentProps { languageCode: string; dictionary: LayoutDictionaryModel["footer"]; - auth0Logo: StaticImageMetadataModel; - siteLogo: React.ReactNode; } export const FooterComponent: React.FC = ({ languageCode, dictionary, - auth0Logo, - siteLogo, }) => { const [modalState, setModalState] = useState( ModalStateValues.CLOSED, ); + const images = getImageDictionary(languageCode); const languagePathPrefix: string = languageCode === DEFAULT_LANGUAGE_CODE @@ -66,9 +64,7 @@ export const FooterComponent: React.FC = ({ contentClassName={styles.content} > - - {siteLogo} - + @@ -162,17 +158,7 @@ export const FooterComponent: React.FC = ({ target="_blank" href="https://auth0.com/" > - + {dictionary.copyright} diff --git a/src/features/common/components/footer/footer.module.scss b/src/features/common/components/footer/footer.module.scss index 0f39c24d..44e04595 100644 --- a/src/features/common/components/footer/footer.module.scss +++ b/src/features/common/components/footer/footer.module.scss @@ -267,8 +267,5 @@ padding-bottom: 1rem; row-gap: 2rem; - color: $neutrals-light-100-snow; - - @media #{$breakpoint-dimension-xs} { - } + color: var(--color_fg_default); } diff --git a/src/features/common/components/headers/header/header.component.tsx b/src/features/common/components/headers/header/header.component.tsx index 733b84ca..7002824d 100644 --- a/src/features/common/components/headers/header/header.component.tsx +++ b/src/features/common/components/headers/header/header.component.tsx @@ -1,6 +1,6 @@ "use client"; -import React from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { usePathname } from "next/navigation"; import { DEFAULT_LANGUAGE_CODE } from "@/features/localization/localization.config"; import { LayoutDictionaryModel } from "@/features/localization/models/layout-dictionary.model"; @@ -10,19 +10,32 @@ import styles from "./header.module.scss"; import { BoxComponent } from "@/features/common/components/box/box.component"; import Link from "next/link"; import { SiteBrandComponent } from "@/features/common/components/site-brand/site-brand.component"; +import { ThemePickerComponent } from "../../theme-picker/theme-picker.component"; +import { + getSanitizedThemePickerCodeValue, + isLightThemePreference, + isSystemThemePreference, +} from "@/features/themes/services/theme.utils"; +import { SystemIconComponent } from "../../bars/ribbon/assets/system-icon.component"; +import { LightIconComponent } from "../../bars/ribbon/assets/light-icon.component"; +import { DarkIconComponent } from "../../bars/ribbon/assets/dark-icon.component"; +import { + ThemeCookieValues, + ThemePickerCodeValues, +} from "@/features/common/values/theme.values"; +import { ThemeModel } from "@/features/common/models/theme.model"; +import { savePreferredThemeInCookie } from "@/features/themes/services/theme.client.utils"; interface HeaderComponentProps { + themeCode: ThemeCookieValues; languageCode: string; - dictionary: LayoutDictionaryModel["header"]; - siteLogo: React.ReactNode; - ribbon: React.ReactNode; + dictionary: LayoutDictionaryModel; } export const HeaderComponent: React.FC = ({ + themeCode, languageCode, dictionary, - siteLogo, - ribbon, }) => { const pathname = usePathname(); const pathnameSegments = getPathnameSegments(pathname); @@ -37,22 +50,68 @@ export const HeaderComponent: React.FC = ({ ? sitePaths.root : createUrlPath([languageCode]); + const themeOptions = useMemo( + () => + dictionary.ribbon.themePicker.options.map((option) => { + return { + code: option.code, + label: option.label, + icon: isSystemThemePreference(option.code) ? ( + + ) : isLightThemePreference(option.code) ? ( + + ) : ( + + ), + }; + }), + [dictionary.ribbon.themePicker.options] + ); + + const sanitizedThemePickerCodeValue = useMemo(() => { + return getSanitizedThemePickerCodeValue(themeCode); + }, [themeCode]); + + const [currentTheme, setCurrentTheme] = useState( + dictionary.ribbon.themePicker.options.filter((element) => + isSystemThemePreference(themeCode) + ? isSystemThemePreference(element.code) + : element.code === sanitizedThemePickerCodeValue + )[0] + ); + + const handleThemeSelection = useCallback( + async (value: ThemePickerCodeValues) => { + const themePreference = await savePreferredThemeInCookie( + value, + languageCode + ); + + if (themePreference) { + setCurrentTheme(themePreference); + } + }, + [languageCode] + ); + return ( - - {ribbon} - - - {siteLogo} - + + + + + - {dictionary.links.map((link) => { + {dictionary.header.links.map((link) => { const linkPath = languageCode === DEFAULT_LANGUAGE_CODE || link.isExternal ? link.path @@ -77,7 +136,14 @@ export const HeaderComponent: React.FC = ({ })} - - + + + + + ); }; diff --git a/src/features/common/components/headers/header/header.module.scss b/src/features/common/components/headers/header/header.module.scss index f6a79992..3f27108d 100644 --- a/src/features/common/components/headers/header/header.module.scss +++ b/src/features/common/components/headers/header/header.module.scss @@ -1,22 +1,22 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; -.header { - position: fixed; - top: 0; - right: 0; - left: 0; - - z-index: 9001; - backdrop-filter: blur(2rem); -} - .container { @include Container; + max-width: calc(100% - 2rem); display: none; - + position: fixed; + top: 1rem; + right: 0; + left: 0; + border-radius: 1.25rem; + margin: 0 auto; + box-sizing: border-box; background: var(--color_bg_app_bar); - border-bottom: 1px solid rgba(#555, 0.32); + border: 1px solid var(--color_bg_app_bar); + box-shadow: 0 12px 24px -12px rgba(0, 0, 0, .04); + backdrop-filter: blur(3rem); + z-index: 100; @media #{$breakpoint-dimension-sm} { display: block; @@ -29,20 +29,37 @@ } .content { - @include InnerContentFlex; + display: flex; + width: 100%; + margin: 0 auto; height: 100%; position: relative; - grid-column: 1 / -1; align-items: center; justify-content: space-between; } +.brand { + display: flex; + align-items: center; + height: 1rem; + margin-left: 1.5rem; + z-index: 100; +} + +.navContainer { + display: flex; + justify-content: center; + width: 100%; + position: absolute; + left: 0; +} + .navTabs { - flex: 1; display: flex; align-items: center; - justify-content: flex-end; - gap: 3rem; + justify-content: center; + border-radius: 9999px; + padding: .25rem; } .navList { @@ -50,39 +67,33 @@ padding: 0; list-style-type: none; margin: 0; - height: 100%; - - @media #{$breakpoint-dimension-sm} { - gap: 2rem; - } - - @media #{$breakpoint-dimension-md} { - gap: 3rem; - } + gap: 0.25rem; } .navList__item { position: relative; - border-bottom: 0.125rem solid transparent; - color: var(--color_fg_link); &[data-active="true"] { - color: var(--color_fg_selected); - border-bottom: 1px solid var(--color_border_selected); + a { + background-color: var(--color_bg_app_bar); + color: var(--color_fg_bold); + cursor: default; + } } } -.navList__item, .navList__item > a { display: flex; align-items: center; - - font-size: 0.875rem; + padding: .5rem 1rem; + color: var(--color_fg_default); + font-size: .875rem; font-style: normal; - font-weight: 500; - line-height: 1.5rem; - letter-spacing: 0.2px; + font-weight: 600; + line-height: 1.5; + letter-spacing: -.1px; + border-radius: 9999px; &:focus-visible { outline: solid 1px var(--color_border_focus); @@ -90,3 +101,13 @@ border-radius: 0.125rem; } } + +.actions { + display: flex; + gap: .5rem; + + @media #{$breakpoint-dimension-md} { + gap: 1rem; + margin-right: 1.5rem; + } +} \ No newline at end of file diff --git a/src/features/common/components/headers/mobile-header/mobile-header.component.tsx b/src/features/common/components/headers/mobile-header/mobile-header.component.tsx index ce7c1789..32f1080b 100644 --- a/src/features/common/components/headers/mobile-header/mobile-header.component.tsx +++ b/src/features/common/components/headers/mobile-header/mobile-header.component.tsx @@ -11,19 +11,17 @@ import { DEFAULT_LANGUAGE_CODE } from "@/features/localization/localization.conf import { sitePaths } from "@/features/seo/site-tree"; import { createUrlPath, getPathnameSegments } from "@/libs/utils/path.utils"; import { SiteBrandComponent } from "@/features/common/components/site-brand/site-brand.component"; +import { ThemeCookieValues } from "@/features/common/values/theme.values"; interface MobileHeaderComponentProps { + themeCode: ThemeCookieValues; languageCode: string; - dictionary: LayoutDictionaryModel["header"]; - siteLogo: React.ReactNode; - ribbon: React.ReactNode; + dictionary: LayoutDictionaryModel; } export const MobileHeaderComponent: React.FC = ({ languageCode, dictionary, - siteLogo, - ribbon, }) => { const pathname = usePathname(); const [currentPathname, setCurrentPathname] = useState(null); @@ -80,8 +78,6 @@ export const MobileHeaderComponent: React.FC = ({ return ( <> - - {ribbon} = ({ contentClassName={styles.content} > - - {siteLogo} - + @@ -109,7 +103,6 @@ export const MobileHeaderComponent: React.FC = ({ /> - = ({ contentClassName={styles.menuContent} > - {dictionary.links.map((link) => { + {dictionary.header.links.map((link) => { const linkPath = languageCode === DEFAULT_LANGUAGE_CODE || link.isExternal ? link.path diff --git a/src/features/common/components/headers/mobile-header/mobile-header.module.scss b/src/features/common/components/headers/mobile-header/mobile-header.module.scss index f3f7e107..c5559533 100644 --- a/src/features/common/components/headers/mobile-header/mobile-header.module.scss +++ b/src/features/common/components/headers/mobile-header/mobile-header.module.scss @@ -1,22 +1,19 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; -.header { +.container { + width: calc(100% - 2rem); position: fixed; - top: 0; + top: 1rem; right: 0; left: 0; - - z-index: 9001; - backdrop-filter: blur(2rem); -} - -.container { - @include Container; - + border-radius: 1rem; + margin: 0 auto; background: var(--color_bg_app_bar); - border-bottom: 1px solid rgba(#555, 0.32); - + border: 1px solid var(--color_bg_app_bar_border); + backdrop-filter: blur(2rem); + z-index: 100; + @media #{$breakpoint-dimension-sm} { display: none; } @@ -111,12 +108,8 @@ } .menu { - position: fixed; - top: $main-nav-height-mobile; - z-index: 99999; - height: calc(100% - $main-nav-height-mobile); - width: 100%; - overflow: hidden; + opacity: 1; + transition: all .3s ease-in-out; &[aria-hidden="false"] { display: block; @@ -134,16 +127,22 @@ } .menuContainer { - height: 100%; - width: 100%; - overflow-y: scroll; - background: var(--color_bg_page); + width: calc(100% - 2rem); + position: fixed; + left: 1rem; + top: 4.5rem; + border-radius: 1rem; + background: rgba(0, 0, 0, .04); + border: 1px solid rgba(0, 0, 0, .04); + box-shadow: 0 1px 1px -.5px rgba(0, 0, 0, .04), 0 2px 2px -1px rgba(0, 0, 0, .04), 0 4px 4px -2px rgba(0, 0, 0, .04), 0 8px 8px -4px rgba(0, 0, 0, .04), 0 12px 12px -6px rgba(0, 0, 0, .04); + backdrop-filter: blur(2rem); + z-index: 100; } .menuContent { @include InnerContentFlex; - padding: 0 1.5rem 1.5rem; width: 100%; + padding: .25rem; } .menu__list { @@ -156,25 +155,27 @@ position: relative; list-style: none; width: 100%; - border-bottom: 1px solid $neutrals-functional-300; margin: 0; - padding: 1.5rem 0.5rem; } .menu__item__link { - font-size: 1.25rem; - line-height: 1.75rem; - letter-spacing: -0.1px; + display: flex; + align-items: center; + justify-content: center; + border-radius: .75rem; + width: 100%; + font-size: 1rem; + letter-spacing: -.1px; color: var(--color_fg_bold); text-decoration: none; font-weight: 500; - transition: color 0.2s; + transition: color .2s; cursor: pointer; user-select: none; - padding-bottom: 0.25rem; - border-bottom: 1px solid transparent; + padding: .75rem .5rem; &[data-active="true"] { - border-bottom: 1px solid var(--color_fg_bold); + background-color: hsla(0, 0%, 100%, .5); + box-shadow: 0 0 1px 2px rgba(0, 0, 0, .04); } } diff --git a/src/features/common/components/layout/page-header/page-header.component.tsx b/src/features/common/components/layout/page-header/page-header.component.tsx index 468f4626..6ba75f9c 100644 --- a/src/features/common/components/layout/page-header/page-header.component.tsx +++ b/src/features/common/components/layout/page-header/page-header.component.tsx @@ -1,5 +1,6 @@ +"use client"; + import React from "react"; -import { RibbonComponent } from "@/features/common/components/bars/ribbon/ribbon.component"; import { MobileHeaderComponent } from "@/features/common/components/headers/mobile-header/mobile-header.component"; import { HeaderComponent } from "@/features/common/components/headers/header/header.component"; import { ThemeCookieValues } from "@/features/common/values/theme.values"; @@ -8,42 +9,26 @@ import { getLayoutDictionary } from "@/features/localization/services/language-d interface PageHeaderComponentProps { languageCode: string; themeCode: ThemeCookieValues; - siteLogo: React.ReactNode; } export const PageHeaderComponent: React.FC = ({ themeCode, languageCode, - siteLogo, }) => { const layoutDictionary = getLayoutDictionary(languageCode); return ( - <> + - } + dictionary={layoutDictionary} /> - } + dictionary={layoutDictionary} /> - > + ); }; diff --git a/src/features/common/components/layout/page-layout/page-layout.component.tsx b/src/features/common/components/layout/page-layout/page-layout.component.tsx index 5c1cdfdb..bc4d9d7b 100644 --- a/src/features/common/components/layout/page-layout/page-layout.component.tsx +++ b/src/features/common/components/layout/page-layout/page-layout.component.tsx @@ -4,9 +4,7 @@ import { getLayoutDictionary } from "@/features/localization/services/language-d import { ShellComponent } from "@/features/common/components/shell/shell.component"; import { FooterComponent } from "@/features/common/components/footer/footer.component"; import { ThemeCookieValues } from "@/features/common/values/theme.values"; -import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; import { PageHeaderComponent } from "@/features/common/components/layout/page-header/page-header.component"; -import { SiteLogoComponent } from "@/features/common/components/site-logo/site-logo.component"; interface LayoutComponentProps extends PropsWithChildren { languageCode: string; @@ -19,7 +17,6 @@ export const PageLayoutComponent: React.FC = ({ children, }) => { const layoutDictionary = getLayoutDictionary(languageCode); - const images = getImageDictionary(languageCode); return ( @@ -74,14 +71,11 @@ export const PageLayoutComponent: React.FC = ({ } /> {children} } /> diff --git a/src/features/common/components/site-brand/site-brand.component.tsx b/src/features/common/components/site-brand/site-brand.component.tsx index 8ab48d77..f7e7fd1b 100644 --- a/src/features/common/components/site-brand/site-brand.component.tsx +++ b/src/features/common/components/site-brand/site-brand.component.tsx @@ -1,18 +1,34 @@ import React, { PropsWithChildren } from "react"; import styles from "./site-brand.module.scss"; import Link from "next/link"; +import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; +import { SecondaryFont } from "@/libs/theme/fonts"; +import clsx from "clsx"; +import { JwtLogoComponent } from "../../assets/jwt-logo.component"; +import { JwtWordmarkComponent } from "../../assets/jwt-wordmark.component"; interface SiteBrandComponentProps extends PropsWithChildren { path: string; + languageCode: string; } export const SiteBrandComponent: React.FC = ({ path, - children, + languageCode, }) => { + const images = getImageDictionary(languageCode); + return ( - - {children} + + + + + + + + + Debugger + ); }; diff --git a/src/features/common/components/site-brand/site-brand.module.scss b/src/features/common/components/site-brand/site-brand.module.scss index 459c9a51..09dbd56c 100644 --- a/src/features/common/components/site-brand/site-brand.module.scss +++ b/src/features/common/components/site-brand/site-brand.module.scss @@ -1,8 +1,11 @@ .brand { + width: 100%; display: flex; align-items: center; - height: 2rem; + height: 1.5rem; + gap: 0.5rem; position: relative; + cursor: pointer; svg { height: inherit; @@ -15,3 +18,57 @@ border-radius: 0.125rem; } } + +.container { + position: relative; + display: flex; + height: 100%; + align-items: center; +} + +.brand__logo { + position: relative; + display: flex; + align-items: center; + height: 1.5rem; + animation: rotate 10s linear infinite; +} + +@keyframes rotate { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(1turn); + } +} + +.brand__wordmark { + position: relative; + display: flex; + align-items: center; + height: 1rem; +} + +.brand__headline { + display: flex; + flex-direction: column; + color: var(--color_fg_bold); +} + +.brand__title { + display: flex; + font-size: 1.25rem; + line-height: 1.25rem; + margin-top: 0; + letter-spacing: 0.02rem; +} + +.brand__subtitle { + display: flex; + font-size: 1rem; + font-weight: 500; + line-height: .75rem; + margin-top: 1px; + letter-spacing: .02rem; +} diff --git a/src/features/common/components/site-logo/site-logo.component.tsx b/src/features/common/components/site-logo/site-logo.component.tsx deleted file mode 100644 index 3e981687..00000000 --- a/src/features/common/components/site-logo/site-logo.component.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import styles from "./site-logo.module.scss"; -import Image from "next/image"; -import clsx from "clsx"; -import { SecondaryFont } from "@/libs/theme/fonts"; -import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; - -interface SiteLogoComponentProps { - languageCode: string; -} - -export const SiteLogoComponent: React.FC = ({ - languageCode, -}) => { - const images = getImageDictionary(languageCode); - - return ( - - - - JWT - Debugger - - - ); -}; diff --git a/src/features/common/components/site-logo/site-logo.module.scss b/src/features/common/components/site-logo/site-logo.module.scss deleted file mode 100644 index 76d0d92a..00000000 --- a/src/features/common/components/site-logo/site-logo.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -.container { - position: relative; - display: flex; - height: 100%; - align-items: center; -} - -.brand__logo { - position: relative; - display: flex; - align-items: center; -} - -.brand__headline { - display: flex; - flex-direction: column; - margin-left: 0.625rem; - color: var(--color_fg_bold); -} - -.brand__title { - display: flex; - font-size: 1.25rem; - line-height: 1.25rem; - margin-top: 0; - letter-spacing: 0.02rem; -} - -.brand__subtitle { - display: flex; - font-size: 0.75rem; - line-height: 0.75rem; - margin-top: 1px; - letter-spacing: 0.02rem; -} diff --git a/src/features/common/components/theme-picker/theme-picker.component.tsx b/src/features/common/components/theme-picker/theme-picker.component.tsx new file mode 100644 index 00000000..2981e145 --- /dev/null +++ b/src/features/common/components/theme-picker/theme-picker.component.tsx @@ -0,0 +1,41 @@ +import styles from "./theme-picker.module.scss"; +import { ThemePickerCodeValues } from "../../values/theme.values"; + +interface ThemePickerComponentProps { + options: { + code: ThemePickerCodeValues; + icon: React.ReactNode; + label: string; + }[]; + selectedOptionCode: string; + handleSelection: (value: ThemePickerCodeValues) => Promise; +} + +export const ThemePickerComponent: React.FC = ({ + options, + selectedOptionCode, + handleSelection, +}) => { + return ( + + + {options.map((option) => { + return ( + { + console.log(option.label) + await handleSelection(option.code); + }} + > + {option.icon} + + ); + })} + + + ); +}; diff --git a/src/features/common/components/theme-picker/theme-picker.module.scss b/src/features/common/components/theme-picker/theme-picker.module.scss new file mode 100644 index 00000000..90049ed9 --- /dev/null +++ b/src/features/common/components/theme-picker/theme-picker.module.scss @@ -0,0 +1,50 @@ +.container { + display: flex; + align-items: center; + justify-content: center; +} + +.wrapper { + display: flex; + background-color: var(--color_bg_app_bar); + border: 1px solid var(--color_border_default); + border-radius: 9999px; + overflow: hidden; + width: -moz-fit-content; + width: fit-content; + padding: 0.25rem; + gap: 0.125rem; +} + +.option { + display: flex; + align-items: center; + justify-content: center; + color: var(--color_fg_default); + cursor: pointer; + padding: 0.25rem; + position: relative; + transition: all 0.2s ease; + border-radius: 9999px; + width: 2.5rem; + height: 1.75rem; + + &[data-active="true"] { + background-color: var(--color_bg_layer); + color: var(--color_fg_bold); + box-shadow: 0 1px 2px rgba(0, 0, 0, .1); + } +} + +.option__icon { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + + svg { + height: 1rem; + width: 1rem; + } +} diff --git a/src/features/common/models/static-image-metadata.model.ts b/src/features/common/models/static-image-metadata.model.ts index f65aabdb..c9e1aaa7 100644 --- a/src/features/common/models/static-image-metadata.model.ts +++ b/src/features/common/models/static-image-metadata.model.ts @@ -1,6 +1,6 @@ export interface StaticImageMetadataModel { src: string; alt: string; - width: number; - height: number; + width?: number; + height?: number; } diff --git a/src/features/localization/dictionaries/images/en.tsx b/src/features/localization/dictionaries/images/en.tsx index 3c571f8d..0eb49401 100644 --- a/src/features/localization/dictionaries/images/en.tsx +++ b/src/features/localization/dictionaries/images/en.tsx @@ -1,20 +1,35 @@ -import auth0Logo from "@/features/common/assets/auth0-logo.png"; -import jwtLogo from "@/features/common/assets/jwt-flower.png"; -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; +import { BrandDictionaryModel } from "@/features/localization/models/images-dictionary.model"; -export const enImagesDictionary: ImagesDictionaryModel = { - logos: { - site: { - src: jwtLogo.src, - alt: "A token that resembles a flower with petals of a different color.", - width: jwtLogo.width, - height: jwtLogo.height, +export const enBrandDictionary: BrandDictionaryModel = { + title: "Right-click or long-press for logo options", + menu: { + brand: { + label: "Brand", + items: [ + {icon: "", + label: "Copy Logo SVG" + }, + {icon: "", + label: "Download Logo" + }, + {icon: "", + label: "Copy Symbol SVG" + }, + {icon: "", + label: "Download Symbol" + }, + {icon: "", + label: "Copy Wordmark SVG" + }, + {icon: "", + label: "Download Wordmark" + }, + ] }, - auth0: { - src: auth0Logo.src, - alt: "This logo has the word “Auth0” and a shield on its left side. The shield has a four-pointed star inside, which spans across its surface.", - width: auth0Logo.width, - height: auth0Logo.height, - }, - }, + tools: { + label: "Tools", + items: [ + ] + } + } }; diff --git a/src/features/localization/dictionaries/images/ja.tsx b/src/features/localization/dictionaries/images/ja.tsx index 112f37b3..42dc0ebb 100644 --- a/src/features/localization/dictionaries/images/ja.tsx +++ b/src/features/localization/dictionaries/images/ja.tsx @@ -1,20 +1,35 @@ -import auth0Logo from "@/features/common/assets/auth0-logo.png"; -import jwtLogo from "@/features/common/assets/jwt-flower.png"; -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; +import { BrandDictionaryModel } from "@/features/localization/models/images-dictionary.model"; -export const jaImagesDictionary: ImagesDictionaryModel = { - logos: { - site: { - src: jwtLogo.src, - alt: "異なる色の花びらを持つ花に似たトークン。", - width: jwtLogo.width, - height: jwtLogo.height, +export const jaImagesDictionary: BrandDictionaryModel = { + title: "Right-click or long-press for logo options", + menu: { + brand: { + label: "Brand", + items: [ + {icon: "", + label: "Copy Logo SVG" + }, + {icon: "", + label: "Download Logo" + }, + {icon: "", + label: "Copy Symbol SVG" + }, + {icon: "", + label: "Download Symbol" + }, + {icon: "", + label: "Copy Wordmark SVG" + }, + {icon: "", + label: "Download Wordmark" + }, + ] }, - auth0: { - src: auth0Logo.src, - alt: "“Auth0”ロゴ。盾の中央から四方八方に伸びる星が描かれている。", - width: auth0Logo.width, - height: auth0Logo.height, - }, - }, + tools: { + label: "Tools", + items: [ + ] + } + } }; diff --git a/src/features/localization/models/images-dictionary.model.ts b/src/features/localization/models/images-dictionary.model.ts index 392e4e75..529fcde5 100644 --- a/src/features/localization/models/images-dictionary.model.ts +++ b/src/features/localization/models/images-dictionary.model.ts @@ -1,8 +1,17 @@ -import { StaticImageMetadataModel } from "@/features/common/models/static-image-metadata.model"; +interface BrandMenuItem { + icon: string; + label: string; +} +interface BrandMenuSection { + label: string; + items: BrandMenuItem[]; +} +interface BrandMenu { + brand: BrandMenuSection; + tools: BrandMenuSection; +} -export interface ImagesDictionaryModel { - logos: { - site: StaticImageMetadataModel; - auth0: StaticImageMetadataModel; - }; +export interface BrandDictionaryModel { + title: string; + menu: BrandMenu; } diff --git a/src/features/localization/services/images-dictionary.service.tsx b/src/features/localization/services/images-dictionary.service.tsx index acd51002..1a14acee 100644 --- a/src/features/localization/services/images-dictionary.service.tsx +++ b/src/features/localization/services/images-dictionary.service.tsx @@ -1,11 +1,11 @@ -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; -import { enImagesDictionary } from "@/features/localization/dictionaries/images/en"; +import { BrandDictionaryModel } from "@/features/localization/models/images-dictionary.model"; +import { enBrandDictionary } from "@/features/localization/dictionaries/images/en"; import { jaImagesDictionary } from "@/features/localization/dictionaries/images/ja"; const imagesDictionaries: { - [index: string]: ImagesDictionaryModel; + [index: string]: BrandDictionaryModel; } = { - en: enImagesDictionary, + en: enBrandDictionary, ja: jaImagesDictionary, }; diff --git a/src/libs/theme/styles/_variables.scss b/src/libs/theme/styles/_variables.scss index e5a0bd15..ea9ad6a5 100644 --- a/src/libs/theme/styles/_variables.scss +++ b/src/libs/theme/styles/_variables.scss @@ -150,7 +150,7 @@ $gradient-app-card---resting: linear-gradient( $ribbon-height: 2.5rem; $ribbon-height-mobile: 2.5rem; -$navbar-height: 3rem; +$navbar-height: 5rem; $navbar-height-mobile: 3rem; $main-nav-height: calc($ribbon-height + $navbar-height); $main-nav-height-mobile: calc($ribbon-height-mobile + $navbar-height-mobile); diff --git a/src/libs/theme/styles/globals.scss b/src/libs/theme/styles/globals.scss index 051ef32b..7c779af1 100644 --- a/src/libs/theme/styles/globals.scss +++ b/src/libs/theme/styles/globals.scss @@ -45,10 +45,11 @@ :root { --color_bg_page: var(--functional-gray-950); --color_fg_bold: var(--functional-gray-50); - --color_fg_default: var(--functional-gray-200); + --color_fg_default: var(--functional-gray-500); --color_fg_link_primary: var(--cloud); - --color_bg_app_bar: rgba(17, 17, 17, 0.66); + --color_bg_app_bar: hsla(0,0%,7%,.04); + --color_bg_app_bar_border: hsla(0, 0%, 7%, .12); --color_bg_app_bar_plain: rgba(17, 17, 17); --color_fg_link: var(--functional-gray-50); @@ -195,10 +196,8 @@ html[data-theme="system-light"] { --color_bg_page: var(--functional-gray-0); --color_fg_bold: var(--charcoal2); - --color_fg_default: var(--functional-gray-650); --color_fg_link_primary: var(--sky); - --color_bg_app_bar: rgba(241, 241, 241, 0.66); --color_bg_app_bar_plain: rgba(241, 241, 241); --color_fg_link: var(--charcoal2);