@pihanga2/shadcn 0.2.4 → 0.2.6
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/AGENT.building-cards.md +87 -0
- package/AGENT.using-cards.md +47 -0
- package/README.md +5 -1
- package/cards/avatar/avatar.component.d.ts +11 -0
- package/cards/avatar/avatar.component.js +26 -0
- package/cards/avatar/avatar.component.js.map +1 -0
- package/cards/avatar/avatar.types.d.ts +46 -0
- package/cards/avatar/avatar.types.js +7 -0
- package/cards/avatar/avatar.types.js.map +1 -0
- package/cards/avatar/index.d.ts +1 -0
- package/cards/avatar/index.js +12 -0
- package/cards/avatar/index.js.map +1 -0
- package/cards/badge/badge.component.js +4 -4
- package/cards/codeMirror/codeMirror.component.d.ts +4 -0
- package/cards/codeMirror/codeMirror.types.d.ts +83 -0
- package/cards/codeMirror/index.d.ts +1 -0
- package/cards/dataTable/dataTable.component.js +43 -42
- package/cards/dataTable/dataTable.component.js.map +1 -1
- package/cards/dataTable/dataTable.types.d.ts +26 -2
- package/cards/dataTable/dataTable.types.js +1 -0
- package/cards/dataTable/dataTable.types.js.map +1 -1
- package/cards/drawer/drawer.component.d.ts +4 -0
- package/cards/drawer/drawer.component.js +83 -0
- package/cards/drawer/drawer.component.js.map +1 -0
- package/cards/drawer/drawer.types.d.ts +95 -0
- package/cards/drawer/drawer.types.js +11 -0
- package/cards/drawer/drawer.types.js.map +1 -0
- package/cards/drawer/index.d.ts +1 -0
- package/cards/drawer/index.js +13 -0
- package/cards/drawer/index.js.map +1 -0
- package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
- package/cards/emptyCard/index.d.ts +7 -0
- package/cards/fileDrop/fileDrop.component.js +1 -1
- package/cards/fileDrop/fileDrop.css +1 -0
- package/cards/graphin/eventDispatcher.component.d.ts +2 -1
- package/cards/graphin/graphin.types.d.ts +14 -0
- package/cards/jsonViewer/jsonViewer.component.js +1 -1
- package/cards/jsonViewer/jsonViewer.css +1 -0
- package/cards/list/list.component.js +21 -21
- package/cards/loadingOverlay/loadingOverlay.component.js +1 -1
- package/cards/loadingOverlay/loadingOverlay.css +1 -0
- package/cards/pageWithNavbar/pageWithNavbar.component.js +1 -1
- package/cards/pageWithNavbar/pageWithNavbar.css +1 -0
- package/cards/pageWithNavbarMeta/index.d.ts +1 -0
- package/cards/pageWithNavbarMeta/index.js +118 -0
- package/cards/pageWithNavbarMeta/index.js.map +1 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +78 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js +7 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js.map +1 -0
- package/cards/pasteTarget/pasteTarget.component.js +1 -1
- package/cards/pasteTarget/pasteTarget.css +1 -0
- package/cards/scrollbarWithAnnotations/index.d.ts +1 -0
- package/cards/scrollbarWithAnnotations/index.js +13 -0
- package/cards/scrollbarWithAnnotations/index.js.map +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.d.ts +23 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js +78 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js.map +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.css +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.d.ts +123 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js +7 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js.map +1 -0
- package/cards/slider/slider.component.js +67 -48
- package/cards/slider/slider.component.js.map +1 -1
- package/cards/slider/slider.types.d.ts +31 -0
- package/cards/slider/slider.types.js.map +1 -1
- package/cards/stepper/stepper.component.js +1 -1
- package/cards/stepper/stepper.css +1 -0
- package/components/ui/avatar.js +5 -5
- package/components/ui/badge.js +7 -7
- package/components/ui/button.js +6 -6
- package/components/ui/drawer.js +79 -0
- package/components/ui/drawer.js.map +1 -0
- package/components/ui/field.js +16 -16
- package/components/ui/label.js +3 -3
- package/components/ui/separator.js +1 -1
- package/components/ui/toggle-group.js +5 -5
- package/components/ui/toggle.js +2 -2
- package/lib/utils.d.ts +15 -0
- package/lib/utils.js.map +1 -1
- package/package.json +28 -3
- package/pihanga-shadcn.css +0 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { GraphinNodeEventContext } from './graphin.types';
|
|
1
|
+
import { GraphinAfterLayoutContext, GraphinNodeEventContext } from './graphin.types';
|
|
2
2
|
export type GraphinEventDispatcherProps = {
|
|
3
3
|
onNodeHovered?: (ctx: GraphinNodeEventContext) => void;
|
|
4
4
|
onNodeHoverEnd?: (ctx: GraphinNodeEventContext) => void;
|
|
5
5
|
onNodeClicked?: (ctx: GraphinNodeEventContext) => void;
|
|
6
6
|
onNodeDblClicked?: (ctx: GraphinNodeEventContext) => void;
|
|
7
|
+
onAfterLayout?: (ctx: GraphinAfterLayoutContext) => void;
|
|
7
8
|
};
|
|
8
9
|
export declare function GraphinEventDispatcher(props: GraphinEventDispatcherProps): null;
|
|
@@ -12,6 +12,7 @@ export declare const GRAPHIN_ACTION: {
|
|
|
12
12
|
TOOLTIP_CLOSE: string;
|
|
13
13
|
CONTEXT_MENU_OPEN: string;
|
|
14
14
|
CONTEXT_MENU_CLOSE: string;
|
|
15
|
+
AFTER_LAYOUT: string;
|
|
15
16
|
};
|
|
16
17
|
export declare const onGraphinNodeHovered: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, ReduxAction & {
|
|
17
18
|
cardID: string;
|
|
@@ -37,6 +38,17 @@ export declare const onGraphinContextMenuOpen: <S extends import('@pihanga2/core
|
|
|
37
38
|
export declare const onGraphinContextMenuClose: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, ReduxAction & {
|
|
38
39
|
cardID: string;
|
|
39
40
|
} & GraphinNodeEventContext<Record<string, unknown>>>) => void;
|
|
41
|
+
export declare const onGraphinAfterLayout: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, ReduxAction & {
|
|
42
|
+
cardID: string;
|
|
43
|
+
} & Record<string, unknown> & {
|
|
44
|
+
cardID: string;
|
|
45
|
+
}>) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Payload carried by the `afterlayout` lifecycle event.
|
|
48
|
+
*/
|
|
49
|
+
export type GraphinAfterLayoutContext = Record<string, unknown> & {
|
|
50
|
+
cardID: string;
|
|
51
|
+
};
|
|
40
52
|
/**
|
|
41
53
|
* Payload carried by all node interaction events.
|
|
42
54
|
* Also forwarded as props to tooltip / context-menu `PiCard` content cards
|
|
@@ -594,4 +606,6 @@ export type GraphinEvents = {
|
|
|
594
606
|
onContextMenuOpen: GraphinNodeEventContext;
|
|
595
607
|
/** Fired when the context-menu panel closes */
|
|
596
608
|
onContextMenuClose: GraphinNodeEventContext;
|
|
609
|
+
/** Fired when the G6 layout engine finishes positioning all nodes */
|
|
610
|
+
onAfterLayout: GraphinAfterLayoutContext;
|
|
597
611
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getIconElement as e } from "../icons.js";
|
|
2
|
-
|
|
2
|
+
import './jsonViewer.css';import '../../node_modules/react-json-view-lite/dist/index.css';/* empty css */
|
|
3
3
|
/* empty css */
|
|
4
4
|
import { useCallback as t, useLayoutEffect as n, useRef as r, useState as i } from "react";
|
|
5
5
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.jv-wrapper{position:relative}.jv-copy-btn{z-index:10;width:22px;height:22px;color:hsl(var(--muted-foreground,0 0% 55%));cursor:pointer;opacity:.35;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;padding:0;transition:opacity .15s,color .15s,background .15s,border-color .15s;display:inline-flex;position:absolute;top:4px;right:4px}.jv-wrapper:hover .jv-copy-btn,.jv-wrapper:focus-within .jv-copy-btn{opacity:1}.jv-copy-btn:hover{color:hsl(var(--foreground));background:hsl(var(--muted,0 0% 96%));border-color:hsl(var(--border,0 0% 88%))}.jv-copy-btn--done{opacity:1;color:#2e7d32}.dark .jv-copy-btn--done{color:#81c784}.jv-container{white-space:pre-wrap;word-wrap:break-word;color:var(--foreground);background:0 0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;font-size:12.5px;font-weight:400;line-height:1.55}.jv-basic-child{margin:0;padding:0 0 0 1.1em;display:block;position:relative}.jv-label{color:var(--foreground);margin-right:0;font-weight:400}.jv-clickable-label{color:var(--foreground);cursor:pointer;margin-right:0;font-weight:400}.jv-clickable-label:hover{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.jv-punctuation{color:var(--foreground);font-weight:400}.jv-expand-icon,.jv-collapse-icon{width:1em;color:hsl(var(--muted-foreground,0 0% 55%));-webkit-user-select:none;user-select:none;cursor:pointer;justify-content:center;align-items:center;font-size:.65em;line-height:1;display:inline-flex;position:absolute;top:.775em;left:0;transform:translateY(-50%)}.jv-expand-icon:after{content:"▶"}.jv-collapse-icon:after{content:"▼"}.jv-collapsed-content{cursor:pointer;color:hsl(var(--muted-foreground,0 0% 55%))}.jv-collapsed-content:after{content:" …"}.jv-child-fields-container{border-left:1px solid hsl(var(--border,0 0% 88%));margin:0 0 0 .3em;padding:0 0 0 1.25em}.jv-null,.jv-undefined{color:#c0392b}.jv-string{color:#2e7d32}.jv-number{color:#1565c0}.jv-boolean{color:#00796b}.jv-other{color:var(--foreground)}.dark .jv-string{color:#81c784}.dark .jv-number{color:#64b5f6}.dark .jv-boolean{color:#4db6ac}.dark .jv-null,.dark .jv-undefined{color:#ef9a9a}.dark .jv-child-fields-container{border-left-color:hsl(var(--border,0 0% 25%))}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getIcon as e } from "../icons.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { cn as t } from "../../lib/utils.js";
|
|
3
|
+
import { Avatar as n, AvatarFallback as r, AvatarImage as i } from "../../components/ui/avatar.js";
|
|
4
|
+
import { Badge as a } from "../../components/ui/badge.js";
|
|
5
5
|
import * as o from "react";
|
|
6
6
|
import { Card as s } from "@pihanga2/core";
|
|
7
7
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
@@ -24,14 +24,14 @@ function m(o, u, d) {
|
|
|
24
24
|
if (!o) return null;
|
|
25
25
|
switch (o.type) {
|
|
26
26
|
case "icon": return /* @__PURE__ */ c("span", {
|
|
27
|
-
className:
|
|
27
|
+
className: t("flex shrink-0 items-center [&>svg]:size-4", o.className),
|
|
28
28
|
children: e(o.name)
|
|
29
29
|
});
|
|
30
|
-
case "avatar": return /* @__PURE__ */ l(
|
|
31
|
-
className:
|
|
32
|
-
children: [/* @__PURE__ */ c(
|
|
30
|
+
case "avatar": return /* @__PURE__ */ l(n, {
|
|
31
|
+
className: t(p[u], o.className),
|
|
32
|
+
children: [/* @__PURE__ */ c(i, { src: o.src }), /* @__PURE__ */ c(r, { children: o.fallback ?? "" })]
|
|
33
33
|
});
|
|
34
|
-
case "chip": return /* @__PURE__ */ c(
|
|
34
|
+
case "chip": return /* @__PURE__ */ c(a, {
|
|
35
35
|
variant: "secondary",
|
|
36
36
|
className: o.className,
|
|
37
37
|
children: o.text
|
|
@@ -43,52 +43,52 @@ function m(o, u, d) {
|
|
|
43
43
|
default: return null;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
function h({ item: e, size:
|
|
46
|
+
function h({ item: e, size: n, onItemClicked: r, cardName: i }) {
|
|
47
47
|
let [a, s] = o.useState(!1), p = !!e.nested?.length;
|
|
48
48
|
function g() {
|
|
49
49
|
p ? s((e) => !e) : r({ itemID: e.id });
|
|
50
50
|
}
|
|
51
51
|
return /* @__PURE__ */ l("li", { children: [/* @__PURE__ */ l("button", {
|
|
52
52
|
type: "button",
|
|
53
|
-
className:
|
|
53
|
+
className: t("flex w-full items-center rounded-sm outline-none transition-colors", "hover:bg-accent hover:text-accent-foreground", "focus-visible:ring-1 focus-visible:ring-ring", e.isSelected && "bg-accent text-accent-foreground font-medium", d[n], e.className),
|
|
54
54
|
onClick: g,
|
|
55
55
|
"aria-expanded": p ? a : void 0,
|
|
56
56
|
"data-selected": e.isSelected || void 0,
|
|
57
57
|
children: [
|
|
58
|
-
m(e.startDecorator,
|
|
58
|
+
m(e.startDecorator, n, i),
|
|
59
59
|
/* @__PURE__ */ l("span", {
|
|
60
60
|
className: "flex min-w-0 flex-1 flex-col items-start",
|
|
61
61
|
children: [/* @__PURE__ */ c("span", {
|
|
62
62
|
className: "truncate leading-none",
|
|
63
63
|
children: e.title
|
|
64
64
|
}), e.subTitle && /* @__PURE__ */ c("span", {
|
|
65
|
-
className:
|
|
65
|
+
className: t("mt-0.5 truncate text-muted-foreground", f[n]),
|
|
66
66
|
children: e.subTitle
|
|
67
67
|
})]
|
|
68
68
|
}),
|
|
69
|
-
!p && m(e.endDecorator,
|
|
70
|
-
p && /* @__PURE__ */ c(u, { className:
|
|
69
|
+
!p && m(e.endDecorator, n, i),
|
|
70
|
+
p && /* @__PURE__ */ c(u, { className: t("ml-auto size-4 shrink-0 text-muted-foreground transition-transform duration-200", a && "rotate-180") })
|
|
71
71
|
]
|
|
72
72
|
}), p && a && /* @__PURE__ */ c("ul", {
|
|
73
|
-
className:
|
|
74
|
-
children: e.nested.map((e,
|
|
73
|
+
className: t("ml-3 mt-0.5 flex flex-col gap-0.5 border-l border-border pl-2", "list-none p-0", n === "lg" ? "ml-4 pl-3" : "ml-3 pl-2"),
|
|
74
|
+
children: e.nested.map((e, t) => /* @__PURE__ */ c(h, {
|
|
75
75
|
item: e,
|
|
76
|
-
size:
|
|
76
|
+
size: n,
|
|
77
77
|
onItemClicked: r,
|
|
78
78
|
cardName: i
|
|
79
|
-
}, e.id ??
|
|
79
|
+
}, e.id ?? t))
|
|
80
80
|
})] });
|
|
81
81
|
}
|
|
82
82
|
var g = (e) => {
|
|
83
|
-
let { items:
|
|
83
|
+
let { items: n, size: r = "md", marker: i, className: a, style: o, onItemClicked: s, cardName: l } = e, u = {
|
|
84
84
|
...o,
|
|
85
85
|
...i && i !== "none" ? { listStyleType: i } : void 0
|
|
86
86
|
};
|
|
87
87
|
return /* @__PURE__ */ c("ul", {
|
|
88
|
-
className:
|
|
88
|
+
className: t("flex flex-col gap-0.5 p-0", i && i !== "none" ? "list-inside" : "list-none", a),
|
|
89
89
|
style: u,
|
|
90
90
|
"data-pihanga": l,
|
|
91
|
-
children:
|
|
91
|
+
children: n.map((e, t) => /* @__PURE__ */ c(h, {
|
|
92
92
|
item: e,
|
|
93
93
|
size: r,
|
|
94
94
|
onItemClicked: s,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.overlay-wrapper{flex-direction:column;width:100%;min-width:0;display:flex;position:relative}.overlay-wrapper.is-loading.fill-parent{min-height:12rem}.overlay-content{flex-direction:column;flex-grow:1;width:100%;min-width:0;display:flex;position:relative;overflow-y:hidden}.overlay-wrapper.fill-parent .overlay-content{min-height:inherit}.loading-overlay{opacity:0;pointer-events:none;z-index:2;background:oklch(100% 0 0/.7);justify-content:center;align-items:center;transition:opacity .15s;display:flex;position:absolute;inset:0}.overlay-wrapper.viewport-centered .loading-overlay{z-index:50;position:fixed;inset:0}.dark .loading-overlay{background:oklch(14.5% 0 0/.5)}.overlay-wrapper.is-loading .loading-overlay{opacity:1;pointer-events:auto}.loading-overlay__content{color:var(--muted-foreground);align-items:center;gap:.5rem;font-size:.875rem;display:flex}
|
|
@@ -2,7 +2,7 @@ import { SCREEN_SIZE_ORDER as e, SCREEN_SIZE_WIDTHS as t, ScreenSize as n } from
|
|
|
2
2
|
import { getIconElement as r } from "../icons.js";
|
|
3
3
|
import { Button as i } from "../../components/ui/button.js";
|
|
4
4
|
import { Sheet as a, SheetContent as o, SheetTrigger as s } from "../../components/ui/sheet.js";
|
|
5
|
-
|
|
5
|
+
import './pageWithNavbar.css';/* empty css */
|
|
6
6
|
import { useEffect as c, useRef as l, useState as u } from "react";
|
|
7
7
|
import { Card as d } from "@pihanga2/core";
|
|
8
8
|
import f from "clsx";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.window{justify-content:center;width:100%;height:100%;display:flex}.page{flex-direction:column;flex:1;width:100%;height:100%;display:flex}.header{border-bottom:1px solid var(--border);background-color:var(--background);flex-shrink:0;align-items:center;gap:1rem;padding-left:1rem;padding-right:1rem;display:flex}@media (width>=768px){.header{padding-left:1.5rem;padding-right:1.5rem}}.title-section{align-items:center;gap:.5rem;display:inline-flex}.title-section .title-icon{flex-shrink:0;width:1.5rem;height:1.5rem}.title-section .title-text{color:var(--foreground);font-size:1.125rem;font-weight:600;line-height:1.75rem}.nav-md{display:none}@media (width>=768px){.nav-md{flex-direction:row;align-items:center;gap:1.25rem;display:flex}}@media (width>=1024px){.nav-md{gap:1.5rem}}.nav-md .nav-link{color:var(--muted-foreground);padding-left:0;padding-right:0;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.nav-md .nav-link:hover{color:var(--foreground)}.nav-sm{gap:1.5rem;padding:1rem;font-size:1.125rem;font-weight:500;line-height:1.75rem;display:grid}.nav-sm .nav-link{color:var(--muted-foreground);justify-content:flex-start;padding-left:0;padding-right:0;font-size:1.125rem;line-height:1.75rem}.nav-sm .nav-link:hover{color:var(--foreground)}.header-actions{align-items:center;gap:.5rem;margin-left:auto;display:flex}@media (width>=1024px){.header-actions{gap:1rem}}.main{background-color:var(--background);flex:1;min-height:0;padding:.5rem 1rem;overflow-y:auto}@media (width>=768px){.main{padding:1rem 2rem}}.footer{background-color:var(--background);color:var(--muted-foreground);flex-shrink:0;padding:.5rem 1rem}@media (width>=768px){.footer{padding:1rem 2rem}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pageWithNavbarMeta.types';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Box as e } from "../box/box.types.js";
|
|
2
|
+
import "../box/index.js";
|
|
3
|
+
import { Button as t } from "../button/button.types.js";
|
|
4
|
+
import "../button/index.js";
|
|
5
|
+
import { Conditional as n } from "../conditional/conditional.types.js";
|
|
6
|
+
import "../conditional/index.js";
|
|
7
|
+
import { Drawer as r } from "../drawer/drawer.types.js";
|
|
8
|
+
import "../drawer/index.js";
|
|
9
|
+
import { Stack as i } from "../stack/stack.types.js";
|
|
10
|
+
import "../stack/index.js";
|
|
11
|
+
import { Typography as a } from "../typography/typography.types.js";
|
|
12
|
+
import "../typography/index.js";
|
|
13
|
+
import { PAGE_WITH_NAVBAR_META_ACTION as o, PI_PAGE_WITH_NAVBAR_META_CARD as s, PageWithNavbarMeta as c, onPageWithNavbarMetaNavigateTo as l } from "./pageWithNavbarMeta.types.js";
|
|
14
|
+
import { registerMetaCard as u } from "@pihanga2/core";
|
|
15
|
+
//#region src/cards/pageWithNavbarMeta/index.ts
|
|
16
|
+
function d(e) {
|
|
17
|
+
return e ? e.charAt(0).toLocaleUpperCase() + e.slice(1) : "";
|
|
18
|
+
}
|
|
19
|
+
function f(s, c, l) {
|
|
20
|
+
let u = c.navLinks ?? [], f = c.iconName, p = c.className, m = c.footer, h = [];
|
|
21
|
+
f && h.push(t({
|
|
22
|
+
iconLabel: f,
|
|
23
|
+
opts: {
|
|
24
|
+
variant: "none",
|
|
25
|
+
size: "icon"
|
|
26
|
+
},
|
|
27
|
+
className: "h-6 w-6 shrink-0 pointer-events-none"
|
|
28
|
+
})), h.push(a({
|
|
29
|
+
text: c.title,
|
|
30
|
+
level: "large",
|
|
31
|
+
className: "leading-none"
|
|
32
|
+
}));
|
|
33
|
+
let g = l("title", i({
|
|
34
|
+
direction: "row",
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
spacing: 2,
|
|
37
|
+
content: h
|
|
38
|
+
})), _ = u.map((e, n) => l(`nav-link-${n}`, t({
|
|
39
|
+
id: e.id,
|
|
40
|
+
label: e.title ?? d(e.id),
|
|
41
|
+
opts: { variant: "ghost" },
|
|
42
|
+
className: "px-0 text-muted-foreground hover:text-foreground h-auto p-0",
|
|
43
|
+
onClickedMapper: () => ({
|
|
44
|
+
type: o.NAVIGATE_TO,
|
|
45
|
+
id: e.id
|
|
46
|
+
})
|
|
47
|
+
}))), v = l("nav-md", n({
|
|
48
|
+
showOn: "md",
|
|
49
|
+
content: l("nav-md-inner", i({
|
|
50
|
+
direction: "row",
|
|
51
|
+
alignItems: "center",
|
|
52
|
+
spacing: 5,
|
|
53
|
+
content: [g, ..._]
|
|
54
|
+
}))
|
|
55
|
+
})), y = u.length > 0 ? l("nav-sm", n({
|
|
56
|
+
showOn: "<md",
|
|
57
|
+
content: l("nav-sm-drawer", r({
|
|
58
|
+
direction: "left",
|
|
59
|
+
trigger: t({
|
|
60
|
+
iconLabel: "menu",
|
|
61
|
+
opts: {
|
|
62
|
+
variant: "outline",
|
|
63
|
+
size: "icon"
|
|
64
|
+
},
|
|
65
|
+
ariaLabel: "Toggle navigation menu"
|
|
66
|
+
}),
|
|
67
|
+
content: l("nav-sm-content", i({
|
|
68
|
+
direction: "column",
|
|
69
|
+
spacing: 4,
|
|
70
|
+
className: "p-4",
|
|
71
|
+
content: [g, ..._]
|
|
72
|
+
})),
|
|
73
|
+
footerCloseButtonText: null
|
|
74
|
+
}))
|
|
75
|
+
})) : l("nav-sm-title", n({
|
|
76
|
+
showOn: "<md",
|
|
77
|
+
content: g
|
|
78
|
+
})), b = [];
|
|
79
|
+
c.headerLeftCard && b.push(c.headerLeftCard), c.headerRightCard && b.push(c.headerRightCard);
|
|
80
|
+
let x = [v, y];
|
|
81
|
+
b.length > 0 && x.push(l("header-actions", i({
|
|
82
|
+
direction: "row",
|
|
83
|
+
alignItems: "center",
|
|
84
|
+
className: "ml-auto gap-2 lg:gap-4",
|
|
85
|
+
content: b
|
|
86
|
+
})));
|
|
87
|
+
let S = [l("header", e({
|
|
88
|
+
className: "shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6",
|
|
89
|
+
content: x
|
|
90
|
+
})), l("main", e({
|
|
91
|
+
className: "flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4",
|
|
92
|
+
content: ((e, t) => {
|
|
93
|
+
let n = t.resolve(c.main);
|
|
94
|
+
return n == null ? [] : [n];
|
|
95
|
+
})
|
|
96
|
+
}))];
|
|
97
|
+
return m && S.push(l("footer", e({
|
|
98
|
+
className: "shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4",
|
|
99
|
+
content: [m]
|
|
100
|
+
}))), i({
|
|
101
|
+
direction: "row",
|
|
102
|
+
className: `w-full h-full justify-center${p ? ` ${p}` : ""}`,
|
|
103
|
+
content: [l("page", i({
|
|
104
|
+
direction: "column",
|
|
105
|
+
className: "flex-1 h-full w-full",
|
|
106
|
+
content: S
|
|
107
|
+
}))]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
u({
|
|
111
|
+
type: s,
|
|
112
|
+
mapper: f,
|
|
113
|
+
events: o
|
|
114
|
+
});
|
|
115
|
+
//#endregion
|
|
116
|
+
export { o as PAGE_WITH_NAVBAR_META_ACTION, s as PI_PAGE_WITH_NAVBAR_META_CARD, c as PageWithNavbarMeta, l as onPageWithNavbarMetaNavigateTo };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/index.ts"],"sourcesContent":["import {\n registerMetaCard,\n type PiCardDef,\n type PiCardRef,\n type PiMetaProps,\n type PiMetaResolveCtx,\n type PiRegisterMetaCard,\n type RegisterCardF,\n} from \"@pihanga2/core\";\n\nimport {Stack} from \"@/cards/stack\";\nimport {Box} from \"@/cards/box\";\nimport {Button} from \"@/cards/button\";\nimport {Typography} from \"@/cards/typography\";\nimport {Conditional} from \"@/cards/conditional\";\nimport {Drawer} from \"@/cards/drawer\";\n\nimport {\n PAGE_WITH_NAVBAR_META_ACTION,\n PI_PAGE_WITH_NAVBAR_META_CARD,\n type NavLink,\n type PageWithNavbarMetaDynProps,\n type PageWithNavbarMetaEvents,\n type PageWithNavbarMetaStaticProps,\n} from \"./pageWithNavbarMeta.types\";\n\nexport * from \"./pageWithNavbarMeta.types\";\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toLocaleUpperCase() + s.slice(1) : \"\";\n}\n\n// ── Mapper ───────────────────────────────────────────────────────────────────\n\n/**\n * `StaticProps` arrive as their plain types — TypeScript refuses memo selectors.\n * `DynProps` arrive as `StateMapper<T>` functions — must be resolved via `resolve()`.\n */\ntype MapperProps = PiMetaProps<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>;\n\nfunction PageWithNavbarMetaMapper(\n _cardName: string,\n props: MapperProps,\n reg: RegisterCardF,\n): PiCardDef {\n // ── Static props: plain types, no resolve() needed ───────────────────────\n const navLinks = props.navLinks ?? [];\n const iconName = props.iconName;\n const wrapperClass = props.className;\n const footer = props.footer;\n\n // ── Title (icon + text) ─────────────────────────────────────────────────\n // props.title is StateMapper<string> — a function, NOT a string.\n // Typography's `text` prop is typed (via PiMapProps) as `string | StateMapper<string>`,\n // so we forward the selector function directly. The framework resolves it lazily\n // (calls props.title(state, ctx)) when Typography renders. This is different from\n // using props.title as a string, which TypeScript would reject.\n const titleContent: PiCardRef[] = [];\n if (iconName) {\n titleContent.push(\n Button({\n iconLabel: iconName,\n opts: {variant: \"none\", size: \"icon\"},\n className: \"h-6 w-6 shrink-0 pointer-events-none\",\n }),\n );\n }\n titleContent.push(\n Typography({\n text: props.title,\n level: \"large\",\n className: \"leading-none\",\n }),\n );\n\n const titleStack = reg(\n \"title\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 2,\n content: titleContent,\n }),\n );\n\n // ── Nav link buttons (shared between desktop and mobile) ────────────────\n const linkButtons = navLinks.map((link: NavLink, i: number) =>\n reg(\n `nav-link-${i}`,\n Button({\n id: link.id,\n label: link.title ?? capitalize(link.id),\n opts: {variant: \"ghost\"},\n className:\n \"px-0 text-muted-foreground hover:text-foreground h-auto p-0\",\n onClickedMapper: () => ({\n type: PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n id: link.id,\n }),\n }),\n ),\n );\n\n // ── Desktop nav (md+): title + links in a row ───────────────────────────\n const desktopNav = reg(\n \"nav-md\",\n Conditional({\n showOn: \"md\",\n content: reg(\n \"nav-md-inner\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 5,\n content: [titleStack, ...linkButtons],\n }),\n ),\n }),\n );\n\n // ── Mobile nav (< md) ───────────────────────────────────────────────────\n // With nav links: hamburger drawer (left slide-in using pi/drawer).\n // Without nav links: just show the title inline.\n const mobileNav: PiCardRef =\n navLinks.length > 0\n ? reg(\n \"nav-sm\",\n Conditional({\n showOn: \"<md\",\n content: reg(\n \"nav-sm-drawer\",\n Drawer({\n direction: \"left\",\n trigger: Button({\n iconLabel: \"menu\",\n opts: {variant: \"outline\", size: \"icon\"},\n ariaLabel: \"Toggle navigation menu\",\n }),\n content: reg(\n \"nav-sm-content\",\n Stack({\n direction: \"column\",\n spacing: 4,\n className: \"p-4\",\n content: [titleStack, ...linkButtons],\n }),\n ),\n footerCloseButtonText: null,\n }),\n ),\n }),\n )\n : reg(\n \"nav-sm-title\",\n Conditional({\n showOn: \"<md\",\n content: titleStack,\n }),\n );\n\n // ── Header action slots ─────────────────────────────────────────────────\n // Static PiCardRefs — TypeScript already refuses memo() selectors here.\n const actionRefs: PiCardRef[] = [];\n if (props.headerLeftCard) {\n actionRefs.push(props.headerLeftCard);\n }\n if (props.headerRightCard) {\n actionRefs.push(props.headerRightCard);\n }\n\n const headerContent: PiCardRef[] = [desktopNav, mobileNav];\n if (actionRefs.length > 0) {\n headerContent.push(\n reg(\n \"header-actions\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n className: \"ml-auto gap-2 lg:gap-4\",\n content: actionRefs,\n }),\n ),\n );\n }\n\n // ── Header ──────────────────────────────────────────────────────────────\n const header = reg(\n \"header\",\n Box({\n className:\n \"shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6\",\n content: headerContent,\n }),\n );\n\n // ── Main ────────────────────────────────────────────────────────────────\n // props.main is a StateMapper — resolved lazily so React re-renders when\n // the referenced card changes.\n const mainBox = reg(\n \"main\",\n Box({\n className:\n \"flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4\",\n content: ((_: unknown, ctx: PiMetaResolveCtx) => {\n const ref = ctx.resolve(props.main);\n return ref != null ? [ref as PiCardRef] : [];\n }) as unknown as PiCardRef[],\n }),\n );\n\n // ── Page column ─────────────────────────────────────────────────────────\n const pageContent: PiCardRef[] = [header, mainBox];\n\n // ── Footer (optional) ───────────────────────────────────────────────────\n // `footer` is a static plain PiCardRef — use directly.\n if (footer) {\n pageContent.push(\n reg(\n \"footer\",\n Box({\n className:\n \"shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4\",\n content: [footer],\n }),\n ),\n );\n }\n\n // ── Assemble ────────────────────────────────────────────────────────────\n return Stack({\n direction: \"row\",\n className: `w-full h-full justify-center${wrapperClass ? ` ${wrapperClass}` : \"\"}`,\n content: [\n reg(\n \"page\",\n Stack({\n direction: \"column\",\n className: \"flex-1 h-full w-full\",\n content: pageContent,\n }),\n ),\n ],\n });\n}\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nregisterMetaCard({\n type: PI_PAGE_WITH_NAVBAR_META_CARD,\n mapper: PageWithNavbarMetaMapper,\n events: PAGE_WITH_NAVBAR_META_ACTION,\n} satisfies PiRegisterMetaCard);\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,EAAW,GAAmB;CACrC,OAAO,IAAI,EAAE,OAAO,CAAC,EAAE,kBAAkB,IAAI,EAAE,MAAM,CAAC,IAAI;AAC5D;AAcA,SAAS,EACP,GACA,GACA,GACW;CAEX,IAAM,IAAW,EAAM,YAAY,CAAC,GAC9B,IAAW,EAAM,UACjB,IAAe,EAAM,WACrB,IAAS,EAAM,QAQf,IAA4B,CAAC;CAUnC,AATI,KACF,EAAa,KACX,EAAO;EACL,WAAW;EACX,MAAM;GAAC,SAAS;GAAQ,MAAM;EAAM;EACpC,WAAW;CACb,CAAC,CACH,GAEF,EAAa,KACX,EAAW;EACT,MAAM,EAAM;EACZ,OAAO;EACP,WAAW;CACb,CAAC,CACH;CAEA,IAAM,IAAa,EACjB,SACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,SAAS;EACT,SAAS;CACX,CAAC,CACH,GAGM,IAAc,EAAS,KAAK,GAAe,MAC/C,EACE,YAAY,KACZ,EAAO;EACL,IAAI,EAAK;EACT,OAAO,EAAK,SAAS,EAAW,EAAK,EAAE;EACvC,MAAM,EAAC,SAAS,QAAO;EACvB,WACE;EACF,wBAAwB;GACtB,MAAM,EAA6B;GACnC,IAAI,EAAK;EACX;CACF,CAAC,CACH,CACF,GAGM,IAAa,EACjB,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,gBACA,EAAM;GACJ,WAAW;GACX,YAAY;GACZ,SAAS;GACT,SAAS,CAAC,GAAY,GAAG,CAAW;EACtC,CAAC,CACH;CACF,CAAC,CACH,GAKM,IACJ,EAAS,SAAS,IACd,EACE,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,iBACA,EAAO;GACL,WAAW;GACX,SAAS,EAAO;IACd,WAAW;IACX,MAAM;KAAC,SAAS;KAAW,MAAM;IAAM;IACvC,WAAW;GACb,CAAC;GACD,SAAS,EACP,kBACA,EAAM;IACJ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS,CAAC,GAAY,GAAG,CAAW;GACtC,CAAC,CACH;GACA,uBAAuB;EACzB,CAAC,CACH;CACF,CAAC,CACH,IACA,EACE,gBACA,EAAY;EACV,QAAQ;EACR,SAAS;CACX,CAAC,CACH,GAIA,IAA0B,CAAC;CAIjC,AAHI,EAAM,kBACR,EAAW,KAAK,EAAM,cAAc,GAElC,EAAM,mBACR,EAAW,KAAK,EAAM,eAAe;CAGvC,IAAM,IAA6B,CAAC,GAAY,CAAS;CACzD,AAAI,EAAW,SAAS,KACtB,EAAc,KACZ,EACE,kBACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,SAAS;CACX,CAAC,CACH,CACF;CA6BF,IAAM,IAA2B,CAzBlB,EACb,UACA,EAAI;EACF,WACE;EACF,SAAS;CACX,CAAC,CAmB+B,GAblB,EACd,QACA,EAAI;EACF,WACE;EACF,WAAW,GAAY,MAA0B;GAC/C,IAAM,IAAM,EAAI,QAAQ,EAAM,IAAI;GAClC,OAAO,KAAO,OAA4B,CAAC,IAAtB,CAAC,CAAgB;EACxC;CACF,CAAC,CAIuC,CAAO;CAkBjD,OAdI,KACF,EAAY,KACV,EACE,UACA,EAAI;EACF,WACE;EACF,SAAS,CAAC,CAAM;CAClB,CAAC,CACH,CACF,GAIK,EAAM;EACX,WAAW;EACX,WAAW,+BAA+B,IAAe,IAAI,MAAiB;EAC9E,SAAS,CACP,EACE,QACA,EAAM;GACJ,WAAW;GACX,WAAW;GACX,SAAS;EACX,CAAC,CACH,CACF;CACF,CAAC;AACH;AAIA,EAAiB;CACf,MAAM;CACN,QAAQ;CACR,QAAQ;AACV,CAA8B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { PiCardRef } from '@pihanga2/core';
|
|
2
|
+
export declare const PI_PAGE_WITH_NAVBAR_META_CARD = "pi/pageWithNavbarMeta";
|
|
3
|
+
export declare const PageWithNavbarMeta: <S extends import('@pihanga2/core').ReduxState>(p: PageWithNavbarMetaStaticProps & {
|
|
4
|
+
title: string | import('@pihanga2/core').StateMapper<string, S, import('@pihanga2/core').PiDefCtxtProps>;
|
|
5
|
+
main: PiCardRef | import('@pihanga2/core').StateMapper<PiCardRef, S, import('@pihanga2/core').PiDefCtxtProps>;
|
|
6
|
+
} & import('@pihanga2/core/types').EventHandler<PageWithNavbarMetaEvents, S> & import('@pihanga2/core/types').EventMapper<PageWithNavbarMetaEvents, import('@pihanga2/core').PiDefCtxtProps>) => import('@pihanga2/core').PiCardDef;
|
|
7
|
+
export declare const PAGE_WITH_NAVBAR_META_ACTION: {
|
|
8
|
+
NAVIGATE_TO: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const onPageWithNavbarMetaNavigateTo: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
11
|
+
cardID: string;
|
|
12
|
+
} & PageWithNavbarMetaNavigateToEvent>) => void;
|
|
13
|
+
export type NavLink = {
|
|
14
|
+
id: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Props that are evaluated **statically** in the mapper body.
|
|
19
|
+
* Passing a `memo(...)` selector for any of these will throw at runtime.
|
|
20
|
+
*/
|
|
21
|
+
export type PageWithNavbarMetaStaticProps = {
|
|
22
|
+
/**
|
|
23
|
+
* Name of an icon registered via {@link registerIcon}.
|
|
24
|
+
* When provided, the icon is rendered next to the title in the header.
|
|
25
|
+
*/
|
|
26
|
+
iconName?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Optional footer card rendered below the main content area.
|
|
29
|
+
* When omitted the footer row is not rendered.
|
|
30
|
+
*
|
|
31
|
+
* To conditionally show/hide a footer, wrap it in a `Conditional` card.
|
|
32
|
+
*/
|
|
33
|
+
footer?: PiCardRef;
|
|
34
|
+
/**
|
|
35
|
+
* Navigation links rendered in the header.
|
|
36
|
+
* On small screens they are collapsed behind a hamburger drawer.
|
|
37
|
+
*/
|
|
38
|
+
navLinks?: NavLink[];
|
|
39
|
+
/**
|
|
40
|
+
* Reserved — not yet implemented.
|
|
41
|
+
* When `Box` gains `scrollResetKey` support, this prop will scroll
|
|
42
|
+
* the main content area back to the top whenever the value changes.
|
|
43
|
+
*/
|
|
44
|
+
scrollResetKey?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Optional card shown on the left side of the header action area.
|
|
47
|
+
* To use a reactive card ref, wrap it in a stable `registerCard` slot.
|
|
48
|
+
*/
|
|
49
|
+
headerLeftCard?: PiCardRef;
|
|
50
|
+
/**
|
|
51
|
+
* Optional card shown on the right side of the header action area.
|
|
52
|
+
* To use a reactive card ref, wrap it in a stable `registerCard` slot.
|
|
53
|
+
*/
|
|
54
|
+
headerRightCard?: PiCardRef;
|
|
55
|
+
/** Additional Tailwind classes applied to the outermost wrapper. */
|
|
56
|
+
className?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Props that support **reactive** state selectors (`memo(...)`).
|
|
60
|
+
* These are resolved lazily inside child card prop functions via `resolve()`.
|
|
61
|
+
*/
|
|
62
|
+
export type PageWithNavbarMetaDynProps = {
|
|
63
|
+
/** Page title displayed in the header. Supports reactive selectors. */
|
|
64
|
+
title: string;
|
|
65
|
+
/**
|
|
66
|
+
* The main content card.
|
|
67
|
+
* Supports reactive selectors (e.g. `memo((s) => s.currentPage, ...)`).
|
|
68
|
+
*/
|
|
69
|
+
main: PiCardRef;
|
|
70
|
+
};
|
|
71
|
+
/** Combined props type — intersection of static and dynamic props. */
|
|
72
|
+
export type PageWithNavbarMetaProps = PageWithNavbarMetaStaticProps & PageWithNavbarMetaDynProps;
|
|
73
|
+
export type PageWithNavbarMetaNavigateToEvent = {
|
|
74
|
+
id: string;
|
|
75
|
+
};
|
|
76
|
+
export type PageWithNavbarMetaEvents = {
|
|
77
|
+
onNavigateTo: PageWithNavbarMetaNavigateToEvent;
|
|
78
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCardDeclaration2 as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
|
|
2
|
+
//#region src/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.ts
|
|
3
|
+
var r = "pi/pageWithNavbarMeta", i = e(r), a = n(r, ["navigate_to"]), o = t(a.NAVIGATE_TO);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { a as PAGE_WITH_NAVBAR_META_ACTION, r as PI_PAGE_WITH_NAVBAR_META_CARD, i as PageWithNavbarMeta, o as onPageWithNavbarMetaNavigateTo };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=pageWithNavbarMeta.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageWithNavbarMeta.types.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.ts"],"sourcesContent":["import {\n createCardDeclaration2,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_PAGE_WITH_NAVBAR_META_CARD = \"pi/pageWithNavbarMeta\";\n\nexport const PageWithNavbarMeta = createCardDeclaration2<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>(PI_PAGE_WITH_NAVBAR_META_CARD);\n\nexport const PAGE_WITH_NAVBAR_META_ACTION = registerActions(\n PI_PAGE_WITH_NAVBAR_META_CARD,\n [\"navigate_to\"],\n);\n\nexport const onPageWithNavbarMetaNavigateTo =\n createOnAction<PageWithNavbarMetaNavigateToEvent>(\n PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n );\n\nexport type NavLink = {\n id: string;\n title?: string;\n};\n\n/**\n * Props that are evaluated **statically** in the mapper body.\n * Passing a `memo(...)` selector for any of these will throw at runtime.\n */\nexport type PageWithNavbarMetaStaticProps = {\n /**\n * Name of an icon registered via {@link registerIcon}.\n * When provided, the icon is rendered next to the title in the header.\n */\n iconName?: string;\n\n /**\n * Optional footer card rendered below the main content area.\n * When omitted the footer row is not rendered.\n *\n * To conditionally show/hide a footer, wrap it in a `Conditional` card.\n */\n footer?: PiCardRef;\n\n /**\n * Navigation links rendered in the header.\n * On small screens they are collapsed behind a hamburger drawer.\n */\n navLinks?: NavLink[];\n\n /**\n * Reserved — not yet implemented.\n * When `Box` gains `scrollResetKey` support, this prop will scroll\n * the main content area back to the top whenever the value changes.\n */\n scrollResetKey?: string;\n\n /**\n * Optional card shown on the left side of the header action area.\n * To use a reactive card ref, wrap it in a stable `registerCard` slot.\n */\n headerLeftCard?: PiCardRef;\n\n /**\n * Optional card shown on the right side of the header action area.\n * To use a reactive card ref, wrap it in a stable `registerCard` slot.\n */\n headerRightCard?: PiCardRef;\n\n /** Additional Tailwind classes applied to the outermost wrapper. */\n className?: string;\n};\n\n/**\n * Props that support **reactive** state selectors (`memo(...)`).\n * These are resolved lazily inside child card prop functions via `resolve()`.\n */\nexport type PageWithNavbarMetaDynProps = {\n /** Page title displayed in the header. Supports reactive selectors. */\n title: string;\n\n /**\n * The main content card.\n * Supports reactive selectors (e.g. `memo((s) => s.currentPage, ...)`).\n */\n main: PiCardRef;\n};\n\n/** Combined props type — intersection of static and dynamic props. */\nexport type PageWithNavbarMetaProps = PageWithNavbarMetaStaticProps &\n PageWithNavbarMetaDynProps;\n\nexport type PageWithNavbarMetaNavigateToEvent = {id: string};\n\nexport type PageWithNavbarMetaEvents = {\n onNavigateTo: PageWithNavbarMetaNavigateToEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAgC,yBAEhC,IAAqB,EAIhC,CAA6B,GAElB,IAA+B,EAC1C,GACA,CAAC,aAAa,CAChB,GAEa,IACX,EACE,EAA6B,WAC/B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Button as e } from "../../components/ui/button.js";
|
|
2
2
|
import { DEF_ERROR_COLOR as t, DEF_HEIGHT as n, DEF_OVERLAY_OPACITY as r, DEF_PASTE_FIRST_REMINDER as i, DEF_SUCCESS_COLOR as a } from "./pasteTarget.types.js";
|
|
3
|
-
|
|
3
|
+
import './pasteTarget.css';/* empty css */
|
|
4
4
|
import o, { useRef as s, useState as c } from "react";
|
|
5
5
|
import l from "clsx";
|
|
6
6
|
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.pihanga-paste-target{border:2px dashed #999}.pihanga-paste-target .paste-target-msg-title{font-size:1.2em}.pihanga-paste-target textarea:focus{outline:none}.pihanga-paste-target-focused{border-width:3px;border-color:#007bff}.pihanga-paste-target-focused .paste-target-focus-reminder{display:none}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './scrollbarWithAnnotations.types';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ScrollbarWithAnnotationsComponent as e } from "./scrollbarWithAnnotations.component.js";
|
|
2
|
+
import { SCROLLBAR_WITH_ANNOTATIONS_ACTION as t, SCROLLBAR_WITH_ANNOTATIONS_CARD as n, ScrollbarWithAnnotations as r, onScrollbarAnnotationClicked as i, onScrollbarAnnotationHovered as a } from "./scrollbarWithAnnotations.types.js";
|
|
3
|
+
import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
|
|
4
|
+
//#region src/cards/scrollbarWithAnnotations/index.ts
|
|
5
|
+
s({
|
|
6
|
+
name: n,
|
|
7
|
+
component: e,
|
|
8
|
+
events: o(t)
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as SCROLLBAR_WITH_ANNOTATIONS_ACTION, n as SCROLLBAR_WITH_ANNOTATIONS_CARD, r as ScrollbarWithAnnotations, i as onScrollbarAnnotationClicked, a as onScrollbarAnnotationHovered };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/index.ts"],"sourcesContent":["import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {ScrollbarWithAnnotationsComponent} from \"./scrollbarWithAnnotations.component\";\nimport {\n SCROLLBAR_WITH_ANNOTATIONS_ACTION,\n SCROLLBAR_WITH_ANNOTATIONS_CARD,\n} from \"./scrollbarWithAnnotations.types\";\n\nexport * from \"./scrollbarWithAnnotations.types\";\n\nregisterCardComponent({\n name: SCROLLBAR_WITH_ANNOTATIONS_CARD,\n component: ScrollbarWithAnnotationsComponent,\n events: actionTypesToEvents(SCROLLBAR_WITH_ANNOTATIONS_ACTION),\n});\n"],"mappings":";;;;AAUA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAiC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { PiCardProps } from '@pihanga2/core';
|
|
3
|
+
import { ScrollbarWithAnnotationsProps, ScrollbarWithAnnotationsEvents } from './scrollbarWithAnnotations.types';
|
|
4
|
+
/**
|
|
5
|
+
* ScrollbarWithAnnotations component.
|
|
6
|
+
*
|
|
7
|
+
* Renders a scrollable area (content comes from a Pihanga card reference) with
|
|
8
|
+
* a minimap-style overlay on the scrollbar track showing coloured markers for
|
|
9
|
+
* each annotation. Clicking a marker scrolls to its position **and** emits
|
|
10
|
+
* `onAnnotationClicked` so parent code can react (e.g. open a dialog/panel).
|
|
11
|
+
*
|
|
12
|
+
* Three marker shapes are supported (see `MarkerType` in the types file):
|
|
13
|
+
* - `"point"` – small circular dot (default)
|
|
14
|
+
* - `"bar"` – short rectangle with fixed CSS height
|
|
15
|
+
* - `"range"` – rectangle proportional to `extent`, CSS `min-height` ensures
|
|
16
|
+
* it stays clickable even for very small extents
|
|
17
|
+
*
|
|
18
|
+
* All visual properties (size, colour, opacity, transitions) are controlled
|
|
19
|
+
* entirely by CSS classes so they can be overridden without touching JS.
|
|
20
|
+
*
|
|
21
|
+
* See `scrollbarWithAnnotations.example.ts` for wiring with a Pihanga Dialog.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ScrollbarWithAnnotationsComponent: (props: PiCardProps<ScrollbarWithAnnotationsProps, ScrollbarWithAnnotationsEvents>) => React.ReactNode;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import './scrollbarWithAnnotations.css';/* empty css */
|
|
2
|
+
import { useCallback as e, useEffect as t, useRef as n } from "react";
|
|
3
|
+
import { Card as r } from "@pihanga2/core";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
//#region src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.tsx
|
|
6
|
+
var o = (o) => {
|
|
7
|
+
let { contentCard: s, annotations: c = [], className: l, reportEventsOnScroll: u = !1, cardName: d, onAnnotationClicked: f, onAnnotationHovered: p } = o, m = n(null), h = n(null), g = n(!1), _ = n(null), v = e(() => {
|
|
8
|
+
let e = h.current, t = m.current;
|
|
9
|
+
if (!e || !t) return;
|
|
10
|
+
e.innerHTML = "";
|
|
11
|
+
let n = e.clientHeight, r = t.scrollHeight || 1;
|
|
12
|
+
c.forEach((i) => {
|
|
13
|
+
let a = i.markerType ?? "point", o = i.position / r * n, s = document.createElement("div");
|
|
14
|
+
if (s.className = [
|
|
15
|
+
"swa-marker",
|
|
16
|
+
`swa-marker-${a}`,
|
|
17
|
+
`swa-type-${i.type}`,
|
|
18
|
+
i.className
|
|
19
|
+
].filter(Boolean).join(" "), s.style.top = `${o}px`, a === "range" && i.extent !== void 0) {
|
|
20
|
+
let e = i.extent / r * n;
|
|
21
|
+
s.style.height = `${e}px`;
|
|
22
|
+
}
|
|
23
|
+
s.onmouseenter = () => {
|
|
24
|
+
g.current || (s.classList.add("swa-marker--hover"), p?.({
|
|
25
|
+
annotationId: i.id,
|
|
26
|
+
annotation: i
|
|
27
|
+
}));
|
|
28
|
+
}, s.onmouseleave = () => {
|
|
29
|
+
g.current || (s.classList.remove("swa-marker--hover"), p?.({
|
|
30
|
+
annotationId: null,
|
|
31
|
+
annotation: null
|
|
32
|
+
}));
|
|
33
|
+
}, s.onclick = (e) => {
|
|
34
|
+
e.stopPropagation(), t && (t.scrollTop = i.position - 50), f({
|
|
35
|
+
annotationId: i.id,
|
|
36
|
+
annotation: i
|
|
37
|
+
});
|
|
38
|
+
}, e.appendChild(s);
|
|
39
|
+
});
|
|
40
|
+
}, [
|
|
41
|
+
c,
|
|
42
|
+
f,
|
|
43
|
+
p
|
|
44
|
+
]);
|
|
45
|
+
return t(() => {
|
|
46
|
+
let e = h.current, t = m.current, n = new ResizeObserver(() => v());
|
|
47
|
+
e && n.observe(e);
|
|
48
|
+
let r = () => {
|
|
49
|
+
u || (g.current = !0, _.current !== null && clearTimeout(_.current), _.current = setTimeout(() => {
|
|
50
|
+
g.current = !1, _.current = null;
|
|
51
|
+
}, 150));
|
|
52
|
+
};
|
|
53
|
+
return t?.addEventListener("scroll", r, { passive: !0 }), () => {
|
|
54
|
+
n.disconnect(), t?.removeEventListener("scroll", r), _.current !== null && clearTimeout(_.current);
|
|
55
|
+
};
|
|
56
|
+
}, [v, u]), /* @__PURE__ */ i("div", {
|
|
57
|
+
"data-pihanga": d,
|
|
58
|
+
className: `swa-root${l ? ` ${l}` : ""}`,
|
|
59
|
+
children: /* @__PURE__ */ a("div", {
|
|
60
|
+
className: "swa-content-wrapper",
|
|
61
|
+
children: [/* @__PURE__ */ i("div", {
|
|
62
|
+
ref: m,
|
|
63
|
+
className: "swa-scroll-container",
|
|
64
|
+
children: /* @__PURE__ */ i(r, {
|
|
65
|
+
cardName: s,
|
|
66
|
+
parentCard: d
|
|
67
|
+
})
|
|
68
|
+
}), /* @__PURE__ */ i("div", {
|
|
69
|
+
ref: h,
|
|
70
|
+
className: "swa-overlay"
|
|
71
|
+
})]
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { o as ScrollbarWithAnnotationsComponent };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=scrollbarWithAnnotations.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollbarWithAnnotations.component.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.tsx"],"sourcesContent":["import React, {useRef, useEffect, useCallback} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\n\nimport type {\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents,\n ScrollbarAnnotation,\n} from \"./scrollbarWithAnnotations.types\";\n\nimport \"./scrollbarWithAnnotations.css\";\n\n/**\n * ScrollbarWithAnnotations component.\n *\n * Renders a scrollable area (content comes from a Pihanga card reference) with\n * a minimap-style overlay on the scrollbar track showing coloured markers for\n * each annotation. Clicking a marker scrolls to its position **and** emits\n * `onAnnotationClicked` so parent code can react (e.g. open a dialog/panel).\n *\n * Three marker shapes are supported (see `MarkerType` in the types file):\n * - `\"point\"` – small circular dot (default)\n * - `\"bar\"` – short rectangle with fixed CSS height\n * - `\"range\"` – rectangle proportional to `extent`, CSS `min-height` ensures\n * it stays clickable even for very small extents\n *\n * All visual properties (size, colour, opacity, transitions) are controlled\n * entirely by CSS classes so they can be overridden without touching JS.\n *\n * See `scrollbarWithAnnotations.example.ts` for wiring with a Pihanga Dialog.\n */\nexport const ScrollbarWithAnnotationsComponent = (\n props: PiCardProps<\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents\n >,\n): React.ReactNode => {\n const {\n contentCard,\n annotations = [],\n className,\n reportEventsOnScroll = false,\n cardName,\n onAnnotationClicked,\n onAnnotationHovered,\n } = props;\n\n const contentRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n\n /**\n * True while the user is actively scrolling the content container.\n * Hover events are suppressed during this period to avoid a flood of\n * `onAnnotationHovered` dispatches as the overlay passes under the cursor.\n */\n const isScrollingRef = useRef(false);\n const scrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n /**\n * (Re-)renders all annotation markers inside the overlay div.\n * Called whenever annotations change or the window is resized.\n */\n const renderMarkers = useCallback(() => {\n const overlay = overlayRef.current;\n const content = contentRef.current;\n if (!overlay || !content) return;\n\n overlay.innerHTML = \"\";\n const overlayH = overlay.clientHeight;\n const contentScrollH = content.scrollHeight || 1;\n\n annotations.forEach((anno: ScrollbarAnnotation) => {\n const markerType = anno.markerType ?? \"point\";\n const topPx = (anno.position / contentScrollH) * overlayH;\n\n const el = document.createElement(\"div\");\n // Shape class + type class carry all visual styling – no inline colour.\n // anno.className allows per-annotation overrides (e.g. \"swa-selected\").\n el.className = [\n \"swa-marker\",\n `swa-marker-${markerType}`,\n `swa-type-${anno.type}`,\n anno.className,\n ]\n .filter(Boolean)\n .join(\" \");\n el.style.top = `${topPx}px`;\n\n // For range markers, set a proportional height via inline style so the\n // overlay scales with scroll content. CSS `min-height` (defined on\n // .swa-marker-range) guarantees a minimum regardless of the ratio.\n if (markerType === \"range\" && anno.extent !== undefined) {\n const heightPx = (anno.extent / contentScrollH) * overlayH;\n el.style.height = `${heightPx}px`;\n }\n\n el.onmouseenter = () => {\n if (isScrollingRef.current) return;\n el.classList.add(\"swa-marker--hover\");\n onAnnotationHovered?.({annotationId: anno.id, annotation: anno});\n };\n el.onmouseleave = () => {\n if (isScrollingRef.current) return;\n el.classList.remove(\"swa-marker--hover\");\n onAnnotationHovered?.({annotationId: null, annotation: null});\n };\n el.onclick = (e) => {\n e.stopPropagation();\n if (content) {\n content.scrollTop = anno.position - 50;\n }\n onAnnotationClicked({annotationId: anno.id, annotation: anno});\n };\n\n overlay.appendChild(el);\n });\n }, [annotations, onAnnotationClicked, onAnnotationHovered]);\n\n // Re-render markers whenever annotations change, or the overlay is resized.\n // ResizeObserver fires on initial layout (when clientHeight goes from 0 to\n // the real value) as well as on subsequent window/container resizes, so\n // markers are always positioned against the actual DOM height.\n useEffect(() => {\n const overlay = overlayRef.current;\n const content = contentRef.current;\n\n // Observe the overlay element so markers are re-drawn whenever its size\n // changes — including the very first layout pass.\n const ro = new ResizeObserver(() => renderMarkers());\n if (overlay) ro.observe(overlay);\n\n const handleScroll = () => {\n // When reporting on scroll is enabled, skip suppression entirely.\n if (reportEventsOnScroll) return;\n\n // Set the scrolling flag so marker hover events are suppressed.\n // We intentionally do NOT dispatch a hover-clear here — marker\n // onMouseLeave events handle that when the pointer actually leaves,\n // and dispatching during scroll can interfere with parent state.\n isScrollingRef.current = true;\n\n // Reset the idle timer on every scroll event.\n if (scrollTimerRef.current !== null) {\n clearTimeout(scrollTimerRef.current);\n }\n scrollTimerRef.current = setTimeout(() => {\n isScrollingRef.current = false;\n scrollTimerRef.current = null;\n }, 150);\n };\n\n content?.addEventListener(\"scroll\", handleScroll, {passive: true});\n\n return () => {\n ro.disconnect();\n content?.removeEventListener(\"scroll\", handleScroll);\n if (scrollTimerRef.current !== null) {\n clearTimeout(scrollTimerRef.current);\n }\n };\n }, [renderMarkers, reportEventsOnScroll]);\n\n return (\n <div\n data-pihanga={cardName}\n className={`swa-root${className ? ` ${className}` : \"\"}`}\n >\n <div className=\"swa-content-wrapper\">\n {/* Scrollable content area */}\n <div ref={contentRef} className=\"swa-scroll-container\">\n <Card cardName={contentCard} parentCard={cardName} />\n </div>\n\n {/* Annotation minimap overlay – sits on top of the scrollbar track */}\n <div ref={overlayRef} className=\"swa-overlay\" />\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;AA8BA,IAAa,KACX,MAIoB;CACpB,IAAM,EACJ,gBACA,iBAAc,CAAC,GACf,cACA,0BAAuB,IACvB,aACA,wBACA,2BACE,GAEE,IAAa,EAAuB,IAAI,GACxC,IAAa,EAAuB,IAAI,GAOxC,IAAiB,EAAO,EAAK,GAC7B,IAAiB,EAA6C,IAAI,GAMlE,IAAgB,QAAkB;EACtC,IAAM,IAAU,EAAW,SACrB,IAAU,EAAW;EAC3B,IAAI,CAAC,KAAW,CAAC,GAAS;EAE1B,EAAQ,YAAY;EACpB,IAAM,IAAW,EAAQ,cACnB,IAAiB,EAAQ,gBAAgB;EAE/C,EAAY,SAAS,MAA8B;GACjD,IAAM,IAAa,EAAK,cAAc,SAChC,IAAS,EAAK,WAAW,IAAkB,GAE3C,IAAK,SAAS,cAAc,KAAK;GAgBvC,IAbA,EAAG,YAAY;IACb;IACA,cAAc;IACd,YAAY,EAAK;IACjB,EAAK;GACP,EACG,OAAO,OAAO,EACd,KAAK,GAAG,GACX,EAAG,MAAM,MAAM,GAAG,EAAM,KAKpB,MAAe,WAAW,EAAK,WAAW,KAAA,GAAW;IACvD,IAAM,IAAY,EAAK,SAAS,IAAkB;IAClD,EAAG,MAAM,SAAS,GAAG,EAAS;GAChC;GAoBA,AAlBA,EAAG,qBAAqB;IAClB,EAAe,YACnB,EAAG,UAAU,IAAI,mBAAmB,GACpC,IAAsB;KAAC,cAAc,EAAK;KAAI,YAAY;IAAI,CAAC;GACjE,GACA,EAAG,qBAAqB;IAClB,EAAe,YACnB,EAAG,UAAU,OAAO,mBAAmB,GACvC,IAAsB;KAAC,cAAc;KAAM,YAAY;IAAI,CAAC;GAC9D,GACA,EAAG,WAAW,MAAM;IAKlB,AAJA,EAAE,gBAAgB,GACd,MACF,EAAQ,YAAY,EAAK,WAAW,KAEtC,EAAoB;KAAC,cAAc,EAAK;KAAI,YAAY;IAAI,CAAC;GAC/D,GAEA,EAAQ,YAAY,CAAE;EACxB,CAAC;CACH,GAAG;EAAC;EAAa;EAAqB;CAAmB,CAAC;CA8C1D,OAxCA,QAAgB;EACd,IAAM,IAAU,EAAW,SACrB,IAAU,EAAW,SAIrB,IAAK,IAAI,qBAAqB,EAAc,CAAC;EACnD,AAAI,KAAS,EAAG,QAAQ,CAAO;EAE/B,IAAM,UAAqB;GAErB,MAMJ,EAAe,UAAU,IAGrB,EAAe,YAAY,QAC7B,aAAa,EAAe,OAAO,GAErC,EAAe,UAAU,iBAAiB;IAExC,AADA,EAAe,UAAU,IACzB,EAAe,UAAU;GAC3B,GAAG,GAAG;EACR;EAIA,OAFA,GAAS,iBAAiB,UAAU,GAAc,EAAC,SAAS,GAAI,CAAC,SAEpD;GAGX,AAFA,EAAG,WAAW,GACd,GAAS,oBAAoB,UAAU,CAAY,GAC/C,EAAe,YAAY,QAC7B,aAAa,EAAe,OAAO;EAEvC;CACF,GAAG,CAAC,GAAe,CAAoB,CAAC,GAGtC,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,WAAW,IAAY,IAAI,MAAc;YAEpD,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,KAAK;IAAY,WAAU;cAC9B,kBAAC,GAAD;KAAM,UAAU;KAAa,YAAY;IAAW,CAAA;GACjD,CAAA,GAGL,kBAAC,OAAD;IAAK,KAAK;IAAY,WAAU;GAAe,CAAA,CAC5C;;CACF,CAAA;AAET"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.swa-root{flex-direction:column;min-height:0;display:flex}.swa-content-wrapper{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.swa-scroll-container{flex:1;min-height:0;overflow:auto}.swa-scroll-container::-webkit-scrollbar{width:14px}.swa-scroll-container::-webkit-scrollbar-track{background:var(--color-background-tertiary,#f5f5f5)}.swa-scroll-container::-webkit-scrollbar-thumb{background:var(--color-border-secondary,#ccc);border:2px solid var(--color-background-primary,#fff);border-radius:6px}.swa-overlay{pointer-events:none;z-index:1;width:12px;height:100%;position:absolute;top:0;right:2px}.swa-marker{cursor:pointer;pointer-events:auto;transition:opacity .15s,transform .15s,box-shadow .15s;position:absolute;left:0}:root{--swa-point-size:10px}.swa-marker-point{width:var(--swa-point-size);height:var(--swa-point-size);border:2px solid #fff;border-radius:50%;left:2px;transform:translateY(-50%);box-shadow:0 0 4px #0000004d}.swa-marker-point.swa-marker--hover{transform:translateY(-50%)scale(1.5)}:root{--swa-bar-width:10px;--swa-bar-height:10px}.swa-marker-bar{width:var(--swa-bar-width);height:var(--swa-bar-height);opacity:.8;border-radius:1px;transform:translateY(-50%)}.swa-marker-bar.swa-marker--hover{opacity:1;box-shadow:0 0 4px #0006}:root{--swa-range-width:8px;--swa-range-min-height:8px}.swa-marker-range{width:var(--swa-range-width);min-height:var(--swa-range-min-height);opacity:.4;border-left:2px solid #fff;border-radius:2px;box-shadow:inset 0 0 2px #0003}.swa-marker-range.swa-marker--hover{opacity:.65;box-shadow:0 0 6px #0006}:root{--swa-color-error:#e24b4a;--swa-color-warning:#f39c12;--swa-color-todo:#378add;--swa-color-comment:#95a5a6;--swa-color-review:#888780;--swa-color-fixme:#ba7517}.swa-type-error{background:var(--swa-color-error)}.swa-type-warning{background:var(--swa-color-warning)}.swa-type-todo{background:var(--swa-color-todo)}.swa-type-comment{background:var(--swa-color-comment)}.swa-type-review{background:var(--swa-color-review)}.swa-type-fixme{background:var(--swa-color-fixme)}
|