mordoc 0.1.13 → 1.0.0
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.
- package/LICENSE +7 -0
- package/bin/cli.js +24 -71
- package/dist/cli/asset-rewrite.d.ts +40 -0
- package/dist/cli/asset-rewrite.d.ts.map +1 -0
- package/dist/cli/asset-rewrite.js +67 -0
- package/dist/cli/asset-rewrite.js.map +1 -0
- package/dist/cli/build.d.ts +45 -15
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/build.js +186 -101
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts +26 -14
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +116 -159
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/pagefind-indexer.d.ts +15 -0
- package/dist/cli/pagefind-indexer.d.ts.map +1 -0
- package/dist/cli/pagefind-indexer.js +68 -0
- package/dist/cli/pagefind-indexer.js.map +1 -0
- package/dist/cli/paths.d.ts +26 -0
- package/dist/cli/paths.d.ts.map +1 -0
- package/dist/cli/paths.js +32 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/ssg-runner.d.ts +58 -0
- package/dist/cli/ssg-runner.d.ts.map +1 -0
- package/dist/cli/ssg-runner.js +126 -0
- package/dist/cli/ssg-runner.js.map +1 -0
- package/dist/config/assets-loader.d.ts +11 -0
- package/dist/config/assets-loader.d.ts.map +1 -0
- package/dist/config/assets-loader.js +46 -0
- package/dist/config/assets-loader.js.map +1 -0
- package/dist/config/language-loader.d.ts +11 -0
- package/dist/config/language-loader.d.ts.map +1 -0
- package/dist/config/language-loader.js +61 -0
- package/dist/config/language-loader.js.map +1 -0
- package/dist/config/language.d.ts +11 -0
- package/dist/config/language.d.ts.map +1 -0
- package/dist/config/language.js +61 -0
- package/dist/config/language.js.map +1 -0
- package/dist/config/sidenav-loader.d.ts +14 -0
- package/dist/config/sidenav-loader.d.ts.map +1 -0
- package/dist/config/sidenav-loader.js +78 -0
- package/dist/config/sidenav-loader.js.map +1 -0
- package/dist/config/site-loader.d.ts +11 -0
- package/dist/config/site-loader.d.ts.map +1 -0
- package/dist/config/site-loader.js +72 -0
- package/dist/config/site-loader.js.map +1 -0
- package/dist/config/site.d.ts +11 -0
- package/dist/config/site.d.ts.map +1 -0
- package/dist/config/site.js +72 -0
- package/dist/config/site.js.map +1 -0
- package/dist/config/topnav-loader.d.ts +10 -0
- package/dist/config/topnav-loader.d.ts.map +1 -0
- package/dist/config/topnav-loader.js +78 -0
- package/dist/config/topnav-loader.js.map +1 -0
- package/dist/config/translations-loader.d.ts +7 -0
- package/dist/config/translations-loader.d.ts.map +1 -0
- package/dist/config/translations-loader.js +51 -0
- package/dist/config/translations-loader.js.map +1 -0
- package/dist/content/content-loader.d.ts +16 -0
- package/dist/content/content-loader.d.ts.map +1 -0
- package/dist/content/content-loader.js +126 -0
- package/dist/content/content-loader.js.map +1 -0
- package/dist/content/content-parser.d.ts +12 -0
- package/dist/content/content-parser.d.ts.map +1 -0
- package/dist/content/content-parser.js +54 -0
- package/dist/content/content-parser.js.map +1 -0
- package/dist/content/content-transformer.d.ts +17 -0
- package/dist/content/content-transformer.d.ts.map +1 -0
- package/dist/content/content-transformer.js +94 -0
- package/dist/content/content-transformer.js.map +1 -0
- package/dist/content/markdoc-config.d.ts +13 -0
- package/dist/content/markdoc-config.d.ts.map +1 -0
- package/dist/content/markdoc-config.js +210 -0
- package/dist/content/markdoc-config.js.map +1 -0
- package/dist/content/slug.d.ts +26 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +31 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/pipeline.d.ts +61 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +123 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/types/assets.d.ts +15 -0
- package/dist/types/assets.d.ts.map +1 -0
- package/dist/types/assets.js +2 -0
- package/dist/types/assets.js.map +1 -0
- package/dist/types/content.d.ts +114 -32
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/content.js +1 -6
- package/dist/types/content.js.map +1 -1
- package/dist/types/language.d.ts +9 -0
- package/dist/types/language.d.ts.map +1 -0
- package/dist/types/language.js +2 -0
- package/dist/types/language.js.map +1 -0
- package/dist/types/navigation.d.ts +24 -36
- package/dist/types/navigation.d.ts.map +1 -1
- package/dist/types/navigation.js +1 -6
- package/dist/types/navigation.js.map +1 -1
- package/dist/types/pipeline.d.ts +70 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +2 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/types/site.d.ts +20 -0
- package/dist/types/site.d.ts.map +1 -0
- package/dist/types/site.js +2 -0
- package/dist/types/site.js.map +1 -0
- package/dist/utils/lang-utils.d.ts +23 -0
- package/dist/utils/lang-utils.d.ts.map +1 -0
- package/dist/utils/lang-utils.js +40 -0
- package/dist/utils/lang-utils.js.map +1 -0
- package/dist/utils/paths.d.ts +25 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +31 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/vite/plugin.d.ts +93 -0
- package/dist/vite/plugin.d.ts.map +1 -0
- package/dist/vite/plugin.js +435 -0
- package/dist/vite/plugin.js.map +1 -0
- package/package.json +46 -61
- package/src/app/App.module.css +82 -0
- package/src/app/App.tsx +95 -0
- package/src/app/content/Content.module.css +357 -0
- package/src/app/content/Content.tsx +212 -0
- package/src/app/content/callout/Callout.module.css +110 -0
- package/src/app/content/callout/Callout.tsx +82 -0
- package/src/app/content/card/Card.module.css +146 -0
- package/src/app/content/card/Card.tsx +110 -0
- package/src/app/content/card/CardGrid.module.css +22 -0
- package/src/app/content/card/CardGrid.tsx +34 -0
- package/src/app/content/code-block/CodeBlock.module.css +237 -0
- package/src/app/content/code-block/CodeBlock.tsx +123 -0
- package/src/app/content/heading/Heading.module.css +52 -0
- package/src/app/content/heading/Heading.tsx +75 -0
- package/src/app/content/image/Image.module.css +113 -0
- package/src/app/content/image/Image.tsx +98 -0
- package/src/app/content/link/ContentLink.tsx +46 -0
- package/src/app/data-context.tsx +39 -0
- package/src/app/entry-server.tsx +58 -0
- package/src/app/footer/Footer.module.css +36 -0
- package/src/app/footer/Footer.tsx +28 -0
- package/src/app/globals.d.ts +40 -0
- package/src/app/header/Header.module.css +205 -0
- package/src/app/header/Header.tsx +188 -0
- package/src/app/header/LanguagePicker.module.css +97 -0
- package/src/app/header/LanguagePicker.tsx +174 -0
- package/src/app/header/SearchBar.module.css +92 -0
- package/src/app/header/SearchBar.tsx +37 -0
- package/src/app/header/SearchModal.module.css +185 -0
- package/src/app/header/SearchModal.tsx +245 -0
- package/src/app/header/Topnav.module.css +37 -0
- package/src/app/header/Topnav.tsx +30 -0
- package/src/app/index.css +119 -0
- package/src/app/index.html +13 -0
- package/src/app/landing/LandingPage.module.css +14 -0
- package/src/app/landing/LandingPage.tsx +62 -0
- package/src/app/landing/button/Button.module.css +37 -0
- package/src/app/landing/button/Button.tsx +50 -0
- package/src/app/landing/hero/Hero.module.css +108 -0
- package/src/app/landing/hero/Hero.tsx +81 -0
- package/src/app/landing/section/Section.module.css +100 -0
- package/src/app/landing/section/Section.tsx +61 -0
- package/src/app/lang-utils.ts +11 -0
- package/src/app/main.tsx +67 -0
- package/src/app/not-found/NotFound.module.css +92 -0
- package/src/app/not-found/NotFound.tsx +34 -0
- package/src/app/routes.tsx +86 -0
- package/src/app/sidenav/Sidenav.module.css +239 -0
- package/src/app/sidenav/Sidenav.tsx +182 -0
- package/src/app/skeleton/Skeleton.module.css +100 -0
- package/src/app/skeleton/Skeleton.tsx +75 -0
- package/src/app/toc/Toc.module.css +59 -0
- package/src/app/toc/Toc.tsx +77 -0
- package/src/app/tsconfig.json +18 -0
- package/src/app/virtual-modules.d.ts +74 -0
- package/dist/assets/fonts/inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/dist/assets/fonts/inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/dist/assets/fonts/inter/OFL.txt +0 -93
- package/dist/build/Builder.d.ts +0 -92
- package/dist/build/Builder.d.ts.map +0 -1
- package/dist/build/Builder.js +0 -394
- package/dist/build/Builder.js.map +0 -1
- package/dist/build/ClientBundler.d.ts +0 -48
- package/dist/build/ClientBundler.d.ts.map +0 -1
- package/dist/build/ClientBundler.js +0 -169
- package/dist/build/ClientBundler.js.map +0 -1
- package/dist/build/HtmlGenerator.d.ts +0 -46
- package/dist/build/HtmlGenerator.d.ts.map +0 -1
- package/dist/build/HtmlGenerator.js +0 -190
- package/dist/build/HtmlGenerator.js.map +0 -1
- package/dist/build/SearchIndexer.d.ts +0 -31
- package/dist/build/SearchIndexer.d.ts.map +0 -1
- package/dist/build/SearchIndexer.js +0 -116
- package/dist/build/SearchIndexer.js.map +0 -1
- package/dist/bundles/client.js +0 -126
- package/dist/cli/create-app.d.ts +0 -14
- package/dist/cli/create-app.d.ts.map +0 -1
- package/dist/cli/create-app.js +0 -241
- package/dist/cli/create-app.js.map +0 -1
- package/dist/client/App.d.ts +0 -17
- package/dist/client/App.d.ts.map +0 -1
- package/dist/client/App.js +0 -91
- package/dist/client/App.js.map +0 -1
- package/dist/client/contexts/ConfigContext.d.ts +0 -22
- package/dist/client/contexts/ConfigContext.d.ts.map +0 -1
- package/dist/client/contexts/ConfigContext.js +0 -27
- package/dist/client/contexts/ConfigContext.js.map +0 -1
- package/dist/client/contexts/ContentContext.d.ts +0 -31
- package/dist/client/contexts/ContentContext.d.ts.map +0 -1
- package/dist/client/contexts/ContentContext.js +0 -46
- package/dist/client/contexts/ContentContext.js.map +0 -1
- package/dist/client/contexts/SearchContext.d.ts +0 -38
- package/dist/client/contexts/SearchContext.d.ts.map +0 -1
- package/dist/client/contexts/SearchContext.js +0 -185
- package/dist/client/contexts/SearchContext.js.map +0 -1
- package/dist/client/contexts/ThemeContext.d.ts +0 -23
- package/dist/client/contexts/ThemeContext.d.ts.map +0 -1
- package/dist/client/contexts/ThemeContext.js +0 -53
- package/dist/client/contexts/ThemeContext.js.map +0 -1
- package/dist/client/hooks/useContent.d.ts +0 -12
- package/dist/client/hooks/useContent.d.ts.map +0 -1
- package/dist/client/hooks/useContent.js +0 -74
- package/dist/client/hooks/useContent.js.map +0 -1
- package/dist/client/hooks/useNavigation.d.ts +0 -15
- package/dist/client/hooks/useNavigation.d.ts.map +0 -1
- package/dist/client/hooks/useNavigation.js +0 -101
- package/dist/client/hooks/useNavigation.js.map +0 -1
- package/dist/client/hooks/useSearch.d.ts +0 -22
- package/dist/client/hooks/useSearch.d.ts.map +0 -1
- package/dist/client/hooks/useSearch.js +0 -64
- package/dist/client/hooks/useSearch.js.map +0 -1
- package/dist/client/main.d.ts +0 -5
- package/dist/client/main.d.ts.map +0 -1
- package/dist/client/main.js +0 -66
- package/dist/client/main.js.map +0 -1
- package/dist/components/Callout.d.ts +0 -9
- package/dist/components/Callout.d.ts.map +0 -1
- package/dist/components/Callout.js +0 -24
- package/dist/components/Callout.js.map +0 -1
- package/dist/components/Card.d.ts +0 -10
- package/dist/components/Card.d.ts.map +0 -1
- package/dist/components/Card.js +0 -15
- package/dist/components/Card.js.map +0 -1
- package/dist/components/CardGrid.d.ts +0 -8
- package/dist/components/CardGrid.d.ts.map +0 -1
- package/dist/components/CardGrid.js +0 -9
- package/dist/components/CardGrid.js.map +0 -1
- package/dist/components/CodeBlock.d.ts +0 -28
- package/dist/components/CodeBlock.d.ts.map +0 -1
- package/dist/components/CodeBlock.js +0 -80
- package/dist/components/CodeBlock.js.map +0 -1
- package/dist/components/ContentPage.d.ts +0 -9
- package/dist/components/ContentPage.d.ts.map +0 -1
- package/dist/components/ContentPage.js +0 -102
- package/dist/components/ContentPage.js.map +0 -1
- package/dist/components/Header.d.ts +0 -14
- package/dist/components/Header.d.ts.map +0 -1
- package/dist/components/Header.js +0 -30
- package/dist/components/Header.js.map +0 -1
- package/dist/components/Heading.d.ts +0 -16
- package/dist/components/Heading.d.ts.map +0 -1
- package/dist/components/Heading.js +0 -31
- package/dist/components/Heading.js.map +0 -1
- package/dist/components/Image.d.ts +0 -8
- package/dist/components/Image.d.ts.map +0 -1
- package/dist/components/Image.js +0 -24
- package/dist/components/Image.js.map +0 -1
- package/dist/components/Layout.d.ts +0 -14
- package/dist/components/Layout.d.ts.map +0 -1
- package/dist/components/Layout.js +0 -32
- package/dist/components/Layout.js.map +0 -1
- package/dist/components/MarkdocRenderer.d.ts +0 -15
- package/dist/components/MarkdocRenderer.d.ts.map +0 -1
- package/dist/components/MarkdocRenderer.js +0 -73
- package/dist/components/MarkdocRenderer.js.map +0 -1
- package/dist/components/MobileMenu.d.ts +0 -14
- package/dist/components/MobileMenu.d.ts.map +0 -1
- package/dist/components/MobileMenu.js +0 -45
- package/dist/components/MobileMenu.js.map +0 -1
- package/dist/components/PageNavigation.d.ts +0 -9
- package/dist/components/PageNavigation.d.ts.map +0 -1
- package/dist/components/PageNavigation.js +0 -23
- package/dist/components/PageNavigation.js.map +0 -1
- package/dist/components/SearchModal.d.ts +0 -9
- package/dist/components/SearchModal.d.ts.map +0 -1
- package/dist/components/SearchModal.js +0 -74
- package/dist/components/SearchModal.js.map +0 -1
- package/dist/components/SideNav.d.ts +0 -9
- package/dist/components/SideNav.d.ts.map +0 -1
- package/dist/components/SideNav.js +0 -66
- package/dist/components/SideNav.js.map +0 -1
- package/dist/components/TableOfContents.d.ts +0 -10
- package/dist/components/TableOfContents.d.ts.map +0 -1
- package/dist/components/TableOfContents.js +0 -151
- package/dist/components/TableOfContents.js.map +0 -1
- package/dist/config/ConfigLoader.d.ts +0 -50
- package/dist/config/ConfigLoader.d.ts.map +0 -1
- package/dist/config/ConfigLoader.js +0 -214
- package/dist/config/ConfigLoader.js.map +0 -1
- package/dist/config/StyleCompiler.d.ts +0 -17
- package/dist/config/StyleCompiler.d.ts.map +0 -1
- package/dist/config/StyleCompiler.js +0 -116
- package/dist/config/StyleCompiler.js.map +0 -1
- package/dist/config/ThemeGenerator.d.ts +0 -14
- package/dist/config/ThemeGenerator.d.ts.map +0 -1
- package/dist/config/ThemeGenerator.js +0 -129
- package/dist/config/ThemeGenerator.js.map +0 -1
- package/dist/content/ContentLoader.d.ts +0 -70
- package/dist/content/ContentLoader.d.ts.map +0 -1
- package/dist/content/ContentLoader.js +0 -146
- package/dist/content/ContentLoader.js.map +0 -1
- package/dist/content/ContentProcessor.d.ts +0 -84
- package/dist/content/ContentProcessor.d.ts.map +0 -1
- package/dist/content/ContentProcessor.js +0 -380
- package/dist/content/ContentProcessor.js.map +0 -1
- package/dist/content/RouteManager.d.ts +0 -69
- package/dist/content/RouteManager.d.ts.map +0 -1
- package/dist/content/RouteManager.js +0 -143
- package/dist/content/RouteManager.js.map +0 -1
- package/dist/styles/components/callout.d.ts +0 -11
- package/dist/styles/components/callout.d.ts.map +0 -1
- package/dist/styles/components/callout.js +0 -87
- package/dist/styles/components/callout.js.map +0 -1
- package/dist/styles/components/card.d.ts +0 -11
- package/dist/styles/components/card.d.ts.map +0 -1
- package/dist/styles/components/card.js +0 -179
- package/dist/styles/components/card.js.map +0 -1
- package/dist/styles/components/codeblock.d.ts +0 -11
- package/dist/styles/components/codeblock.d.ts.map +0 -1
- package/dist/styles/components/codeblock.js +0 -251
- package/dist/styles/components/codeblock.js.map +0 -1
- package/dist/styles/components/content.d.ts +0 -11
- package/dist/styles/components/content.d.ts.map +0 -1
- package/dist/styles/components/content.js +0 -197
- package/dist/styles/components/content.js.map +0 -1
- package/dist/styles/components/fonts.d.ts +0 -11
- package/dist/styles/components/fonts.d.ts.map +0 -1
- package/dist/styles/components/fonts.js +0 -34
- package/dist/styles/components/fonts.js.map +0 -1
- package/dist/styles/components/header.d.ts +0 -11
- package/dist/styles/components/header.d.ts.map +0 -1
- package/dist/styles/components/header.js +0 -293
- package/dist/styles/components/header.js.map +0 -1
- package/dist/styles/components/heading.d.ts +0 -11
- package/dist/styles/components/heading.d.ts.map +0 -1
- package/dist/styles/components/heading.js +0 -115
- package/dist/styles/components/heading.js.map +0 -1
- package/dist/styles/components/layout.d.ts +0 -11
- package/dist/styles/components/layout.d.ts.map +0 -1
- package/dist/styles/components/layout.js +0 -79
- package/dist/styles/components/layout.js.map +0 -1
- package/dist/styles/components/mobilemenu.d.ts +0 -11
- package/dist/styles/components/mobilemenu.d.ts.map +0 -1
- package/dist/styles/components/mobilemenu.js +0 -112
- package/dist/styles/components/mobilemenu.js.map +0 -1
- package/dist/styles/components/reset.d.ts +0 -11
- package/dist/styles/components/reset.d.ts.map +0 -1
- package/dist/styles/components/reset.js +0 -131
- package/dist/styles/components/reset.js.map +0 -1
- package/dist/styles/components/searchmodal.d.ts +0 -11
- package/dist/styles/components/searchmodal.d.ts.map +0 -1
- package/dist/styles/components/searchmodal.js +0 -333
- package/dist/styles/components/searchmodal.js.map +0 -1
- package/dist/styles/components/sidenav.d.ts +0 -11
- package/dist/styles/components/sidenav.d.ts.map +0 -1
- package/dist/styles/components/sidenav.js +0 -212
- package/dist/styles/components/sidenav.js.map +0 -1
- package/dist/styles/components/toc.d.ts +0 -11
- package/dist/styles/components/toc.d.ts.map +0 -1
- package/dist/styles/components/toc.js +0 -120
- package/dist/styles/components/toc.js.map +0 -1
- package/dist/styles/components/typography.d.ts +0 -11
- package/dist/styles/components/typography.d.ts.map +0 -1
- package/dist/styles/components/typography.js +0 -248
- package/dist/styles/components/typography.js.map +0 -1
- package/dist/styles/components/utility.d.ts +0 -11
- package/dist/styles/components/utility.d.ts.map +0 -1
- package/dist/styles/components/utility.js +0 -231
- package/dist/styles/components/utility.js.map +0 -1
- package/dist/styles/types.d.ts +0 -79
- package/dist/styles/types.d.ts.map +0 -1
- package/dist/styles/types.js +0 -7
- package/dist/styles/types.js.map +0 -1
- package/dist/styles/utils.d.ts +0 -21
- package/dist/styles/utils.d.ts.map +0 -1
- package/dist/styles/utils.js +0 -50
- package/dist/styles/utils.js.map +0 -1
- package/dist/styles/variables/main.d.ts +0 -15
- package/dist/styles/variables/main.d.ts.map +0 -1
- package/dist/styles/variables/main.js +0 -116
- package/dist/styles/variables/main.js.map +0 -1
- package/dist/types/config.d.ts +0 -43
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -7
- package/dist/types/config.js.map +0 -1
- package/dist/utils/language-utils.d.ts +0 -41
- package/dist/utils/language-utils.d.ts.map +0 -1
- package/dist/utils/language-utils.js +0 -79
- package/dist/utils/language-utils.js.map +0 -1
- package/dist/utils/slugify.d.ts +0 -20
- package/dist/utils/slugify.d.ts.map +0 -1
- package/dist/utils/slugify.js +0 -44
- package/dist/utils/slugify.js.map +0 -1
- package/templates/default/config/favicon.ico +0 -0
- package/templates/default/config/logo-dark.png +0 -0
- package/templates/default/config/logo.png +0 -0
- package/templates/default/config/sidenav.yaml +0 -36
- package/templates/default/config/site.json +0 -16
- package/templates/default/config/styles/main.json +0 -6
- package/templates/default/config/styles/typography.json +0 -6
- package/templates/default/content/en/changelog.md +0 -35
- package/templates/default/content/en/faq.md +0 -50
- package/templates/default/content/en/field-manual/engines.md +0 -59
- package/templates/default/content/en/field-manual/relativity.md +0 -46
- package/templates/default/content/en/field-manual/safety.md +0 -44
- package/templates/default/content/en/field-manual.md +0 -22
- package/templates/default/content/en/flight-school/navigation.md +0 -61
- package/templates/default/content/en/flight-school/primer.md +0 -64
- package/templates/default/content/en/flight-school.md +0 -48
- package/templates/default/content/en/index.md +0 -83
- package/templates/default/content/en/ship-systems/flux-sails.md +0 -33
- package/templates/default/content/en/ship-systems/photonic-core.md +0 -39
- package/templates/default/content/en/ship-systems.md +0 -25
- package/templates/default/package.json +0 -21
- package/templates/default/public/icons/academy.svg +0 -15
- package/templates/default/public/icons/manual.svg +0 -16
- package/templates/default/public/icons/relativity.svg +0 -16
- package/templates/default/public/icons/systems.svg +0 -14
- package/templates/default/public/icons/warning.svg +0 -14
- package/templates/default/public/images/flux-sails.svg +0 -33
- package/templates/default/public/images/photonic-core.svg +0 -44
- package/templates/default/public/images/starwake.svg +0 -49
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { Link, useLocation, useNavigate } from 'react-router';
|
|
3
|
+
import { useMordocData } from '../data-context.js';
|
|
4
|
+
import { detectCurrentLang, buildLangPrefix, stripLangPrefix } from '../lang-utils.js';
|
|
5
|
+
import { SearchBar } from './SearchBar.js';
|
|
6
|
+
import { Topnav } from './Topnav.js';
|
|
7
|
+
import { LanguagePicker } from './LanguagePicker.js';
|
|
8
|
+
import styles from './Header.module.css';
|
|
9
|
+
|
|
10
|
+
type Theme = 'light' | 'dark';
|
|
11
|
+
|
|
12
|
+
interface HeaderProps {
|
|
13
|
+
sidenavOpen: boolean;
|
|
14
|
+
onMenuToggle: () => void;
|
|
15
|
+
onSearchOpen: () => void;
|
|
16
|
+
/** When false, the hamburger/close menu button is not rendered (e.g. on landing pages that have no sidenav). */
|
|
17
|
+
showMenu?: boolean;
|
|
18
|
+
/** Structural layout class injected by App.module.css (.headerArea) */
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function HamburgerIcon() {
|
|
23
|
+
return (
|
|
24
|
+
<svg
|
|
25
|
+
width="var(--menu-btn-icon, 20px)"
|
|
26
|
+
height="var(--menu-btn-icon, 20px)"
|
|
27
|
+
viewBox="0 0 24 24"
|
|
28
|
+
fill="none"
|
|
29
|
+
stroke="currentColor"
|
|
30
|
+
strokeWidth="2"
|
|
31
|
+
strokeLinecap="round"
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
>
|
|
34
|
+
<line x1="3" y1="6" x2="21" y2="6" />
|
|
35
|
+
<line x1="3" y1="12" x2="21" y2="12" />
|
|
36
|
+
<line x1="3" y1="18" x2="21" y2="18" />
|
|
37
|
+
</svg>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function CloseIcon() {
|
|
42
|
+
return (
|
|
43
|
+
<svg
|
|
44
|
+
width="var(--menu-btn-icon, 20px)"
|
|
45
|
+
height="var(--menu-btn-icon, 20px)"
|
|
46
|
+
viewBox="0 0 24 24"
|
|
47
|
+
fill="none"
|
|
48
|
+
stroke="currentColor"
|
|
49
|
+
strokeWidth="2"
|
|
50
|
+
strokeLinecap="round"
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
>
|
|
53
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
54
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function MoonIcon() {
|
|
60
|
+
return (
|
|
61
|
+
<svg
|
|
62
|
+
viewBox="0 0 24 24"
|
|
63
|
+
fill="none"
|
|
64
|
+
stroke="currentColor"
|
|
65
|
+
strokeWidth="2"
|
|
66
|
+
strokeLinecap="round"
|
|
67
|
+
strokeLinejoin="round"
|
|
68
|
+
aria-hidden="true"
|
|
69
|
+
style={{ width: 'var(--toggle-icon-size)', height: 'var(--toggle-icon-size)' }}
|
|
70
|
+
>
|
|
71
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
|
72
|
+
</svg>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function SunIcon() {
|
|
77
|
+
return (
|
|
78
|
+
<svg
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
strokeWidth="2"
|
|
83
|
+
strokeLinecap="round"
|
|
84
|
+
strokeLinejoin="round"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
style={{ width: 'var(--toggle-icon-size)', height: 'var(--toggle-icon-size)' }}
|
|
87
|
+
>
|
|
88
|
+
<circle cx="12" cy="12" r="5" />
|
|
89
|
+
<line x1="12" y1="1" x2="12" y2="3" />
|
|
90
|
+
<line x1="12" y1="21" x2="12" y2="23" />
|
|
91
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
|
92
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
|
93
|
+
<line x1="1" y1="12" x2="3" y2="12" />
|
|
94
|
+
<line x1="21" y1="12" x2="23" y2="12" />
|
|
95
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
|
96
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
|
97
|
+
</svg>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function Header({ sidenavOpen, onMenuToggle, onSearchOpen, showMenu = true, className }: HeaderProps) {
|
|
102
|
+
const { site, assets, language, navigation } = useMordocData();
|
|
103
|
+
const location = useLocation();
|
|
104
|
+
const navigate = useNavigate();
|
|
105
|
+
const [theme, setTheme] = useState<Theme>(() => {
|
|
106
|
+
try {
|
|
107
|
+
const stored = localStorage.getItem('mordoc-theme');
|
|
108
|
+
if (stored === 'light' || stored === 'dark') return stored as Theme;
|
|
109
|
+
} catch (e) {}
|
|
110
|
+
return 'light';
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
document.documentElement.classList.toggle('dark', theme === 'dark');
|
|
115
|
+
localStorage.setItem('mordoc-theme', theme);
|
|
116
|
+
}, [theme]);
|
|
117
|
+
|
|
118
|
+
const currentLang = detectCurrentLang(location.pathname, language, site.defaultLanguage);
|
|
119
|
+
const currentContentPath = stripLangPrefix(location.pathname, currentLang, site.defaultLanguage);
|
|
120
|
+
const logo = theme === 'dark' ? (assets.logoDark ?? assets.logo) : assets.logo;
|
|
121
|
+
|
|
122
|
+
function handleLangChange(newLang: string) {
|
|
123
|
+
const prefix = buildLangPrefix(newLang, site.defaultLanguage);
|
|
124
|
+
const target =
|
|
125
|
+
currentContentPath === '/' ? prefix || '/' : `${prefix}${currentContentPath}`;
|
|
126
|
+
navigate(target);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const hasTopnav = navigation.kind === 'topnav';
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<header className={`${styles.header}${className ? ` ${className}` : ''}`}>
|
|
133
|
+
{/* Top bar */}
|
|
134
|
+
<div className={styles.inner}>
|
|
135
|
+
{/* Brand — hamburger + logo */}
|
|
136
|
+
<div className={styles.brand}>
|
|
137
|
+
{showMenu && (
|
|
138
|
+
<button
|
|
139
|
+
className={styles.menuBtn}
|
|
140
|
+
onClick={onMenuToggle}
|
|
141
|
+
aria-label={sidenavOpen ? 'Close menu' : 'Open menu'}
|
|
142
|
+
aria-expanded={sidenavOpen}
|
|
143
|
+
>
|
|
144
|
+
{sidenavOpen ? <CloseIcon /> : <HamburgerIcon />}
|
|
145
|
+
</button>
|
|
146
|
+
)}
|
|
147
|
+
<Link to="/" className={styles.logo}>
|
|
148
|
+
{logo ? (
|
|
149
|
+
<img src={logo} alt={site.name} className={styles.logoImage} />
|
|
150
|
+
) : (
|
|
151
|
+
<span className={styles.logoText}>{site.name}</span>
|
|
152
|
+
)}
|
|
153
|
+
</Link>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
{/* Centered search */}
|
|
157
|
+
<div className={styles.search}>
|
|
158
|
+
<SearchBar onOpen={onSearchOpen} />
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{/* Right actions */}
|
|
162
|
+
<div className={styles.actions}>
|
|
163
|
+
{language && language.languages.length > 1 && (
|
|
164
|
+
<LanguagePicker
|
|
165
|
+
languages={language.languages}
|
|
166
|
+
currentLang={currentLang}
|
|
167
|
+
onChange={handleLangChange}
|
|
168
|
+
/>
|
|
169
|
+
)}
|
|
170
|
+
<button
|
|
171
|
+
onClick={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))}
|
|
172
|
+
aria-label={theme === 'light' ? 'Switch to dark mode' : 'Switch to light mode'}
|
|
173
|
+
className={styles.themeToggle}
|
|
174
|
+
>
|
|
175
|
+
{theme === 'light' ? <MoonIcon /> : <SunIcon />}
|
|
176
|
+
</button>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
{/* Topnav second row — desktop only, only when topnav navigation is configured */}
|
|
181
|
+
{hasTopnav && (
|
|
182
|
+
<div className={styles.topnavRow}>
|
|
183
|
+
<Topnav />
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
</header>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
LANGUAGE PICKER TOKENS
|
|
3
|
+
============================================================ */
|
|
4
|
+
:root {
|
|
5
|
+
--lang-height: 36px;
|
|
6
|
+
--lang-px: 10px;
|
|
7
|
+
--lang-gap: 6px;
|
|
8
|
+
--lang-radius: 6px;
|
|
9
|
+
--lang-font-size: 14px;
|
|
10
|
+
--lang-icon-size: 16px;
|
|
11
|
+
--lang-fg: #383838;
|
|
12
|
+
--lang-fg-hover: #1c1c1c;
|
|
13
|
+
--lang-bg-hover: #f5f5f5;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:global(.dark) {
|
|
17
|
+
--lang-fg: #9e9e9e;
|
|
18
|
+
--lang-fg-hover: #ebebeb;
|
|
19
|
+
--lang-bg-hover: #1f1f1f;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.wrapper {
|
|
23
|
+
position: relative;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.trigger {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: var(--lang-gap);
|
|
30
|
+
height: var(--lang-height);
|
|
31
|
+
padding: 0 var(--lang-px);
|
|
32
|
+
border: 0;
|
|
33
|
+
background: transparent;
|
|
34
|
+
border-radius: var(--lang-radius);
|
|
35
|
+
font-family: inherit;
|
|
36
|
+
font-size: var(--lang-font-size);
|
|
37
|
+
font-weight: 500;
|
|
38
|
+
color: var(--lang-fg);
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
transition: background-color 0.15s, color 0.15s;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.trigger:hover {
|
|
44
|
+
color: var(--lang-fg-hover);
|
|
45
|
+
background-color: var(--lang-bg-hover);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.trigger:focus-visible {
|
|
49
|
+
outline: 2px solid var(--accent-emphasis);
|
|
50
|
+
outline-offset: 2px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Hide language code on small phones — globe icon only */
|
|
54
|
+
@media (max-width: 479px) {
|
|
55
|
+
.code {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.trigger {
|
|
60
|
+
padding: 0 8px;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.dropdown {
|
|
65
|
+
position: absolute;
|
|
66
|
+
top: calc(100% + 6px);
|
|
67
|
+
right: 0;
|
|
68
|
+
min-width: 120px;
|
|
69
|
+
margin: 0;
|
|
70
|
+
padding: 4px;
|
|
71
|
+
list-style: none;
|
|
72
|
+
background: var(--color-bg);
|
|
73
|
+
border: 1px solid var(--color-border);
|
|
74
|
+
border-radius: var(--radius-md);
|
|
75
|
+
box-shadow: var(--shadow-md);
|
|
76
|
+
z-index: 100;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.option {
|
|
80
|
+
padding: 0.5rem 0.75rem;
|
|
81
|
+
border-radius: var(--radius-sm);
|
|
82
|
+
font-size: var(--lang-font-size);
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
color: var(--color-fg-muted);
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
transition: background-color 0.1s, color 0.1s;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.option:hover {
|
|
90
|
+
background: var(--color-bg-hover);
|
|
91
|
+
color: var(--color-fg);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.optionActive {
|
|
95
|
+
color: var(--accent-emphasis);
|
|
96
|
+
background: var(--accent-subtle);
|
|
97
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import styles from './LanguagePicker.module.css';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Maps ISO 639-1 (and common BCP-47) language codes to their native-script autonyms.
|
|
6
|
+
* Keys are lowercase. Add entries here as needed.
|
|
7
|
+
*/
|
|
8
|
+
const LANGUAGE_NAMES: Record<string, string> = {
|
|
9
|
+
af: 'Afrikaans',
|
|
10
|
+
am: 'አማርኛ',
|
|
11
|
+
ar: 'العربية',
|
|
12
|
+
az: 'Azərbaycan',
|
|
13
|
+
be: 'Беларуская',
|
|
14
|
+
bg: 'Български',
|
|
15
|
+
bn: 'বাংলা',
|
|
16
|
+
bs: 'Bosanski',
|
|
17
|
+
ca: 'Català',
|
|
18
|
+
cs: 'Čeština',
|
|
19
|
+
cy: 'Cymraeg',
|
|
20
|
+
da: 'Dansk',
|
|
21
|
+
de: 'Deutsch',
|
|
22
|
+
el: 'Ελληνικά',
|
|
23
|
+
en: 'English',
|
|
24
|
+
eo: 'Esperanto',
|
|
25
|
+
es: 'Español',
|
|
26
|
+
et: 'Eesti',
|
|
27
|
+
eu: 'Euskara',
|
|
28
|
+
fa: 'فارسی',
|
|
29
|
+
fi: 'Suomi',
|
|
30
|
+
fil: 'Filipino',
|
|
31
|
+
fr: 'Français',
|
|
32
|
+
ga: 'Gaeilge',
|
|
33
|
+
gl: 'Galego',
|
|
34
|
+
gu: 'ગુજરાતી',
|
|
35
|
+
he: 'עברית',
|
|
36
|
+
hi: 'हिन्दी',
|
|
37
|
+
hr: 'Hrvatski',
|
|
38
|
+
hu: 'Magyar',
|
|
39
|
+
hy: 'Հայերեն',
|
|
40
|
+
id: 'Indonesia',
|
|
41
|
+
is: 'Íslenska',
|
|
42
|
+
it: 'Italiano',
|
|
43
|
+
ja: '日本語',
|
|
44
|
+
ka: 'ქართული',
|
|
45
|
+
kk: 'Қазақша',
|
|
46
|
+
km: 'ភាសាខ្មែរ',
|
|
47
|
+
kn: 'ಕನ್ನಡ',
|
|
48
|
+
ko: '한국어',
|
|
49
|
+
lt: 'Lietuvių',
|
|
50
|
+
lv: 'Latviešu',
|
|
51
|
+
mk: 'Македонски',
|
|
52
|
+
ml: 'മലയാളം',
|
|
53
|
+
mn: 'Монгол',
|
|
54
|
+
mr: 'मराठी',
|
|
55
|
+
ms: 'Melayu',
|
|
56
|
+
my: 'မြန်မာ',
|
|
57
|
+
nb: 'Norsk',
|
|
58
|
+
ne: 'नेपाली',
|
|
59
|
+
nl: 'Nederlands',
|
|
60
|
+
pa: 'ਪੰਜਾਬੀ',
|
|
61
|
+
pl: 'Polski',
|
|
62
|
+
pt: 'Português',
|
|
63
|
+
ro: 'Română',
|
|
64
|
+
ru: 'Русский',
|
|
65
|
+
si: 'සිංහල',
|
|
66
|
+
sk: 'Slovenčina',
|
|
67
|
+
sl: 'Slovenščina',
|
|
68
|
+
sq: 'Shqip',
|
|
69
|
+
sr: 'Српски',
|
|
70
|
+
sv: 'Svenska',
|
|
71
|
+
sw: 'Kiswahili',
|
|
72
|
+
ta: 'தமிழ்',
|
|
73
|
+
te: 'తెలుగు',
|
|
74
|
+
th: 'ภาษาไทย',
|
|
75
|
+
tr: 'Türkçe',
|
|
76
|
+
uk: 'Українська',
|
|
77
|
+
ur: 'اردو',
|
|
78
|
+
uz: 'Oʻzbek',
|
|
79
|
+
vi: 'Tiếng Việt',
|
|
80
|
+
zh: '中文',
|
|
81
|
+
'zh-cn': '中文(简体)',
|
|
82
|
+
'zh-tw': '中文(繁體)',
|
|
83
|
+
zu: 'IsiZulu',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** Returns the display name for a language code, falling back to the uppercased code. */
|
|
87
|
+
function getLanguageName(code: string): string {
|
|
88
|
+
return LANGUAGE_NAMES[code.toLowerCase()] ?? code.toUpperCase();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface LanguagePickerProps {
|
|
92
|
+
languages: string[];
|
|
93
|
+
currentLang: string;
|
|
94
|
+
onChange: (lang: string) => void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function GlobeIcon() {
|
|
98
|
+
return (
|
|
99
|
+
<svg
|
|
100
|
+
viewBox="0 0 24 24"
|
|
101
|
+
fill="none"
|
|
102
|
+
stroke="currentColor"
|
|
103
|
+
strokeWidth="2"
|
|
104
|
+
strokeLinecap="round"
|
|
105
|
+
strokeLinejoin="round"
|
|
106
|
+
aria-hidden="true"
|
|
107
|
+
style={{ width: 'var(--lang-icon-size)', height: 'var(--lang-icon-size)', flexShrink: 0 }}
|
|
108
|
+
>
|
|
109
|
+
<circle cx="12" cy="12" r="10" />
|
|
110
|
+
<line x1="2" y1="12" x2="22" y2="12" />
|
|
111
|
+
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
|
112
|
+
</svg>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function LanguagePicker({ languages, currentLang, onChange }: LanguagePickerProps) {
|
|
117
|
+
const [open, setOpen] = useState(false);
|
|
118
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (!open) return;
|
|
122
|
+
|
|
123
|
+
function handlePointerDown(e: MouseEvent) {
|
|
124
|
+
if (ref.current && !ref.current.contains(e.target as Node)) {
|
|
125
|
+
setOpen(false);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
130
|
+
if (e.key === 'Escape') setOpen(false);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
document.addEventListener('mousedown', handlePointerDown);
|
|
134
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
135
|
+
return () => {
|
|
136
|
+
document.removeEventListener('mousedown', handlePointerDown);
|
|
137
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
138
|
+
};
|
|
139
|
+
}, [open]);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div className={styles.wrapper} ref={ref}>
|
|
143
|
+
<button
|
|
144
|
+
className={styles.trigger}
|
|
145
|
+
onClick={() => setOpen((o) => !o)}
|
|
146
|
+
aria-haspopup="listbox"
|
|
147
|
+
aria-expanded={open}
|
|
148
|
+
aria-label={`Language: ${getLanguageName(currentLang)}`}
|
|
149
|
+
>
|
|
150
|
+
<GlobeIcon />
|
|
151
|
+
<span className={styles.code}>{getLanguageName(currentLang)}</span>
|
|
152
|
+
</button>
|
|
153
|
+
|
|
154
|
+
{open && (
|
|
155
|
+
<ul className={styles.dropdown} role="listbox" aria-label="Select language">
|
|
156
|
+
{languages.map((lang) => (
|
|
157
|
+
<li
|
|
158
|
+
key={lang}
|
|
159
|
+
role="option"
|
|
160
|
+
aria-selected={lang === currentLang}
|
|
161
|
+
className={`${styles.option}${lang === currentLang ? ` ${styles.optionActive}` : ''}`}
|
|
162
|
+
onClick={() => {
|
|
163
|
+
onChange(lang);
|
|
164
|
+
setOpen(false);
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
{getLanguageName(lang)}
|
|
168
|
+
</li>
|
|
169
|
+
))}
|
|
170
|
+
</ul>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
SEARCH BAR TOKENS
|
|
3
|
+
============================================================ */
|
|
4
|
+
:root {
|
|
5
|
+
--search-width: 256px;
|
|
6
|
+
--search-height: 36px;
|
|
7
|
+
--search-radius: 8px;
|
|
8
|
+
--search-px: 12px;
|
|
9
|
+
--search-gap: 8px;
|
|
10
|
+
--search-font-size: 14px;
|
|
11
|
+
--search-icon-size: 16px;
|
|
12
|
+
--search-bg: rgba(245, 245, 245, 0.5);
|
|
13
|
+
--search-bg-hover: #f5f5f5;
|
|
14
|
+
--search-border: #e5e5e5;
|
|
15
|
+
--search-border-hover: color-mix(in oklch, var(--accent) 30%, transparent);
|
|
16
|
+
--search-fg: #666666;
|
|
17
|
+
--kbd-height: 20px;
|
|
18
|
+
--kbd-px: 6px;
|
|
19
|
+
--kbd-font-size: 10px;
|
|
20
|
+
--kbd-radius: 4px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:global(.dark) {
|
|
24
|
+
--search-bg: rgba(36, 36, 36, 0.5);
|
|
25
|
+
--search-bg-hover: #242424;
|
|
26
|
+
--search-border: #2e2e2e;
|
|
27
|
+
--search-fg: #9e9e9e;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@media (min-width: 768px) {
|
|
31
|
+
:root { --search-width: 220px; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (min-width: 1024px) {
|
|
35
|
+
:root { --search-width: 256px; }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.searchBar {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--search-gap);
|
|
42
|
+
width: var(--search-width);
|
|
43
|
+
max-width: 100%;
|
|
44
|
+
height: var(--search-height);
|
|
45
|
+
padding: 0 var(--search-px);
|
|
46
|
+
background: var(--search-bg);
|
|
47
|
+
color: var(--search-fg);
|
|
48
|
+
border: 1px solid var(--search-border);
|
|
49
|
+
border-radius: var(--search-radius);
|
|
50
|
+
font-size: var(--search-font-size);
|
|
51
|
+
font-family: inherit;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
text-align: left;
|
|
54
|
+
transition: background-color 0.15s, border-color 0.15s;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.searchBar:hover {
|
|
58
|
+
background-color: var(--search-bg-hover);
|
|
59
|
+
border-color: var(--search-border-hover);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.searchBar:focus-visible {
|
|
63
|
+
outline: 2px solid var(--accent-emphasis);
|
|
64
|
+
outline-offset: 2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.icon {
|
|
68
|
+
width: var(--search-icon-size);
|
|
69
|
+
height: var(--search-icon-size);
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
color: var(--search-fg);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.placeholder {
|
|
75
|
+
flex: 1;
|
|
76
|
+
color: var(--search-fg);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.kbd {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
height: var(--kbd-height);
|
|
83
|
+
padding: 0 var(--kbd-px);
|
|
84
|
+
border: 1px solid var(--search-border);
|
|
85
|
+
border-radius: var(--kbd-radius);
|
|
86
|
+
background: var(--toggle-bg);
|
|
87
|
+
font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace;
|
|
88
|
+
font-size: var(--kbd-font-size);
|
|
89
|
+
font-weight: 500;
|
|
90
|
+
color: var(--search-fg);
|
|
91
|
+
flex-shrink: 0;
|
|
92
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import styles from './SearchBar.module.css';
|
|
3
|
+
|
|
4
|
+
export function SearchBar({ onOpen }: { onOpen: () => void }) {
|
|
5
|
+
const [shortcut, setShortcut] = useState('Ctrl K');
|
|
6
|
+
|
|
7
|
+
// Detect Mac after mount — navigator is unavailable during SSR.
|
|
8
|
+
// Starting with 'Ctrl K' keeps the server and initial client render
|
|
9
|
+
// identical, avoiding a hydration mismatch.
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (/Mac|iPod|iPhone|iPad/.test(navigator.platform)) {
|
|
12
|
+
setShortcut('⌘K');
|
|
13
|
+
}
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<button className={styles.searchBar} onClick={onOpen}>
|
|
18
|
+
<svg
|
|
19
|
+
className={styles.icon}
|
|
20
|
+
width="16"
|
|
21
|
+
height="16"
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="none"
|
|
24
|
+
stroke="currentColor"
|
|
25
|
+
strokeWidth="2"
|
|
26
|
+
strokeLinecap="round"
|
|
27
|
+
strokeLinejoin="round"
|
|
28
|
+
aria-hidden="true"
|
|
29
|
+
>
|
|
30
|
+
<circle cx="11" cy="11" r="8" />
|
|
31
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
32
|
+
</svg>
|
|
33
|
+
<span className={styles.placeholder}>Search...</span>
|
|
34
|
+
<kbd className={styles.kbd}>{shortcut}</kbd>
|
|
35
|
+
</button>
|
|
36
|
+
);
|
|
37
|
+
}
|