@genomicx/ui 0.2.0 → 0.4.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.
@@ -1,6 +1,7 @@
1
1
  interface AppFooterProps {
2
2
  appName?: string;
3
3
  onReportBug?: () => void;
4
+ bugReportUrl?: string;
4
5
  }
5
- export declare function AppFooter({ appName, onReportBug }: AppFooterProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function AppFooter({ appName, onReportBug, bugReportUrl }: AppFooterProps): import("react/jsx-runtime").JSX.Element;
6
7
  export {};
@@ -3,9 +3,11 @@ export interface NavBarProps {
3
3
  appName: string;
4
4
  appSubtitle?: string;
5
5
  version?: string;
6
+ /** Custom SVG icon element. Defaults to GenomicX rings logo. */
7
+ icon?: ReactNode;
6
8
  /** Extra items in the desktop nav (right side, before theme toggle) */
7
9
  actions?: ReactNode;
8
10
  /** Extra items in the mobile dropdown */
9
11
  mobileActions?: ReactNode;
10
12
  }
11
- export declare function NavBar({ appName, appSubtitle, version, actions, mobileActions }: NavBarProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function NavBar({ appName, appSubtitle, version, icon, actions, mobileActions }: NavBarProps): import("react/jsx-runtime").JSX.Element;
package/dist/index.js CHANGED
@@ -1,233 +1,184 @@
1
- import { jsxs as o, jsx as e } from "react/jsx-runtime";
2
- import { useState as h, useRef as f } from "react";
3
- import { Link as m } from "react-router-dom";
4
- import u from "react-hot-toast";
5
- function p({ disabled: t = !1 }) {
6
- const [r, a] = h(
7
- () => document.documentElement.getAttribute("data-theme") || "light"
8
- ), l = (n) => {
9
- a(n), document.documentElement.setAttribute("data-theme", n), localStorage.setItem("gx-theme", n);
1
+ import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
+ import { useState as x, useRef as p } from "react";
3
+ import { Link as d } from "react-router-dom";
4
+ import g from "react-hot-toast";
5
+ function u({ disabled: n = !1 }) {
6
+ const [o, t] = x(
7
+ () => document.documentElement.getAttribute("data-theme") || "dark"
8
+ ), l = (r) => {
9
+ t(r), document.documentElement.setAttribute("data-theme", r), localStorage.setItem("gx-theme", r);
10
10
  };
11
- return /* @__PURE__ */ o(
12
- "div",
13
- {
14
- className: `flex items-center rounded-full border overflow-hidden text-xs font-medium ${t ? "opacity-40 pointer-events-none" : ""}`,
15
- style: { borderColor: "var(--gx-border)" },
16
- title: t ? "Theme switching disabled" : void 0,
17
- children: [
18
- /* @__PURE__ */ e(
19
- "button",
20
- {
21
- onClick: () => !t && l("dark"),
22
- className: "px-3 py-1.5 transition-colors",
23
- style: r === "dark" ? { background: "var(--gx-accent)", color: "var(--gx-text-inverted)" } : { color: "var(--gx-text-muted)" },
24
- "aria-label": "Dark theme",
25
- disabled: t,
26
- children: /* @__PURE__ */ e("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { d: "M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" }) })
27
- }
28
- ),
29
- /* @__PURE__ */ e(
30
- "button",
31
- {
32
- onClick: () => !t && l("light"),
33
- className: "px-3 py-1.5 transition-colors",
34
- style: r === "light" ? { background: "var(--gx-accent)", color: "var(--gx-text-inverted)" } : { color: "var(--gx-text-muted)" },
35
- "aria-label": "Light theme",
36
- disabled: t,
37
- children: /* @__PURE__ */ e("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) })
38
- }
39
- )
40
- ]
41
- }
42
- );
11
+ return /* @__PURE__ */ a("div", { className: `gx-theme-toggle${n ? " disabled" : ""}`, title: n ? "Theme switching disabled" : void 0, children: [
12
+ /* @__PURE__ */ e(
13
+ "button",
14
+ {
15
+ onClick: () => !n && l("dark"),
16
+ className: `gx-theme-btn${o === "dark" ? " active" : ""}`,
17
+ "aria-label": "Dark theme",
18
+ disabled: n,
19
+ children: /* @__PURE__ */ e("svg", { className: "gx-theme-btn-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { d: "M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" }) })
20
+ }
21
+ ),
22
+ /* @__PURE__ */ e(
23
+ "button",
24
+ {
25
+ onClick: () => !n && l("light"),
26
+ className: `gx-theme-btn${o === "light" ? " active" : ""}`,
27
+ "aria-label": "Light theme",
28
+ disabled: n,
29
+ children: /* @__PURE__ */ e("svg", { className: "gx-theme-btn-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) })
30
+ }
31
+ )
32
+ ] });
43
33
  }
44
- function b({ appName: t, appSubtitle: r, version: a, actions: l, mobileActions: n }) {
45
- const [s, c] = h(!1);
46
- return /* @__PURE__ */ o("nav", { className: "sticky top-0 z-40", style: { background: "var(--gx-nav-bg)", backdropFilter: "blur(12px)", WebkitBackdropFilter: "blur(12px)", borderBottom: "1px solid var(--gx-border)" }, children: [
47
- /* @__PURE__ */ e("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ o("div", { className: "flex items-center justify-between h-[60px]", children: [
48
- /* @__PURE__ */ o(m, { to: "/", className: "flex items-center gap-3 hover:opacity-90 transition-opacity", children: [
49
- /* @__PURE__ */ o("svg", { className: "w-7 h-7", viewBox: "0 0 24 24", fill: "none", stroke: "var(--gx-accent)", strokeWidth: "2", children: [
50
- /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
51
- /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "6" }),
52
- /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "2" })
53
- ] }),
54
- /* @__PURE__ */ o("div", { children: [
55
- /* @__PURE__ */ o("h1", { className: "text-lg font-bold", style: { color: "var(--gx-text)" }, children: [
56
- t,
57
- a && /* @__PURE__ */ o("span", { className: "text-xs font-normal ml-1", style: { color: "var(--gx-text-muted)" }, children: [
34
+ const f = () => /* @__PURE__ */ a("svg", { className: "gx-nav-logo-icon", viewBox: "0 0 24 24", fill: "none", stroke: "var(--gx-accent)", strokeWidth: "2", children: [
35
+ /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
36
+ /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "6" }),
37
+ /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "2" })
38
+ ] });
39
+ function N({ appName: n, appSubtitle: o, version: t, icon: l, actions: r, mobileActions: i }) {
40
+ const [c, s] = x(!1);
41
+ return /* @__PURE__ */ a("nav", { className: "gx-nav", children: [
42
+ /* @__PURE__ */ e("div", { className: "gx-nav-inner", children: /* @__PURE__ */ a("div", { className: "gx-nav-row", children: [
43
+ /* @__PURE__ */ a(d, { to: "/", className: "gx-nav-logo", children: [
44
+ l ?? /* @__PURE__ */ e(f, {}),
45
+ /* @__PURE__ */ a("div", { children: [
46
+ /* @__PURE__ */ a("h1", { className: "gx-nav-logo-name", children: [
47
+ n,
48
+ t && /* @__PURE__ */ a("span", { className: "gx-nav-logo-version", children: [
58
49
  "v",
59
- a
50
+ t
60
51
  ] })
61
52
  ] }),
62
- r && /* @__PURE__ */ e("p", { className: "text-xs", style: { color: "var(--gx-text-muted)" }, children: r })
53
+ o && /* @__PURE__ */ e("p", { className: "gx-nav-logo-sub", children: o })
63
54
  ] })
64
55
  ] }),
65
- /* @__PURE__ */ o("div", { className: "hidden md:flex items-center gap-6", children: [
66
- l,
67
- /* @__PURE__ */ e(m, { to: "/about", className: "text-sm font-medium transition-colors", style: { color: "var(--gx-text-muted)" }, children: "About" }),
68
- /* @__PURE__ */ o(
69
- "a",
70
- {
71
- href: "https://github.com/happykhan",
72
- target: "_blank",
73
- rel: "noopener noreferrer",
74
- className: "text-sm font-medium transition-colors inline-flex items-center gap-1",
75
- style: { color: "var(--gx-text-muted)" },
76
- children: [
77
- "GitHub",
78
- /* @__PURE__ */ e("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
79
- ]
80
- }
81
- ),
82
- /* @__PURE__ */ e(p, {})
56
+ /* @__PURE__ */ a("div", { className: "gx-nav-desktop", children: [
57
+ r,
58
+ /* @__PURE__ */ e(d, { to: "/about", className: "gx-nav-link", children: "About" }),
59
+ /* @__PURE__ */ a("a", { href: "https://github.com/happykhan", target: "_blank", rel: "noopener noreferrer", className: "gx-nav-link", children: [
60
+ "GitHub",
61
+ /* @__PURE__ */ e("svg", { className: "gx-nav-link-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
62
+ ] }),
63
+ /* @__PURE__ */ e(u, {})
83
64
  ] }),
84
- /* @__PURE__ */ o("div", { className: "flex md:hidden items-center gap-3", children: [
85
- /* @__PURE__ */ e(p, {}),
86
- /* @__PURE__ */ e(
87
- "button",
88
- {
89
- onClick: () => c(!s),
90
- className: "p-2 rounded",
91
- style: { color: "var(--gx-text-muted)" },
92
- "aria-label": "Toggle menu",
93
- children: s ? /* @__PURE__ */ e("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ e("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) })
94
- }
95
- )
65
+ /* @__PURE__ */ a("div", { className: "gx-nav-mobile-toggle", children: [
66
+ /* @__PURE__ */ e(u, {}),
67
+ /* @__PURE__ */ e("button", { onClick: () => s(!c), className: "gx-nav-hamburger", "aria-label": "Toggle menu", children: c ? /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) }) })
96
68
  ] })
97
69
  ] }) }),
98
- s && /* @__PURE__ */ o("div", { className: "md:hidden px-4 pb-4 space-y-2", style: { borderTop: "1px solid var(--gx-border)", background: "var(--gx-nav-bg)" }, children: [
99
- n,
100
- /* @__PURE__ */ e(m, { to: "/about", onClick: () => c(!1), className: "block text-sm py-2 transition-colors", style: { color: "var(--gx-text-muted)" }, children: "About" }),
101
- /* @__PURE__ */ o(
102
- "a",
103
- {
104
- href: "https://github.com/happykhan",
105
- target: "_blank",
106
- rel: "noopener noreferrer",
107
- className: "inline-flex items-center gap-1 text-sm py-2 transition-colors",
108
- style: { color: "var(--gx-text-muted)" },
109
- children: [
110
- "GitHub",
111
- /* @__PURE__ */ e("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
112
- ]
113
- }
114
- )
70
+ c && /* @__PURE__ */ a("div", { className: "gx-nav-dropdown", children: [
71
+ i,
72
+ /* @__PURE__ */ e(d, { to: "/about", onClick: () => s(!1), className: "gx-nav-dropdown-link", children: "About" }),
73
+ /* @__PURE__ */ e("a", { href: "https://github.com/happykhan", target: "_blank", rel: "noopener noreferrer", className: "gx-nav-dropdown-link", children: "GitHub ↗" })
115
74
  ] })
116
75
  ] });
117
76
  }
118
- function y({ appName: t = "GenomicX", onReportBug: r }) {
119
- return /* @__PURE__ */ e("footer", { className: "mt-auto py-6", style: { borderTop: "1px solid var(--gx-border)", background: "var(--gx-bg-alt)" }, children: /* @__PURE__ */ e("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ o("div", { className: "flex flex-col md:flex-row justify-between items-center", children: [
120
- /* @__PURE__ */ o("div", { className: "text-sm mb-4 md:mb-0", style: { color: "var(--gx-text-muted)" }, children: [
121
- /* @__PURE__ */ o("p", { className: "font-semibold", style: { color: "var(--gx-text)" }, children: [
122
- t,
123
- " — Powered by BLAST & WebAssembly"
77
+ function k({ appName: n = "GenomicX", onReportBug: o, bugReportUrl: t }) {
78
+ return /* @__PURE__ */ e("footer", { className: "gx-footer", children: /* @__PURE__ */ e("div", { className: "gx-footer-inner", children: /* @__PURE__ */ a("div", { className: "gx-footer-content", children: [
79
+ /* @__PURE__ */ a("div", { className: "gx-footer-text", children: [
80
+ /* @__PURE__ */ a("p", { className: "gx-footer-text-title", children: [
81
+ n,
82
+ " — Powered by WebAssembly"
124
83
  ] }),
125
- /* @__PURE__ */ e("p", { className: "mt-1", children: "All processing runs locally in your browser — no data leaves your computer" })
84
+ /* @__PURE__ */ e("p", { className: "gx-footer-text-sub", children: "All processing runs locally in your browser — no data leaves your computer" })
126
85
  ] }),
127
- /* @__PURE__ */ o("div", { className: "flex gap-6 text-sm", children: [
128
- /* @__PURE__ */ e("a", { href: "https://genomicx.org", target: "_blank", rel: "noopener noreferrer", className: "transition-colors hover:text-[var(--gx-accent)]", style: { color: "var(--gx-text-muted)" }, children: "genomicx.org" }),
129
- r && /* @__PURE__ */ e("button", { onClick: r, className: "transition-colors hover:text-[var(--gx-accent)]", style: { color: "var(--gx-text-muted)" }, children: "Report Bug" })
86
+ /* @__PURE__ */ a("div", { className: "gx-footer-links", children: [
87
+ /* @__PURE__ */ e("a", { href: "https://genomicx.org", target: "_blank", rel: "noopener noreferrer", className: "gx-footer-link", children: "genomicx.org" }),
88
+ t && /* @__PURE__ */ e("a", { href: t, target: "_blank", rel: "noopener noreferrer", className: "gx-footer-link", children: "Report Bug" }),
89
+ o && !t && /* @__PURE__ */ e("button", { onClick: o, className: "gx-footer-link", children: "Report Bug" })
130
90
  ] })
131
91
  ] }) }) });
132
92
  }
133
- function C({ children: t, onReportBug: r, ...a }) {
134
- return /* @__PURE__ */ o("div", { className: "min-h-screen flex flex-col", style: { background: "var(--gx-bg)" }, children: [
135
- /* @__PURE__ */ e(b, { ...a }),
136
- /* @__PURE__ */ e("main", { className: "flex-1", children: t }),
137
- /* @__PURE__ */ e(y, { appName: a.appName, onReportBug: r })
93
+ function C({ children: n, onReportBug: o, ...t }) {
94
+ return /* @__PURE__ */ a("div", { style: { minHeight: "100vh", display: "flex", flexDirection: "column", background: "var(--gx-bg)" }, children: [
95
+ /* @__PURE__ */ e(N, { ...t }),
96
+ /* @__PURE__ */ e("main", { style: { flex: 1 }, children: n }),
97
+ /* @__PURE__ */ e(k, { appName: t.appName, onReportBug: o })
138
98
  ] });
139
99
  }
140
- function j({ logs: t, progress: r, title: a = "Console" }) {
141
- const [l, n] = h(!0), s = f(null), c = () => {
142
- navigator.clipboard.writeText(t.join(`
100
+ function $({ logs: n, progress: o, title: t = "Console" }) {
101
+ const l = p(null), r = () => {
102
+ navigator.clipboard.writeText(n.join(`
143
103
  `)).then(() => {
144
- u.success("Logs copied to clipboard!");
104
+ g.success("Logs copied to clipboard!");
145
105
  }).catch(() => {
146
- u.error("Failed to copy logs");
106
+ g.error("Failed to copy logs");
147
107
  });
148
- }, i = r && r.step !== "idle" && r.step !== "Complete!";
149
- return /* @__PURE__ */ o("div", { className: "card mt-6", children: [
150
- i && /* @__PURE__ */ o("div", { className: "mb-4 pb-4", style: { borderBottom: "1px solid var(--gx-border)" }, children: [
151
- /* @__PURE__ */ o("div", { className: "flex items-center justify-between mb-2", children: [
152
- /* @__PURE__ */ e("span", { className: "text-sm font-medium", style: { color: "var(--gx-text)" }, children: r.step }),
153
- /* @__PURE__ */ o("span", { className: "text-sm", style: { color: "var(--gx-text-muted)" }, children: [
154
- r.percent,
108
+ }, i = o && o.step !== "idle" && o.step !== "Complete!";
109
+ return /* @__PURE__ */ a("div", { className: "gx-console", children: [
110
+ i && /* @__PURE__ */ a("div", { className: "gx-console-progress", children: [
111
+ /* @__PURE__ */ a("div", { className: "gx-console-progress-row", children: [
112
+ /* @__PURE__ */ e("span", { className: "gx-console-progress-step", children: o.step }),
113
+ /* @__PURE__ */ a("span", { className: "gx-console-progress-pct", children: [
114
+ o.percent,
155
115
  "%"
156
116
  ] })
157
117
  ] }),
158
- /* @__PURE__ */ e("div", { className: "progress-bg", children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${r.percent}%` } }) }),
159
- r.message && /* @__PURE__ */ e("div", { className: "mt-2 text-xs", style: { color: "var(--gx-text-muted)" }, children: r.message })
118
+ /* @__PURE__ */ e("div", { className: "progress-bg", children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${o.percent}%` } }) }),
119
+ o.message && /* @__PURE__ */ e("div", { className: "gx-console-progress-msg", children: o.message })
160
120
  ] }),
161
- /* @__PURE__ */ o("div", { className: "flex items-center justify-between mb-3", children: [
162
- /* @__PURE__ */ o("div", { className: "flex items-center gap-2", children: [
163
- /* @__PURE__ */ e("button", { onClick: () => n(!l), style: { color: "var(--gx-text-muted)" }, children: l ? "▼" : "▶" }),
164
- /* @__PURE__ */ e("h3", { className: "font-semibold", style: { color: "var(--gx-text)" }, children: a }),
165
- /* @__PURE__ */ o("span", { className: "text-xs", style: { color: "var(--gx-text-muted)" }, children: [
121
+ /* @__PURE__ */ a("div", { className: "gx-console-header", children: [
122
+ /* @__PURE__ */ a("div", { className: "gx-console-title-row", children: [
123
+ /* @__PURE__ */ e("h3", { className: "gx-console-title", children: t }),
124
+ /* @__PURE__ */ a("span", { className: "gx-console-count", children: [
166
125
  "(",
167
- t.length,
126
+ n.length,
168
127
  " messages)"
169
128
  ] })
170
129
  ] }),
171
- /* @__PURE__ */ o("button", { onClick: c, className: "btn-secondary text-xs px-3 py-1", disabled: t.length === 0, children: [
172
- /* @__PURE__ */ e("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
130
+ /* @__PURE__ */ a("button", { onClick: r, className: "gx-console-copy", disabled: n.length === 0, children: [
131
+ /* @__PURE__ */ e("svg", { className: "gx-console-copy-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
173
132
  "Copy"
174
133
  ] })
175
134
  ] }),
176
- l && /* @__PURE__ */ e(
177
- "div",
178
- {
179
- ref: s,
180
- className: "font-mono text-xs p-4 rounded max-h-96 overflow-y-auto",
181
- style: { background: "var(--gx-code-bg)", color: "var(--gx-accent)", border: "1px solid var(--gx-border)" },
182
- children: t.length === 0 ? /* @__PURE__ */ e("div", { style: { color: "var(--gx-text-muted)" }, children: "No logs yet..." }) : t.map((d, g) => /* @__PURE__ */ e("div", { className: "mb-1 whitespace-pre-wrap break-all", children: d }, g))
183
- }
184
- )
135
+ /* @__PURE__ */ e("div", { ref: l, className: "gx-console-body", children: n.length === 0 ? /* @__PURE__ */ e("div", { className: "gx-console-empty", children: "No logs yet..." }) : n.map((c, s) => /* @__PURE__ */ e("div", { className: "gx-console-line", children: c }, s)) })
185
136
  ] });
186
137
  }
187
- const k = "https://static.genomicx.org/wasm", x = /* @__PURE__ */ new Map();
188
- async function N(t, r = k) {
189
- const a = `${r}/${t}`;
190
- if (x.has(a)) return x.get(a);
191
- const [l, n] = await Promise.all([
192
- fetch(`${r}/${t}.js`),
193
- fetch(`${r}/${t}.wasm`)
138
+ const b = "https://static.genomicx.org/wasm", h = /* @__PURE__ */ new Map();
139
+ async function w(n, o = b) {
140
+ const t = `${o}/${n}`;
141
+ if (h.has(t)) return h.get(t);
142
+ const [l, r] = await Promise.all([
143
+ fetch(`${o}/${n}.js`),
144
+ fetch(`${o}/${n}.wasm`)
194
145
  ]);
195
- if (!l.ok) throw new Error(`Failed to fetch ${t}.js: ${l.status}`);
196
- if (!n.ok) throw new Error(`Failed to fetch ${t}.wasm: ${n.status}`);
197
- const [s, c] = await Promise.all([
146
+ if (!l.ok) throw new Error(`Failed to fetch ${n}.js: ${l.status}`);
147
+ if (!r.ok) throw new Error(`Failed to fetch ${n}.wasm: ${r.status}`);
148
+ const [i, c] = await Promise.all([
198
149
  l.text(),
199
- n.arrayBuffer()
200
- ]), d = { factory: new Function("Module", s + "; return Module;")({}), wasmBinary: c };
201
- return x.set(a, d), d;
150
+ r.arrayBuffer()
151
+ ]), m = { factory: new Function("Module", i + "; return Module;")({}), wasmBinary: c };
152
+ return h.set(t, m), m;
202
153
  }
203
- async function A(t, r) {
204
- const { factory: a, wasmBinary: l } = await N(t, r), n = [], s = [], c = await a({
154
+ async function j(n, o) {
155
+ const { factory: t, wasmBinary: l } = await w(n, o), r = [], i = [], c = await t({
205
156
  wasmBinary: l.slice(0),
206
- print: (i) => n.push(i),
207
- printErr: (i) => s.push(i),
157
+ print: (s) => r.push(s),
158
+ printErr: (s) => i.push(s),
208
159
  noInitialRun: !0
209
160
  });
210
- return c._stdout = n, c._stderr = s, c;
161
+ return c._stdout = r, c._stderr = i, c;
211
162
  }
212
- function v(t, r) {
213
- const a = URL.createObjectURL(t), l = document.createElement("a");
214
- l.href = a, l.download = r, l.click(), URL.revokeObjectURL(a);
163
+ function v(n, o) {
164
+ const t = URL.createObjectURL(n), l = document.createElement("a");
165
+ l.href = t, l.download = o, l.click(), URL.revokeObjectURL(t);
215
166
  }
216
- function T(t, r, a = "text/plain") {
217
- v(new Blob([t], { type: a }), r);
167
+ function A(n, o, t = "text/plain") {
168
+ v(new Blob([n], { type: t }), o);
218
169
  }
219
- function z(t, r) {
220
- v(new Blob([t]), r);
170
+ function z(n, o) {
171
+ v(new Blob([n]), o);
221
172
  }
222
173
  export {
223
- y as AppFooter,
174
+ k as AppFooter,
224
175
  C as AppShell,
225
- j as LogConsole,
226
- b as NavBar,
227
- p as ThemeToggle,
228
- A as createModuleInstance,
176
+ $ as LogConsole,
177
+ N as NavBar,
178
+ u as ThemeToggle,
179
+ j as createModuleInstance,
229
180
  v as downloadBlob,
230
181
  z as downloadBuffer,
231
- T as downloadText,
232
- N as loadWasmModule
182
+ A as downloadText,
183
+ w as loadWasmModule
233
184
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genomicx/ui",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Shared UI components, styles, and WASM loader for GenomicX tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,125 +1,400 @@
1
- /* GenomicX Tailwind component classesimport after @tailwind directives */
2
-
3
- @layer base {
4
- html {
5
- scroll-behavior: smooth;
6
- -webkit-font-smoothing: antialiased;
7
- -moz-osx-font-smoothing: grayscale;
8
- }
9
-
10
- body {
11
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
12
- background-color: var(--gx-bg);
13
- color: var(--gx-text);
14
- line-height: 1.7;
15
- transition: background-color var(--gx-transition), color var(--gx-transition);
16
- margin: 0;
17
- }
18
-
19
- * {
20
- transition: background-color var(--gx-transition), border-color var(--gx-transition), color var(--gx-transition);
21
- }
22
-
23
- code {
24
- font-family: 'JetBrains Mono', 'Fira Code', monospace;
25
- }
26
-
27
- ::-webkit-scrollbar { width: 10px; height: 10px; }
28
- ::-webkit-scrollbar-track { background: var(--gx-bg); }
29
- ::-webkit-scrollbar-thumb { background: var(--gx-border); border-radius: 999px; }
30
- ::-webkit-scrollbar-thumb:hover { background: var(--gx-text-muted); }
31
- }
32
-
33
- @layer components {
34
- .card {
35
- background: var(--gx-bg-alt);
36
- border: 1px solid var(--gx-border);
37
- border-radius: var(--gx-radius-lg);
38
- padding: 1.5rem;
39
- transition: border-color var(--gx-transition);
40
- }
41
-
42
- .card:hover {
43
- border-color: var(--gx-accent);
44
- }
45
-
46
- .btn-primary {
47
- display: inline-flex;
48
- align-items: center;
49
- justify-content: center;
50
- gap: 0.5rem;
51
- background: var(--gx-accent);
52
- color: var(--gx-text-inverted);
53
- font-weight: 600;
54
- font-size: 0.875rem;
55
- padding: 0.7rem 1.4rem;
56
- border-radius: 6px;
57
- border: none;
58
- cursor: pointer;
59
- transition: all var(--gx-transition);
60
- }
61
-
62
- .btn-primary:hover { background: var(--gx-accent-hover); }
63
- .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
64
-
65
- .btn-secondary {
66
- display: inline-flex;
67
- align-items: center;
68
- justify-content: center;
69
- gap: 0.5rem;
70
- background: transparent;
71
- color: var(--gx-text);
72
- font-weight: 600;
73
- font-size: 0.875rem;
74
- padding: 0.7rem 1.4rem;
75
- border-radius: 6px;
76
- border: 1px solid var(--gx-border);
77
- cursor: pointer;
78
- transition: all var(--gx-transition);
79
- }
80
-
81
- .btn-secondary:hover { border-color: var(--gx-accent); color: var(--gx-accent); }
82
-
83
- .input-field {
84
- background: var(--gx-bg);
85
- border: 1px solid var(--gx-border);
86
- color: var(--gx-text);
87
- border-radius: 6px;
88
- padding: 0.5rem 0.75rem;
89
- font-size: 0.875rem;
90
- transition: border-color var(--gx-transition);
91
- outline: none;
92
- }
93
-
94
- .input-field:focus { border-color: var(--gx-accent); }
95
-
96
- .label {
97
- display: block;
98
- font-size: 0.8125rem;
99
- font-weight: 500;
100
- color: var(--gx-text);
101
- margin-bottom: 0.5rem;
102
- }
103
-
104
- .section-title {
105
- font-size: 1.25rem;
106
- font-weight: 700;
107
- color: var(--gx-text);
108
- margin-bottom: 1rem;
109
- letter-spacing: -0.01em;
110
- }
111
-
112
- .progress-bg {
113
- background: var(--gx-bg);
114
- height: 6px;
115
- border-radius: 999px;
116
- overflow: hidden;
117
- }
118
-
119
- .progress-bar {
120
- background: var(--gx-accent);
121
- height: 6px;
122
- border-radius: 999px;
123
- transition: width 0.3s ease;
124
- }
1
+ /* GenomicX component stylesno Tailwind dependency */
2
+
3
+ /* ── Base resets ─────────────────────────────── */
4
+ html {
5
+ scroll-behavior: smooth;
6
+ -webkit-font-smoothing: antialiased;
7
+ -moz-osx-font-smoothing: grayscale;
8
+ }
9
+
10
+ body {
11
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
12
+ background-color: var(--gx-bg);
13
+ color: var(--gx-text);
14
+ line-height: 1.7;
15
+ transition: background-color var(--gx-transition), color var(--gx-transition);
16
+ margin: 0;
17
+ }
18
+
19
+ * {
20
+ transition: background-color var(--gx-transition), border-color var(--gx-transition), color var(--gx-transition);
21
+ }
22
+
23
+ code {
24
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
25
+ }
26
+
27
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
28
+ ::-webkit-scrollbar-track { background: var(--gx-bg); }
29
+ ::-webkit-scrollbar-thumb { background: var(--gx-border); border-radius: 999px; }
30
+ ::-webkit-scrollbar-thumb:hover { background: var(--gx-text-muted); }
31
+
32
+ /* ── NavBar ──────────────────────────────────── */
33
+ .gx-nav {
34
+ position: sticky;
35
+ top: 0;
36
+ z-index: 40;
37
+ background: var(--gx-nav-bg);
38
+ backdrop-filter: blur(12px);
39
+ -webkit-backdrop-filter: blur(12px);
40
+ border-bottom: 1px solid var(--gx-border);
41
+ }
42
+
43
+ .gx-nav-inner {
44
+ max-width: 80rem;
45
+ margin: 0 auto;
46
+ padding: 0 1rem;
47
+ }
48
+
49
+ @media (min-width: 640px) { .gx-nav-inner { padding: 0 1.5rem; } }
50
+ @media (min-width: 1024px) { .gx-nav-inner { padding: 0 2rem; } }
51
+
52
+ .gx-nav-row {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ height: 60px;
57
+ }
58
+
59
+ .gx-nav-logo {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 0.75rem;
63
+ text-decoration: none;
64
+ opacity: 1;
65
+ transition: opacity var(--gx-transition);
66
+ }
67
+ .gx-nav-logo:hover { opacity: 0.85; }
68
+
69
+ .gx-nav-logo-icon { width: 28px; height: 28px; flex-shrink: 0; }
70
+
71
+ .gx-nav-logo-name {
72
+ font-size: 1.125rem;
73
+ font-weight: 700;
74
+ color: var(--gx-text);
75
+ margin: 0;
76
+ line-height: 1.3;
77
+ }
78
+
79
+ .gx-nav-logo-version {
80
+ font-size: 0.75rem;
81
+ font-weight: 400;
82
+ margin-left: 0.25rem;
83
+ color: var(--gx-text-muted);
84
+ }
85
+
86
+ .gx-nav-logo-sub {
87
+ font-size: 0.75rem;
88
+ color: var(--gx-text-muted);
89
+ margin: 0;
90
+ line-height: 1.2;
91
+ }
92
+
93
+ .gx-nav-desktop {
94
+ display: none;
95
+ align-items: center;
96
+ gap: 1.5rem;
97
+ }
98
+ @media (min-width: 768px) { .gx-nav-desktop { display: flex; } }
99
+
100
+ .gx-nav-link {
101
+ font-size: 0.875rem;
102
+ font-weight: 500;
103
+ color: var(--gx-text-muted);
104
+ text-decoration: none;
105
+ transition: color var(--gx-transition);
106
+ display: inline-flex;
107
+ align-items: center;
108
+ gap: 0.25rem;
109
+ }
110
+ .gx-nav-link:hover { color: var(--gx-text); }
111
+
112
+ .gx-nav-link-icon { width: 14px; height: 14px; }
113
+
114
+ .gx-nav-mobile-toggle {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 0.75rem;
118
+ }
119
+ @media (min-width: 768px) { .gx-nav-mobile-toggle { display: none; } }
120
+
121
+ .gx-nav-hamburger {
122
+ background: none;
123
+ border: none;
124
+ cursor: pointer;
125
+ padding: 0.5rem;
126
+ border-radius: 4px;
127
+ color: var(--gx-text-muted);
128
+ display: flex;
129
+ align-items: center;
130
+ }
131
+ .gx-nav-hamburger:hover { color: var(--gx-text); }
132
+
133
+ .gx-nav-hamburger-icon { width: 20px; height: 20px; }
134
+
135
+ .gx-nav-dropdown {
136
+ display: block;
137
+ padding: 0 1rem 1rem;
138
+ border-top: 1px solid var(--gx-border);
139
+ background: var(--gx-nav-bg);
140
+ }
141
+ @media (min-width: 768px) { .gx-nav-dropdown { display: none; } }
142
+
143
+ .gx-nav-dropdown-link {
144
+ display: block;
145
+ font-size: 0.875rem;
146
+ padding: 0.5rem 0;
147
+ color: var(--gx-text-muted);
148
+ text-decoration: none;
149
+ transition: color var(--gx-transition);
150
+ }
151
+ .gx-nav-dropdown-link:hover { color: var(--gx-text); }
152
+
153
+ /* ── Footer ──────────────────────────────────── */
154
+ .gx-footer {
155
+ margin-top: auto;
156
+ padding: 1.5rem 0;
157
+ border-top: 1px solid var(--gx-border);
158
+ background: var(--gx-bg-alt);
159
+ }
160
+
161
+ .gx-footer-inner {
162
+ max-width: 80rem;
163
+ margin: 0 auto;
164
+ padding: 0 1rem;
165
+ }
166
+ @media (min-width: 640px) { .gx-footer-inner { padding: 0 1.5rem; } }
167
+ @media (min-width: 1024px) { .gx-footer-inner { padding: 0 2rem; } }
168
+
169
+ .gx-footer-content {
170
+ display: flex;
171
+ flex-direction: column;
172
+ align-items: center;
173
+ gap: 1rem;
174
+ }
175
+ @media (min-width: 768px) {
176
+ .gx-footer-content { flex-direction: row; justify-content: space-between; }
177
+ }
178
+
179
+ .gx-footer-text { font-size: 0.875rem; color: var(--gx-text-muted); }
180
+ .gx-footer-text-title { font-weight: 600; color: var(--gx-text); margin: 0 0 0.25rem; }
181
+ .gx-footer-text-sub { margin: 0; }
182
+
183
+ .gx-footer-links {
184
+ display: flex;
185
+ gap: 1.5rem;
186
+ font-size: 0.875rem;
187
+ }
188
+
189
+ .gx-footer-link {
190
+ color: var(--gx-text-muted);
191
+ text-decoration: none;
192
+ background: none;
193
+ border: none;
194
+ cursor: pointer;
195
+ padding: 0;
196
+ font-size: 0.875rem;
197
+ transition: color var(--gx-transition);
198
+ }
199
+ .gx-footer-link:hover { color: var(--gx-accent); }
200
+
201
+ /* ── ThemeToggle ─────────────────────────────── */
202
+ .gx-theme-toggle {
203
+ display: flex;
204
+ align-items: center;
205
+ border-radius: 999px;
206
+ border: 1px solid var(--gx-border);
207
+ overflow: hidden;
208
+ font-size: 0.75rem;
209
+ font-weight: 500;
210
+ }
211
+ .gx-theme-toggle.disabled { opacity: 0.4; pointer-events: none; }
212
+
213
+ .gx-theme-btn {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: center;
217
+ padding: 0.375rem 0.75rem;
218
+ background: none;
219
+ border: none;
220
+ cursor: pointer;
221
+ transition: background var(--gx-transition), color var(--gx-transition);
222
+ color: var(--gx-text-muted);
223
+ }
224
+ .gx-theme-btn:hover { color: var(--gx-text); }
225
+ .gx-theme-btn-icon { width: 14px; height: 14px; }
226
+ .gx-theme-btn.active {
227
+ background: var(--gx-accent);
228
+ color: var(--gx-text-inverted);
229
+ }
230
+
231
+ /* ── LogConsole ──────────────────────────────── */
232
+ .gx-console {
233
+ background: var(--gx-bg-alt);
234
+ border: 1px solid var(--gx-border);
235
+ border-radius: var(--gx-radius-lg);
236
+ padding: 1.5rem;
237
+ margin-top: 1.5rem;
238
+ }
239
+
240
+ .gx-console-progress {
241
+ margin-bottom: 1rem;
242
+ padding-bottom: 1rem;
243
+ border-bottom: 1px solid var(--gx-border);
244
+ }
245
+
246
+ .gx-console-progress-row {
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: space-between;
250
+ margin-bottom: 0.5rem;
251
+ }
252
+
253
+ .gx-console-progress-step { font-size: 0.875rem; font-weight: 500; color: var(--gx-text); }
254
+ .gx-console-progress-pct { font-size: 0.875rem; color: var(--gx-text-muted); }
255
+ .gx-console-progress-msg { margin-top: 0.5rem; font-size: 0.75rem; color: var(--gx-text-muted); }
256
+
257
+ .gx-console-header {
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: space-between;
261
+ margin-bottom: 0.75rem;
262
+ }
263
+
264
+ .gx-console-title-row {
265
+ display: flex;
266
+ align-items: center;
267
+ gap: 0.5rem;
268
+ }
269
+
270
+ .gx-console-toggle {
271
+ background: none;
272
+ border: none;
273
+ cursor: pointer;
274
+ color: var(--gx-text-muted);
275
+ padding: 0;
276
+ font-size: 0.75rem;
277
+ }
278
+
279
+ .gx-console-title { font-weight: 600; color: var(--gx-text); margin: 0; font-size: 0.875rem; }
280
+ .gx-console-count { font-size: 0.75rem; color: var(--gx-text-muted); }
281
+
282
+ .gx-console-copy {
283
+ display: inline-flex;
284
+ align-items: center;
285
+ gap: 0.25rem;
286
+ font-size: 0.75rem;
287
+ padding: 0.25rem 0.75rem;
288
+ background: transparent;
289
+ color: var(--gx-text);
290
+ border: 1px solid var(--gx-border);
291
+ border-radius: 6px;
292
+ cursor: pointer;
293
+ transition: all var(--gx-transition);
294
+ font-weight: 600;
295
+ }
296
+ .gx-console-copy:hover { border-color: var(--gx-accent); color: var(--gx-accent); }
297
+ .gx-console-copy:disabled { opacity: 0.5; cursor: not-allowed; }
298
+ .gx-console-copy-icon { width: 16px; height: 16px; }
299
+
300
+ .gx-console-body {
301
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
302
+ font-size: 0.75rem;
303
+ padding: 1rem;
304
+ border-radius: 6px;
305
+ max-height: 24rem;
306
+ overflow-y: auto;
307
+ background: var(--gx-code-bg);
308
+ color: var(--gx-accent);
309
+ border: 1px solid var(--gx-border);
310
+ }
311
+
312
+ .gx-console-empty { color: var(--gx-text-muted); }
313
+ .gx-console-line { margin-bottom: 0.25rem; white-space: pre-wrap; word-break: break-all; }
314
+
315
+ /* ── Shared utility classes ──────────────────── */
316
+ .card {
317
+ background: var(--gx-bg-alt);
318
+ border: 1px solid var(--gx-border);
319
+ border-radius: var(--gx-radius-lg);
320
+ padding: 1.5rem;
321
+ transition: border-color var(--gx-transition);
322
+ }
323
+ .card:hover { border-color: var(--gx-accent); }
324
+
325
+ .btn-primary {
326
+ display: inline-flex;
327
+ align-items: center;
328
+ justify-content: center;
329
+ gap: 0.5rem;
330
+ background: var(--gx-accent);
331
+ color: var(--gx-text-inverted);
332
+ font-weight: 600;
333
+ font-size: 0.875rem;
334
+ padding: 0.7rem 1.4rem;
335
+ border-radius: 6px;
336
+ border: none;
337
+ cursor: pointer;
338
+ transition: all var(--gx-transition);
339
+ }
340
+ .btn-primary:hover { background: var(--gx-accent-hover); }
341
+ .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
342
+
343
+ .btn-secondary {
344
+ display: inline-flex;
345
+ align-items: center;
346
+ justify-content: center;
347
+ gap: 0.5rem;
348
+ background: transparent;
349
+ color: var(--gx-text);
350
+ font-weight: 600;
351
+ font-size: 0.875rem;
352
+ padding: 0.7rem 1.4rem;
353
+ border-radius: 6px;
354
+ border: 1px solid var(--gx-border);
355
+ cursor: pointer;
356
+ transition: all var(--gx-transition);
357
+ }
358
+ .btn-secondary:hover { border-color: var(--gx-accent); color: var(--gx-accent); }
359
+
360
+ .input-field {
361
+ background: var(--gx-bg);
362
+ border: 1px solid var(--gx-border);
363
+ color: var(--gx-text);
364
+ border-radius: 6px;
365
+ padding: 0.5rem 0.75rem;
366
+ font-size: 0.875rem;
367
+ transition: border-color var(--gx-transition);
368
+ outline: none;
369
+ }
370
+ .input-field:focus { border-color: var(--gx-accent); }
371
+
372
+ .label {
373
+ display: block;
374
+ font-size: 0.8125rem;
375
+ font-weight: 500;
376
+ color: var(--gx-text);
377
+ margin-bottom: 0.5rem;
378
+ }
379
+
380
+ .section-title {
381
+ font-size: 1.25rem;
382
+ font-weight: 700;
383
+ color: var(--gx-text);
384
+ margin-bottom: 1rem;
385
+ letter-spacing: -0.01em;
386
+ }
387
+
388
+ .progress-bg {
389
+ background: var(--gx-bg);
390
+ height: 6px;
391
+ border-radius: 999px;
392
+ overflow: hidden;
393
+ }
394
+
395
+ .progress-bar {
396
+ background: var(--gx-accent);
397
+ height: 6px;
398
+ border-radius: 999px;
399
+ transition: width 0.3s ease;
125
400
  }
@@ -20,6 +20,7 @@
20
20
  --gx-code-bg: #f1f5f9;
21
21
  --gx-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
22
22
  --gx-transition: 0.2s ease;
23
+ --gx-max-width: 1280px;
23
24
  --gx-radius: 8px;
24
25
  --gx-radius-lg: 12px;
25
26
  }