@rcnr/theme 2.0.6 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +94 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -39
- package/dist/index.mjs.map +1 -1
- package/index.css +46 -11
- package/package.json +3 -1
package/dist/index.d.mts
CHANGED
|
@@ -41,6 +41,8 @@ interface RCNRMountainLogoProps {
|
|
|
41
41
|
}
|
|
42
42
|
declare function RCNRMountainLogo({ href, className, }: RCNRMountainLogoProps): react_jsx_runtime.JSX.Element;
|
|
43
43
|
|
|
44
|
+
declare function ThemeToggle(): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
44
46
|
interface ReportIssueModalProps {
|
|
45
47
|
isOpen: boolean;
|
|
46
48
|
onClose: () => void;
|
|
@@ -59,4 +61,4 @@ interface RequestToolModalProps {
|
|
|
59
61
|
}
|
|
60
62
|
declare function RequestToolModal({ isOpen, onClose, toolName, apiBaseUrl, userEmail, }: RequestToolModalProps): react_jsx_runtime.JSX.Element | null;
|
|
61
63
|
|
|
62
|
-
export { RCNRFooter, type RCNRFooterProps, RCNRHeader, type RCNRHeaderProps, RCNRMountainLogo, RCNRSubNav, type RCNRSubNavProps, ReportIssueModal, RequestToolModal };
|
|
64
|
+
export { RCNRFooter, type RCNRFooterProps, RCNRHeader, type RCNRHeaderProps, RCNRMountainLogo, RCNRSubNav, type RCNRSubNavProps, ReportIssueModal, RequestToolModal, ThemeToggle };
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ interface RCNRMountainLogoProps {
|
|
|
41
41
|
}
|
|
42
42
|
declare function RCNRMountainLogo({ href, className, }: RCNRMountainLogoProps): react_jsx_runtime.JSX.Element;
|
|
43
43
|
|
|
44
|
+
declare function ThemeToggle(): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
44
46
|
interface ReportIssueModalProps {
|
|
45
47
|
isOpen: boolean;
|
|
46
48
|
onClose: () => void;
|
|
@@ -59,4 +61,4 @@ interface RequestToolModalProps {
|
|
|
59
61
|
}
|
|
60
62
|
declare function RequestToolModal({ isOpen, onClose, toolName, apiBaseUrl, userEmail, }: RequestToolModalProps): react_jsx_runtime.JSX.Element | null;
|
|
61
63
|
|
|
62
|
-
export { RCNRFooter, type RCNRFooterProps, RCNRHeader, type RCNRHeaderProps, RCNRMountainLogo, RCNRSubNav, type RCNRSubNavProps, ReportIssueModal, RequestToolModal };
|
|
64
|
+
export { RCNRFooter, type RCNRFooterProps, RCNRHeader, type RCNRHeaderProps, RCNRMountainLogo, RCNRSubNav, type RCNRSubNavProps, ReportIssueModal, RequestToolModal, ThemeToggle };
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,8 @@ __export(index_exports, {
|
|
|
25
25
|
RCNRMountainLogo: () => RCNRMountainLogo_default,
|
|
26
26
|
RCNRSubNav: () => RCNRSubNav_default,
|
|
27
27
|
ReportIssueModal: () => ReportIssueModal,
|
|
28
|
-
RequestToolModal: () => RequestToolModal
|
|
28
|
+
RequestToolModal: () => RequestToolModal,
|
|
29
|
+
ThemeToggle: () => ThemeToggle
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(index_exports);
|
|
31
32
|
|
|
@@ -254,9 +255,49 @@ function RCNRFooter({
|
|
|
254
255
|
}
|
|
255
256
|
var RCNRFooter_default = RCNRFooter;
|
|
256
257
|
|
|
257
|
-
// src/
|
|
258
|
+
// src/ThemeToggle.tsx
|
|
258
259
|
var import_react = require("react");
|
|
260
|
+
var import_lucide_react = require("lucide-react");
|
|
259
261
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
262
|
+
var STORAGE_KEY = "rcnr-theme";
|
|
263
|
+
function getInitialTheme() {
|
|
264
|
+
if (typeof window === "undefined") return "dark";
|
|
265
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
266
|
+
if (stored === "light" || stored === "dark") return stored;
|
|
267
|
+
return "dark";
|
|
268
|
+
}
|
|
269
|
+
function ThemeToggle() {
|
|
270
|
+
const [theme, setTheme] = (0, import_react.useState)(getInitialTheme);
|
|
271
|
+
(0, import_react.useEffect)(() => {
|
|
272
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
273
|
+
localStorage.setItem(STORAGE_KEY, theme);
|
|
274
|
+
}, [theme]);
|
|
275
|
+
const toggle = () => setTheme((prev) => prev === "dark" ? "light" : "dark");
|
|
276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
277
|
+
"button",
|
|
278
|
+
{
|
|
279
|
+
onClick: toggle,
|
|
280
|
+
"aria-label": `Switch to ${theme === "dark" ? "light" : "dark"} mode`,
|
|
281
|
+
style: {
|
|
282
|
+
background: "transparent",
|
|
283
|
+
border: "none",
|
|
284
|
+
cursor: "pointer",
|
|
285
|
+
padding: "6px",
|
|
286
|
+
borderRadius: "6px",
|
|
287
|
+
display: "inline-flex",
|
|
288
|
+
alignItems: "center",
|
|
289
|
+
justifyContent: "center",
|
|
290
|
+
color: "var(--rcnr-text2, #6888aa)",
|
|
291
|
+
transition: "color 0.2s ease"
|
|
292
|
+
},
|
|
293
|
+
children: theme === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Sun, { size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Moon, { size: 18 })
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/ReportIssueModal.tsx
|
|
299
|
+
var import_react2 = require("react");
|
|
300
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
260
301
|
function ReportIssueModal({
|
|
261
302
|
isOpen,
|
|
262
303
|
onClose,
|
|
@@ -264,17 +305,17 @@ function ReportIssueModal({
|
|
|
264
305
|
apiBaseUrl = "https://api.rcnr.net",
|
|
265
306
|
userEmail
|
|
266
307
|
}) {
|
|
267
|
-
const [description, setDescription] = (0,
|
|
268
|
-
const [submitting, setSubmitting] = (0,
|
|
269
|
-
const [submitted, setSubmitted] = (0,
|
|
270
|
-
const [error, setError] = (0,
|
|
271
|
-
const handleClose = (0,
|
|
308
|
+
const [description, setDescription] = (0, import_react2.useState)("");
|
|
309
|
+
const [submitting, setSubmitting] = (0, import_react2.useState)(false);
|
|
310
|
+
const [submitted, setSubmitted] = (0, import_react2.useState)(false);
|
|
311
|
+
const [error, setError] = (0, import_react2.useState)("");
|
|
312
|
+
const handleClose = (0, import_react2.useCallback)(() => {
|
|
272
313
|
setDescription("");
|
|
273
314
|
setError("");
|
|
274
315
|
setSubmitted(false);
|
|
275
316
|
onClose();
|
|
276
317
|
}, [onClose]);
|
|
277
|
-
(0,
|
|
318
|
+
(0, import_react2.useEffect)(() => {
|
|
278
319
|
if (!isOpen) return;
|
|
279
320
|
const onKey = (e) => {
|
|
280
321
|
if (e.key === "Escape") handleClose();
|
|
@@ -306,38 +347,38 @@ function ReportIssueModal({
|
|
|
306
347
|
setSubmitting(false);
|
|
307
348
|
}
|
|
308
349
|
};
|
|
309
|
-
return /* @__PURE__ */ (0,
|
|
350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
310
351
|
"div",
|
|
311
352
|
{
|
|
312
353
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
313
354
|
style: { background: "rgba(0,12,23,0.85)", backdropFilter: "blur(6px)" },
|
|
314
355
|
onClick: handleClose,
|
|
315
|
-
children: /* @__PURE__ */ (0,
|
|
356
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
316
357
|
"div",
|
|
317
358
|
{
|
|
318
359
|
className: "relative glass-card rounded-2xl w-full max-w-md p-8",
|
|
319
360
|
style: { animation: "fadeIn 0.15s ease" },
|
|
320
361
|
onClick: (e) => e.stopPropagation(),
|
|
321
362
|
children: [
|
|
322
|
-
/* @__PURE__ */ (0,
|
|
363
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
323
364
|
"button",
|
|
324
365
|
{
|
|
325
366
|
onClick: handleClose,
|
|
326
367
|
className: "absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors",
|
|
327
368
|
"aria-label": "Close",
|
|
328
|
-
children: /* @__PURE__ */ (0,
|
|
369
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
329
370
|
}
|
|
330
371
|
),
|
|
331
|
-
submitted ? /* @__PURE__ */ (0,
|
|
332
|
-
/* @__PURE__ */ (0,
|
|
333
|
-
/* @__PURE__ */ (0,
|
|
334
|
-
] }) : /* @__PURE__ */ (0,
|
|
335
|
-
/* @__PURE__ */ (0,
|
|
336
|
-
/* @__PURE__ */ (0,
|
|
337
|
-
/* @__PURE__ */ (0,
|
|
338
|
-
/* @__PURE__ */ (0,
|
|
339
|
-
/* @__PURE__ */ (0,
|
|
340
|
-
/* @__PURE__ */ (0,
|
|
372
|
+
submitted ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-center py-6", children: [
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "text-emerald-400", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-white font-semibold", children: "Report sent. We'll fix it fast." })
|
|
375
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "text-xl font-bold text-white font-serif mb-1", children: "Report an Issue" }),
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-brand/50 text-sm mb-6", children: "Found a bug or something broken? Let us know." }),
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
380
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "Tool" }),
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
341
382
|
"input",
|
|
342
383
|
{
|
|
343
384
|
type: "text",
|
|
@@ -347,9 +388,9 @@ function ReportIssueModal({
|
|
|
347
388
|
}
|
|
348
389
|
)
|
|
349
390
|
] }),
|
|
350
|
-
/* @__PURE__ */ (0,
|
|
351
|
-
/* @__PURE__ */ (0,
|
|
352
|
-
/* @__PURE__ */ (0,
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
392
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "What went wrong?" }),
|
|
393
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
353
394
|
"textarea",
|
|
354
395
|
{
|
|
355
396
|
value: description,
|
|
@@ -361,8 +402,8 @@ function ReportIssueModal({
|
|
|
361
402
|
}
|
|
362
403
|
)
|
|
363
404
|
] }),
|
|
364
|
-
error && /* @__PURE__ */ (0,
|
|
365
|
-
/* @__PURE__ */ (0,
|
|
405
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-red-400 text-sm", children: error }),
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
366
407
|
"button",
|
|
367
408
|
{
|
|
368
409
|
type: "submit",
|
|
@@ -381,8 +422,8 @@ function ReportIssueModal({
|
|
|
381
422
|
}
|
|
382
423
|
|
|
383
424
|
// src/RequestToolModal.tsx
|
|
384
|
-
var
|
|
385
|
-
var
|
|
425
|
+
var import_react3 = require("react");
|
|
426
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
386
427
|
function RequestToolModal({
|
|
387
428
|
isOpen,
|
|
388
429
|
onClose,
|
|
@@ -390,17 +431,17 @@ function RequestToolModal({
|
|
|
390
431
|
apiBaseUrl = "https://api.rcnr.net",
|
|
391
432
|
userEmail
|
|
392
433
|
}) {
|
|
393
|
-
const [description, setDescription] = (0,
|
|
394
|
-
const [submitting, setSubmitting] = (0,
|
|
395
|
-
const [submitted, setSubmitted] = (0,
|
|
396
|
-
const [error, setError] = (0,
|
|
397
|
-
const handleClose = (0,
|
|
434
|
+
const [description, setDescription] = (0, import_react3.useState)("");
|
|
435
|
+
const [submitting, setSubmitting] = (0, import_react3.useState)(false);
|
|
436
|
+
const [submitted, setSubmitted] = (0, import_react3.useState)(false);
|
|
437
|
+
const [error, setError] = (0, import_react3.useState)("");
|
|
438
|
+
const handleClose = (0, import_react3.useCallback)(() => {
|
|
398
439
|
setDescription("");
|
|
399
440
|
setError("");
|
|
400
441
|
setSubmitted(false);
|
|
401
442
|
onClose();
|
|
402
443
|
}, [onClose]);
|
|
403
|
-
(0,
|
|
444
|
+
(0, import_react3.useEffect)(() => {
|
|
404
445
|
if (!isOpen) return;
|
|
405
446
|
const onKey = (e) => {
|
|
406
447
|
if (e.key === "Escape") handleClose();
|
|
@@ -432,38 +473,38 @@ function RequestToolModal({
|
|
|
432
473
|
setSubmitting(false);
|
|
433
474
|
}
|
|
434
475
|
};
|
|
435
|
-
return /* @__PURE__ */ (0,
|
|
476
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
436
477
|
"div",
|
|
437
478
|
{
|
|
438
479
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
439
480
|
style: { background: "rgba(0,12,23,0.85)", backdropFilter: "blur(6px)" },
|
|
440
481
|
onClick: handleClose,
|
|
441
|
-
children: /* @__PURE__ */ (0,
|
|
482
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
442
483
|
"div",
|
|
443
484
|
{
|
|
444
485
|
className: "relative glass-card rounded-2xl w-full max-w-md p-8",
|
|
445
486
|
style: { animation: "fadeIn 0.15s ease" },
|
|
446
487
|
onClick: (e) => e.stopPropagation(),
|
|
447
488
|
children: [
|
|
448
|
-
/* @__PURE__ */ (0,
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
449
490
|
"button",
|
|
450
491
|
{
|
|
451
492
|
onClick: handleClose,
|
|
452
493
|
className: "absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors",
|
|
453
494
|
"aria-label": "Close",
|
|
454
|
-
children: /* @__PURE__ */ (0,
|
|
495
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
455
496
|
}
|
|
456
497
|
),
|
|
457
|
-
submitted ? /* @__PURE__ */ (0,
|
|
458
|
-
/* @__PURE__ */ (0,
|
|
459
|
-
/* @__PURE__ */ (0,
|
|
460
|
-
] }) : /* @__PURE__ */ (0,
|
|
461
|
-
/* @__PURE__ */ (0,
|
|
462
|
-
/* @__PURE__ */ (0,
|
|
463
|
-
/* @__PURE__ */ (0,
|
|
464
|
-
/* @__PURE__ */ (0,
|
|
465
|
-
/* @__PURE__ */ (0,
|
|
466
|
-
/* @__PURE__ */ (0,
|
|
498
|
+
submitted ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-center py-6", children: [
|
|
499
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "text-brand", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-white font-semibold", children: "Request received. Thanks!" })
|
|
501
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
502
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "text-xl font-bold text-white font-serif mb-1", children: "Request a Tool" }),
|
|
503
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-brand/50 text-sm mb-6", children: "Have an idea for something we should build?" }),
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "Describe what you need" }),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
467
508
|
"textarea",
|
|
468
509
|
{
|
|
469
510
|
value: description,
|
|
@@ -475,8 +516,8 @@ function RequestToolModal({
|
|
|
475
516
|
}
|
|
476
517
|
)
|
|
477
518
|
] }),
|
|
478
|
-
error && /* @__PURE__ */ (0,
|
|
479
|
-
/* @__PURE__ */ (0,
|
|
519
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-red-400 text-sm", children: error }),
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
480
521
|
"button",
|
|
481
522
|
{
|
|
482
523
|
type: "submit",
|
|
@@ -500,6 +541,7 @@ function RequestToolModal({
|
|
|
500
541
|
RCNRMountainLogo,
|
|
501
542
|
RCNRSubNav,
|
|
502
543
|
ReportIssueModal,
|
|
503
|
-
RequestToolModal
|
|
544
|
+
RequestToolModal,
|
|
545
|
+
ThemeToggle
|
|
504
546
|
});
|
|
505
547
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/RCNRMountainLogo.tsx","../src/RCNRHeader.tsx","../src/RCNRSubNav.tsx","../src/RCNRFooter.tsx","../src/ReportIssueModal.tsx","../src/RequestToolModal.tsx"],"sourcesContent":["export { default as RCNRHeader } from './RCNRHeader'\r\nexport { default as RCNRSubNav } from './RCNRSubNav'\r\nexport { default as RCNRFooter } from './RCNRFooter'\r\nexport { default as RCNRMountainLogo } from './RCNRMountainLogo'\r\nexport { ReportIssueModal } from './ReportIssueModal'\r\nexport { RequestToolModal } from './RequestToolModal'\r\n\r\nexport type {\r\n RCNRHeaderProps,\r\n RCNRSubNavProps,\r\n RCNRFooterProps,\r\n} from './types'\r\n","interface RCNRMountainLogoProps {\r\n href?: string\r\n className?: string\r\n}\r\n\r\nfunction RCNRMountainLogo({\r\n href = 'https://teacher.rcnr.net',\r\n className = '',\r\n}: RCNRMountainLogoProps) {\r\n return (\r\n <a\r\n href={href}\r\n className={`flex items-center justify-center w-10 h-10 rounded-lg bg-brand/10 hover:bg-brand/20 transition-colors ${className}`}\r\n title=\"Back to Dashboard\"\r\n >\r\n <svg\r\n width=\"28\"\r\n height=\"24\"\r\n viewBox=\"0 0 120 100\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M10,90l26.48-39.76h.31s4.54,5.02,4.54,5.02l.32-.16,23.06-37.14,17.34,28.63,3.65-4.61,30.22,48.03h-8.43c-7.17-12.26-15.51-24.35-23.06-36.26-1.43.52-2.03,3.6-3.49,3.97l-16.31-25.93-21.87,34.36-5.09-5.01-19.48,28.87h-8.19Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n <path\r\n d=\"M89.84,90h-5.73c-6.34-8.18-12.93-16.89-19.64-24.65-6.66,8.19-13.04,16.6-19.89,24.65h-5.81l25.69-39.76,25.37,39.76Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n </svg>\r\n </a>\r\n )\r\n}\r\n\r\nexport default RCNRMountainLogo\r\n","import type { ReactNode } from 'react'\r\nimport type { RCNRHeaderProps } from './types'\r\nimport RCNRMountainLogo from './RCNRMountainLogo'\r\n\r\nfunction NavButton({\r\n onClick,\r\n icon,\r\n label,\r\n title,\r\n}: {\r\n onClick: () => void\r\n icon: ReactNode\r\n label: string\r\n title?: string\r\n}) {\r\n return (\r\n <button\r\n onClick={onClick}\r\n className=\"flex items-center gap-2 px-3 py-2 text-brand/70 hover:text-brand hover:bg-brand/5 rounded-lg transition-colors\"\r\n title={title ?? label}\r\n >\r\n {icon}\r\n <span className=\"hidden md:inline text-sm\">{label}</span>\r\n </button>\r\n )\r\n}\r\n\r\nconst defaultReportIssue = () =>\r\n window.open('mailto:support@rcnr.net?subject=Bug%20Report', '_blank')\r\n\r\nconst defaultRequestTool = () =>\r\n window.open('mailto:support@rcnr.net?subject=Feature%20Request', '_blank')\r\n\r\nfunction RCNRHeader({\r\n toolName,\r\n dashboardUrl = 'https://teacher.rcnr.net',\r\n extraNavItems,\r\n userAvatar,\r\n onHowItWorks,\r\n onReportIssue = defaultReportIssue,\r\n onRequestTool = defaultRequestTool,\r\n}: RCNRHeaderProps) {\r\n return (\r\n <header className=\"glass-card border-b border-brand/15 px-6 py-4\">\r\n <div className=\"flex items-center justify-between\">\r\n {/* Left: Logo + Tool Name */}\r\n <div className=\"flex items-center gap-4\">\r\n <RCNRMountainLogo href={dashboardUrl} />\r\n <span className=\"text-xl font-serif text-brand\">{toolName}</span>\r\n </div>\r\n\r\n {/* Right: Nav Actions */}\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tool-specific nav items first */}\r\n {extraNavItems?.map((item) => (\r\n <NavButton\r\n key={item.label}\r\n onClick={item.onClick}\r\n icon={item.icon}\r\n label={item.label}\r\n />\r\n ))}\r\n\r\n {/* Standard nav items in fixed order */}\r\n {onHowItWorks && (\r\n <NavButton\r\n onClick={onHowItWorks}\r\n label=\"How It Works\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3\"\r\n />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n }\r\n />\r\n )}\r\n\r\n <NavButton\r\n onClick={onReportIssue}\r\n label=\"Report Issue\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n <NavButton\r\n onClick={onRequestTool}\r\n label=\"Request Tool\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n {userAvatar}\r\n </div>\r\n </div>\r\n </header>\r\n )\r\n}\r\n\r\nexport default RCNRHeader\r\n","import type { RCNRSubNavProps } from './types'\r\n\r\nfunction RCNRSubNav({ tabs }: RCNRSubNavProps) {\r\n return (\r\n <nav className=\"flex items-center gap-1 px-6 py-2 border-b border-brand/10 bg-surface/50\">\r\n {tabs.map((tab) => {\r\n const isWarning = tab.variant === 'warning'\r\n const activeClass = isWarning\r\n ? 'bg-warning/10 text-warning border border-warning/20'\r\n : 'bg-brand/15 text-brand'\r\n const inactiveClass = isWarning\r\n ? 'text-warning/70 hover:text-warning hover:bg-warning/5 border border-warning/10'\r\n : 'text-brand/50 hover:text-brand hover:bg-brand/5'\r\n\r\n const className = `flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors ${\r\n tab.active ? activeClass : inactiveClass\r\n }`\r\n\r\n if (tab.href) {\r\n return (\r\n <a key={tab.label} href={tab.href} className={className}>\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </a>\r\n )\r\n }\r\n\r\n return (\r\n <button\r\n key={tab.label}\r\n onClick={tab.onClick}\r\n className={className}\r\n >\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </button>\r\n )\r\n })}\r\n </nav>\r\n )\r\n}\r\n\r\nexport default RCNRSubNav\r\n","import type { RCNRFooterProps } from './types'\r\n\r\nfunction RCNRFooter({\r\n toolName,\r\n linkUrl = 'https://rcnr.net',\r\n}: RCNRFooterProps) {\r\n return (\r\n <footer className=\"mt-auto py-4 text-center text-sm text-brand-dark/50\">\r\n <a\r\n href={linkUrl}\r\n className=\"hover:text-brand transition-colors\"\r\n >\r\n {toolName} — Part of the RCNR Teacher Toolbox\r\n </a>\r\n </footer>\r\n )\r\n}\r\n\r\nexport default RCNRFooter\r\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface ReportIssueModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function ReportIssueModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: ReportIssueModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/report`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send report. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-emerald-400\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Report sent. We'll fix it fast.</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Report an Issue</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Found a bug or something broken? Let us know.</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">Tool</label>\n <input\n type=\"text\"\n value={toolName}\n disabled\n className=\"w-full px-4 py-2.5 rounded-xl bg-white/5 border border-brand/10 text-brand/40 text-sm\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n What went wrong?\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the issue...\"\n rows={4}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Report'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface RequestToolModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function RequestToolModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: RequestToolModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/request`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send request. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-brand\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Request received. Thanks!</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Request a Tool</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Have an idea for something we should build?</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n Describe what you need\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What problem would this tool solve? What would it do?\"\n rows={5}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Request'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/RCNRMountainLogo.tsx","../src/RCNRHeader.tsx","../src/RCNRSubNav.tsx","../src/RCNRFooter.tsx","../src/ThemeToggle.tsx","../src/ReportIssueModal.tsx","../src/RequestToolModal.tsx"],"sourcesContent":["export { default as RCNRHeader } from './RCNRHeader'\r\nexport { default as RCNRSubNav } from './RCNRSubNav'\r\nexport { default as RCNRFooter } from './RCNRFooter'\r\nexport { default as RCNRMountainLogo } from './RCNRMountainLogo'\r\nexport { default as ThemeToggle } from './ThemeToggle'\r\nexport { ReportIssueModal } from './ReportIssueModal'\r\nexport { RequestToolModal } from './RequestToolModal'\r\n\r\nexport type {\r\n RCNRHeaderProps,\r\n RCNRSubNavProps,\r\n RCNRFooterProps,\r\n} from './types'\r\n","interface RCNRMountainLogoProps {\r\n href?: string\r\n className?: string\r\n}\r\n\r\nfunction RCNRMountainLogo({\r\n href = 'https://teacher.rcnr.net',\r\n className = '',\r\n}: RCNRMountainLogoProps) {\r\n return (\r\n <a\r\n href={href}\r\n className={`flex items-center justify-center w-10 h-10 rounded-lg bg-brand/10 hover:bg-brand/20 transition-colors ${className}`}\r\n title=\"Back to Dashboard\"\r\n >\r\n <svg\r\n width=\"28\"\r\n height=\"24\"\r\n viewBox=\"0 0 120 100\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M10,90l26.48-39.76h.31s4.54,5.02,4.54,5.02l.32-.16,23.06-37.14,17.34,28.63,3.65-4.61,30.22,48.03h-8.43c-7.17-12.26-15.51-24.35-23.06-36.26-1.43.52-2.03,3.6-3.49,3.97l-16.31-25.93-21.87,34.36-5.09-5.01-19.48,28.87h-8.19Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n <path\r\n d=\"M89.84,90h-5.73c-6.34-8.18-12.93-16.89-19.64-24.65-6.66,8.19-13.04,16.6-19.89,24.65h-5.81l25.69-39.76,25.37,39.76Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n </svg>\r\n </a>\r\n )\r\n}\r\n\r\nexport default RCNRMountainLogo\r\n","import type { ReactNode } from 'react'\r\nimport type { RCNRHeaderProps } from './types'\r\nimport RCNRMountainLogo from './RCNRMountainLogo'\r\n\r\nfunction NavButton({\r\n onClick,\r\n icon,\r\n label,\r\n title,\r\n}: {\r\n onClick: () => void\r\n icon: ReactNode\r\n label: string\r\n title?: string\r\n}) {\r\n return (\r\n <button\r\n onClick={onClick}\r\n className=\"flex items-center gap-2 px-3 py-2 text-brand/70 hover:text-brand hover:bg-brand/5 rounded-lg transition-colors\"\r\n title={title ?? label}\r\n >\r\n {icon}\r\n <span className=\"hidden md:inline text-sm\">{label}</span>\r\n </button>\r\n )\r\n}\r\n\r\nconst defaultReportIssue = () =>\r\n window.open('mailto:support@rcnr.net?subject=Bug%20Report', '_blank')\r\n\r\nconst defaultRequestTool = () =>\r\n window.open('mailto:support@rcnr.net?subject=Feature%20Request', '_blank')\r\n\r\nfunction RCNRHeader({\r\n toolName,\r\n dashboardUrl = 'https://teacher.rcnr.net',\r\n extraNavItems,\r\n userAvatar,\r\n onHowItWorks,\r\n onReportIssue = defaultReportIssue,\r\n onRequestTool = defaultRequestTool,\r\n}: RCNRHeaderProps) {\r\n return (\r\n <header className=\"glass-card border-b border-brand/15 px-6 py-4\">\r\n <div className=\"flex items-center justify-between\">\r\n {/* Left: Logo + Tool Name */}\r\n <div className=\"flex items-center gap-4\">\r\n <RCNRMountainLogo href={dashboardUrl} />\r\n <span className=\"text-xl font-serif text-brand\">{toolName}</span>\r\n </div>\r\n\r\n {/* Right: Nav Actions */}\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tool-specific nav items first */}\r\n {extraNavItems?.map((item) => (\r\n <NavButton\r\n key={item.label}\r\n onClick={item.onClick}\r\n icon={item.icon}\r\n label={item.label}\r\n />\r\n ))}\r\n\r\n {/* Standard nav items in fixed order */}\r\n {onHowItWorks && (\r\n <NavButton\r\n onClick={onHowItWorks}\r\n label=\"How It Works\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3\"\r\n />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n }\r\n />\r\n )}\r\n\r\n <NavButton\r\n onClick={onReportIssue}\r\n label=\"Report Issue\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n <NavButton\r\n onClick={onRequestTool}\r\n label=\"Request Tool\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n {userAvatar}\r\n </div>\r\n </div>\r\n </header>\r\n )\r\n}\r\n\r\nexport default RCNRHeader\r\n","import type { RCNRSubNavProps } from './types'\r\n\r\nfunction RCNRSubNav({ tabs }: RCNRSubNavProps) {\r\n return (\r\n <nav className=\"flex items-center gap-1 px-6 py-2 border-b border-brand/10 bg-surface/50\">\r\n {tabs.map((tab) => {\r\n const isWarning = tab.variant === 'warning'\r\n const activeClass = isWarning\r\n ? 'bg-warning/10 text-warning border border-warning/20'\r\n : 'bg-brand/15 text-brand'\r\n const inactiveClass = isWarning\r\n ? 'text-warning/70 hover:text-warning hover:bg-warning/5 border border-warning/10'\r\n : 'text-brand/50 hover:text-brand hover:bg-brand/5'\r\n\r\n const className = `flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors ${\r\n tab.active ? activeClass : inactiveClass\r\n }`\r\n\r\n if (tab.href) {\r\n return (\r\n <a key={tab.label} href={tab.href} className={className}>\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </a>\r\n )\r\n }\r\n\r\n return (\r\n <button\r\n key={tab.label}\r\n onClick={tab.onClick}\r\n className={className}\r\n >\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </button>\r\n )\r\n })}\r\n </nav>\r\n )\r\n}\r\n\r\nexport default RCNRSubNav\r\n","import type { RCNRFooterProps } from './types'\r\n\r\nfunction RCNRFooter({\r\n toolName,\r\n linkUrl = 'https://rcnr.net',\r\n}: RCNRFooterProps) {\r\n return (\r\n <footer className=\"mt-auto py-4 text-center text-sm text-brand-dark/50\">\r\n <a\r\n href={linkUrl}\r\n className=\"hover:text-brand transition-colors\"\r\n >\r\n {toolName} — Part of the RCNR Teacher Toolbox\r\n </a>\r\n </footer>\r\n )\r\n}\r\n\r\nexport default RCNRFooter\r\n","import { useEffect, useState } from 'react'\r\nimport { Sun, Moon } from 'lucide-react'\r\n\r\ntype Theme = 'light' | 'dark'\r\n\r\nconst STORAGE_KEY = 'rcnr-theme'\r\n\r\nfunction getInitialTheme(): Theme {\r\n if (typeof window === 'undefined') return 'dark'\r\n const stored = localStorage.getItem(STORAGE_KEY)\r\n if (stored === 'light' || stored === 'dark') return stored\r\n return 'dark'\r\n}\r\n\r\nexport default function ThemeToggle() {\r\n const [theme, setTheme] = useState<Theme>(getInitialTheme)\r\n\r\n useEffect(() => {\r\n document.documentElement.setAttribute('data-theme', theme)\r\n localStorage.setItem(STORAGE_KEY, theme)\r\n }, [theme])\r\n\r\n const toggle = () => setTheme(prev => (prev === 'dark' ? 'light' : 'dark'))\r\n\r\n return (\r\n <button\r\n onClick={toggle}\r\n aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}\r\n style={{\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n borderRadius: '6px',\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n color: 'var(--rcnr-text2, #6888aa)',\r\n transition: 'color 0.2s ease',\r\n }}\r\n >\r\n {theme === 'dark' ? <Sun size={18} /> : <Moon size={18} />}\r\n </button>\r\n )\r\n}\r\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface ReportIssueModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function ReportIssueModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: ReportIssueModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/report`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send report. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-emerald-400\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Report sent. We'll fix it fast.</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Report an Issue</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Found a bug or something broken? Let us know.</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">Tool</label>\n <input\n type=\"text\"\n value={toolName}\n disabled\n className=\"w-full px-4 py-2.5 rounded-xl bg-white/5 border border-brand/10 text-brand/40 text-sm\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n What went wrong?\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the issue...\"\n rows={4}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Report'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface RequestToolModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function RequestToolModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: RequestToolModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/request`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send request. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-brand\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Request received. Thanks!</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Request a Tool</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Have an idea for something we should build?</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n Describe what you need\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What problem would this tool solve? What would it do?\"\n rows={5}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Request'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
package/dist/index.mjs
CHANGED
|
@@ -223,9 +223,49 @@ function RCNRFooter({
|
|
|
223
223
|
}
|
|
224
224
|
var RCNRFooter_default = RCNRFooter;
|
|
225
225
|
|
|
226
|
+
// src/ThemeToggle.tsx
|
|
227
|
+
import { useEffect, useState } from "react";
|
|
228
|
+
import { Sun, Moon } from "lucide-react";
|
|
229
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
230
|
+
var STORAGE_KEY = "rcnr-theme";
|
|
231
|
+
function getInitialTheme() {
|
|
232
|
+
if (typeof window === "undefined") return "dark";
|
|
233
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
234
|
+
if (stored === "light" || stored === "dark") return stored;
|
|
235
|
+
return "dark";
|
|
236
|
+
}
|
|
237
|
+
function ThemeToggle() {
|
|
238
|
+
const [theme, setTheme] = useState(getInitialTheme);
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
241
|
+
localStorage.setItem(STORAGE_KEY, theme);
|
|
242
|
+
}, [theme]);
|
|
243
|
+
const toggle = () => setTheme((prev) => prev === "dark" ? "light" : "dark");
|
|
244
|
+
return /* @__PURE__ */ jsx5(
|
|
245
|
+
"button",
|
|
246
|
+
{
|
|
247
|
+
onClick: toggle,
|
|
248
|
+
"aria-label": `Switch to ${theme === "dark" ? "light" : "dark"} mode`,
|
|
249
|
+
style: {
|
|
250
|
+
background: "transparent",
|
|
251
|
+
border: "none",
|
|
252
|
+
cursor: "pointer",
|
|
253
|
+
padding: "6px",
|
|
254
|
+
borderRadius: "6px",
|
|
255
|
+
display: "inline-flex",
|
|
256
|
+
alignItems: "center",
|
|
257
|
+
justifyContent: "center",
|
|
258
|
+
color: "var(--rcnr-text2, #6888aa)",
|
|
259
|
+
transition: "color 0.2s ease"
|
|
260
|
+
},
|
|
261
|
+
children: theme === "dark" ? /* @__PURE__ */ jsx5(Sun, { size: 18 }) : /* @__PURE__ */ jsx5(Moon, { size: 18 })
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
226
266
|
// src/ReportIssueModal.tsx
|
|
227
|
-
import { useState, useEffect, useCallback } from "react";
|
|
228
|
-
import { Fragment, jsx as
|
|
267
|
+
import { useState as useState2, useEffect as useEffect2, useCallback } from "react";
|
|
268
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
229
269
|
function ReportIssueModal({
|
|
230
270
|
isOpen,
|
|
231
271
|
onClose,
|
|
@@ -233,17 +273,17 @@ function ReportIssueModal({
|
|
|
233
273
|
apiBaseUrl = "https://api.rcnr.net",
|
|
234
274
|
userEmail
|
|
235
275
|
}) {
|
|
236
|
-
const [description, setDescription] =
|
|
237
|
-
const [submitting, setSubmitting] =
|
|
238
|
-
const [submitted, setSubmitted] =
|
|
239
|
-
const [error, setError] =
|
|
276
|
+
const [description, setDescription] = useState2("");
|
|
277
|
+
const [submitting, setSubmitting] = useState2(false);
|
|
278
|
+
const [submitted, setSubmitted] = useState2(false);
|
|
279
|
+
const [error, setError] = useState2("");
|
|
240
280
|
const handleClose = useCallback(() => {
|
|
241
281
|
setDescription("");
|
|
242
282
|
setError("");
|
|
243
283
|
setSubmitted(false);
|
|
244
284
|
onClose();
|
|
245
285
|
}, [onClose]);
|
|
246
|
-
|
|
286
|
+
useEffect2(() => {
|
|
247
287
|
if (!isOpen) return;
|
|
248
288
|
const onKey = (e) => {
|
|
249
289
|
if (e.key === "Escape") handleClose();
|
|
@@ -275,7 +315,7 @@ function ReportIssueModal({
|
|
|
275
315
|
setSubmitting(false);
|
|
276
316
|
}
|
|
277
317
|
};
|
|
278
|
-
return /* @__PURE__ */
|
|
318
|
+
return /* @__PURE__ */ jsx6(
|
|
279
319
|
"div",
|
|
280
320
|
{
|
|
281
321
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
@@ -288,25 +328,25 @@ function ReportIssueModal({
|
|
|
288
328
|
style: { animation: "fadeIn 0.15s ease" },
|
|
289
329
|
onClick: (e) => e.stopPropagation(),
|
|
290
330
|
children: [
|
|
291
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ jsx6(
|
|
292
332
|
"button",
|
|
293
333
|
{
|
|
294
334
|
onClick: handleClose,
|
|
295
335
|
className: "absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors",
|
|
296
336
|
"aria-label": "Close",
|
|
297
|
-
children: /* @__PURE__ */
|
|
337
|
+
children: /* @__PURE__ */ jsx6("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx6("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
298
338
|
}
|
|
299
339
|
),
|
|
300
340
|
submitted ? /* @__PURE__ */ jsxs5("div", { className: "text-center py-6", children: [
|
|
301
|
-
/* @__PURE__ */
|
|
302
|
-
/* @__PURE__ */
|
|
341
|
+
/* @__PURE__ */ jsx6("div", { className: "w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx6("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "text-emerald-400", children: /* @__PURE__ */ jsx6("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
342
|
+
/* @__PURE__ */ jsx6("p", { className: "text-white font-semibold", children: "Report sent. We'll fix it fast." })
|
|
303
343
|
] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
304
|
-
/* @__PURE__ */
|
|
305
|
-
/* @__PURE__ */
|
|
344
|
+
/* @__PURE__ */ jsx6("h2", { className: "text-xl font-bold text-white font-serif mb-1", children: "Report an Issue" }),
|
|
345
|
+
/* @__PURE__ */ jsx6("p", { className: "text-brand/50 text-sm mb-6", children: "Found a bug or something broken? Let us know." }),
|
|
306
346
|
/* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
307
347
|
/* @__PURE__ */ jsxs5("div", { children: [
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
348
|
+
/* @__PURE__ */ jsx6("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "Tool" }),
|
|
349
|
+
/* @__PURE__ */ jsx6(
|
|
310
350
|
"input",
|
|
311
351
|
{
|
|
312
352
|
type: "text",
|
|
@@ -317,8 +357,8 @@ function ReportIssueModal({
|
|
|
317
357
|
)
|
|
318
358
|
] }),
|
|
319
359
|
/* @__PURE__ */ jsxs5("div", { children: [
|
|
320
|
-
/* @__PURE__ */
|
|
321
|
-
/* @__PURE__ */
|
|
360
|
+
/* @__PURE__ */ jsx6("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "What went wrong?" }),
|
|
361
|
+
/* @__PURE__ */ jsx6(
|
|
322
362
|
"textarea",
|
|
323
363
|
{
|
|
324
364
|
value: description,
|
|
@@ -330,8 +370,8 @@ function ReportIssueModal({
|
|
|
330
370
|
}
|
|
331
371
|
)
|
|
332
372
|
] }),
|
|
333
|
-
error && /* @__PURE__ */
|
|
334
|
-
/* @__PURE__ */
|
|
373
|
+
error && /* @__PURE__ */ jsx6("p", { className: "text-red-400 text-sm", children: error }),
|
|
374
|
+
/* @__PURE__ */ jsx6(
|
|
335
375
|
"button",
|
|
336
376
|
{
|
|
337
377
|
type: "submit",
|
|
@@ -350,8 +390,8 @@ function ReportIssueModal({
|
|
|
350
390
|
}
|
|
351
391
|
|
|
352
392
|
// src/RequestToolModal.tsx
|
|
353
|
-
import { useState as
|
|
354
|
-
import { Fragment as Fragment2, jsx as
|
|
393
|
+
import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2 } from "react";
|
|
394
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
355
395
|
function RequestToolModal({
|
|
356
396
|
isOpen,
|
|
357
397
|
onClose,
|
|
@@ -359,17 +399,17 @@ function RequestToolModal({
|
|
|
359
399
|
apiBaseUrl = "https://api.rcnr.net",
|
|
360
400
|
userEmail
|
|
361
401
|
}) {
|
|
362
|
-
const [description, setDescription] =
|
|
363
|
-
const [submitting, setSubmitting] =
|
|
364
|
-
const [submitted, setSubmitted] =
|
|
365
|
-
const [error, setError] =
|
|
402
|
+
const [description, setDescription] = useState3("");
|
|
403
|
+
const [submitting, setSubmitting] = useState3(false);
|
|
404
|
+
const [submitted, setSubmitted] = useState3(false);
|
|
405
|
+
const [error, setError] = useState3("");
|
|
366
406
|
const handleClose = useCallback2(() => {
|
|
367
407
|
setDescription("");
|
|
368
408
|
setError("");
|
|
369
409
|
setSubmitted(false);
|
|
370
410
|
onClose();
|
|
371
411
|
}, [onClose]);
|
|
372
|
-
|
|
412
|
+
useEffect3(() => {
|
|
373
413
|
if (!isOpen) return;
|
|
374
414
|
const onKey = (e) => {
|
|
375
415
|
if (e.key === "Escape") handleClose();
|
|
@@ -401,7 +441,7 @@ function RequestToolModal({
|
|
|
401
441
|
setSubmitting(false);
|
|
402
442
|
}
|
|
403
443
|
};
|
|
404
|
-
return /* @__PURE__ */
|
|
444
|
+
return /* @__PURE__ */ jsx7(
|
|
405
445
|
"div",
|
|
406
446
|
{
|
|
407
447
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
@@ -414,25 +454,25 @@ function RequestToolModal({
|
|
|
414
454
|
style: { animation: "fadeIn 0.15s ease" },
|
|
415
455
|
onClick: (e) => e.stopPropagation(),
|
|
416
456
|
children: [
|
|
417
|
-
/* @__PURE__ */
|
|
457
|
+
/* @__PURE__ */ jsx7(
|
|
418
458
|
"button",
|
|
419
459
|
{
|
|
420
460
|
onClick: handleClose,
|
|
421
461
|
className: "absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors",
|
|
422
462
|
"aria-label": "Close",
|
|
423
|
-
children: /* @__PURE__ */
|
|
463
|
+
children: /* @__PURE__ */ jsx7("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx7("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
424
464
|
}
|
|
425
465
|
),
|
|
426
466
|
submitted ? /* @__PURE__ */ jsxs6("div", { className: "text-center py-6", children: [
|
|
427
|
-
/* @__PURE__ */
|
|
428
|
-
/* @__PURE__ */
|
|
467
|
+
/* @__PURE__ */ jsx7("div", { className: "w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx7("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "text-brand", children: /* @__PURE__ */ jsx7("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
468
|
+
/* @__PURE__ */ jsx7("p", { className: "text-white font-semibold", children: "Request received. Thanks!" })
|
|
429
469
|
] }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
430
|
-
/* @__PURE__ */
|
|
431
|
-
/* @__PURE__ */
|
|
470
|
+
/* @__PURE__ */ jsx7("h2", { className: "text-xl font-bold text-white font-serif mb-1", children: "Request a Tool" }),
|
|
471
|
+
/* @__PURE__ */ jsx7("p", { className: "text-brand/50 text-sm mb-6", children: "Have an idea for something we should build?" }),
|
|
432
472
|
/* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
433
473
|
/* @__PURE__ */ jsxs6("div", { children: [
|
|
434
|
-
/* @__PURE__ */
|
|
435
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ jsx7("label", { className: "block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2", children: "Describe what you need" }),
|
|
475
|
+
/* @__PURE__ */ jsx7(
|
|
436
476
|
"textarea",
|
|
437
477
|
{
|
|
438
478
|
value: description,
|
|
@@ -444,8 +484,8 @@ function RequestToolModal({
|
|
|
444
484
|
}
|
|
445
485
|
)
|
|
446
486
|
] }),
|
|
447
|
-
error && /* @__PURE__ */
|
|
448
|
-
/* @__PURE__ */
|
|
487
|
+
error && /* @__PURE__ */ jsx7("p", { className: "text-red-400 text-sm", children: error }),
|
|
488
|
+
/* @__PURE__ */ jsx7(
|
|
449
489
|
"button",
|
|
450
490
|
{
|
|
451
491
|
type: "submit",
|
|
@@ -468,6 +508,7 @@ export {
|
|
|
468
508
|
RCNRMountainLogo_default as RCNRMountainLogo,
|
|
469
509
|
RCNRSubNav_default as RCNRSubNav,
|
|
470
510
|
ReportIssueModal,
|
|
471
|
-
RequestToolModal
|
|
511
|
+
RequestToolModal,
|
|
512
|
+
ThemeToggle
|
|
472
513
|
};
|
|
473
514
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/RCNRMountainLogo.tsx","../src/RCNRHeader.tsx","../src/RCNRSubNav.tsx","../src/RCNRFooter.tsx","../src/ReportIssueModal.tsx","../src/RequestToolModal.tsx"],"sourcesContent":["interface RCNRMountainLogoProps {\r\n href?: string\r\n className?: string\r\n}\r\n\r\nfunction RCNRMountainLogo({\r\n href = 'https://teacher.rcnr.net',\r\n className = '',\r\n}: RCNRMountainLogoProps) {\r\n return (\r\n <a\r\n href={href}\r\n className={`flex items-center justify-center w-10 h-10 rounded-lg bg-brand/10 hover:bg-brand/20 transition-colors ${className}`}\r\n title=\"Back to Dashboard\"\r\n >\r\n <svg\r\n width=\"28\"\r\n height=\"24\"\r\n viewBox=\"0 0 120 100\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M10,90l26.48-39.76h.31s4.54,5.02,4.54,5.02l.32-.16,23.06-37.14,17.34,28.63,3.65-4.61,30.22,48.03h-8.43c-7.17-12.26-15.51-24.35-23.06-36.26-1.43.52-2.03,3.6-3.49,3.97l-16.31-25.93-21.87,34.36-5.09-5.01-19.48,28.87h-8.19Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n <path\r\n d=\"M89.84,90h-5.73c-6.34-8.18-12.93-16.89-19.64-24.65-6.66,8.19-13.04,16.6-19.89,24.65h-5.81l25.69-39.76,25.37,39.76Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n </svg>\r\n </a>\r\n )\r\n}\r\n\r\nexport default RCNRMountainLogo\r\n","import type { ReactNode } from 'react'\r\nimport type { RCNRHeaderProps } from './types'\r\nimport RCNRMountainLogo from './RCNRMountainLogo'\r\n\r\nfunction NavButton({\r\n onClick,\r\n icon,\r\n label,\r\n title,\r\n}: {\r\n onClick: () => void\r\n icon: ReactNode\r\n label: string\r\n title?: string\r\n}) {\r\n return (\r\n <button\r\n onClick={onClick}\r\n className=\"flex items-center gap-2 px-3 py-2 text-brand/70 hover:text-brand hover:bg-brand/5 rounded-lg transition-colors\"\r\n title={title ?? label}\r\n >\r\n {icon}\r\n <span className=\"hidden md:inline text-sm\">{label}</span>\r\n </button>\r\n )\r\n}\r\n\r\nconst defaultReportIssue = () =>\r\n window.open('mailto:support@rcnr.net?subject=Bug%20Report', '_blank')\r\n\r\nconst defaultRequestTool = () =>\r\n window.open('mailto:support@rcnr.net?subject=Feature%20Request', '_blank')\r\n\r\nfunction RCNRHeader({\r\n toolName,\r\n dashboardUrl = 'https://teacher.rcnr.net',\r\n extraNavItems,\r\n userAvatar,\r\n onHowItWorks,\r\n onReportIssue = defaultReportIssue,\r\n onRequestTool = defaultRequestTool,\r\n}: RCNRHeaderProps) {\r\n return (\r\n <header className=\"glass-card border-b border-brand/15 px-6 py-4\">\r\n <div className=\"flex items-center justify-between\">\r\n {/* Left: Logo + Tool Name */}\r\n <div className=\"flex items-center gap-4\">\r\n <RCNRMountainLogo href={dashboardUrl} />\r\n <span className=\"text-xl font-serif text-brand\">{toolName}</span>\r\n </div>\r\n\r\n {/* Right: Nav Actions */}\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tool-specific nav items first */}\r\n {extraNavItems?.map((item) => (\r\n <NavButton\r\n key={item.label}\r\n onClick={item.onClick}\r\n icon={item.icon}\r\n label={item.label}\r\n />\r\n ))}\r\n\r\n {/* Standard nav items in fixed order */}\r\n {onHowItWorks && (\r\n <NavButton\r\n onClick={onHowItWorks}\r\n label=\"How It Works\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3\"\r\n />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n }\r\n />\r\n )}\r\n\r\n <NavButton\r\n onClick={onReportIssue}\r\n label=\"Report Issue\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n <NavButton\r\n onClick={onRequestTool}\r\n label=\"Request Tool\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n {userAvatar}\r\n </div>\r\n </div>\r\n </header>\r\n )\r\n}\r\n\r\nexport default RCNRHeader\r\n","import type { RCNRSubNavProps } from './types'\r\n\r\nfunction RCNRSubNav({ tabs }: RCNRSubNavProps) {\r\n return (\r\n <nav className=\"flex items-center gap-1 px-6 py-2 border-b border-brand/10 bg-surface/50\">\r\n {tabs.map((tab) => {\r\n const isWarning = tab.variant === 'warning'\r\n const activeClass = isWarning\r\n ? 'bg-warning/10 text-warning border border-warning/20'\r\n : 'bg-brand/15 text-brand'\r\n const inactiveClass = isWarning\r\n ? 'text-warning/70 hover:text-warning hover:bg-warning/5 border border-warning/10'\r\n : 'text-brand/50 hover:text-brand hover:bg-brand/5'\r\n\r\n const className = `flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors ${\r\n tab.active ? activeClass : inactiveClass\r\n }`\r\n\r\n if (tab.href) {\r\n return (\r\n <a key={tab.label} href={tab.href} className={className}>\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </a>\r\n )\r\n }\r\n\r\n return (\r\n <button\r\n key={tab.label}\r\n onClick={tab.onClick}\r\n className={className}\r\n >\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </button>\r\n )\r\n })}\r\n </nav>\r\n )\r\n}\r\n\r\nexport default RCNRSubNav\r\n","import type { RCNRFooterProps } from './types'\r\n\r\nfunction RCNRFooter({\r\n toolName,\r\n linkUrl = 'https://rcnr.net',\r\n}: RCNRFooterProps) {\r\n return (\r\n <footer className=\"mt-auto py-4 text-center text-sm text-brand-dark/50\">\r\n <a\r\n href={linkUrl}\r\n className=\"hover:text-brand transition-colors\"\r\n >\r\n {toolName} — Part of the RCNR Teacher Toolbox\r\n </a>\r\n </footer>\r\n )\r\n}\r\n\r\nexport default RCNRFooter\r\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface ReportIssueModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function ReportIssueModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: ReportIssueModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/report`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send report. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-emerald-400\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Report sent. We'll fix it fast.</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Report an Issue</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Found a bug or something broken? Let us know.</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">Tool</label>\n <input\n type=\"text\"\n value={toolName}\n disabled\n className=\"w-full px-4 py-2.5 rounded-xl bg-white/5 border border-brand/10 text-brand/40 text-sm\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n What went wrong?\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the issue...\"\n rows={4}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Report'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface RequestToolModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function RequestToolModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: RequestToolModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/request`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send request. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-brand\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Request received. Thanks!</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Request a Tool</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Have an idea for something we should build?</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n Describe what you need\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What problem would this tool solve? What would it do?\"\n rows={5}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Request'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState","useEffect","useCallback","Fragment","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/RCNRMountainLogo.tsx","../src/RCNRHeader.tsx","../src/RCNRSubNav.tsx","../src/RCNRFooter.tsx","../src/ThemeToggle.tsx","../src/ReportIssueModal.tsx","../src/RequestToolModal.tsx"],"sourcesContent":["interface RCNRMountainLogoProps {\r\n href?: string\r\n className?: string\r\n}\r\n\r\nfunction RCNRMountainLogo({\r\n href = 'https://teacher.rcnr.net',\r\n className = '',\r\n}: RCNRMountainLogoProps) {\r\n return (\r\n <a\r\n href={href}\r\n className={`flex items-center justify-center w-10 h-10 rounded-lg bg-brand/10 hover:bg-brand/20 transition-colors ${className}`}\r\n title=\"Back to Dashboard\"\r\n >\r\n <svg\r\n width=\"28\"\r\n height=\"24\"\r\n viewBox=\"0 0 120 100\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M10,90l26.48-39.76h.31s4.54,5.02,4.54,5.02l.32-.16,23.06-37.14,17.34,28.63,3.65-4.61,30.22,48.03h-8.43c-7.17-12.26-15.51-24.35-23.06-36.26-1.43.52-2.03,3.6-3.49,3.97l-16.31-25.93-21.87,34.36-5.09-5.01-19.48,28.87h-8.19Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n <path\r\n d=\"M89.84,90h-5.73c-6.34-8.18-12.93-16.89-19.64-24.65-6.66,8.19-13.04,16.6-19.89,24.65h-5.81l25.69-39.76,25.37,39.76Z\"\r\n fill=\"#99D9D9\"\r\n />\r\n </svg>\r\n </a>\r\n )\r\n}\r\n\r\nexport default RCNRMountainLogo\r\n","import type { ReactNode } from 'react'\r\nimport type { RCNRHeaderProps } from './types'\r\nimport RCNRMountainLogo from './RCNRMountainLogo'\r\n\r\nfunction NavButton({\r\n onClick,\r\n icon,\r\n label,\r\n title,\r\n}: {\r\n onClick: () => void\r\n icon: ReactNode\r\n label: string\r\n title?: string\r\n}) {\r\n return (\r\n <button\r\n onClick={onClick}\r\n className=\"flex items-center gap-2 px-3 py-2 text-brand/70 hover:text-brand hover:bg-brand/5 rounded-lg transition-colors\"\r\n title={title ?? label}\r\n >\r\n {icon}\r\n <span className=\"hidden md:inline text-sm\">{label}</span>\r\n </button>\r\n )\r\n}\r\n\r\nconst defaultReportIssue = () =>\r\n window.open('mailto:support@rcnr.net?subject=Bug%20Report', '_blank')\r\n\r\nconst defaultRequestTool = () =>\r\n window.open('mailto:support@rcnr.net?subject=Feature%20Request', '_blank')\r\n\r\nfunction RCNRHeader({\r\n toolName,\r\n dashboardUrl = 'https://teacher.rcnr.net',\r\n extraNavItems,\r\n userAvatar,\r\n onHowItWorks,\r\n onReportIssue = defaultReportIssue,\r\n onRequestTool = defaultRequestTool,\r\n}: RCNRHeaderProps) {\r\n return (\r\n <header className=\"glass-card border-b border-brand/15 px-6 py-4\">\r\n <div className=\"flex items-center justify-between\">\r\n {/* Left: Logo + Tool Name */}\r\n <div className=\"flex items-center gap-4\">\r\n <RCNRMountainLogo href={dashboardUrl} />\r\n <span className=\"text-xl font-serif text-brand\">{toolName}</span>\r\n </div>\r\n\r\n {/* Right: Nav Actions */}\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tool-specific nav items first */}\r\n {extraNavItems?.map((item) => (\r\n <NavButton\r\n key={item.label}\r\n onClick={item.onClick}\r\n icon={item.icon}\r\n label={item.label}\r\n />\r\n ))}\r\n\r\n {/* Standard nav items in fixed order */}\r\n {onHowItWorks && (\r\n <NavButton\r\n onClick={onHowItWorks}\r\n label=\"How It Works\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3\"\r\n />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n }\r\n />\r\n )}\r\n\r\n <NavButton\r\n onClick={onReportIssue}\r\n label=\"Report Issue\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n <NavButton\r\n onClick={onRequestTool}\r\n label=\"Request Tool\"\r\n icon={\r\n <svg\r\n className=\"w-[18px] h-[18px]\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z\"\r\n />\r\n </svg>\r\n }\r\n />\r\n\r\n {userAvatar}\r\n </div>\r\n </div>\r\n </header>\r\n )\r\n}\r\n\r\nexport default RCNRHeader\r\n","import type { RCNRSubNavProps } from './types'\r\n\r\nfunction RCNRSubNav({ tabs }: RCNRSubNavProps) {\r\n return (\r\n <nav className=\"flex items-center gap-1 px-6 py-2 border-b border-brand/10 bg-surface/50\">\r\n {tabs.map((tab) => {\r\n const isWarning = tab.variant === 'warning'\r\n const activeClass = isWarning\r\n ? 'bg-warning/10 text-warning border border-warning/20'\r\n : 'bg-brand/15 text-brand'\r\n const inactiveClass = isWarning\r\n ? 'text-warning/70 hover:text-warning hover:bg-warning/5 border border-warning/10'\r\n : 'text-brand/50 hover:text-brand hover:bg-brand/5'\r\n\r\n const className = `flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors ${\r\n tab.active ? activeClass : inactiveClass\r\n }`\r\n\r\n if (tab.href) {\r\n return (\r\n <a key={tab.label} href={tab.href} className={className}>\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </a>\r\n )\r\n }\r\n\r\n return (\r\n <button\r\n key={tab.label}\r\n onClick={tab.onClick}\r\n className={className}\r\n >\r\n {tab.icon}\r\n <span>{tab.label}</span>\r\n </button>\r\n )\r\n })}\r\n </nav>\r\n )\r\n}\r\n\r\nexport default RCNRSubNav\r\n","import type { RCNRFooterProps } from './types'\r\n\r\nfunction RCNRFooter({\r\n toolName,\r\n linkUrl = 'https://rcnr.net',\r\n}: RCNRFooterProps) {\r\n return (\r\n <footer className=\"mt-auto py-4 text-center text-sm text-brand-dark/50\">\r\n <a\r\n href={linkUrl}\r\n className=\"hover:text-brand transition-colors\"\r\n >\r\n {toolName} — Part of the RCNR Teacher Toolbox\r\n </a>\r\n </footer>\r\n )\r\n}\r\n\r\nexport default RCNRFooter\r\n","import { useEffect, useState } from 'react'\r\nimport { Sun, Moon } from 'lucide-react'\r\n\r\ntype Theme = 'light' | 'dark'\r\n\r\nconst STORAGE_KEY = 'rcnr-theme'\r\n\r\nfunction getInitialTheme(): Theme {\r\n if (typeof window === 'undefined') return 'dark'\r\n const stored = localStorage.getItem(STORAGE_KEY)\r\n if (stored === 'light' || stored === 'dark') return stored\r\n return 'dark'\r\n}\r\n\r\nexport default function ThemeToggle() {\r\n const [theme, setTheme] = useState<Theme>(getInitialTheme)\r\n\r\n useEffect(() => {\r\n document.documentElement.setAttribute('data-theme', theme)\r\n localStorage.setItem(STORAGE_KEY, theme)\r\n }, [theme])\r\n\r\n const toggle = () => setTheme(prev => (prev === 'dark' ? 'light' : 'dark'))\r\n\r\n return (\r\n <button\r\n onClick={toggle}\r\n aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}\r\n style={{\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n borderRadius: '6px',\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n color: 'var(--rcnr-text2, #6888aa)',\r\n transition: 'color 0.2s ease',\r\n }}\r\n >\r\n {theme === 'dark' ? <Sun size={18} /> : <Moon size={18} />}\r\n </button>\r\n )\r\n}\r\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface ReportIssueModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function ReportIssueModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: ReportIssueModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/report`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send report. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-emerald-500/15 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-emerald-400\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Report sent. We'll fix it fast.</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Report an Issue</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Found a bug or something broken? Let us know.</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">Tool</label>\n <input\n type=\"text\"\n value={toolName}\n disabled\n className=\"w-full px-4 py-2.5 rounded-xl bg-white/5 border border-brand/10 text-brand/40 text-sm\"\n />\n </div>\n\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n What went wrong?\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe the issue...\"\n rows={4}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Report'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useCallback } from 'react'\n\ninterface RequestToolModalProps {\n isOpen: boolean\n onClose: () => void\n toolName: string\n apiBaseUrl?: string\n userEmail?: string\n}\n\nexport function RequestToolModal({\n isOpen,\n onClose,\n toolName,\n apiBaseUrl = 'https://api.rcnr.net',\n userEmail,\n}: RequestToolModalProps) {\n const [description, setDescription] = useState('')\n const [submitting, setSubmitting] = useState(false)\n const [submitted, setSubmitted] = useState(false)\n const [error, setError] = useState('')\n\n const handleClose = useCallback(() => {\n setDescription('')\n setError('')\n setSubmitted(false)\n onClose()\n }, [onClose])\n\n useEffect(() => {\n if (!isOpen) return\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [isOpen, handleClose])\n\n if (!isOpen) return null\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!description.trim()) return\n setSubmitting(true)\n setError('')\n try {\n const res = await fetch(`${apiBaseUrl}/api/feedback/request`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ tool_name: toolName, description, user_email: userEmail }),\n })\n if (res.ok) {\n setSubmitted(true)\n setTimeout(handleClose, 2000)\n } else {\n setError('Something went wrong. Please try again.')\n }\n } catch {\n setError('Could not send request. Check your connection.')\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center p-4\"\n style={{ background: 'rgba(0,12,23,0.85)', backdropFilter: 'blur(6px)' }}\n onClick={handleClose}\n >\n <div\n className=\"relative glass-card rounded-2xl w-full max-w-md p-8\"\n style={{ animation: 'fadeIn 0.15s ease' }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n onClick={handleClose}\n className=\"absolute top-4 right-4 p-2 text-brand/50 hover:text-brand hover:bg-white/5 rounded-lg transition-colors\"\n aria-label=\"Close\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n\n {submitted ? (\n <div className=\"text-center py-6\">\n <div className=\"w-12 h-12 rounded-full bg-brand/10 flex items-center justify-center mx-auto mb-4\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" className=\"text-brand\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <p className=\"text-white font-semibold\">Request received. Thanks!</p>\n </div>\n ) : (\n <>\n <h2 className=\"text-xl font-bold text-white font-serif mb-1\">Request a Tool</h2>\n <p className=\"text-brand/50 text-sm mb-6\">Have an idea for something we should build?</p>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-brand/60 uppercase tracking-wider mb-2\">\n Describe what you need\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What problem would this tool solve? What would it do?\"\n rows={5}\n required\n className=\"w-full px-4 py-3 rounded-xl bg-white/5 border border-brand/15 text-white placeholder-brand/30 text-sm resize-none focus:outline-none focus:border-brand/40 transition-colors\"\n />\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n\n <button\n type=\"submit\"\n disabled={submitting || !description.trim()}\n className=\"btn-ice w-full py-3 text-sm font-semibold rounded-xl disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {submitting ? 'Sending...' : 'Submit Request'}\n </button>\n </form>\n </>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":";AAeM,SAOE,KAPF;AAVN,SAAS,iBAAiB;AAAA,EACxB,OAAO;AAAA,EACP,YAAY;AACd,GAA0B;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,yGAAyG,SAAS;AAAA,MAC7H,OAAM;AAAA,MAEN;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,QAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,OAAM;AAAA,UAEN;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,MAAK;AAAA;AAAA,YACP;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,MAAK;AAAA;AAAA,YACP;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,2BAAQ;;;ACnBX,SAME,OAAAA,MANF,QAAAC,aAAA;AAZJ,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,OAAO,SAAS;AAAA,MAEf;AAAA;AAAA,QACD,gBAAAD,KAAC,UAAK,WAAU,4BAA4B,iBAAM;AAAA;AAAA;AAAA,EACpD;AAEJ;AAEA,IAAM,qBAAqB,MACzB,OAAO,KAAK,gDAAgD,QAAQ;AAEtE,IAAM,qBAAqB,MACzB,OAAO,KAAK,qDAAqD,QAAQ;AAE3E,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,gBAAgB;AAClB,GAAoB;AAClB,SACE,gBAAAA,KAAC,YAAO,WAAU,iDAChB,0BAAAC,MAAC,SAAI,WAAU,qCAEb;AAAA,oBAAAA,MAAC,SAAI,WAAU,2BACb;AAAA,sBAAAD,KAAC,4BAAiB,MAAM,cAAc;AAAA,MACtC,gBAAAA,KAAC,UAAK,WAAU,iCAAiC,oBAAS;AAAA,OAC5D;AAAA,IAGA,gBAAAC,MAAC,SAAI,WAAU,2BAEZ;AAAA,qBAAe,IAAI,CAAC,SACnB,gBAAAD;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,KAAK;AAAA,UACd,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA;AAAA,QAHP,KAAK;AAAA,MAIZ,CACD;AAAA,MAGA,gBACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,OAAM;AAAA,UACN,MACE,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,QAAO;AAAA,cACP,aAAa;AAAA,cAEb;AAAA,gCAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,gBAC/B,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,eAAc;AAAA,oBACd,gBAAe;AAAA,oBACf,GAAE;AAAA;AAAA,gBACJ;AAAA,gBACA,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA;AAAA;AAAA,UAC3C;AAAA;AAAA,MAEJ;AAAA,MAGF,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,OAAM;AAAA,UACN,MACE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,QAAO;AAAA,cACP,aAAa;AAAA,cAEb,0BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,eAAc;AAAA,kBACd,gBAAe;AAAA,kBACf,GAAE;AAAA;AAAA,cACJ;AAAA;AAAA,UACF;AAAA;AAAA,MAEJ;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,OAAM;AAAA,UACN,MACE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,QAAO;AAAA,cACP,aAAa;AAAA,cAEb,0BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,eAAc;AAAA,kBACd,gBAAe;AAAA,kBACf,GAAE;AAAA;AAAA,cACJ;AAAA;AAAA,UACF;AAAA;AAAA,MAEJ;AAAA,MAEC;AAAA,OACH;AAAA,KACF,GACF;AAEJ;AAEA,IAAO,qBAAQ;;;ACnHH,SAEE,OAAAE,MAFF,QAAAC,aAAA;AAlBZ,SAAS,WAAW,EAAE,KAAK,GAAoB;AAC7C,SACE,gBAAAD,KAAC,SAAI,WAAU,4EACZ,eAAK,IAAI,CAAC,QAAQ;AACjB,UAAM,YAAY,IAAI,YAAY;AAClC,UAAM,cAAc,YAChB,wDACA;AACJ,UAAM,gBAAgB,YAClB,mFACA;AAEJ,UAAM,YAAY,0EAChB,IAAI,SAAS,cAAc,aAC7B;AAEA,QAAI,IAAI,MAAM;AACZ,aACE,gBAAAC,MAAC,OAAkB,MAAM,IAAI,MAAM,WAChC;AAAA,YAAI;AAAA,QACL,gBAAAD,KAAC,UAAM,cAAI,OAAM;AAAA,WAFX,IAAI,KAGZ;AAAA,IAEJ;AAEA,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEC,SAAS,IAAI;AAAA,QACb;AAAA,QAEC;AAAA,cAAI;AAAA,UACL,gBAAAD,KAAC,UAAM,cAAI,OAAM;AAAA;AAAA;AAAA,MALZ,IAAI;AAAA,IAMX;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,IAAO,qBAAQ;;;ACnCX,gBAAAE,MACE,QAAAC,aADF;AALJ,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,UAAU;AACZ,GAAoB;AAClB,SACE,gBAAAD,KAAC,YAAO,WAAU,uDAChB,0BAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,WAAU;AAAA,MAET;AAAA;AAAA,QAAS;AAAA;AAAA;AAAA,EACZ,GACF;AAEJ;AAEA,IAAO,qBAAQ;;;AClBf,SAAS,WAAW,gBAAgB;AACpC,SAAS,KAAK,YAAY;AAwCA,gBAAAC,YAAA;AApC1B,IAAM,cAAc;AAEpB,SAAS,kBAAyB;AAChC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,SAAS,aAAa,QAAQ,WAAW;AAC/C,MAAI,WAAW,WAAW,WAAW,OAAQ,QAAO;AACpD,SAAO;AACT;AAEe,SAAR,cAA+B;AACpC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgB,eAAe;AAEzD,YAAU,MAAM;AACd,aAAS,gBAAgB,aAAa,cAAc,KAAK;AACzD,iBAAa,QAAQ,aAAa,KAAK;AAAA,EACzC,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,SAAS,MAAM,SAAS,UAAS,SAAS,SAAS,UAAU,MAAO;AAE1E,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,cAAY,aAAa,UAAU,SAAS,UAAU,MAAM;AAAA,MAC5D,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,MAEC,oBAAU,SAAS,gBAAAA,KAAC,OAAI,MAAM,IAAI,IAAK,gBAAAA,KAAC,QAAK,MAAM,IAAI;AAAA;AAAA,EAC1D;AAEJ;;;AC5CA,SAAS,YAAAC,WAAU,aAAAC,YAAW,mBAAmB;AA+ErC,SAcF,UAdE,OAAAC,MAKF,QAAAC,aALE;AArEL,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AACF,GAA0B;AACxB,QAAM,CAAC,aAAa,cAAc,IAAIH,UAAS,EAAE;AACjD,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AAErC,QAAM,cAAc,YAAY,MAAM;AACpC,mBAAe,EAAE;AACjB,aAAS,EAAE;AACX,iBAAa,KAAK;AAClB,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,CAAC,MAAqB;AAAE,UAAI,EAAE,QAAQ,SAAU,aAAY;AAAA,IAAE;AAC5E,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAAA,EAC5D,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,QAAI,CAAC,YAAY,KAAK,EAAG;AACzB,kBAAc,IAAI;AAClB,aAAS,EAAE;AACX,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,UAAU,wBAAwB;AAAA,QAC3D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,aAAa,YAAY,UAAU,CAAC;AAAA,MAClF,CAAC;AACD,UAAI,IAAI,IAAI;AACV,qBAAa,IAAI;AACjB,mBAAW,aAAa,GAAI;AAAA,MAC9B,OAAO;AACL,iBAAS,yCAAyC;AAAA,MACpD;AAAA,IACF,QAAQ;AACN,eAAS,+CAA+C;AAAA,IAC1D,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,YAAY,sBAAsB,gBAAgB,YAAY;AAAA,MACvE,SAAS;AAAA,MAET,0BAAAC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,WAAW,oBAAoB;AAAA,UACxC,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,UAElC;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACV,cAAW;AAAA,gBAEX,0BAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAC5F,0BAAAA,KAAC,UAAK,GAAE,wBAAuB,GACjC;AAAA;AAAA,YACF;AAAA,YAEC,YACC,gBAAAC,MAAC,SAAI,WAAU,oBACb;AAAA,8BAAAD,KAAC,SAAI,WAAU,0FACb,0BAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,WAAU,oBAC5G,0BAAAA,KAAC,cAAS,QAAO,kBAAiB,GACpC,GACF;AAAA,cACA,gBAAAA,KAAC,OAAE,WAAU,4BAA2B,6CAA+B;AAAA,eACzE,IAEA,gBAAAC,MAAA,YACE;AAAA,8BAAAD,KAAC,QAAG,WAAU,gDAA+C,6BAAe;AAAA,cAC5E,gBAAAA,KAAC,OAAE,WAAU,8BAA6B,2DAA6C;AAAA,cAEvF,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,aACtC;AAAA,gCAAAA,MAAC,SACC;AAAA,kCAAAD,KAAC,WAAM,WAAU,2EAA0E,kBAAI;AAAA,kBAC/F,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,OAAO;AAAA,sBACP,UAAQ;AAAA,sBACR,WAAU;AAAA;AAAA,kBACZ;AAAA,mBACF;AAAA,gBAEA,gBAAAC,MAAC,SACC;AAAA,kCAAAD,KAAC,WAAM,WAAU,2EAA0E,8BAE3F;AAAA,kBACA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,sBACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,sBAC9C,aAAY;AAAA,sBACZ,MAAM;AAAA,sBACN,UAAQ;AAAA,sBACR,WAAU;AAAA;AAAA,kBACZ;AAAA,mBACF;AAAA,gBAEC,SAAS,gBAAAA,KAAC,OAAE,WAAU,wBAAwB,iBAAM;AAAA,gBAErD,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,cAAc,CAAC,YAAY,KAAK;AAAA,oBAC1C,WAAU;AAAA,oBAET,uBAAa,eAAe;AAAA;AAAA,gBAC/B;AAAA,iBACF;AAAA,eACF;AAAA;AAAA;AAAA,MAEJ;AAAA;AAAA,EACF;AAEJ;;;ACzIA,SAAS,YAAAE,WAAU,aAAAC,YAAW,eAAAC,oBAAmB;AA+ErC,SAcF,YAAAC,WAdE,OAAAC,MAKF,QAAAC,aALE;AArEL,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AACF,GAA0B;AACxB,QAAM,CAAC,aAAa,cAAc,IAAIL,UAAS,EAAE;AACjD,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AAErC,QAAM,cAAcE,aAAY,MAAM;AACpC,mBAAe,EAAE;AACjB,aAAS,EAAE;AACX,iBAAa,KAAK;AAClB,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,CAAC,MAAqB;AAAE,UAAI,EAAE,QAAQ,SAAU,aAAY;AAAA,IAAE;AAC5E,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAAA,EAC5D,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,QAAI,CAAC,YAAY,KAAK,EAAG;AACzB,kBAAc,IAAI;AAClB,aAAS,EAAE;AACX,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,UAAU,yBAAyB;AAAA,QAC5D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,aAAa,YAAY,UAAU,CAAC;AAAA,MAClF,CAAC;AACD,UAAI,IAAI,IAAI;AACV,qBAAa,IAAI;AACjB,mBAAW,aAAa,GAAI;AAAA,MAC9B,OAAO;AACL,iBAAS,yCAAyC;AAAA,MACpD;AAAA,IACF,QAAQ;AACN,eAAS,gDAAgD;AAAA,IAC3D,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE,gBAAAG;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,YAAY,sBAAsB,gBAAgB,YAAY;AAAA,MACvE,SAAS;AAAA,MAET,0BAAAC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,WAAW,oBAAoB;AAAA,UACxC,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,UAElC;AAAA,4BAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACV,cAAW;AAAA,gBAEX,0BAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAC5F,0BAAAA,KAAC,UAAK,GAAE,wBAAuB,GACjC;AAAA;AAAA,YACF;AAAA,YAEC,YACC,gBAAAC,MAAC,SAAI,WAAU,oBACb;AAAA,8BAAAD,KAAC,SAAI,WAAU,oFACb,0BAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,WAAU,cAC5G,0BAAAA,KAAC,cAAS,QAAO,kBAAiB,GACpC,GACF;AAAA,cACA,gBAAAA,KAAC,OAAE,WAAU,4BAA2B,uCAAyB;AAAA,eACnE,IAEA,gBAAAC,MAAAF,WAAA,EACE;AAAA,8BAAAC,KAAC,QAAG,WAAU,gDAA+C,4BAAc;AAAA,cAC3E,gBAAAA,KAAC,OAAE,WAAU,8BAA6B,yDAA2C;AAAA,cAErF,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,aACtC;AAAA,gCAAAA,MAAC,SACC;AAAA,kCAAAD,KAAC,WAAM,WAAU,2EAA0E,oCAE3F;AAAA,kBACA,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,sBACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,sBAC9C,aAAY;AAAA,sBACZ,MAAM;AAAA,sBACN,UAAQ;AAAA,sBACR,WAAU;AAAA;AAAA,kBACZ;AAAA,mBACF;AAAA,gBAEC,SAAS,gBAAAA,KAAC,OAAE,WAAU,wBAAwB,iBAAM;AAAA,gBAErD,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,cAAc,CAAC,YAAY,KAAK;AAAA,oBAC1C,WAAU;AAAA,oBAET,uBAAa,eAAe;AAAA;AAAA,gBAC/B;AAAA,iBACF;AAAA,eACF;AAAA;AAAA;AAAA,MAEJ;AAAA;AAAA,EACF;AAEJ;","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useState","useEffect","jsx","jsxs","useState","useEffect","useCallback","Fragment","jsx","jsxs"]}
|
package/index.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/* @rcnr/theme
|
|
2
|
-
RCNR Brand Foundation — tokens,
|
|
1
|
+
/* @rcnr/theme v3.0.0
|
|
2
|
+
RCNR Brand Foundation — tokens, components, scrollbars, shared React components
|
|
3
3
|
|
|
4
4
|
Usage (Tailwind 4):
|
|
5
5
|
@import "tailwindcss";
|
|
@@ -47,21 +47,46 @@
|
|
|
47
47
|
--ice-subtle: #0A1E2E;
|
|
48
48
|
--amber: #F5A623;
|
|
49
49
|
--amber-hover: #FFB84D;
|
|
50
|
-
}
|
|
51
50
|
|
|
52
|
-
/* ---
|
|
51
|
+
/* --- RCNR design tokens (dark mode default) --- */
|
|
52
|
+
--rcnr-bg: #0d1b2a;
|
|
53
|
+
--rcnr-nav: #091422;
|
|
54
|
+
--rcnr-surface: #122035;
|
|
55
|
+
--rcnr-surface2: #162840;
|
|
56
|
+
--rcnr-border: #1e3349;
|
|
57
|
+
--rcnr-text: #e2ecf8;
|
|
58
|
+
--rcnr-text2: #6888aa;
|
|
59
|
+
--rcnr-text3: #344f6a;
|
|
60
|
+
--rcnr-accent: #2dd4bf;
|
|
61
|
+
--rcnr-accent-dim: rgba(45, 212, 191, 0.10);
|
|
62
|
+
--rcnr-cta: #f0b429;
|
|
63
|
+
--rcnr-cta-text: #0d1520;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* --- RCNR design tokens (light mode) --- */
|
|
67
|
+
[data-theme="light"] {
|
|
68
|
+
--rcnr-bg: #eef4fc;
|
|
69
|
+
--rcnr-nav: #ffffff;
|
|
70
|
+
--rcnr-surface: #ffffff;
|
|
71
|
+
--rcnr-surface2: #e4edf8;
|
|
72
|
+
--rcnr-border: #c8d9ee;
|
|
73
|
+
--rcnr-text: #0a1825;
|
|
74
|
+
--rcnr-text2: #3a5878;
|
|
75
|
+
--rcnr-text3: #7a9abc;
|
|
76
|
+
--rcnr-accent: #0d7377;
|
|
77
|
+
--rcnr-accent-dim: rgba(13, 115, 119, 0.08);
|
|
78
|
+
--rcnr-cta: #e0a800;
|
|
79
|
+
--rcnr-cta-text: #1a0f00;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* --- Body --- */
|
|
53
83
|
body {
|
|
54
84
|
margin: 0;
|
|
55
|
-
color: white;
|
|
85
|
+
color: var(--rcnr-text, white);
|
|
56
86
|
font-family: "Geist", ui-sans-serif, system-ui, sans-serif;
|
|
57
87
|
-webkit-font-smoothing: antialiased;
|
|
58
88
|
-moz-osx-font-smoothing: grayscale;
|
|
59
|
-
background:
|
|
60
|
-
linear-gradient(rgba(153, 217, 217, 0.05) 1px, transparent 1px),
|
|
61
|
-
linear-gradient(90deg, rgba(153, 217, 217, 0.05) 1px, transparent 1px),
|
|
62
|
-
#001628;
|
|
63
|
-
background-size: 60px 60px, 60px 60px, auto;
|
|
64
|
-
background-attachment: fixed;
|
|
89
|
+
background: var(--rcnr-bg, #0d1b2a);
|
|
65
90
|
}
|
|
66
91
|
|
|
67
92
|
/* --- Root container --- */
|
|
@@ -144,6 +169,16 @@ body {
|
|
|
144
169
|
color: #99d9d9;
|
|
145
170
|
}
|
|
146
171
|
|
|
172
|
+
/* --- Clerk UserButton popover (dark mode fix) --- */
|
|
173
|
+
.rcnr-clerk-popover {
|
|
174
|
+
background: var(--rcnr-surface) !important;
|
|
175
|
+
border: 1px solid var(--rcnr-border) !important;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.rcnr-clerk-popover-btn:hover {
|
|
179
|
+
background: var(--rcnr-surface2) !important;
|
|
180
|
+
}
|
|
181
|
+
|
|
147
182
|
/* --- Scrollbar --- */
|
|
148
183
|
::-webkit-scrollbar {
|
|
149
184
|
width: 8px;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rcnr/theme",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "RCNR design system: CSS tokens, shared React components (header, footer, subnav), glass cards, buttons, grid",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
"prepublishOnly": "npm run build"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
+
"lucide-react": ">=0.300.0",
|
|
27
28
|
"react": ">=18"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@types/react": "^19.0.0",
|
|
32
|
+
"lucide-react": "^0.577.0",
|
|
31
33
|
"react": "^19.0.0",
|
|
32
34
|
"tsup": "^8.0.0",
|
|
33
35
|
"typescript": "^5.3.0"
|