@genomicx/ui 0.4.0 → 0.5.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.5.0",
4
4
  "description": "Shared UI components, styles, and WASM loader for GenomicX tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -398,3 +398,95 @@ code {
398
398
  border-radius: 999px;
399
399
  transition: width 0.3s ease;
400
400
  }
401
+
402
+ /* ── BugReportModal ──────────────────────────── */
403
+ .gx-modal-overlay {
404
+ position: fixed;
405
+ inset: 0;
406
+ display: flex;
407
+ align-items: center;
408
+ justify-content: center;
409
+ z-index: 50;
410
+ padding: 1rem;
411
+ background: rgba(0, 0, 0, 0.6);
412
+ }
413
+
414
+ .gx-modal {
415
+ background: var(--gx-bg-alt);
416
+ border: 1px solid var(--gx-border);
417
+ border-radius: var(--gx-radius-lg);
418
+ max-width: 28rem;
419
+ width: 100%;
420
+ padding: 1.5rem;
421
+ }
422
+
423
+ .gx-modal-header {
424
+ display: flex;
425
+ justify-content: space-between;
426
+ align-items: center;
427
+ margin-bottom: 1rem;
428
+ }
429
+
430
+ .gx-modal-title {
431
+ font-size: 1.125rem;
432
+ font-weight: 700;
433
+ color: var(--gx-text);
434
+ margin: 0;
435
+ }
436
+
437
+ .gx-modal-close {
438
+ background: none;
439
+ border: none;
440
+ cursor: pointer;
441
+ font-size: 1.25rem;
442
+ line-height: 1;
443
+ color: var(--gx-text-muted);
444
+ padding: 0;
445
+ }
446
+ .gx-modal-close:hover { color: var(--gx-text); }
447
+
448
+ .gx-modal-body {
449
+ font-size: 0.875rem;
450
+ color: var(--gx-text);
451
+ display: flex;
452
+ flex-direction: column;
453
+ gap: 0.75rem;
454
+ }
455
+
456
+ .gx-modal-email {
457
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
458
+ font-weight: 700;
459
+ color: var(--gx-accent);
460
+ margin: 0;
461
+ }
462
+ .gx-modal-email a { color: var(--gx-accent); text-decoration: none; }
463
+ .gx-modal-email a:hover { text-decoration: underline; }
464
+
465
+ .gx-modal-checklist {
466
+ background: var(--gx-bg);
467
+ border: 1px solid var(--gx-border);
468
+ border-radius: 6px;
469
+ padding: 0.75rem 1rem;
470
+ }
471
+
472
+ .gx-modal-checklist-title {
473
+ font-weight: 600;
474
+ margin: 0 0 0.5rem;
475
+ color: var(--gx-text);
476
+ }
477
+
478
+ .gx-modal-checklist-items {
479
+ margin: 0;
480
+ padding-left: 1.25rem;
481
+ color: var(--gx-text-muted);
482
+ display: flex;
483
+ flex-direction: column;
484
+ gap: 0.25rem;
485
+ }
486
+
487
+ .gx-modal-github-hint {
488
+ font-size: 0.75rem;
489
+ color: var(--gx-text-muted);
490
+ margin: 0;
491
+ }
492
+ .gx-modal-github-hint a { color: var(--gx-accent); text-decoration: underline; }