@tollerud/ui 1.1.5 → 3.1.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/AGENTS.md +36 -13
- package/CHANGELOG.md +411 -0
- package/COMPONENTS.md +951 -0
- package/GETTING_STARTED.md +159 -0
- package/README.md +51 -43
- package/SKILL.md +59 -24
- package/components.json +18 -0
- package/dist/accordion.d.ts +20 -0
- package/dist/accordion.js +5 -0
- package/dist/accordion.js.map +1 -0
- package/dist/action-diff.d.ts +26 -0
- package/dist/action-diff.js +5 -0
- package/dist/action-diff.js.map +1 -0
- package/dist/action-row.d.ts +36 -0
- package/dist/action-row.js +6 -0
- package/dist/action-row.js.map +1 -0
- package/dist/alert-inbox.d.ts +23 -0
- package/dist/alert-inbox.js +6 -0
- package/dist/alert-inbox.js.map +1 -0
- package/dist/alert.d.ts +33 -0
- package/dist/alert.js +5 -0
- package/dist/alert.js.map +1 -0
- package/dist/approval-card.d.ts +27 -0
- package/dist/approval-card.js +5 -0
- package/dist/approval-card.js.map +1 -0
- package/dist/area-chart.d.ts +10 -0
- package/dist/area-chart.js +5 -0
- package/dist/area-chart.js.map +1 -0
- package/dist/avatar.d.ts +28 -0
- package/dist/avatar.js +5 -0
- package/dist/avatar.js.map +1 -0
- package/dist/backup-status-panel.d.ts +25 -0
- package/dist/backup-status-panel.js +6 -0
- package/dist/backup-status-panel.js.map +1 -0
- package/dist/badge.d.ts +17 -0
- package/dist/badge.js +5 -0
- package/dist/badge.js.map +1 -0
- package/dist/bar-chart.d.ts +15 -0
- package/dist/bar-chart.js +5 -0
- package/dist/bar-chart.js.map +1 -0
- package/dist/bento-dashboard.d.ts +30 -0
- package/dist/bento-dashboard.js +10 -0
- package/dist/bento-dashboard.js.map +1 -0
- package/dist/breadcrumb.d.ts +16 -0
- package/dist/breadcrumb.js +5 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button.d.ts +29 -0
- package/dist/button.js +5 -0
- package/dist/button.js.map +1 -0
- package/dist/card.d.ts +10 -0
- package/dist/card.js +5 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.d.ts +9 -0
- package/dist/checkbox.js +5 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-2QWKOCWF.js +79 -0
- package/dist/chunk-2QWKOCWF.js.map +1 -0
- package/dist/chunk-3LTW224O.js +53 -0
- package/dist/chunk-3LTW224O.js.map +1 -0
- package/dist/chunk-3XTZPDNV.js +94 -0
- package/dist/chunk-3XTZPDNV.js.map +1 -0
- package/dist/chunk-435JHF7G.js +65 -0
- package/dist/chunk-435JHF7G.js.map +1 -0
- package/dist/chunk-4PA2ACNF.js +52 -0
- package/dist/chunk-4PA2ACNF.js.map +1 -0
- package/dist/chunk-5GWHUJ5D.js +29 -0
- package/dist/chunk-5GWHUJ5D.js.map +1 -0
- package/dist/chunk-6FUKJD3W.js +123 -0
- package/dist/chunk-6FUKJD3W.js.map +1 -0
- package/dist/chunk-6IS2AYYG.js +106 -0
- package/dist/chunk-6IS2AYYG.js.map +1 -0
- package/dist/chunk-6PZKU6ZL.js +78 -0
- package/dist/chunk-6PZKU6ZL.js.map +1 -0
- package/dist/chunk-6SKTH45H.js +75 -0
- package/dist/chunk-6SKTH45H.js.map +1 -0
- package/dist/chunk-6UXW5YUC.js +77 -0
- package/dist/chunk-6UXW5YUC.js.map +1 -0
- package/dist/chunk-7EP2T3OW.js +52 -0
- package/dist/chunk-7EP2T3OW.js.map +1 -0
- package/dist/chunk-7J5QXUQN.js +38 -0
- package/dist/chunk-7J5QXUQN.js.map +1 -0
- package/dist/chunk-A6L5C3IJ.js +47 -0
- package/dist/chunk-A6L5C3IJ.js.map +1 -0
- package/dist/chunk-ADE22JSR.js +54 -0
- package/dist/chunk-ADE22JSR.js.map +1 -0
- package/dist/chunk-ANW6J6PV.js +42 -0
- package/dist/chunk-ANW6J6PV.js.map +1 -0
- package/dist/chunk-APFFKNPS.js +80 -0
- package/dist/chunk-APFFKNPS.js.map +1 -0
- package/dist/chunk-AQT3FZRQ.js +23 -0
- package/dist/chunk-AQT3FZRQ.js.map +1 -0
- package/dist/chunk-AZADSX4Z.js +85 -0
- package/dist/chunk-AZADSX4Z.js.map +1 -0
- package/dist/chunk-BPCH5LJ3.js +36 -0
- package/dist/chunk-BPCH5LJ3.js.map +1 -0
- package/dist/chunk-CDI7353B.js +40 -0
- package/dist/chunk-CDI7353B.js.map +1 -0
- package/dist/chunk-CKNWXYMA.js +53 -0
- package/dist/chunk-CKNWXYMA.js.map +1 -0
- package/dist/chunk-DNJI65VQ.js +22 -0
- package/dist/chunk-DNJI65VQ.js.map +1 -0
- package/dist/chunk-DOUDJU4P.js +63 -0
- package/dist/chunk-DOUDJU4P.js.map +1 -0
- package/dist/chunk-DRCMGIQ6.js +64 -0
- package/dist/chunk-DRCMGIQ6.js.map +1 -0
- package/dist/chunk-DZOBXK2S.js +28 -0
- package/dist/chunk-DZOBXK2S.js.map +1 -0
- package/dist/chunk-EN4OJCEF.js +54 -0
- package/dist/chunk-EN4OJCEF.js.map +1 -0
- package/dist/chunk-EVHZFYWX.js +33 -0
- package/dist/chunk-EVHZFYWX.js.map +1 -0
- package/dist/chunk-G2VKWNZA.js +53 -0
- package/dist/chunk-G2VKWNZA.js.map +1 -0
- package/dist/chunk-GTM2DE4C.js +156 -0
- package/dist/chunk-GTM2DE4C.js.map +1 -0
- package/dist/chunk-H3ZVGTJM.js +165 -0
- package/dist/chunk-H3ZVGTJM.js.map +1 -0
- package/dist/chunk-HWAWUEHC.js +28 -0
- package/dist/chunk-HWAWUEHC.js.map +1 -0
- package/dist/chunk-HWJVRTWO.js +36 -0
- package/dist/chunk-HWJVRTWO.js.map +1 -0
- package/dist/chunk-ILADNTUB.js +77 -0
- package/dist/chunk-ILADNTUB.js.map +1 -0
- package/dist/chunk-IUPVQWO5.js +31 -0
- package/dist/chunk-IUPVQWO5.js.map +1 -0
- package/dist/chunk-JFOW2DI5.js +43 -0
- package/dist/chunk-JFOW2DI5.js.map +1 -0
- package/dist/chunk-JRFSUVSO.js +66 -0
- package/dist/chunk-JRFSUVSO.js.map +1 -0
- package/dist/chunk-KI6OTVID.js +91 -0
- package/dist/chunk-KI6OTVID.js.map +1 -0
- package/dist/chunk-LUM2YJBH.js +73 -0
- package/dist/chunk-LUM2YJBH.js.map +1 -0
- package/dist/chunk-NHPISZWS.js +71 -0
- package/dist/chunk-NHPISZWS.js.map +1 -0
- package/dist/chunk-NOLWJJHT.js +52 -0
- package/dist/chunk-NOLWJJHT.js.map +1 -0
- package/dist/chunk-NPVINX3Q.js +20 -0
- package/dist/chunk-NPVINX3Q.js.map +1 -0
- package/dist/chunk-NSMU66ZX.js +47 -0
- package/dist/chunk-NSMU66ZX.js.map +1 -0
- package/dist/chunk-O5SWPHUQ.js +79 -0
- package/dist/chunk-O5SWPHUQ.js.map +1 -0
- package/dist/chunk-OGVSZ7NV.js +53 -0
- package/dist/chunk-OGVSZ7NV.js.map +1 -0
- package/dist/chunk-OLHMMFQ7.js +43 -0
- package/dist/chunk-OLHMMFQ7.js.map +1 -0
- package/dist/chunk-ONMTHBZ4.js +54 -0
- package/dist/chunk-ONMTHBZ4.js.map +1 -0
- package/dist/chunk-OVSIOZHJ.js +56 -0
- package/dist/chunk-OVSIOZHJ.js.map +1 -0
- package/dist/chunk-Q54CVE3W.js +154 -0
- package/dist/chunk-Q54CVE3W.js.map +1 -0
- package/dist/chunk-QEHTPQHL.js +35 -0
- package/dist/chunk-QEHTPQHL.js.map +1 -0
- package/dist/chunk-QEIEWGHA.js +62 -0
- package/dist/chunk-QEIEWGHA.js.map +1 -0
- package/dist/chunk-QQHBEACI.js +88 -0
- package/dist/chunk-QQHBEACI.js.map +1 -0
- package/dist/chunk-RJTDQOT2.js +73 -0
- package/dist/chunk-RJTDQOT2.js.map +1 -0
- package/dist/chunk-RQ3RXKAZ.js +203 -0
- package/dist/chunk-RQ3RXKAZ.js.map +1 -0
- package/dist/chunk-RZK2S2OO.js +126 -0
- package/dist/chunk-RZK2S2OO.js.map +1 -0
- package/dist/chunk-SAP7JSSO.js +106 -0
- package/dist/chunk-SAP7JSSO.js.map +1 -0
- package/dist/chunk-T3TQPOVM.js +79 -0
- package/dist/chunk-T3TQPOVM.js.map +1 -0
- package/dist/chunk-T3UQ7G4T.js +58 -0
- package/dist/chunk-T3UQ7G4T.js.map +1 -0
- package/dist/chunk-T56TTOI6.js +53 -0
- package/dist/chunk-T56TTOI6.js.map +1 -0
- package/dist/chunk-T7EFDE2L.js +36 -0
- package/dist/chunk-T7EFDE2L.js.map +1 -0
- package/dist/chunk-VFS3V3VY.js +91 -0
- package/dist/chunk-VFS3V3VY.js.map +1 -0
- package/dist/chunk-VOARBYVQ.js +44 -0
- package/dist/chunk-VOARBYVQ.js.map +1 -0
- package/dist/chunk-WDANALHD.js +95 -0
- package/dist/chunk-WDANALHD.js.map +1 -0
- package/dist/chunk-WSQNPRGN.js +12 -0
- package/dist/chunk-WSQNPRGN.js.map +1 -0
- package/dist/chunk-YPP7QHYT.js +393 -0
- package/dist/chunk-YPP7QHYT.js.map +1 -0
- package/dist/chunk-YTU7BRDW.js +72 -0
- package/dist/chunk-YTU7BRDW.js.map +1 -0
- package/dist/chunk-YYWODLER.js +111 -0
- package/dist/chunk-YYWODLER.js.map +1 -0
- package/dist/chunk-ZOXO3G3I.js +50 -0
- package/dist/chunk-ZOXO3G3I.js.map +1 -0
- package/dist/chunk-ZTFOR3AN.js +79 -0
- package/dist/chunk-ZTFOR3AN.js.map +1 -0
- package/dist/code-block.d.ts +14 -0
- package/dist/code-block.js +5 -0
- package/dist/code-block.js.map +1 -0
- package/dist/combobox.d.ts +26 -0
- package/dist/combobox.js +5 -0
- package/dist/combobox.js.map +1 -0
- package/dist/command-menu.d.ts +52 -0
- package/dist/command-menu.js +7 -0
- package/dist/command-menu.js.map +1 -0
- package/dist/container.d.ts +9 -0
- package/dist/container.js +5 -0
- package/dist/container.js.map +1 -0
- package/dist/cta-band.d.ts +12 -0
- package/dist/cta-band.js +5 -0
- package/dist/cta-band.js.map +1 -0
- package/dist/data-table.d.ts +58 -0
- package/dist/data-table.js +12 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +20 -0
- package/dist/date-picker.js +5 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/dialog.d.ts +21 -0
- package/dist/dialog.js +5 -0
- package/dist/dialog.js.map +1 -0
- package/dist/divider.d.ts +12 -0
- package/dist/divider.js +5 -0
- package/dist/divider.js.map +1 -0
- package/dist/docker-stack-card.d.ts +21 -0
- package/dist/docker-stack-card.js +6 -0
- package/dist/docker-stack-card.js.map +1 -0
- package/dist/donut.d.ts +15 -0
- package/dist/donut.js +5 -0
- package/dist/donut.js.map +1 -0
- package/dist/dropdown-menu.d.ts +15 -0
- package/dist/dropdown-menu.js +5 -0
- package/dist/dropdown-menu.js.map +1 -0
- package/dist/empty.d.ts +12 -0
- package/dist/empty.js +5 -0
- package/dist/empty.js.map +1 -0
- package/dist/feature-card.d.ts +11 -0
- package/dist/feature-card.js +6 -0
- package/dist/feature-card.js.map +1 -0
- package/dist/file-upload.d.ts +20 -0
- package/dist/file-upload.js +5 -0
- package/dist/file-upload.js.map +1 -0
- package/dist/footer.d.ts +35 -0
- package/dist/footer.js +6 -0
- package/dist/footer.js.map +1 -0
- package/dist/form-row.d.ts +19 -0
- package/dist/form-row.js +5 -0
- package/dist/form-row.js.map +1 -0
- package/dist/glow-card.d.ts +14 -0
- package/dist/glow-card.js +5 -0
- package/dist/glow-card.js.map +1 -0
- package/dist/hero-block.d.ts +16 -0
- package/dist/hero-block.js +7 -0
- package/dist/hero-block.js.map +1 -0
- package/dist/host-card.d.ts +27 -0
- package/dist/host-card.js +6 -0
- package/dist/host-card.js.map +1 -0
- package/dist/incident-card.d.ts +23 -0
- package/dist/incident-card.js +5 -0
- package/dist/incident-card.js.map +1 -0
- package/dist/index.d.ts +77 -960
- package/dist/index.js +69 -3812
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +10 -0
- package/dist/input.js +5 -0
- package/dist/input.js.map +1 -0
- package/dist/kbd.d.ts +24 -0
- package/dist/kbd.js +5 -0
- package/dist/kbd.js.map +1 -0
- package/dist/log-viewer.d.ts +35 -0
- package/dist/log-viewer.js +5 -0
- package/dist/log-viewer.js.map +1 -0
- package/dist/meter.d.ts +23 -0
- package/dist/meter.js +5 -0
- package/dist/meter.js.map +1 -0
- package/dist/monogram.d.ts +20 -0
- package/dist/monogram.js +5 -0
- package/dist/monogram.js.map +1 -0
- package/dist/noir-glow-background.d.ts +56 -0
- package/dist/noir-glow-background.js +4 -0
- package/dist/noir-glow-background.js.map +1 -0
- package/dist/pagination.d.ts +16 -0
- package/dist/pagination.js +5 -0
- package/dist/pagination.js.map +1 -0
- package/dist/panel.d.ts +12 -0
- package/dist/panel.js +5 -0
- package/dist/panel.js.map +1 -0
- package/dist/password-input.d.ts +10 -0
- package/dist/password-input.js +5 -0
- package/dist/password-input.js.map +1 -0
- package/dist/pill.d.ts +17 -0
- package/dist/pill.js +5 -0
- package/dist/pill.js.map +1 -0
- package/dist/pricing-card.d.ts +20 -0
- package/dist/pricing-card.js +6 -0
- package/dist/pricing-card.js.map +1 -0
- package/dist/progress.d.ts +6 -0
- package/dist/progress.js +5 -0
- package/dist/progress.js.map +1 -0
- package/dist/radio-group.d.ts +18 -0
- package/dist/radio-group.js +5 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/rollback-plan.d.ts +23 -0
- package/dist/rollback-plan.js +5 -0
- package/dist/rollback-plan.js.map +1 -0
- package/dist/segmented.d.ts +17 -0
- package/dist/segmented.js +5 -0
- package/dist/segmented.js.map +1 -0
- package/dist/select.d.ts +18 -0
- package/dist/select.js +5 -0
- package/dist/select.js.map +1 -0
- package/dist/service-health-card.d.ts +21 -0
- package/dist/service-health-card.js +6 -0
- package/dist/service-health-card.js.map +1 -0
- package/dist/sheet.d.ts +25 -0
- package/dist/sheet.js +5 -0
- package/dist/sheet.js.map +1 -0
- package/dist/skeleton.d.ts +13 -0
- package/dist/skeleton.js +5 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/slider.d.ts +12 -0
- package/dist/slider.js +5 -0
- package/dist/slider.js.map +1 -0
- package/dist/sparkline.d.ts +16 -0
- package/dist/sparkline.js +5 -0
- package/dist/sparkline.js.map +1 -0
- package/dist/stat-card.d.ts +15 -0
- package/dist/stat-card.js +5 -0
- package/dist/stat-card.js.map +1 -0
- package/dist/status-dot.d.ts +13 -0
- package/dist/status-dot.js +5 -0
- package/dist/status-dot.js.map +1 -0
- package/dist/stepper.d.ts +16 -0
- package/dist/stepper.js +5 -0
- package/dist/stepper.js.map +1 -0
- package/dist/switch.d.ts +9 -0
- package/dist/switch.js +5 -0
- package/dist/switch.js.map +1 -0
- package/dist/tabs.d.ts +9 -0
- package/dist/tabs.js +5 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tag-input.d.ts +20 -0
- package/dist/tag-input.js +5 -0
- package/dist/tag-input.js.map +1 -0
- package/dist/textarea.d.ts +10 -0
- package/dist/textarea.js +5 -0
- package/dist/textarea.js.map +1 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.js +5 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toaster.d.ts +10 -0
- package/dist/toaster.js +4 -0
- package/dist/toaster.js.map +1 -0
- package/dist/tooltip.d.ts +12 -0
- package/dist/tooltip.js +5 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -0
- package/globals-layers.css +1019 -0
- package/globals-v3.css +17 -0
- package/globals-v4.css +2 -0
- package/globals.css +12 -939
- package/package.json +85 -17
- package/registry.json +936 -0
- package/tailwind.css +9 -0
- package/tokens.css +20 -0
- package/tollerud-avatar-full.png +0 -0
- package/dist/index.cjs +0 -3938
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -960
- /package/{tia-full-figure.svg → tollerud-avatar-full.svg} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { lazy, Suspense } from 'react';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// components/NoirGlowBackground.tsx
|
|
6
|
+
var GrainGradient = lazy(
|
|
7
|
+
() => import('@paper-design/shaders-react').then((module) => ({
|
|
8
|
+
default: module.GrainGradient
|
|
9
|
+
}))
|
|
10
|
+
);
|
|
11
|
+
var intensityMap = {
|
|
12
|
+
subtle: 0.24,
|
|
13
|
+
medium: 0.45,
|
|
14
|
+
loud: 0.68
|
|
15
|
+
};
|
|
16
|
+
var speedMap = {
|
|
17
|
+
still: 0,
|
|
18
|
+
slow: 0.45,
|
|
19
|
+
medium: 1,
|
|
20
|
+
fast: 1.8
|
|
21
|
+
};
|
|
22
|
+
var grainMap = {
|
|
23
|
+
none: 0,
|
|
24
|
+
soft: 0.12,
|
|
25
|
+
high: 0.28
|
|
26
|
+
};
|
|
27
|
+
function cx(...classes) {
|
|
28
|
+
return classes.filter(Boolean).join(" ");
|
|
29
|
+
}
|
|
30
|
+
function CssFallback({ preserveCenter = true, noiseOverlay = true }) {
|
|
31
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
32
|
+
/* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-bg", "aria-hidden": "true" }),
|
|
33
|
+
preserveCenter && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-vignette", "aria-hidden": "true" }),
|
|
34
|
+
noiseOverlay && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-noise", "aria-hidden": "true" })
|
|
35
|
+
] });
|
|
36
|
+
}
|
|
37
|
+
function NoirGlowBackground({
|
|
38
|
+
className,
|
|
39
|
+
style,
|
|
40
|
+
shape = "corners",
|
|
41
|
+
intensity = "medium",
|
|
42
|
+
speed = "medium",
|
|
43
|
+
grain = "none",
|
|
44
|
+
softness = 0.76,
|
|
45
|
+
colorBack = "hsl(0, 0%, 0%)",
|
|
46
|
+
colors = ["hsl(54, 85%, 66%)", "hsl(56, 100%, 80%)", "hsl(56, 100%, 50%)"],
|
|
47
|
+
preserveCenter = false,
|
|
48
|
+
noiseOverlay = false,
|
|
49
|
+
forceCssFallback = false,
|
|
50
|
+
inert = true,
|
|
51
|
+
offsetX = 0,
|
|
52
|
+
offsetY = 0,
|
|
53
|
+
scale = 1
|
|
54
|
+
}) {
|
|
55
|
+
const wrapperClassName = cx(
|
|
56
|
+
"tollerud-noir-glow-root absolute inset-0 z-0 overflow-hidden",
|
|
57
|
+
inert && "pointer-events-none",
|
|
58
|
+
className
|
|
59
|
+
);
|
|
60
|
+
if (forceCssFallback) {
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: wrapperClassName, style, "aria-hidden": "true", children: /* @__PURE__ */ jsx(CssFallback, { preserveCenter, noiseOverlay }) });
|
|
62
|
+
}
|
|
63
|
+
return /* @__PURE__ */ jsxs("div", { className: wrapperClassName, style, "aria-hidden": "true", children: [
|
|
64
|
+
/* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CssFallback, { preserveCenter, noiseOverlay }), children: /* @__PURE__ */ jsx(
|
|
65
|
+
GrainGradient,
|
|
66
|
+
{
|
|
67
|
+
style: { height: "100%", width: "100%" },
|
|
68
|
+
colorBack,
|
|
69
|
+
softness,
|
|
70
|
+
intensity: intensityMap[intensity],
|
|
71
|
+
noise: grainMap[grain],
|
|
72
|
+
shape,
|
|
73
|
+
offsetX,
|
|
74
|
+
offsetY,
|
|
75
|
+
scale,
|
|
76
|
+
rotation: 0,
|
|
77
|
+
speed: speedMap[speed],
|
|
78
|
+
colors
|
|
79
|
+
}
|
|
80
|
+
) }),
|
|
81
|
+
preserveCenter && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-glow-vignette", "aria-hidden": "true" }),
|
|
82
|
+
noiseOverlay && /* @__PURE__ */ jsx("div", { className: "tollerud-noir-noise", "aria-hidden": "true" })
|
|
83
|
+
] });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { NoirGlowBackground };
|
|
87
|
+
//# sourceMappingURL=chunk-QQHBEACI.js.map
|
|
88
|
+
//# sourceMappingURL=chunk-QQHBEACI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../components/NoirGlowBackground.tsx"],"names":[],"mappings":"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","file":"chunk-QQHBEACI.js","sourcesContent":["\"use client\"\n\nimport { lazy, Suspense, type CSSProperties } from \"react\"\n\nconst GrainGradient = lazy(() =>\n import(\"@paper-design/shaders-react\").then((module) => ({\n default: module.GrainGradient,\n }))\n)\n\ntype ShaderShape = \"corners\" | \"wave\" | \"dots\" | \"truchet\" | \"ripple\" | \"blob\" | \"sphere\"\ntype Intensity = \"subtle\" | \"medium\" | \"loud\"\ntype Speed = \"still\" | \"slow\" | \"medium\" | \"fast\"\ntype Grain = \"none\" | \"soft\" | \"high\"\n\nexport interface NoirGlowBackgroundProps {\n /** Extra class names for the outer positioning wrapper. */\n className?: string\n /** Inline style for the outer positioning wrapper. */\n style?: CSSProperties\n /** Canvas/WebGL shape. `corners` matches Tollerud.no. */\n shape?: ShaderShape\n /** Visual strength of the yellow glow. */\n intensity?: Intensity\n /** Ambient animation speed. */\n speed?: Speed\n /** Shader grain/noise amount. */\n grain?: Grain\n /** Softness/falloff of the glow blooms. */\n softness?: number\n /** Background color behind the glow. */\n colorBack?: string\n /** Glow colors. Defaults to the Tollerud/Tia yellow ramp. */\n colors?: string[]\n /** Whether to render a readable center vignette on top of the shader. */\n preserveCenter?: boolean\n /** Add the grain/noise CSS overlay. */\n noiseOverlay?: boolean\n /** Prefer the CSS fallback even if shaders are available. Useful for docs/static contexts. */\n forceCssFallback?: boolean\n /** Disable pointer events so content above remains clickable. */\n inert?: boolean\n /** Horizontal shader offset (-1 to 1). Use for edge-biased layouts. */\n offsetX?: number\n /** Vertical shader offset (-1 to 1). */\n offsetY?: number\n /** Shader scale multiplier. Values > 1 push glow toward edges. */\n scale?: number\n}\n\nconst intensityMap: Record<Intensity, number> = {\n subtle: 0.24,\n medium: 0.45,\n loud: 0.68,\n}\n\nconst speedMap: Record<Speed, number> = {\n still: 0,\n slow: 0.45,\n medium: 1,\n fast: 1.8,\n}\n\nconst grainMap: Record<Grain, number> = {\n none: 0,\n soft: 0.12,\n high: 0.28,\n}\n\nfunction cx(...classes: Array<string | false | null | undefined>) {\n return classes.filter(Boolean).join(\" \")\n}\n\nfunction CssFallback({ preserveCenter = true, noiseOverlay = true }: Pick<NoirGlowBackgroundProps, \"preserveCenter\" | \"noiseOverlay\">) {\n return (\n <>\n <div className=\"tollerud-noir-glow-bg\" aria-hidden=\"true\" />\n {preserveCenter && <div className=\"tollerud-noir-glow-vignette\" aria-hidden=\"true\" />}\n {noiseOverlay && <div className=\"tollerud-noir-noise\" aria-hidden=\"true\" />}\n </>\n )\n}\n\n/**\n * NoirGlowBackground\n *\n * Tia/Tollerud signature background primitive. The defaults replicate\n * MathiasOki/tollerud-landing's `GradientBackground` component.\n *\n * Install dependency in consuming Next.js apps:\n * npm install @paper-design/shaders-react\n *\n * The CSS fallback classes live in `globals.css` and are used during Suspense,\n * reduced-motion contexts, or when `forceCssFallback` is true.\n */\nexport function NoirGlowBackground({\n className,\n style,\n shape = \"corners\",\n intensity = \"medium\",\n speed = \"medium\",\n grain = \"none\",\n softness = 0.76,\n colorBack = \"hsl(0, 0%, 0%)\",\n colors = [\"hsl(54, 85%, 66%)\", \"hsl(56, 100%, 80%)\", \"hsl(56, 100%, 50%)\"],\n preserveCenter = false,\n noiseOverlay = false,\n forceCssFallback = false,\n inert = true,\n offsetX = 0,\n offsetY = 0,\n scale = 1,\n}: NoirGlowBackgroundProps) {\n const wrapperClassName = cx(\n \"tollerud-noir-glow-root absolute inset-0 z-0 overflow-hidden\",\n inert && \"pointer-events-none\",\n className\n )\n\n if (forceCssFallback) {\n return (\n <div className={wrapperClassName} style={style} aria-hidden=\"true\">\n <CssFallback preserveCenter={preserveCenter} noiseOverlay={noiseOverlay} />\n </div>\n )\n }\n\n return (\n <div className={wrapperClassName} style={style} aria-hidden=\"true\">\n <Suspense fallback={<CssFallback preserveCenter={preserveCenter} noiseOverlay={noiseOverlay} />}>\n <GrainGradient\n style={{ height: \"100%\", width: \"100%\" }}\n colorBack={colorBack}\n softness={softness}\n intensity={intensityMap[intensity]}\n noise={grainMap[grain]}\n shape={shape}\n offsetX={offsetX}\n offsetY={offsetY}\n scale={scale}\n rotation={0}\n speed={speedMap[speed]}\n colors={colors}\n />\n </Suspense>\n {preserveCenter && <div className=\"tollerud-noir-glow-vignette\" aria-hidden=\"true\" />}\n {noiseOverlay && <div className=\"tollerud-noir-noise\" aria-hidden=\"true\" />}\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { cn } from './chunk-WSQNPRGN.js';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { ChevronLeft, MoreHorizontal, ChevronRight } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function getPageRange(page, pageCount, siblingCount) {
|
|
8
|
+
const totalVisible = siblingCount * 2 + 5;
|
|
9
|
+
if (pageCount <= totalVisible) {
|
|
10
|
+
return Array.from({ length: pageCount }, (_, i) => i + 1);
|
|
11
|
+
}
|
|
12
|
+
const left = Math.max(page - siblingCount, 1);
|
|
13
|
+
const right = Math.min(page + siblingCount, pageCount);
|
|
14
|
+
const range = [1];
|
|
15
|
+
if (left > 2) range.push("ellipsis");
|
|
16
|
+
for (let p = left === 1 ? 2 : left; p <= (right === pageCount ? pageCount - 1 : right); p++) {
|
|
17
|
+
range.push(p);
|
|
18
|
+
}
|
|
19
|
+
if (right < pageCount - 1) range.push("ellipsis");
|
|
20
|
+
if (pageCount > 1) range.push(pageCount);
|
|
21
|
+
return range;
|
|
22
|
+
}
|
|
23
|
+
var navButtonClasses = "inline-flex h-8 min-w-8 items-center justify-center rounded px-2 text-sm transition-colors duration-[150ms] disabled:opacity-40 disabled:pointer-events-none";
|
|
24
|
+
var Pagination = forwardRef(
|
|
25
|
+
({ className, page, pageCount, onChange, siblingCount = 1, ...props }, ref) => {
|
|
26
|
+
const range = getPageRange(page, pageCount, siblingCount);
|
|
27
|
+
return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": "Pagination", className: cn("flex items-center gap-1", className), ...props, children: [
|
|
28
|
+
/* @__PURE__ */ jsx(
|
|
29
|
+
"button",
|
|
30
|
+
{
|
|
31
|
+
type: "button",
|
|
32
|
+
"aria-label": "Previous page",
|
|
33
|
+
disabled: page <= 1,
|
|
34
|
+
onClick: () => onChange(page - 1),
|
|
35
|
+
className: cn(navButtonClasses, "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"),
|
|
36
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
range.map(
|
|
40
|
+
(item, i) => item === "ellipsis" ? /* @__PURE__ */ jsx("span", { className: "inline-flex h-8 w-8 items-center justify-center text-tollerud-text-muted", children: /* @__PURE__ */ jsx(MoreHorizontal, { size: 16 }) }, `e-${i}`) : /* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
type: "button",
|
|
44
|
+
"aria-current": item === page ? "page" : void 0,
|
|
45
|
+
onClick: () => onChange(item),
|
|
46
|
+
className: cn(
|
|
47
|
+
navButtonClasses,
|
|
48
|
+
item === page ? "bg-tollerud-yellow text-tollerud-noir-black font-medium" : "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"
|
|
49
|
+
),
|
|
50
|
+
children: item
|
|
51
|
+
},
|
|
52
|
+
item
|
|
53
|
+
)
|
|
54
|
+
),
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
"button",
|
|
57
|
+
{
|
|
58
|
+
type: "button",
|
|
59
|
+
"aria-label": "Next page",
|
|
60
|
+
disabled: page >= pageCount,
|
|
61
|
+
onClick: () => onChange(page + 1),
|
|
62
|
+
className: cn(navButtonClasses, "text-tollerud-text-secondary hover:bg-tollerud-surface-hover"),
|
|
63
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { size: 16 })
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
Pagination.displayName = "Pagination";
|
|
70
|
+
|
|
71
|
+
export { Pagination };
|
|
72
|
+
//# sourceMappingURL=chunk-RJTDQOT2.js.map
|
|
73
|
+
//# sourceMappingURL=chunk-RJTDQOT2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../components/Pagination.tsx"],"names":[],"mappings":"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","file":"chunk-RJTDQOT2.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** Current 1-indexed page */\n page: number\n /** Total number of pages */\n pageCount: number\n /** Called with the next page number when the user navigates */\n onChange: (page: number) => void\n /** Number of sibling pages to show on either side of the current page */\n siblingCount?: number\n}\n\nfunction getPageRange(page: number, pageCount: number, siblingCount: number): (number | 'ellipsis')[] {\n const totalVisible = siblingCount * 2 + 5\n if (pageCount <= totalVisible) {\n return Array.from({ length: pageCount }, (_, i) => i + 1)\n }\n\n const left = Math.max(page - siblingCount, 1)\n const right = Math.min(page + siblingCount, pageCount)\n\n const range: (number | 'ellipsis')[] = [1]\n if (left > 2) range.push('ellipsis')\n for (let p = left === 1 ? 2 : left; p <= (right === pageCount ? pageCount - 1 : right); p++) {\n range.push(p)\n }\n if (right < pageCount - 1) range.push('ellipsis')\n if (pageCount > 1) range.push(pageCount)\n return range\n}\n\nconst navButtonClasses =\n 'inline-flex h-8 min-w-8 items-center justify-center rounded px-2 text-sm transition-colors duration-[150ms] disabled:opacity-40 disabled:pointer-events-none'\n\nconst Pagination = forwardRef<HTMLElement, PaginationProps>(\n ({ className, page, pageCount, onChange, siblingCount = 1, ...props }, ref) => {\n const range = getPageRange(page, pageCount, siblingCount)\n\n return (\n <nav ref={ref} aria-label=\"Pagination\" className={cn('flex items-center gap-1', className)} {...props}>\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n disabled={page <= 1}\n onClick={() => onChange(page - 1)}\n className={cn(navButtonClasses, 'text-tollerud-text-secondary hover:bg-tollerud-surface-hover')}\n >\n <ChevronLeft size={16} />\n </button>\n\n {range.map((item, i) =>\n item === 'ellipsis' ? (\n <span key={`e-${i}`} className=\"inline-flex h-8 w-8 items-center justify-center text-tollerud-text-muted\">\n <MoreHorizontal size={16} />\n </span>\n ) : (\n <button\n key={item}\n type=\"button\"\n aria-current={item === page ? 'page' : undefined}\n onClick={() => onChange(item)}\n className={cn(\n navButtonClasses,\n item === page\n ? 'bg-tollerud-yellow text-tollerud-noir-black font-medium'\n : 'text-tollerud-text-secondary hover:bg-tollerud-surface-hover'\n )}\n >\n {item}\n </button>\n )\n )}\n\n <button\n type=\"button\"\n aria-label=\"Next page\"\n disabled={page >= pageCount}\n onClick={() => onChange(page + 1)}\n className={cn(navButtonClasses, 'text-tollerud-text-secondary hover:bg-tollerud-surface-hover')}\n >\n <ChevronRight size={16} />\n </button>\n </nav>\n )\n }\n)\nPagination.displayName = 'Pagination'\n\nexport { Pagination }\n"]}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { ActionRow } from './chunk-OGVSZ7NV.js';
|
|
3
|
+
import { cn } from './chunk-WSQNPRGN.js';
|
|
4
|
+
import { forwardRef, useState, useRef, useCallback, useEffect } from 'react';
|
|
5
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var CommandMenu = forwardRef(
|
|
8
|
+
({
|
|
9
|
+
open,
|
|
10
|
+
onOpenChange,
|
|
11
|
+
groups,
|
|
12
|
+
placeholder = "Type a command\u2026",
|
|
13
|
+
emptyMessage = "No matching commands",
|
|
14
|
+
className,
|
|
15
|
+
filter: customFilter,
|
|
16
|
+
onAction
|
|
17
|
+
}, ref) => {
|
|
18
|
+
const [query, setQuery] = useState("");
|
|
19
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
20
|
+
const inputRef = useRef(null);
|
|
21
|
+
const listRef = useRef(null);
|
|
22
|
+
const flatItems = groups.flatMap((g) => g.items);
|
|
23
|
+
const handleKeyDown = useCallback(
|
|
24
|
+
(e) => {
|
|
25
|
+
if (e.key === "Escape") {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
onOpenChange(false);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (e.key === "ArrowDown") {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
setSelectedIndex(
|
|
33
|
+
(prev) => prev < flatItems.length - 1 ? prev + 1 : 0
|
|
34
|
+
);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (e.key === "ArrowUp") {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
setSelectedIndex(
|
|
40
|
+
(prev) => prev > 0 ? prev - 1 : flatItems.length - 1
|
|
41
|
+
);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (e.key === "Enter") {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
const item = flatItems[selectedIndex];
|
|
47
|
+
if (item && !item.disabled) {
|
|
48
|
+
item.onSelect?.();
|
|
49
|
+
onAction?.(item);
|
|
50
|
+
onOpenChange(false);
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
[flatItems, selectedIndex, onOpenChange, onAction]
|
|
56
|
+
);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
function handleGlobalKey(e) {
|
|
59
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
onOpenChange(!open);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
document.addEventListener("keydown", handleGlobalKey);
|
|
65
|
+
return () => document.removeEventListener("keydown", handleGlobalKey);
|
|
66
|
+
}, [open, onOpenChange]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (open) {
|
|
69
|
+
setQuery("");
|
|
70
|
+
setSelectedIndex(0);
|
|
71
|
+
const timer = setTimeout(() => inputRef.current?.focus(), 50);
|
|
72
|
+
return () => clearTimeout(timer);
|
|
73
|
+
}
|
|
74
|
+
}, [open]);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (open) {
|
|
77
|
+
document.body.style.overflow = "hidden";
|
|
78
|
+
} else {
|
|
79
|
+
document.body.style.overflow = "";
|
|
80
|
+
}
|
|
81
|
+
return () => {
|
|
82
|
+
document.body.style.overflow = "";
|
|
83
|
+
};
|
|
84
|
+
}, [open]);
|
|
85
|
+
const filteredGroups = customFilter ? customFilter(query, groups) : query.trim() ? groups.map((g) => ({
|
|
86
|
+
...g,
|
|
87
|
+
items: g.items.filter(
|
|
88
|
+
(item) => item.label.toLowerCase().includes(query.toLowerCase()) || item.description?.toLowerCase().includes(query.toLowerCase()) || item.group?.toLowerCase().includes(query.toLowerCase())
|
|
89
|
+
)
|
|
90
|
+
})).filter((g) => g.items.length > 0) : groups;
|
|
91
|
+
const currentFlat = filteredGroups.flatMap((g) => g.items);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (selectedIndex >= currentFlat.length) {
|
|
94
|
+
setSelectedIndex(0);
|
|
95
|
+
}
|
|
96
|
+
}, [currentFlat.length, selectedIndex]);
|
|
97
|
+
if (!open) return null;
|
|
98
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
/* @__PURE__ */ jsx(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
className: "tollerud-cmd-overlay",
|
|
103
|
+
onClick: () => onOpenChange(false),
|
|
104
|
+
"aria-hidden": "true"
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsxs(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
ref,
|
|
111
|
+
className: cn("tollerud-cmd", className),
|
|
112
|
+
role: "dialog",
|
|
113
|
+
"aria-modal": "true",
|
|
114
|
+
"aria-label": "Command palette",
|
|
115
|
+
children: [
|
|
116
|
+
/* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__header", children: [
|
|
117
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-cmd__search-icon", children: /* @__PURE__ */ jsxs(
|
|
118
|
+
"svg",
|
|
119
|
+
{
|
|
120
|
+
width: "18",
|
|
121
|
+
height: "18",
|
|
122
|
+
viewBox: "0 0 24 24",
|
|
123
|
+
fill: "none",
|
|
124
|
+
stroke: "currentColor",
|
|
125
|
+
strokeWidth: "2",
|
|
126
|
+
strokeLinecap: "round",
|
|
127
|
+
strokeLinejoin: "round",
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
130
|
+
/* @__PURE__ */ jsx("path", { d: "m21 21-4.35-4.35" })
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
) }),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
"input",
|
|
136
|
+
{
|
|
137
|
+
ref: inputRef,
|
|
138
|
+
type: "text",
|
|
139
|
+
className: "tollerud-cmd__input",
|
|
140
|
+
placeholder,
|
|
141
|
+
value: query,
|
|
142
|
+
onChange: (e) => {
|
|
143
|
+
setQuery(e.target.value);
|
|
144
|
+
setSelectedIndex(0);
|
|
145
|
+
},
|
|
146
|
+
onKeyDown: handleKeyDown,
|
|
147
|
+
autoComplete: "off",
|
|
148
|
+
spellCheck: false
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsxs("div", { ref: listRef, className: "tollerud-cmd__list", role: "listbox", tabIndex: -1, children: [
|
|
153
|
+
filteredGroups.length === 0 && /* @__PURE__ */ jsx("div", { className: "tollerud-cmd__empty", children: emptyMessage }),
|
|
154
|
+
filteredGroups.map((group, gi) => {
|
|
155
|
+
const flatOffset = filteredGroups.slice(0, gi).reduce((acc, g) => acc + g.items.length, 0);
|
|
156
|
+
return /* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__group", children: [
|
|
157
|
+
/* @__PURE__ */ jsx("div", { className: "tollerud-cmd__group-label", children: group.label }),
|
|
158
|
+
group.items.map((item, ii) => {
|
|
159
|
+
const flatIndex = flatOffset + ii;
|
|
160
|
+
return /* @__PURE__ */ jsx(
|
|
161
|
+
ActionRow,
|
|
162
|
+
{
|
|
163
|
+
action: item,
|
|
164
|
+
highlighted: selectedIndex === flatIndex,
|
|
165
|
+
onClick: () => {
|
|
166
|
+
item.onSelect?.();
|
|
167
|
+
onAction?.(item);
|
|
168
|
+
onOpenChange(false);
|
|
169
|
+
},
|
|
170
|
+
onMouseEnter: () => setSelectedIndex(flatIndex)
|
|
171
|
+
},
|
|
172
|
+
item.id
|
|
173
|
+
);
|
|
174
|
+
})
|
|
175
|
+
] }, group.label);
|
|
176
|
+
})
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { className: "tollerud-cmd__footer", children: [
|
|
179
|
+
/* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
|
|
180
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u2191" }) }),
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u2193" }) }),
|
|
182
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "navigate" })
|
|
183
|
+
] }),
|
|
184
|
+
/* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "\u21B5" }) }),
|
|
186
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "select" })
|
|
187
|
+
] }),
|
|
188
|
+
/* @__PURE__ */ jsxs("span", { className: "tollerud-cmd__hint", children: [
|
|
189
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-kbd tollerud-kbd--sm", children: /* @__PURE__ */ jsx("span", { className: "tollerud-kbd__key", children: "Esc" }) }),
|
|
190
|
+
/* @__PURE__ */ jsx("span", { className: "tollerud-cmd__hint-text", children: "close" })
|
|
191
|
+
] })
|
|
192
|
+
] })
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
] });
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
CommandMenu.displayName = "CommandMenu";
|
|
200
|
+
|
|
201
|
+
export { CommandMenu };
|
|
202
|
+
//# sourceMappingURL=chunk-RQ3RXKAZ.js.map
|
|
203
|
+
//# sourceMappingURL=chunk-RQ3RXKAZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../components/CommandMenu.tsx"],"names":[],"mappings":"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","file":"chunk-RQ3RXKAZ.js","sourcesContent":["\"use client\"\n\nimport {\n forwardRef,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react'\nimport { cn } from '@/lib/utils'\nimport { type ActionItem, ActionRow } from './ActionRow'\n\nexport interface CommandGroup {\n /** Group label (e.g. \"Servers\", \"Actions\") */\n label: string\n /** Items in this group */\n items: ActionItem[]\n}\n\nexport interface CommandMenuProps {\n /** Whether the menu is open */\n open: boolean\n /** Called when menu should close */\n onOpenChange: (open: boolean) => void\n /** Command groups to display */\n groups: CommandGroup[]\n /** Placeholder text for the search input */\n placeholder?: string\n /** Empty state message when no results */\n emptyMessage?: string\n /** Custom class for the overlay */\n className?: string\n /** Keyboard shortcut to toggle (default: \"⌘K\") */\n toggleShortcut?: string\n /** Custom search filter override. Return filtered groups. */\n filter?: (query: string, groups: CommandGroup[]) => CommandGroup[]\n /** Callback when an action runs */\n onAction?: (action: ActionItem) => void\n}\n\n/**\n * Command palette — a Raycast-inspired global command menu.\n *\n * ```tsx\n * const [open, setOpen] = useState(false)\n *\n * <CommandMenu\n * open={open}\n * onOpenChange={setOpen}\n * groups={[\n * {\n * label: 'Servers',\n * items: [\n * { id: 'emma', label: 'Emma', icon: <Server />, onSelect: () => {} },\n * ],\n * },\n * ]}\n * />\n * ```\n */\nconst CommandMenu = forwardRef<HTMLDivElement, CommandMenuProps>(\n ({\n open,\n onOpenChange,\n groups,\n placeholder = 'Type a command…',\n emptyMessage = 'No matching commands',\n className,\n filter: customFilter,\n onAction,\n}: CommandMenuProps, ref) => {\n const [query, setQuery] = useState('')\n const [selectedIndex, setSelectedIndex] = useState(0)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n\n // Flatten items with their group indices for keyboard navigation\n const flatItems = groups.flatMap((g) => g.items)\n // Auto-close on Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n onOpenChange(false)\n return\n }\n\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setSelectedIndex((prev) =>\n prev < flatItems.length - 1 ? prev + 1 : 0\n )\n return\n }\n\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setSelectedIndex((prev) =>\n prev > 0 ? prev - 1 : flatItems.length - 1\n )\n return\n }\n\n if (e.key === 'Enter') {\n e.preventDefault()\n const item = flatItems[selectedIndex]\n if (item && !item.disabled) {\n item.onSelect?.()\n onAction?.(item)\n onOpenChange(false)\n }\n return\n }\n },\n [flatItems, selectedIndex, onOpenChange, onAction]\n )\n\n // Open toggle via ⌘K / Ctrl+K\n useEffect(() => {\n function handleGlobalKey(e: globalThis.KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault()\n onOpenChange(!open)\n }\n }\n document.addEventListener('keydown', handleGlobalKey)\n return () => document.removeEventListener('keydown', handleGlobalKey)\n }, [open, onOpenChange])\n\n // Focus input and reset state when opening\n useEffect(() => {\n if (open) {\n setQuery('')\n setSelectedIndex(0)\n // Small delay to let the animation start before focusing\n const timer = setTimeout(() => inputRef.current?.focus(), 50)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n // Lock body scroll when open\n useEffect(() => {\n if (open) {\n document.body.style.overflow = 'hidden'\n } else {\n document.body.style.overflow = ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [open])\n\n // Filter groups based on query\n const filteredGroups = customFilter\n ? customFilter(query, groups)\n : query.trim()\n ? groups\n .map((g) => ({\n ...g,\n items: g.items.filter(\n (item) =>\n item.label.toLowerCase().includes(query.toLowerCase()) ||\n item.description\n ?.toLowerCase()\n .includes(query.toLowerCase()) ||\n item.group?.toLowerCase().includes(query.toLowerCase())\n ),\n }))\n .filter((g) => g.items.length > 0)\n : groups\n\n // Re-index selection when results change\n const currentFlat = filteredGroups.flatMap((g) => g.items)\n useEffect(() => {\n if (selectedIndex >= currentFlat.length) {\n setSelectedIndex(0)\n }\n }, [currentFlat.length, selectedIndex])\n\n if (!open) return null\n\n return (\n <>\n {/* Overlay */}\n <div\n className=\"tollerud-cmd-overlay\"\n onClick={() => onOpenChange(false)}\n aria-hidden=\"true\"\n />\n\n {/* Command Menu */}\n <div\n ref={ref}\n className={cn('tollerud-cmd', className)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n >\n {/* Search Input */}\n <div className=\"tollerud-cmd__header\">\n <span className=\"tollerud-cmd__search-icon\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n </span>\n <input\n ref={inputRef}\n type=\"text\"\n className=\"tollerud-cmd__input\"\n placeholder={placeholder}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value)\n setSelectedIndex(0)\n }}\n onKeyDown={handleKeyDown}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n\n {/* Results */}\n <div ref={listRef} className=\"tollerud-cmd__list\" role=\"listbox\" tabIndex={-1}>\n {filteredGroups.length === 0 && (\n <div className=\"tollerud-cmd__empty\">{emptyMessage}</div>\n )}\n\n {filteredGroups.map((group, gi) => {\n // Calculate flat offset for this group\n const flatOffset = filteredGroups\n .slice(0, gi)\n .reduce((acc, g) => acc + g.items.length, 0)\n\n return (\n <div key={group.label} className=\"tollerud-cmd__group\">\n <div className=\"tollerud-cmd__group-label\">{group.label}</div>\n {group.items.map((item, ii) => {\n const flatIndex = flatOffset + ii\n return (\n <ActionRow\n key={item.id}\n action={item}\n highlighted={selectedIndex === flatIndex}\n onClick={() => {\n item.onSelect?.()\n onAction?.(item)\n onOpenChange(false)\n }}\n onMouseEnter={() => setSelectedIndex(flatIndex)}\n />\n )\n })}\n </div>\n )\n })}\n </div>\n\n {/* Footer hints */}\n <div className=\"tollerud-cmd__footer\">\n <span className=\"tollerud-cmd__hint\">\n <span className=\"tollerud-kbd tollerud-kbd--sm\">\n <span className=\"tollerud-kbd__key\">↑</span>\n </span>\n <span className=\"tollerud-kbd tollerud-kbd--sm\">\n <span className=\"tollerud-kbd__key\">↓</span>\n </span>\n <span className=\"tollerud-cmd__hint-text\">navigate</span>\n </span>\n <span className=\"tollerud-cmd__hint\">\n <span className=\"tollerud-kbd tollerud-kbd--sm\">\n <span className=\"tollerud-kbd__key\">↵</span>\n </span>\n <span className=\"tollerud-cmd__hint-text\">select</span>\n </span>\n <span className=\"tollerud-cmd__hint\">\n <span className=\"tollerud-kbd tollerud-kbd--sm\">\n <span className=\"tollerud-kbd__key\">Esc</span>\n </span>\n <span className=\"tollerud-cmd__hint-text\">close</span>\n </span>\n </div>\n </div>\n </>\n )\n}\n)\nCommandMenu.displayName = 'CommandMenu'\n\nexport { CommandMenu }"]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { cn } from './chunk-WSQNPRGN.js';
|
|
3
|
+
import { forwardRef, useState, useRef, useMemo, useEffect } from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var levelStyles = {
|
|
7
|
+
debug: "text-tollerud-noir-400",
|
|
8
|
+
trace: "text-tollerud-noir-300",
|
|
9
|
+
info: "text-tollerud-foreground",
|
|
10
|
+
warn: "text-tollerud-amber",
|
|
11
|
+
error: "text-tollerud-error"
|
|
12
|
+
};
|
|
13
|
+
var levelLabels = {
|
|
14
|
+
debug: "DBG",
|
|
15
|
+
trace: "TRC",
|
|
16
|
+
info: "INF",
|
|
17
|
+
warn: "WRN",
|
|
18
|
+
error: "ERR"
|
|
19
|
+
};
|
|
20
|
+
var LogViewer = forwardRef(
|
|
21
|
+
({ className, lines, maxLines = 5e3, showLineNumbers = true, showTimestamps = true, follow = true, searchable, height = "400px", loading, ...props }, ref) => {
|
|
22
|
+
const [search, setSearch] = useState("");
|
|
23
|
+
const [isFollowing, setIsFollowing] = useState(follow);
|
|
24
|
+
const scrollRef = useRef(null);
|
|
25
|
+
const displayedLines = useMemo(() => {
|
|
26
|
+
return lines.length > maxLines ? lines.slice(-maxLines) : lines;
|
|
27
|
+
}, [lines, maxLines]);
|
|
28
|
+
const filteredLines = useMemo(() => {
|
|
29
|
+
if (!search.trim()) return displayedLines;
|
|
30
|
+
return displayedLines.filter(
|
|
31
|
+
(l) => l.text.toLowerCase().includes(search.toLowerCase()) || l.source?.toLowerCase().includes(search.toLowerCase())
|
|
32
|
+
);
|
|
33
|
+
}, [displayedLines, search]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isFollowing && scrollRef.current) {
|
|
36
|
+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
37
|
+
}
|
|
38
|
+
}, [filteredLines.length, isFollowing]);
|
|
39
|
+
const handleScroll = (e) => {
|
|
40
|
+
const el = e.currentTarget;
|
|
41
|
+
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;
|
|
42
|
+
setIsFollowing(atBottom);
|
|
43
|
+
};
|
|
44
|
+
const filteredFrom = displayedLines.indexOf(filteredLines[0]);
|
|
45
|
+
return /* @__PURE__ */ jsxs(
|
|
46
|
+
"div",
|
|
47
|
+
{
|
|
48
|
+
ref,
|
|
49
|
+
className: cn(
|
|
50
|
+
"rounded-lg border border-tollerud-border bg-[var(--color-tollerud-surface-raised)] overflow-hidden tollerud-log-viewer",
|
|
51
|
+
loading && "animate-pulse",
|
|
52
|
+
className
|
|
53
|
+
),
|
|
54
|
+
...props,
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-tollerud-border bg-tollerud-noir-900", children: [
|
|
57
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-tollerud-text-muted", children: [
|
|
58
|
+
isFollowing ? /* @__PURE__ */ jsx("span", { className: "text-tollerud-yellow font-medium", children: "\u25CF Live" }) : /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-400", children: "\u25CF Paused" }),
|
|
59
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
60
|
+
filteredLines.length,
|
|
61
|
+
" lines"
|
|
62
|
+
] }),
|
|
63
|
+
lines.length > maxLines && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-amber", children: [
|
|
64
|
+
"(showing last ",
|
|
65
|
+
maxLines,
|
|
66
|
+
")"
|
|
67
|
+
] })
|
|
68
|
+
] }),
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: searchable && /* @__PURE__ */ jsx(
|
|
70
|
+
"input",
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
value: search,
|
|
74
|
+
onChange: (e) => setSearch(e.target.value),
|
|
75
|
+
placeholder: "Search logs\u2026",
|
|
76
|
+
className: cn(
|
|
77
|
+
"w-40 text-[11px] px-2 py-1 rounded bg-tollerud-noir-800",
|
|
78
|
+
"border border-tollerud-noir-600 text-tollerud-foreground",
|
|
79
|
+
"placeholder:text-tollerud-noir-400 outline-none",
|
|
80
|
+
"focus:border-tollerud-yellow/50 transition-colors"
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
) })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsxs(
|
|
86
|
+
"div",
|
|
87
|
+
{
|
|
88
|
+
ref: scrollRef,
|
|
89
|
+
onScroll: handleScroll,
|
|
90
|
+
className: "overflow-y-auto font-mono text-xs leading-relaxed p-3",
|
|
91
|
+
style: { height },
|
|
92
|
+
children: [
|
|
93
|
+
filteredLines.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-tollerud-noir-400 text-xs", children: search ? "No matching log lines" : "No log output" }),
|
|
94
|
+
filteredLines.map((line, i) => {
|
|
95
|
+
const absLineNum = filteredFrom >= 0 ? filteredFrom + i + 1 : i + 1;
|
|
96
|
+
const level = line.level ?? "info";
|
|
97
|
+
return /* @__PURE__ */ jsxs(
|
|
98
|
+
"div",
|
|
99
|
+
{
|
|
100
|
+
className: cn(
|
|
101
|
+
"flex gap-3 hover:bg-[var(--color-tollerud-surface-hover)] px-1 py-px rounded-sm",
|
|
102
|
+
levelStyles[level]
|
|
103
|
+
),
|
|
104
|
+
children: [
|
|
105
|
+
showLineNumbers && /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-500 text-right select-none w-8 flex-shrink-0", children: absLineNum }),
|
|
106
|
+
showTimestamps && line.timestamp && /* @__PURE__ */ jsx("span", { className: "text-tollerud-noir-400 flex-shrink-0 select-none", children: line.timestamp }),
|
|
107
|
+
/* @__PURE__ */ jsx("span", { className: "flex-shrink-0 w-7 text-center font-bold text-[10px] uppercase opacity-60", children: levelLabels[level] }),
|
|
108
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-pre-wrap break-all", children: line.text })
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
`${absLineNum}-${i}`
|
|
112
|
+
);
|
|
113
|
+
})
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
LogViewer.displayName = "LogViewer";
|
|
123
|
+
|
|
124
|
+
export { LogViewer };
|
|
125
|
+
//# sourceMappingURL=chunk-RZK2S2OO.js.map
|
|
126
|
+
//# sourceMappingURL=chunk-RZK2S2OO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../components/LogViewer.tsx"],"names":[],"mappings":";;;;AA6CA,IAAM,WAAA,GAAwC;AAAA,EAC5C,KAAA,EAAO,wBAAA;AAAA,EACP,KAAA,EAAO,wBAAA;AAAA,EACP,IAAA,EAAO,0BAAA;AAAA,EACP,IAAA,EAAO,qBAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,WAAA,GAAwC;AAAA,EAC5C,KAAA,EAAO,KAAA;AAAA,EACP,KAAA,EAAO,KAAA;AAAA,EACP,IAAA,EAAO,KAAA;AAAA,EACP,IAAA,EAAO,KAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAC,EAAE,SAAA,EAAW,OAAO,QAAA,GAAW,GAAA,EAAM,kBAAkB,IAAA,EAAM,cAAA,GAAiB,MAAM,MAAA,GAAS,IAAA,EAAM,YAAY,MAAA,GAAS,OAAA,EAAS,SAAS,GAAG,KAAA,IAAS,GAAA,KAAQ;AAC7J,IAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,EAAE,CAAA;AACvC,IAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,MAAM,CAAA;AACrD,IAAA,MAAM,SAAA,GAAY,OAAuB,IAAI,CAAA;AAG7C,IAAA,MAAM,cAAA,GAAiB,QAAQ,MAAM;AACnC,MAAA,OAAO,MAAM,MAAA,GAAS,QAAA,GAAW,MAAM,KAAA,CAAM,CAAC,QAAQ,CAAA,GAAI,KAAA;AAAA,IAC5D,CAAA,EAAG,CAAC,KAAA,EAAO,QAAQ,CAAC,CAAA;AAGpB,IAAA,MAAM,aAAA,GAAgB,QAAQ,MAAM;AAClC,MAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAK,EAAG,OAAO,cAAA;AAC3B,MAAA,OAAO,cAAA,CAAe,MAAA;AAAA,QAAO,CAAC,CAAA,KAC5B,CAAA,CAAE,KAAK,WAAA,EAAY,CAAE,SAAS,MAAA,CAAO,WAAA,EAAa,CAAA,IAClD,EAAE,MAAA,EAAQ,WAAA,GAAc,QAAA,CAAS,MAAA,CAAO,aAAa;AAAA,OACvD;AAAA,IACF,CAAA,EAAG,CAAC,cAAA,EAAgB,MAAM,CAAC,CAAA;AAG3B,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,IAAI,WAAA,IAAe,UAAU,OAAA,EAAS;AACpC,QAAA,SAAA,CAAU,OAAA,CAAQ,SAAA,GAAY,SAAA,CAAU,OAAA,CAAQ,YAAA;AAAA,MAClD;AAAA,IACF,CAAA,EAAG,CAAC,aAAA,CAAc,MAAA,EAAQ,WAAW,CAAC,CAAA;AAGtC,IAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAA+B;AACnD,MAAA,MAAM,KAAK,CAAA,CAAE,aAAA;AACb,MAAA,MAAM,WAAW,EAAA,CAAG,YAAA,GAAe,EAAA,CAAG,SAAA,GAAY,GAAG,YAAA,GAAe,EAAA;AACpE,MAAA,cAAA,CAAe,QAAQ,CAAA;AAAA,IACzB,CAAA;AAEA,IAAA,MAAM,YAAA,GAAe,cAAA,CAAe,OAAA,CAAQ,aAAA,CAAc,CAAC,CAAC,CAAA;AAE5D,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,wHAAA;AAAA,UACA,OAAA,IAAW,eAAA;AAAA,UACX;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAGJ,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,kGAAA,EACb,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,0DAAA,EACZ,QAAA,EAAA;AAAA,cAAA,WAAA,mBACG,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kCAAA,EAAmC,QAAA,EAAA,aAAA,EAAM,oBACzD,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wBAAA,EAAyB,QAAA,EAAA,eAAA,EAAQ,CAAA;AAAA,mCACpD,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,gBAAA,aAAA,CAAc,MAAA;AAAA,gBAAO;AAAA,eAAA,EAAM,CAAA;AAAA,cACjC,MAAM,MAAA,GAAS,QAAA,oBACd,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,qBAAA,EAAsB,QAAA,EAAA;AAAA,gBAAA,gBAAA;AAAA,gBAAe,QAAA;AAAA,gBAAS;AAAA,eAAA,EAAC;AAAA,aAAA,EAEnE,CAAA;AAAA,4BACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACZ,QAAA,EAAA,UAAA,oBACC,GAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,MAAA;AAAA,gBACL,KAAA,EAAO,MAAA;AAAA,gBACP,UAAU,CAAC,CAAA,KAAM,SAAA,CAAU,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,gBACzC,WAAA,EAAY,mBAAA;AAAA,gBACZ,SAAA,EAAW,EAAA;AAAA,kBACT,yDAAA;AAAA,kBACA,0DAAA;AAAA,kBACA,iDAAA;AAAA,kBACA;AAAA;AACF;AAAA,aACF,EAEJ;AAAA,WAAA,EACF,CAAA;AAAA,0BAGA,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,SAAA;AAAA,cACL,QAAA,EAAU,YAAA;AAAA,cACV,SAAA,EAAU,uDAAA;AAAA,cACV,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,cAEf,QAAA,EAAA;AAAA,gBAAA,aAAA,CAAc,MAAA,KAAW,qBACxB,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wEAAA,EACZ,QAAA,EAAA,MAAA,GAAS,0BAA0B,eAAA,EACtC,CAAA;AAAA,gBAED,aAAA,CAAc,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,KAAM;AAC9B,kBAAA,MAAM,aAAa,YAAA,IAAgB,CAAA,GAAI,YAAA,GAAe,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAClE,kBAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,MAAA;AAC5B,kBAAA,uBACE,IAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBAEC,SAAA,EAAW,EAAA;AAAA,wBACT,iFAAA;AAAA,wBACA,YAAY,KAAK;AAAA,uBACnB;AAAA,sBAEC,QAAA,EAAA;AAAA,wBAAA,eAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iEAAA,EACb,QAAA,EAAA,UAAA,EACH,CAAA;AAAA,wBAED,cAAA,IAAkB,KAAK,SAAA,oBACtB,GAAA,CAAC,UAAK,SAAA,EAAU,kDAAA,EACb,eAAK,SAAA,EACR,CAAA;AAAA,4CAED,MAAA,EAAA,EAAK,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA,WAAA,CAAY,KAAK,CAAA,EACpB,CAAA;AAAA,wCACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAiC,eAAK,IAAA,EAAK;AAAA;AAAA,qBAAA;AAAA,oBAnBtD,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,mBAoBzB;AAAA,gBAEJ,CAAC;AAAA;AAAA;AAAA;AACH;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AACA,SAAA,CAAU,WAAA,GAAc,WAAA","file":"chunk-RZK2S2OO.js","sourcesContent":["'use client'\n\nimport {\n type HTMLAttributes,\n type UIEvent,\n forwardRef,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'trace'\n\nexport interface LogLine {\n /** Line content */\n text: string\n /** Log level for color coding */\n level?: LogLevel\n /** Timestamp string (optional) */\n timestamp?: string\n /** Source/logger name */\n source?: string\n}\n\nexport interface LogViewerProps extends HTMLAttributes<HTMLDivElement> {\n /** Log lines to display */\n lines: LogLine[]\n /** Maximum visible lines (for performance) */\n maxLines?: number\n /** Show line numbers */\n showLineNumbers?: boolean\n /** Show timestamps */\n showTimestamps?: boolean\n /** Whether to auto-scroll (follow new content) */\n follow?: boolean\n /** Enable search */\n searchable?: boolean\n /** Height of the viewer */\n height?: string\n /** Whether the viewer is loading */\n loading?: boolean\n}\n\nconst levelStyles: Record<LogLevel, string> = {\n debug: 'text-tollerud-noir-400',\n trace: 'text-tollerud-noir-300',\n info: 'text-tollerud-foreground',\n warn: 'text-tollerud-amber',\n error: 'text-tollerud-error',\n}\n\nconst levelLabels: Record<LogLevel, string> = {\n debug: 'DBG',\n trace: 'TRC',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n}\n\nconst LogViewer = forwardRef<HTMLDivElement, LogViewerProps>(\n ({ className, lines, maxLines = 5000, showLineNumbers = true, showTimestamps = true, follow = true, searchable, height = '400px', loading, ...props }, ref) => {\n const [search, setSearch] = useState('')\n const [isFollowing, setIsFollowing] = useState(follow)\n const scrollRef = useRef<HTMLDivElement>(null)\n\n // Truncate for performance\n const displayedLines = useMemo(() => {\n return lines.length > maxLines ? lines.slice(-maxLines) : lines\n }, [lines, maxLines])\n\n // Filter by search\n const filteredLines = useMemo(() => {\n if (!search.trim()) return displayedLines\n return displayedLines.filter((l) =>\n l.text.toLowerCase().includes(search.toLowerCase()) ||\n l.source?.toLowerCase().includes(search.toLowerCase())\n )\n }, [displayedLines, search])\n\n // Auto-scroll\n useEffect(() => {\n if (isFollowing && scrollRef.current) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight\n }\n }, [filteredLines.length, isFollowing])\n\n // Detect manual scroll to disable follow\n const handleScroll = (e: UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget\n const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40\n setIsFollowing(atBottom)\n }\n\n const filteredFrom = displayedLines.indexOf(filteredLines[0])\n\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-tollerud-border bg-[var(--color-tollerud-surface-raised)] overflow-hidden tollerud-log-viewer',\n loading && 'animate-pulse',\n className\n )}\n {...props}\n >\n {/* Toolbar */}\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-tollerud-border bg-tollerud-noir-900\">\n <div className=\"flex items-center gap-2 text-xs text-tollerud-text-muted\">\n {isFollowing\n ? <span className=\"text-tollerud-yellow font-medium\">● Live</span>\n : <span className=\"text-tollerud-noir-400\">● Paused</span>}\n <span>{filteredLines.length} lines</span>\n {lines.length > maxLines && (\n <span className=\"text-tollerud-amber\">(showing last {maxLines})</span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {searchable && (\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search logs…\"\n className={cn(\n 'w-40 text-[11px] px-2 py-1 rounded bg-tollerud-noir-800',\n 'border border-tollerud-noir-600 text-tollerud-foreground',\n 'placeholder:text-tollerud-noir-400 outline-none',\n 'focus:border-tollerud-yellow/50 transition-colors'\n )}\n />\n )}\n </div>\n </div>\n\n {/* Log content */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n className=\"overflow-y-auto font-mono text-xs leading-relaxed p-3\"\n style={{ height }}\n >\n {filteredLines.length === 0 && (\n <div className=\"flex items-center justify-center h-full text-tollerud-noir-400 text-xs\">\n {search ? 'No matching log lines' : 'No log output'}\n </div>\n )}\n {filteredLines.map((line, i) => {\n const absLineNum = filteredFrom >= 0 ? filteredFrom + i + 1 : i + 1\n const level = line.level ?? 'info'\n return (\n <div\n key={`${absLineNum}-${i}`}\n className={cn(\n 'flex gap-3 hover:bg-[var(--color-tollerud-surface-hover)] px-1 py-px rounded-sm',\n levelStyles[level]\n )}\n >\n {showLineNumbers && (\n <span className=\"text-tollerud-noir-500 text-right select-none w-8 flex-shrink-0\">\n {absLineNum}\n </span>\n )}\n {showTimestamps && line.timestamp && (\n <span className=\"text-tollerud-noir-400 flex-shrink-0 select-none\">\n {line.timestamp}\n </span>\n )}\n <span className=\"flex-shrink-0 w-7 text-center font-bold text-[10px] uppercase opacity-60\">\n {levelLabels[level]}\n </span>\n <span className=\"whitespace-pre-wrap break-all\">{line.text}</span>\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n)\nLogViewer.displayName = 'LogViewer'\n\nexport { LogViewer }"]}
|