@genomicx/ui 0.4.0 → 0.6.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,7 +1,10 @@
1
1
  interface AppFooterProps {
2
2
  appName?: string;
3
- onReportBug?: () => void;
3
+ bugReportEmail?: string;
4
4
  bugReportUrl?: string;
5
+ /** @deprecated Use bugReportEmail instead */
6
+ onReportBug?: () => void;
7
+ bugReportItems?: string[];
5
8
  }
6
- export declare function AppFooter({ appName, onReportBug, bugReportUrl }: AppFooterProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function AppFooter({ appName, bugReportEmail, bugReportUrl, onReportBug, bugReportItems }: AppFooterProps): import("react/jsx-runtime").JSX.Element;
7
10
  export {};
@@ -0,0 +1,8 @@
1
+ interface BugReportModalProps {
2
+ onClose: () => void;
3
+ bugReportEmail: string;
4
+ bugReportUrl?: string;
5
+ bugReportItems?: string[];
6
+ }
7
+ export declare function BugReportModal({ onClose, bugReportEmail, bugReportUrl, bugReportItems }: BugReportModalProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { ThemeToggle } from './components/ThemeToggle';
2
2
  export { NavBar } from './components/NavBar';
3
3
  export type { NavBarProps } from './components/NavBar';
4
4
  export { AppFooter } from './components/AppFooter';
5
+ export { BugReportModal } from './components/BugReportModal';
5
6
  export { AppShell } from './components/AppShell';
6
7
  export { LogConsole } from './components/LogConsole';
7
8
  export { loadWasmModule, createModuleInstance } from './wasm/loader';
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
- import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
- import { useState as x, useRef as p } from "react";
1
+ import { jsxs as o, jsx as e, Fragment as v } from "react/jsx-runtime";
2
+ import { useState as m, useRef as f } from "react";
3
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(
4
+ import u from "react-hot-toast";
5
+ function p({ disabled: n = !1 }) {
6
+ const [a, l] = m(
7
7
  () => document.documentElement.getAttribute("data-theme") || "dark"
8
- ), l = (r) => {
9
- t(r), document.documentElement.setAttribute("data-theme", r), localStorage.setItem("gx-theme", r);
8
+ ), t = (c) => {
9
+ l(c), document.documentElement.setAttribute("data-theme", c), localStorage.setItem("gx-theme", c);
10
10
  };
11
- return /* @__PURE__ */ a("div", { className: `gx-theme-toggle${n ? " disabled" : ""}`, title: n ? "Theme switching disabled" : void 0, children: [
11
+ return /* @__PURE__ */ o("div", { className: `gx-theme-toggle${n ? " disabled" : ""}`, title: n ? "Theme switching disabled" : void 0, children: [
12
12
  /* @__PURE__ */ e(
13
13
  "button",
14
14
  {
15
- onClick: () => !n && l("dark"),
16
- className: `gx-theme-btn${o === "dark" ? " active" : ""}`,
15
+ onClick: () => !n && t("dark"),
16
+ className: `gx-theme-btn${a === "dark" ? " active" : ""}`,
17
17
  "aria-label": "Dark theme",
18
18
  disabled: n,
19
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" }) })
@@ -22,8 +22,8 @@ function u({ disabled: n = !1 }) {
22
22
  /* @__PURE__ */ e(
23
23
  "button",
24
24
  {
25
- onClick: () => !n && l("light"),
26
- className: `gx-theme-btn${o === "light" ? " active" : ""}`,
25
+ onClick: () => !n && t("light"),
26
+ className: `gx-theme-btn${a === "light" ? " active" : ""}`,
27
27
  "aria-label": "Light theme",
28
28
  disabled: n,
29
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" }) })
@@ -31,154 +31,198 @@ function u({ disabled: n = !1 }) {
31
31
  )
32
32
  ] });
33
33
  }
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: [
34
+ const N = () => /* @__PURE__ */ o("svg", { className: "gx-nav-logo-icon", viewBox: "0 0 24 24", fill: "none", stroke: "var(--gx-accent)", strokeWidth: "2", children: [
35
35
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
36
36
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "6" }),
37
37
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "2" })
38
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: [
39
+ function k({ appName: n, appSubtitle: a, version: l, icon: t, actions: c, mobileActions: r }) {
40
+ const [s, i] = m(!1);
41
+ return /* @__PURE__ */ o("nav", { className: "gx-nav", children: [
42
+ /* @__PURE__ */ e("div", { className: "gx-nav-inner", children: /* @__PURE__ */ o("div", { className: "gx-nav-row", children: [
43
+ /* @__PURE__ */ o(d, { to: "/", className: "gx-nav-logo", children: [
44
+ t ?? /* @__PURE__ */ e(N, {}),
45
+ /* @__PURE__ */ o("div", { children: [
46
+ /* @__PURE__ */ o("h1", { className: "gx-nav-logo-name", children: [
47
47
  n,
48
- t && /* @__PURE__ */ a("span", { className: "gx-nav-logo-version", children: [
48
+ l && /* @__PURE__ */ o("span", { className: "gx-nav-logo-version", children: [
49
49
  "v",
50
- t
50
+ l
51
51
  ] })
52
52
  ] }),
53
- o && /* @__PURE__ */ e("p", { className: "gx-nav-logo-sub", children: o })
53
+ a && /* @__PURE__ */ e("p", { className: "gx-nav-logo-sub", children: a })
54
54
  ] })
55
55
  ] }),
56
- /* @__PURE__ */ a("div", { className: "gx-nav-desktop", children: [
57
- r,
56
+ /* @__PURE__ */ o("div", { className: "gx-nav-desktop", children: [
57
+ c,
58
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: [
59
+ /* @__PURE__ */ o("a", { href: "https://github.com/happykhan", target: "_blank", rel: "noopener noreferrer", className: "gx-nav-link", children: [
60
60
  "GitHub",
61
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
62
  ] }),
63
- /* @__PURE__ */ e(u, {})
63
+ /* @__PURE__ */ e(p, {})
64
64
  ] }),
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" }) }) })
65
+ /* @__PURE__ */ o("div", { className: "gx-nav-mobile-toggle", children: [
66
+ /* @__PURE__ */ e(p, {}),
67
+ /* @__PURE__ */ e("button", { onClick: () => i(!s), className: "gx-nav-hamburger", "aria-label": "Toggle menu", children: s ? /* @__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" }) }) })
68
68
  ] })
69
69
  ] }) }),
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" }),
70
+ s && /* @__PURE__ */ o("div", { className: "gx-nav-dropdown", children: [
71
+ r,
72
+ /* @__PURE__ */ e(d, { to: "/about", onClick: () => i(!1), className: "gx-nav-dropdown-link", children: "About" }),
73
73
  /* @__PURE__ */ e("a", { href: "https://github.com/happykhan", target: "_blank", rel: "noopener noreferrer", className: "gx-nav-dropdown-link", children: "GitHub ↗" })
74
74
  ] })
75
75
  ] });
76
76
  }
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"
83
- ] }),
84
- /* @__PURE__ */ e("p", { className: "gx-footer-text-sub", children: "All processing runs locally in your browser — no data leaves your computer" })
77
+ const w = [
78
+ "A description of what happened and what you expected",
79
+ "Your input files (if applicable)",
80
+ "Browser name and version",
81
+ "Steps to reproduce the issue"
82
+ ];
83
+ function b({ onClose: n, bugReportEmail: a, bugReportUrl: l, bugReportItems: t }) {
84
+ const c = t ?? w;
85
+ return /* @__PURE__ */ e("div", { className: "gx-modal-overlay", onClick: n, children: /* @__PURE__ */ o("div", { className: "gx-modal", onClick: (r) => r.stopPropagation(), children: [
86
+ /* @__PURE__ */ o("div", { className: "gx-modal-header", children: [
87
+ /* @__PURE__ */ e("h3", { className: "gx-modal-title", children: "Report a Bug" }),
88
+ /* @__PURE__ */ e("button", { className: "gx-modal-close", onClick: n, "aria-label": "Close", children: "×" })
85
89
  ] }),
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" })
90
+ /* @__PURE__ */ o("div", { className: "gx-modal-body", children: [
91
+ /* @__PURE__ */ e("p", { children: "To report a bug, please email the following to:" }),
92
+ /* @__PURE__ */ e("p", { className: "gx-modal-email", children: /* @__PURE__ */ e("a", { href: `mailto:${a}`, children: a }) }),
93
+ /* @__PURE__ */ o("div", { className: "gx-modal-checklist", children: [
94
+ /* @__PURE__ */ e("p", { className: "gx-modal-checklist-title", children: "Please include:" }),
95
+ /* @__PURE__ */ e("ol", { className: "gx-modal-checklist-items", children: c.map((r, s) => /* @__PURE__ */ e("li", { children: r }, s)) })
96
+ ] }),
97
+ l && /* @__PURE__ */ o("p", { className: "gx-modal-github-hint", children: [
98
+ "You can also open an issue on",
99
+ " ",
100
+ /* @__PURE__ */ e("a", { href: l, target: "_blank", rel: "noopener noreferrer", children: "GitHub" }),
101
+ "."
102
+ ] })
90
103
  ] })
91
- ] }) }) });
104
+ ] }) });
105
+ }
106
+ function y({ appName: n = "GenomicX", bugReportEmail: a, bugReportUrl: l, onReportBug: t, bugReportItems: c }) {
107
+ const [r, s] = m(!1);
108
+ function i() {
109
+ a ? s(!0) : t && t();
110
+ }
111
+ return /* @__PURE__ */ o(v, { children: [
112
+ /* @__PURE__ */ e("footer", { className: "gx-footer", children: /* @__PURE__ */ e("div", { className: "gx-footer-inner", children: /* @__PURE__ */ o("div", { className: "gx-footer-content", children: [
113
+ /* @__PURE__ */ o("div", { className: "gx-footer-text", children: [
114
+ /* @__PURE__ */ o("p", { className: "gx-footer-text-title", children: [
115
+ n,
116
+ " — Powered by WebAssembly"
117
+ ] }),
118
+ /* @__PURE__ */ e("p", { className: "gx-footer-text-sub", children: "All processing runs locally in your browser — no data leaves your computer" })
119
+ ] }),
120
+ /* @__PURE__ */ o("div", { className: "gx-footer-links", children: [
121
+ /* @__PURE__ */ e("a", { href: "https://genomicx.org", target: "_blank", rel: "noopener noreferrer", className: "gx-footer-link", children: "genomicx.org" }),
122
+ (a || l || t) && /* @__PURE__ */ e("button", { onClick: i, className: "gx-footer-link", children: "Report Bug" })
123
+ ] })
124
+ ] }) }) }),
125
+ r && a && /* @__PURE__ */ e(
126
+ b,
127
+ {
128
+ onClose: () => s(!1),
129
+ bugReportEmail: a,
130
+ bugReportUrl: l,
131
+ bugReportItems: c
132
+ }
133
+ )
134
+ ] });
92
135
  }
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 }),
136
+ function T({ children: n, onReportBug: a, ...l }) {
137
+ return /* @__PURE__ */ o("div", { style: { minHeight: "100vh", display: "flex", flexDirection: "column", background: "var(--gx-bg)" }, children: [
138
+ /* @__PURE__ */ e(k, { ...l }),
96
139
  /* @__PURE__ */ e("main", { style: { flex: 1 }, children: n }),
97
- /* @__PURE__ */ e(k, { appName: t.appName, onReportBug: o })
140
+ /* @__PURE__ */ e(y, { appName: l.appName, onReportBug: a })
98
141
  ] });
99
142
  }
100
- function $({ logs: n, progress: o, title: t = "Console" }) {
101
- const l = p(null), r = () => {
143
+ function j({ logs: n, progress: a, title: l = "Console" }) {
144
+ const t = f(null), c = () => {
102
145
  navigator.clipboard.writeText(n.join(`
103
146
  `)).then(() => {
104
- g.success("Logs copied to clipboard!");
147
+ u.success("Logs copied to clipboard!");
105
148
  }).catch(() => {
106
- g.error("Failed to copy logs");
149
+ u.error("Failed to copy logs");
107
150
  });
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,
151
+ }, r = a && a.step !== "idle" && a.step !== "Complete!";
152
+ return /* @__PURE__ */ o("div", { className: "gx-console", children: [
153
+ r && /* @__PURE__ */ o("div", { className: "gx-console-progress", children: [
154
+ /* @__PURE__ */ o("div", { className: "gx-console-progress-row", children: [
155
+ /* @__PURE__ */ e("span", { className: "gx-console-progress-step", children: a.step }),
156
+ /* @__PURE__ */ o("span", { className: "gx-console-progress-pct", children: [
157
+ a.percent,
115
158
  "%"
116
159
  ] })
117
160
  ] }),
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 })
161
+ /* @__PURE__ */ e("div", { className: "progress-bg", children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${a.percent}%` } }) }),
162
+ a.message && /* @__PURE__ */ e("div", { className: "gx-console-progress-msg", children: a.message })
120
163
  ] }),
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: [
164
+ /* @__PURE__ */ o("div", { className: "gx-console-header", children: [
165
+ /* @__PURE__ */ o("div", { className: "gx-console-title-row", children: [
166
+ /* @__PURE__ */ e("h3", { className: "gx-console-title", children: l }),
167
+ /* @__PURE__ */ o("span", { className: "gx-console-count", children: [
125
168
  "(",
126
169
  n.length,
127
170
  " messages)"
128
171
  ] })
129
172
  ] }),
130
- /* @__PURE__ */ a("button", { onClick: r, className: "gx-console-copy", disabled: n.length === 0, children: [
173
+ /* @__PURE__ */ o("button", { onClick: c, className: "gx-console-copy", disabled: n.length === 0, children: [
131
174
  /* @__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" }) }),
132
175
  "Copy"
133
176
  ] })
134
177
  ] }),
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)) })
178
+ /* @__PURE__ */ e("div", { ref: t, className: "gx-console-body", children: n.length === 0 ? /* @__PURE__ */ e("div", { className: "gx-console-empty", children: "No logs yet..." }) : n.map((s, i) => /* @__PURE__ */ e("div", { className: "gx-console-line", children: s }, i)) })
136
179
  ] });
137
180
  }
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`)
181
+ const M = "https://static.genomicx.org/wasm", h = /* @__PURE__ */ new Map();
182
+ async function C(n, a = M) {
183
+ const l = `${a}/${n}`;
184
+ if (h.has(l)) return h.get(l);
185
+ const [t, c] = await Promise.all([
186
+ fetch(`${a}/${n}.js`),
187
+ fetch(`${a}/${n}.wasm`)
145
188
  ]);
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([
149
- l.text(),
150
- r.arrayBuffer()
151
- ]), m = { factory: new Function("Module", i + "; return Module;")({}), wasmBinary: c };
152
- return h.set(t, m), m;
189
+ if (!t.ok) throw new Error(`Failed to fetch ${n}.js: ${t.status}`);
190
+ if (!c.ok) throw new Error(`Failed to fetch ${n}.wasm: ${c.status}`);
191
+ const [r, s] = await Promise.all([
192
+ t.text(),
193
+ c.arrayBuffer()
194
+ ]), g = { factory: new Function("Module", r + "; return Module;")({}), wasmBinary: s };
195
+ return h.set(l, g), g;
153
196
  }
154
- async function j(n, o) {
155
- const { factory: t, wasmBinary: l } = await w(n, o), r = [], i = [], c = await t({
156
- wasmBinary: l.slice(0),
157
- print: (s) => r.push(s),
158
- printErr: (s) => i.push(s),
197
+ async function z(n, a) {
198
+ const { factory: l, wasmBinary: t } = await C(n, a), c = [], r = [], s = await l({
199
+ wasmBinary: t.slice(0),
200
+ print: (i) => c.push(i),
201
+ printErr: (i) => r.push(i),
159
202
  noInitialRun: !0
160
203
  });
161
- return c._stdout = r, c._stderr = i, c;
204
+ return s._stdout = c, s._stderr = r, s;
162
205
  }
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);
206
+ function x(n, a) {
207
+ const l = URL.createObjectURL(n), t = document.createElement("a");
208
+ t.href = l, t.download = a, t.click(), URL.revokeObjectURL(l);
166
209
  }
167
- function A(n, o, t = "text/plain") {
168
- v(new Blob([n], { type: t }), o);
210
+ function R(n, a, l = "text/plain") {
211
+ x(new Blob([n], { type: l }), a);
169
212
  }
170
- function z(n, o) {
171
- v(new Blob([n]), o);
213
+ function W(n, a) {
214
+ x(new Blob([n]), a);
172
215
  }
173
216
  export {
174
- k as AppFooter,
175
- C as AppShell,
176
- $ as LogConsole,
177
- N as NavBar,
178
- u as ThemeToggle,
179
- j as createModuleInstance,
180
- v as downloadBlob,
181
- z as downloadBuffer,
182
- A as downloadText,
183
- w as loadWasmModule
217
+ y as AppFooter,
218
+ T as AppShell,
219
+ b as BugReportModal,
220
+ j as LogConsole,
221
+ k as NavBar,
222
+ p as ThemeToggle,
223
+ z as createModuleInstance,
224
+ x as downloadBlob,
225
+ W as downloadBuffer,
226
+ R as downloadText,
227
+ C as loadWasmModule
184
228
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genomicx/ui",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Shared UI components, styles, and WASM loader for GenomicX tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -357,17 +357,44 @@ code {
357
357
  }
358
358
  .btn-secondary:hover { border-color: var(--gx-accent); color: var(--gx-accent); }
359
359
 
360
- .input-field {
360
+ .input-field,
361
+ .gx-input,
362
+ .gx-select {
361
363
  background: var(--gx-bg);
362
364
  border: 1px solid var(--gx-border);
363
365
  color: var(--gx-text);
364
366
  border-radius: 6px;
365
367
  padding: 0.5rem 0.75rem;
366
368
  font-size: 0.875rem;
369
+ font-family: inherit;
367
370
  transition: border-color var(--gx-transition);
368
371
  outline: none;
369
372
  }
370
- .input-field:focus { border-color: var(--gx-accent); }
373
+ .input-field:focus,
374
+ .gx-input:focus,
375
+ .gx-select:focus { border-color: var(--gx-accent); box-shadow: 0 0 0 3px var(--gx-accent-dim); }
376
+
377
+ /* ── gx-btn variants ─────────────────────────── */
378
+ .gx-btn {
379
+ display: inline-flex;
380
+ align-items: center;
381
+ justify-content: center;
382
+ gap: 0.375rem;
383
+ font-family: inherit;
384
+ font-weight: 600;
385
+ font-size: 0.875rem;
386
+ padding: 0.6rem 1.25rem;
387
+ border-radius: 6px;
388
+ border: none;
389
+ cursor: pointer;
390
+ transition: all var(--gx-transition);
391
+ }
392
+ .gx-btn:disabled { opacity: 0.5; cursor: not-allowed; }
393
+ .gx-btn-sm { padding: 0.375rem 0.875rem; font-size: 0.8125rem; }
394
+ .gx-btn-primary { background: var(--gx-accent); color: var(--gx-text-inverted); }
395
+ .gx-btn-primary:hover:not(:disabled) { background: var(--gx-accent-hover); }
396
+ .gx-btn-secondary { background: transparent; color: var(--gx-text); border: 1px solid var(--gx-border); }
397
+ .gx-btn-secondary:hover:not(:disabled) { border-color: var(--gx-accent); color: var(--gx-accent); }
371
398
 
372
399
  .label {
373
400
  display: block;
@@ -398,3 +425,95 @@ code {
398
425
  border-radius: 999px;
399
426
  transition: width 0.3s ease;
400
427
  }
428
+
429
+ /* ── BugReportModal ──────────────────────────── */
430
+ .gx-modal-overlay {
431
+ position: fixed;
432
+ inset: 0;
433
+ display: flex;
434
+ align-items: center;
435
+ justify-content: center;
436
+ z-index: 50;
437
+ padding: 1rem;
438
+ background: rgba(0, 0, 0, 0.6);
439
+ }
440
+
441
+ .gx-modal {
442
+ background: var(--gx-bg-alt);
443
+ border: 1px solid var(--gx-border);
444
+ border-radius: var(--gx-radius-lg);
445
+ max-width: 28rem;
446
+ width: 100%;
447
+ padding: 1.5rem;
448
+ }
449
+
450
+ .gx-modal-header {
451
+ display: flex;
452
+ justify-content: space-between;
453
+ align-items: center;
454
+ margin-bottom: 1rem;
455
+ }
456
+
457
+ .gx-modal-title {
458
+ font-size: 1.125rem;
459
+ font-weight: 700;
460
+ color: var(--gx-text);
461
+ margin: 0;
462
+ }
463
+
464
+ .gx-modal-close {
465
+ background: none;
466
+ border: none;
467
+ cursor: pointer;
468
+ font-size: 1.25rem;
469
+ line-height: 1;
470
+ color: var(--gx-text-muted);
471
+ padding: 0;
472
+ }
473
+ .gx-modal-close:hover { color: var(--gx-text); }
474
+
475
+ .gx-modal-body {
476
+ font-size: 0.875rem;
477
+ color: var(--gx-text);
478
+ display: flex;
479
+ flex-direction: column;
480
+ gap: 0.75rem;
481
+ }
482
+
483
+ .gx-modal-email {
484
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
485
+ font-weight: 700;
486
+ color: var(--gx-accent);
487
+ margin: 0;
488
+ }
489
+ .gx-modal-email a { color: var(--gx-accent); text-decoration: none; }
490
+ .gx-modal-email a:hover { text-decoration: underline; }
491
+
492
+ .gx-modal-checklist {
493
+ background: var(--gx-bg);
494
+ border: 1px solid var(--gx-border);
495
+ border-radius: 6px;
496
+ padding: 0.75rem 1rem;
497
+ }
498
+
499
+ .gx-modal-checklist-title {
500
+ font-weight: 600;
501
+ margin: 0 0 0.5rem;
502
+ color: var(--gx-text);
503
+ }
504
+
505
+ .gx-modal-checklist-items {
506
+ margin: 0;
507
+ padding-left: 1.25rem;
508
+ color: var(--gx-text-muted);
509
+ display: flex;
510
+ flex-direction: column;
511
+ gap: 0.25rem;
512
+ }
513
+
514
+ .gx-modal-github-hint {
515
+ font-size: 0.75rem;
516
+ color: var(--gx-text-muted);
517
+ margin: 0;
518
+ }
519
+ .gx-modal-github-hint a { color: var(--gx-accent); text-decoration: underline; }
@@ -16,6 +16,7 @@
16
16
  --gx-success: #0d9488;
17
17
  --gx-warning: #F59E0B;
18
18
  --gx-error: #EF4444;
19
+ --gx-accent-dim: rgba(13, 148, 136, 0.1);
19
20
  --gx-nav-bg: rgba(255, 255, 255, 0.9);
20
21
  --gx-code-bg: #f1f5f9;
21
22
  --gx-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
@@ -23,6 +24,7 @@
23
24
  --gx-max-width: 1280px;
24
25
  --gx-radius: 8px;
25
26
  --gx-radius-lg: 12px;
27
+ --gx-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
26
28
  }
27
29
 
28
30
  [data-theme="dark"] {
@@ -39,6 +41,7 @@
39
41
  --gx-accent: #2dd4bf;
40
42
  --gx-accent-hover: #14b8a6;
41
43
  --gx-indigo: #818cf8;
44
+ --gx-accent-dim: rgba(45, 212, 191, 0.12);
42
45
  --gx-nav-bg: rgba(15, 23, 42, 0.9);
43
46
  --gx-code-bg: #0f172a;
44
47
  --gx-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);