boltdocs 1.3.0 → 1.3.2

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.
Files changed (103) hide show
  1. package/dist/{cache-EHR7SXRU.mjs → cache-GQHF6BXI.mjs} +1 -1
  2. package/dist/{chunk-GSYECEZY.mjs → chunk-CYBWLFOG.mjs} +5 -1
  3. package/dist/node/index.js +36 -20
  4. package/dist/node/index.mjs +34 -22
  5. package/package.json +1 -1
  6. package/src/client/app/index.tsx +344 -344
  7. package/src/client/app/preload.tsx +56 -56
  8. package/src/client/index.ts +40 -40
  9. package/src/client/ssr.tsx +51 -51
  10. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +76 -76
  11. package/src/client/theme/components/CodeBlock/index.ts +1 -1
  12. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +154 -154
  13. package/src/client/theme/components/PackageManagerTabs/index.ts +1 -1
  14. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +64 -64
  15. package/src/client/theme/components/Playground/Playground.tsx +124 -124
  16. package/src/client/theme/components/Playground/index.ts +1 -1
  17. package/src/client/theme/components/Playground/playground.css +168 -168
  18. package/src/client/theme/components/Video/Video.tsx +84 -84
  19. package/src/client/theme/components/Video/index.ts +1 -1
  20. package/src/client/theme/components/Video/video.css +41 -41
  21. package/src/client/theme/components/mdx/Admonition.tsx +80 -80
  22. package/src/client/theme/components/mdx/Badge.tsx +31 -31
  23. package/src/client/theme/components/mdx/Button.tsx +50 -50
  24. package/src/client/theme/components/mdx/Card.tsx +80 -80
  25. package/src/client/theme/components/mdx/List.tsx +57 -57
  26. package/src/client/theme/components/mdx/Tabs.tsx +94 -94
  27. package/src/client/theme/components/mdx/index.ts +18 -18
  28. package/src/client/theme/components/mdx/mdx-components.css +424 -424
  29. package/src/client/theme/icons/bun.tsx +62 -62
  30. package/src/client/theme/icons/deno.tsx +20 -20
  31. package/src/client/theme/icons/discord.tsx +12 -12
  32. package/src/client/theme/icons/github.tsx +15 -15
  33. package/src/client/theme/icons/npm.tsx +13 -13
  34. package/src/client/theme/icons/pnpm.tsx +72 -72
  35. package/src/client/theme/icons/twitter.tsx +12 -12
  36. package/src/client/theme/styles/markdown.css +343 -343
  37. package/src/client/theme/styles/variables.css +162 -162
  38. package/src/client/theme/styles.css +37 -37
  39. package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +10 -10
  40. package/src/client/theme/ui/BackgroundGradient/index.ts +1 -1
  41. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +68 -68
  42. package/src/client/theme/ui/Breadcrumbs/index.ts +1 -1
  43. package/src/client/theme/ui/Footer/footer.css +32 -32
  44. package/src/client/theme/ui/Head/Head.tsx +69 -69
  45. package/src/client/theme/ui/Head/index.ts +1 -1
  46. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +125 -125
  47. package/src/client/theme/ui/LanguageSwitcher/index.ts +1 -1
  48. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +98 -98
  49. package/src/client/theme/ui/Layout/Layout.tsx +202 -202
  50. package/src/client/theme/ui/Layout/base.css +76 -76
  51. package/src/client/theme/ui/Layout/index.ts +2 -2
  52. package/src/client/theme/ui/Layout/pagination.css +72 -72
  53. package/src/client/theme/ui/Layout/responsive.css +36 -36
  54. package/src/client/theme/ui/Link/Link.tsx +254 -254
  55. package/src/client/theme/ui/Link/index.ts +2 -2
  56. package/src/client/theme/ui/Loading/Loading.tsx +10 -10
  57. package/src/client/theme/ui/Loading/index.ts +1 -1
  58. package/src/client/theme/ui/Loading/loading.css +30 -30
  59. package/src/client/theme/ui/Navbar/GithubStars.tsx +27 -27
  60. package/src/client/theme/ui/Navbar/Navbar.tsx +145 -145
  61. package/src/client/theme/ui/Navbar/index.ts +2 -2
  62. package/src/client/theme/ui/Navbar/navbar.css +233 -233
  63. package/src/client/theme/ui/NotFound/NotFound.tsx +19 -19
  64. package/src/client/theme/ui/NotFound/index.ts +1 -1
  65. package/src/client/theme/ui/NotFound/not-found.css +64 -64
  66. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +235 -235
  67. package/src/client/theme/ui/OnThisPage/index.ts +1 -1
  68. package/src/client/theme/ui/OnThisPage/toc.css +132 -132
  69. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +18 -18
  70. package/src/client/theme/ui/PoweredBy/index.ts +1 -1
  71. package/src/client/theme/ui/PoweredBy/powered-by.css +76 -76
  72. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +199 -199
  73. package/src/client/theme/ui/SearchDialog/index.ts +1 -1
  74. package/src/client/theme/ui/SearchDialog/search.css +152 -152
  75. package/src/client/theme/ui/Sidebar/Sidebar.tsx +204 -204
  76. package/src/client/theme/ui/Sidebar/index.ts +1 -1
  77. package/src/client/theme/ui/Sidebar/sidebar.css +236 -236
  78. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +69 -69
  79. package/src/client/theme/ui/ThemeToggle/index.ts +1 -1
  80. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +136 -136
  81. package/src/client/theme/ui/VersionSwitcher/index.ts +1 -1
  82. package/src/client/types.ts +50 -50
  83. package/src/client/utils.ts +26 -26
  84. package/src/node/cache.ts +408 -408
  85. package/src/node/config.ts +192 -192
  86. package/src/node/index.ts +21 -21
  87. package/src/node/mdx.ts +120 -120
  88. package/src/node/plugin/entry.ts +58 -58
  89. package/src/node/plugin/html.ts +55 -55
  90. package/src/node/plugin/index.ts +193 -193
  91. package/src/node/plugin/types.ts +11 -11
  92. package/src/node/routes/cache.ts +28 -28
  93. package/src/node/routes/index.ts +167 -167
  94. package/src/node/routes/parser.ts +153 -127
  95. package/src/node/routes/sorter.ts +42 -42
  96. package/src/node/routes/types.ts +49 -49
  97. package/src/node/ssg/index.ts +114 -114
  98. package/src/node/ssg/meta.ts +33 -34
  99. package/src/node/ssg/options.ts +13 -13
  100. package/src/node/ssg/sitemap.ts +55 -54
  101. package/src/node/utils.ts +145 -134
  102. package/tsconfig.json +20 -20
  103. package/tsup.config.ts +22 -22
@@ -1,69 +1,69 @@
1
- import { useEffect } from "react";
2
- import { useLocation } from "react-router-dom";
3
-
4
- interface HeadProps {
5
- siteTitle: string;
6
- siteDescription?: string;
7
- routes: Array<{ path: string; title: string; description?: string }>;
8
- }
9
-
10
- export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
11
- const location = useLocation();
12
-
13
- useEffect(() => {
14
- // Find the current route's metadata
15
- const currentRoute = routes.find((r) => r.path === location.pathname);
16
- const pageTitle = currentRoute?.title;
17
- const pageDescription = currentRoute?.description || siteDescription || "";
18
-
19
- // Update document title
20
- document.title = pageTitle ? `${pageTitle} | ${siteTitle}` : siteTitle;
21
-
22
- // Update or create meta description
23
- let metaDesc = document.querySelector(
24
- 'meta[name="description"]',
25
- ) as HTMLMetaElement | null;
26
- if (!metaDesc) {
27
- metaDesc = document.createElement("meta");
28
- metaDesc.name = "description";
29
- document.head.appendChild(metaDesc);
30
- }
31
- metaDesc.content = pageDescription;
32
-
33
- // Update OG tags
34
- setMetaTag("property", "og:title", document.title);
35
- setMetaTag("property", "og:description", pageDescription);
36
- setMetaTag("property", "og:type", "article");
37
- setMetaTag("property", "og:url", window.location.href);
38
-
39
- // Twitter card
40
- setMetaTag("name", "twitter:card", "summary");
41
- setMetaTag("name", "twitter:title", document.title);
42
- setMetaTag("name", "twitter:description", pageDescription);
43
-
44
- // Canonical URL
45
- let canonical = document.querySelector(
46
- 'link[rel="canonical"]',
47
- ) as HTMLLinkElement | null;
48
- if (!canonical) {
49
- canonical = document.createElement("link");
50
- canonical.rel = "canonical";
51
- document.head.appendChild(canonical);
52
- }
53
- canonical.href = window.location.origin + location.pathname;
54
- }, [location.pathname, siteTitle, siteDescription, routes]);
55
-
56
- return null; // This component only manages <head>, no visual output
57
- }
58
-
59
- function setMetaTag(attr: "name" | "property", key: string, content: string) {
60
- let tag = document.querySelector(
61
- `meta[${attr}="${key}"]`,
62
- ) as HTMLMetaElement | null;
63
- if (!tag) {
64
- tag = document.createElement("meta");
65
- tag.setAttribute(attr, key);
66
- document.head.appendChild(tag);
67
- }
68
- tag.content = content;
69
- }
1
+ import { useEffect } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+
4
+ interface HeadProps {
5
+ siteTitle: string;
6
+ siteDescription?: string;
7
+ routes: Array<{ path: string; title: string; description?: string }>;
8
+ }
9
+
10
+ export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
11
+ const location = useLocation();
12
+
13
+ useEffect(() => {
14
+ // Find the current route's metadata
15
+ const currentRoute = routes.find((r) => r.path === location.pathname);
16
+ const pageTitle = currentRoute?.title;
17
+ const pageDescription = currentRoute?.description || siteDescription || "";
18
+
19
+ // Update document title
20
+ document.title = pageTitle ? `${pageTitle} | ${siteTitle}` : siteTitle;
21
+
22
+ // Update or create meta description
23
+ let metaDesc = document.querySelector(
24
+ 'meta[name="description"]',
25
+ ) as HTMLMetaElement | null;
26
+ if (!metaDesc) {
27
+ metaDesc = document.createElement("meta");
28
+ metaDesc.name = "description";
29
+ document.head.appendChild(metaDesc);
30
+ }
31
+ metaDesc.content = pageDescription;
32
+
33
+ // Update OG tags
34
+ setMetaTag("property", "og:title", document.title);
35
+ setMetaTag("property", "og:description", pageDescription);
36
+ setMetaTag("property", "og:type", "article");
37
+ setMetaTag("property", "og:url", window.location.href);
38
+
39
+ // Twitter card
40
+ setMetaTag("name", "twitter:card", "summary");
41
+ setMetaTag("name", "twitter:title", document.title);
42
+ setMetaTag("name", "twitter:description", pageDescription);
43
+
44
+ // Canonical URL
45
+ let canonical = document.querySelector(
46
+ 'link[rel="canonical"]',
47
+ ) as HTMLLinkElement | null;
48
+ if (!canonical) {
49
+ canonical = document.createElement("link");
50
+ canonical.rel = "canonical";
51
+ document.head.appendChild(canonical);
52
+ }
53
+ canonical.href = window.location.origin + location.pathname;
54
+ }, [location.pathname, siteTitle, siteDescription, routes]);
55
+
56
+ return null; // This component only manages <head>, no visual output
57
+ }
58
+
59
+ function setMetaTag(attr: "name" | "property", key: string, content: string) {
60
+ let tag = document.querySelector(
61
+ `meta[${attr}="${key}"]`,
62
+ ) as HTMLMetaElement | null;
63
+ if (!tag) {
64
+ tag = document.createElement("meta");
65
+ tag.setAttribute(attr, key);
66
+ document.head.appendChild(tag);
67
+ }
68
+ tag.content = content;
69
+ }
@@ -1 +1 @@
1
- export { Head } from "./Head";
1
+ export { Head } from "./Head";
@@ -1,125 +1,125 @@
1
- import React, { useState, useRef, useEffect } from "react";
2
- import { Globe, ChevronDown } from "lucide-react";
3
- import { useNavigate, useLocation } from "react-router-dom";
4
- import { BoltdocsI18nConfig } from "../../../../node/config";
5
- import { ComponentRoute } from "../../../types";
6
-
7
- function getBaseFilePath(
8
- filePath: string,
9
- version: string | undefined,
10
- locale: string | undefined,
11
- ): string {
12
- let path = filePath;
13
- if (version && (path === version || path.startsWith(version + "/"))) {
14
- path = path === version ? "index.md" : path.slice(version.length + 1);
15
- }
16
- if (locale && (path === locale || path.startsWith(locale + "/"))) {
17
- path = path === locale ? "index.md" : path.slice(locale.length + 1);
18
- }
19
- return path;
20
- }
21
-
22
- export function LanguageSwitcher({
23
- i18n,
24
- currentLocale,
25
- allRoutes,
26
- }: {
27
- i18n: BoltdocsI18nConfig;
28
- currentLocale: string;
29
- allRoutes: ComponentRoute[];
30
- }) {
31
- const [isOpen, setIsOpen] = useState(false);
32
- const dropdownRef = useRef<HTMLDivElement>(null);
33
- const navigate = useNavigate();
34
- const location = useLocation();
35
-
36
- useEffect(() => {
37
- function handleClickOutside(event: MouseEvent) {
38
- if (
39
- dropdownRef.current &&
40
- !dropdownRef.current.contains(event.target as Node)
41
- ) {
42
- setIsOpen(false);
43
- }
44
- }
45
- document.addEventListener("mousedown", handleClickOutside);
46
- return () => document.removeEventListener("mousedown", handleClickOutside);
47
- }, []);
48
-
49
- const handleSelect = (locale: string) => {
50
- setIsOpen(false);
51
- if (locale === currentLocale) return;
52
-
53
- const currentRoute = allRoutes.find((r) => r.path === location.pathname);
54
- let targetPath = "/";
55
-
56
- if (currentRoute) {
57
- const baseFile = getBaseFilePath(
58
- currentRoute.filePath,
59
- currentRoute.version,
60
- currentRoute.locale,
61
- );
62
- const targetRoute = allRoutes.find(
63
- (r) =>
64
- getBaseFilePath(r.filePath, r.version, r.locale) === baseFile &&
65
- (r.locale || i18n.defaultLocale) === locale &&
66
- r.version === currentRoute.version,
67
- );
68
- if (targetRoute) {
69
- targetPath = targetRoute.path;
70
- } else {
71
- const defaultIndexRoute = allRoutes.find(
72
- (r) =>
73
- getBaseFilePath(r.filePath, r.version, r.locale) === "index.md" &&
74
- (r.locale || i18n.defaultLocale) === locale &&
75
- r.version === currentRoute.version,
76
- );
77
- targetPath = defaultIndexRoute
78
- ? defaultIndexRoute.path
79
- : locale === i18n.defaultLocale
80
- ? currentRoute.version
81
- ? `/${currentRoute.version}`
82
- : "/"
83
- : currentRoute.version
84
- ? `/${currentRoute.version}/${locale}`
85
- : `/${locale}`;
86
- }
87
- } else {
88
- targetPath = locale === i18n.defaultLocale ? "/" : `/${locale}`;
89
- }
90
-
91
- navigate(targetPath);
92
- };
93
-
94
- return (
95
- <div className="boltdocs-language-switcher" ref={dropdownRef}>
96
- <button
97
- className="language-btn"
98
- onClick={() => setIsOpen(!isOpen)}
99
- aria-label="Switch language"
100
- aria-expanded={isOpen}
101
- aria-haspopup="listbox"
102
- >
103
- <Globe size={18} />
104
- <span className="language-label">
105
- {i18n.locales[currentLocale] || currentLocale}
106
- </span>
107
- <ChevronDown size={14} />
108
- </button>
109
-
110
- {isOpen && (
111
- <div className="language-dropdown">
112
- {Object.entries(i18n.locales).map(([key, label]) => (
113
- <button
114
- key={key}
115
- className={`language-option ${key === currentLocale ? "active" : ""}`}
116
- onClick={() => handleSelect(key)}
117
- >
118
- {label}
119
- </button>
120
- ))}
121
- </div>
122
- )}
123
- </div>
124
- );
125
- }
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import { Globe, ChevronDown } from "lucide-react";
3
+ import { useNavigate, useLocation } from "react-router-dom";
4
+ import { BoltdocsI18nConfig } from "../../../../node/config";
5
+ import { ComponentRoute } from "../../../types";
6
+
7
+ function getBaseFilePath(
8
+ filePath: string,
9
+ version: string | undefined,
10
+ locale: string | undefined,
11
+ ): string {
12
+ let path = filePath;
13
+ if (version && (path === version || path.startsWith(version + "/"))) {
14
+ path = path === version ? "index.md" : path.slice(version.length + 1);
15
+ }
16
+ if (locale && (path === locale || path.startsWith(locale + "/"))) {
17
+ path = path === locale ? "index.md" : path.slice(locale.length + 1);
18
+ }
19
+ return path;
20
+ }
21
+
22
+ export function LanguageSwitcher({
23
+ i18n,
24
+ currentLocale,
25
+ allRoutes,
26
+ }: {
27
+ i18n: BoltdocsI18nConfig;
28
+ currentLocale: string;
29
+ allRoutes: ComponentRoute[];
30
+ }) {
31
+ const [isOpen, setIsOpen] = useState(false);
32
+ const dropdownRef = useRef<HTMLDivElement>(null);
33
+ const navigate = useNavigate();
34
+ const location = useLocation();
35
+
36
+ useEffect(() => {
37
+ function handleClickOutside(event: MouseEvent) {
38
+ if (
39
+ dropdownRef.current &&
40
+ !dropdownRef.current.contains(event.target as Node)
41
+ ) {
42
+ setIsOpen(false);
43
+ }
44
+ }
45
+ document.addEventListener("mousedown", handleClickOutside);
46
+ return () => document.removeEventListener("mousedown", handleClickOutside);
47
+ }, []);
48
+
49
+ const handleSelect = (locale: string) => {
50
+ setIsOpen(false);
51
+ if (locale === currentLocale) return;
52
+
53
+ const currentRoute = allRoutes.find((r) => r.path === location.pathname);
54
+ let targetPath = "/";
55
+
56
+ if (currentRoute) {
57
+ const baseFile = getBaseFilePath(
58
+ currentRoute.filePath,
59
+ currentRoute.version,
60
+ currentRoute.locale,
61
+ );
62
+ const targetRoute = allRoutes.find(
63
+ (r) =>
64
+ getBaseFilePath(r.filePath, r.version, r.locale) === baseFile &&
65
+ (r.locale || i18n.defaultLocale) === locale &&
66
+ r.version === currentRoute.version,
67
+ );
68
+ if (targetRoute) {
69
+ targetPath = targetRoute.path;
70
+ } else {
71
+ const defaultIndexRoute = allRoutes.find(
72
+ (r) =>
73
+ getBaseFilePath(r.filePath, r.version, r.locale) === "index.md" &&
74
+ (r.locale || i18n.defaultLocale) === locale &&
75
+ r.version === currentRoute.version,
76
+ );
77
+ targetPath = defaultIndexRoute
78
+ ? defaultIndexRoute.path
79
+ : locale === i18n.defaultLocale
80
+ ? currentRoute.version
81
+ ? `/${currentRoute.version}`
82
+ : "/"
83
+ : currentRoute.version
84
+ ? `/${currentRoute.version}/${locale}`
85
+ : `/${locale}`;
86
+ }
87
+ } else {
88
+ targetPath = locale === i18n.defaultLocale ? "/" : `/${locale}`;
89
+ }
90
+
91
+ navigate(targetPath);
92
+ };
93
+
94
+ return (
95
+ <div className="boltdocs-language-switcher" ref={dropdownRef}>
96
+ <button
97
+ className="language-btn"
98
+ onClick={() => setIsOpen(!isOpen)}
99
+ aria-label="Switch language"
100
+ aria-expanded={isOpen}
101
+ aria-haspopup="listbox"
102
+ >
103
+ <Globe size={18} />
104
+ <span className="language-label">
105
+ {i18n.locales[currentLocale] || currentLocale}
106
+ </span>
107
+ <ChevronDown size={14} />
108
+ </button>
109
+
110
+ {isOpen && (
111
+ <div className="language-dropdown">
112
+ {Object.entries(i18n.locales).map(([key, label]) => (
113
+ <button
114
+ key={key}
115
+ className={`language-option ${key === currentLocale ? "active" : ""}`}
116
+ onClick={() => handleSelect(key)}
117
+ >
118
+ {label}
119
+ </button>
120
+ ))}
121
+ </div>
122
+ )}
123
+ </div>
124
+ );
125
+ }
@@ -1 +1 @@
1
- export { LanguageSwitcher } from "./LanguageSwitcher";
1
+ export { LanguageSwitcher } from "./LanguageSwitcher";
@@ -1,98 +1,98 @@
1
- .boltdocs-language-switcher {
2
- position: relative;
3
- display: flex;
4
- align-items: center;
5
- }
6
-
7
- .language-btn {
8
- display: flex;
9
- align-items: center;
10
- gap: 0.35rem;
11
- padding: 0.4rem 0.6rem;
12
- background: transparent;
13
- color: var(--ld-text-muted);
14
- border: none;
15
- border-radius: var(--ld-radius-md);
16
- font-size: 0.8125rem;
17
- font-weight: 500;
18
- cursor: pointer;
19
- transition:
20
- background-color 0.2s,
21
- color 0.2s;
22
- }
23
-
24
- .language-btn svg {
25
- width: 15px;
26
- height: 15px;
27
- opacity: 0.8;
28
- }
29
-
30
- .language-btn:hover {
31
- background-color: var(--ld-bg-mute);
32
- color: var(--ld-text-main);
33
- }
34
-
35
- .language-dropdown {
36
- position: absolute;
37
- top: 100%;
38
- right: 0;
39
- margin-top: 0.35rem;
40
- min-width: 130px;
41
- background-color: rgba(15, 15, 24, 0.85); /* Smooth translucent dark match */
42
- backdrop-filter: blur(12px);
43
- -webkit-backdrop-filter: blur(12px);
44
- border: 1px solid var(--ld-border-strong);
45
- border-radius: var(--ld-radius-md);
46
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
47
- padding: 0.35rem;
48
- z-index: 200;
49
- display: flex;
50
- flex-direction: column;
51
- gap: 0.15rem;
52
- animation: languageDropdownIn 0.15s ease-out;
53
- }
54
-
55
- @keyframes languageDropdownIn {
56
- from {
57
- opacity: 0;
58
- transform: translateY(-4px);
59
- }
60
- to {
61
- opacity: 1;
62
- transform: translateY(0);
63
- }
64
- }
65
-
66
- /* Light mode fallback */
67
- [data-theme="light"] .language-dropdown,
68
- .theme-light .language-dropdown {
69
- background-color: rgba(255, 255, 255, 0.9);
70
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
71
- }
72
-
73
- .language-option {
74
- display: block;
75
- width: 100%;
76
- text-align: left;
77
- padding: 0.4rem 0.6rem;
78
- background: transparent;
79
- border: none;
80
- border-radius: var(--ld-radius-sm);
81
- color: var(--ld-text-muted);
82
- font-size: 0.8125rem;
83
- font-weight: 500;
84
- cursor: pointer;
85
- transition:
86
- background-color 0.2s,
87
- color 0.2s;
88
- }
89
-
90
- .language-option:hover {
91
- background-color: var(--ld-bg-mute);
92
- color: var(--ld-text-main);
93
- }
94
-
95
- .language-option.active {
96
- background-color: var(--ld-color-primary-muted);
97
- color: var(--ld-color-primary);
98
- }
1
+ .boltdocs-language-switcher {
2
+ position: relative;
3
+ display: flex;
4
+ align-items: center;
5
+ }
6
+
7
+ .language-btn {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 0.35rem;
11
+ padding: 0.4rem 0.6rem;
12
+ background: transparent;
13
+ color: var(--ld-text-muted);
14
+ border: none;
15
+ border-radius: var(--ld-radius-md);
16
+ font-size: 0.8125rem;
17
+ font-weight: 500;
18
+ cursor: pointer;
19
+ transition:
20
+ background-color 0.2s,
21
+ color 0.2s;
22
+ }
23
+
24
+ .language-btn svg {
25
+ width: 15px;
26
+ height: 15px;
27
+ opacity: 0.8;
28
+ }
29
+
30
+ .language-btn:hover {
31
+ background-color: var(--ld-bg-mute);
32
+ color: var(--ld-text-main);
33
+ }
34
+
35
+ .language-dropdown {
36
+ position: absolute;
37
+ top: 100%;
38
+ right: 0;
39
+ margin-top: 0.35rem;
40
+ min-width: 130px;
41
+ background-color: rgba(15, 15, 24, 0.85); /* Smooth translucent dark match */
42
+ backdrop-filter: blur(12px);
43
+ -webkit-backdrop-filter: blur(12px);
44
+ border: 1px solid var(--ld-border-strong);
45
+ border-radius: var(--ld-radius-md);
46
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
47
+ padding: 0.35rem;
48
+ z-index: 200;
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 0.15rem;
52
+ animation: languageDropdownIn 0.15s ease-out;
53
+ }
54
+
55
+ @keyframes languageDropdownIn {
56
+ from {
57
+ opacity: 0;
58
+ transform: translateY(-4px);
59
+ }
60
+ to {
61
+ opacity: 1;
62
+ transform: translateY(0);
63
+ }
64
+ }
65
+
66
+ /* Light mode fallback */
67
+ [data-theme="light"] .language-dropdown,
68
+ .theme-light .language-dropdown {
69
+ background-color: rgba(255, 255, 255, 0.9);
70
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
71
+ }
72
+
73
+ .language-option {
74
+ display: block;
75
+ width: 100%;
76
+ text-align: left;
77
+ padding: 0.4rem 0.6rem;
78
+ background: transparent;
79
+ border: none;
80
+ border-radius: var(--ld-radius-sm);
81
+ color: var(--ld-text-muted);
82
+ font-size: 0.8125rem;
83
+ font-weight: 500;
84
+ cursor: pointer;
85
+ transition:
86
+ background-color 0.2s,
87
+ color 0.2s;
88
+ }
89
+
90
+ .language-option:hover {
91
+ background-color: var(--ld-bg-mute);
92
+ color: var(--ld-text-main);
93
+ }
94
+
95
+ .language-option.active {
96
+ background-color: var(--ld-color-primary-muted);
97
+ color: var(--ld-color-primary);
98
+ }