mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-10-05 10:58:26 +02:00
@@ -9,6 +9,7 @@
|
|||||||
"zod": "^4.5.4",
|
"zod": "^4.5.4",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@opentui/core": "^0.5.9",
|
||||||
"@opentui/keymap": "^0.5.9",
|
"@opentui/keymap": "^0.5.9",
|
||||||
"@opentui/solid": "^0.5.9",
|
"@opentui/solid": "^0.5.9",
|
||||||
"@types/bun": "^1.3.14",
|
"@types/bun": "^1.3.14",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"solid-js": ">=1.9.0",
|
"solid-js": ">=1.9.0",
|
||||||
},
|
},
|
||||||
"optionalPeers": [
|
"optionalPeers": [
|
||||||
|
"@opentui/core",
|
||||||
"@opentui/keymap",
|
"@opentui/keymap",
|
||||||
"@opentui/solid",
|
"@opentui/solid",
|
||||||
"opentui-spinner",
|
"opentui-spinner",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
Modal
|
Modal
|
||||||
} from "./chunk-840y6ygm.js";
|
} from "./chunk-4j2gzwtd.js";
|
||||||
import {
|
import {
|
||||||
helpOpen,
|
helpOpen,
|
||||||
toggleHelp
|
toggleHelp
|
||||||
+4
-2
@@ -37,7 +37,7 @@ function Modal(props) {
|
|||||||
_$setProp(_el$2, "paddingBottom", 1);
|
_$setProp(_el$2, "paddingBottom", 1);
|
||||||
_$insert(_el$2, () => props.children);
|
_$insert(_el$2, () => props.children);
|
||||||
_$effect((_p$) => {
|
_$effect((_p$) => {
|
||||||
var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = Math.floor(dimensions().height / 4), _v$4 = props.backdropColor ?? RGBA.fromInts(0, 0, 0, 150), _v$5 = theme.mouse ? props.onDismiss : undefined, _v$6 = props.width ?? 50, _v$7 = theme.borderStyle, _v$8 = props.accentColor ?? theme.primary, _v$9 = props.backgroundColor ?? theme.background;
|
var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = Math.floor(dimensions().height / 4), _v$4 = props.backdropColor ?? RGBA.fromInts(0, 0, 0, 150), _v$5 = theme.mouse ? props.onDismiss : undefined, _v$6 = props.width ?? 50, _v$7 = theme.borderStyle, _v$8 = props.accentColor ?? theme.primary, _v$9 = props.backgroundColor ?? theme.background, _v$0 = theme.mouse ? (event) => event.stopPropagation() : undefined;
|
||||||
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
||||||
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t));
|
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t));
|
||||||
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "paddingTop", _v$3, _p$.a));
|
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "paddingTop", _v$3, _p$.a));
|
||||||
@@ -47,6 +47,7 @@ function Modal(props) {
|
|||||||
_v$7 !== _p$.s && (_p$.s = _$setProp(_el$2, "borderStyle", _v$7, _p$.s));
|
_v$7 !== _p$.s && (_p$.s = _$setProp(_el$2, "borderStyle", _v$7, _p$.s));
|
||||||
_v$8 !== _p$.h && (_p$.h = _$setProp(_el$2, "borderColor", _v$8, _p$.h));
|
_v$8 !== _p$.h && (_p$.h = _$setProp(_el$2, "borderColor", _v$8, _p$.h));
|
||||||
_v$9 !== _p$.r && (_p$.r = _$setProp(_el$2, "backgroundColor", _v$9, _p$.r));
|
_v$9 !== _p$.r && (_p$.r = _$setProp(_el$2, "backgroundColor", _v$9, _p$.r));
|
||||||
|
_v$0 !== _p$.d && (_p$.d = _$setProp(_el$2, "onMouseDown", _v$0, _p$.d));
|
||||||
return _p$;
|
return _p$;
|
||||||
}, {
|
}, {
|
||||||
e: undefined,
|
e: undefined,
|
||||||
@@ -57,7 +58,8 @@ function Modal(props) {
|
|||||||
n: undefined,
|
n: undefined,
|
||||||
s: undefined,
|
s: undefined,
|
||||||
h: undefined,
|
h: undefined,
|
||||||
r: undefined
|
r: undefined,
|
||||||
|
d: undefined
|
||||||
});
|
});
|
||||||
return _el$;
|
return _el$;
|
||||||
}
|
}
|
||||||
+29
-24
@@ -4,7 +4,6 @@ import {
|
|||||||
} from "./chunk-57mam43k.js";
|
} from "./chunk-57mam43k.js";
|
||||||
|
|
||||||
// src/components/Tabs.tsx
|
// src/components/Tabs.tsx
|
||||||
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
||||||
import { effect as _$effect } from "@opentui/solid";
|
import { effect as _$effect } from "@opentui/solid";
|
||||||
import { insertNode as _$insertNode } from "@opentui/solid";
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
||||||
import { createComponent as _$createComponent } from "@opentui/solid";
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
||||||
@@ -12,7 +11,7 @@ import { insert as _$insert } from "@opentui/solid";
|
|||||||
import { use as _$use } from "@opentui/solid";
|
import { use as _$use } from "@opentui/solid";
|
||||||
import { setProp as _$setProp } from "@opentui/solid";
|
import { setProp as _$setProp } from "@opentui/solid";
|
||||||
import { createElement as _$createElement } from "@opentui/solid";
|
import { createElement as _$createElement } from "@opentui/solid";
|
||||||
import { CliRenderEvents, TextAttributes } from "@opentui/core";
|
import { BorderChars, CliRenderEvents, TextAttributes } from "@opentui/core";
|
||||||
import { onResize, useRenderer } from "@opentui/solid";
|
import { onResize, useRenderer } from "@opentui/solid";
|
||||||
import { createMemo, createSignal, For } from "solid-js";
|
import { createMemo, createSignal, For } from "solid-js";
|
||||||
function stepTabValue(items, value, delta) {
|
function stepTabValue(items, value, delta) {
|
||||||
@@ -27,21 +26,21 @@ function innerWidth(label) {
|
|||||||
function segmentWidth(label) {
|
function segmentWidth(label) {
|
||||||
return innerWidth(label) + 2;
|
return innerWidth(label) + 2;
|
||||||
}
|
}
|
||||||
function topEdge(label) {
|
function topEdge(chars, label) {
|
||||||
return `\u256D${"\u2500".repeat(innerWidth(label))}\u256E`;
|
return `${chars.topLeft}${chars.horizontal.repeat(innerWidth(label))}${chars.topRight}`;
|
||||||
}
|
}
|
||||||
function bottomEdge(label, isFirst, isLast, isActive) {
|
function bottomEdge(chars, label, isFirst, isLast, isActive) {
|
||||||
const left = isFirst ? isActive ? "\u2502" : "\u251C" : isActive ? "\u256F" : "\u2534";
|
const left = isFirst ? isActive ? chars.vertical : chars.leftT : isActive ? chars.bottomRight : chars.bottomT;
|
||||||
const right = isLast ? isActive ? "\u2502" : "\u2524" : isActive ? "\u2570" : "\u2534";
|
const right = isLast ? isActive ? chars.vertical : chars.rightT : isActive ? chars.bottomLeft : chars.bottomT;
|
||||||
const fill = isActive ? " " : "\u2500";
|
const fill = isActive ? " " : chars.horizontal;
|
||||||
return left + fill.repeat(innerWidth(label)) + right;
|
return left + fill.repeat(innerWidth(label)) + right;
|
||||||
}
|
}
|
||||||
function buildBottomRow(segments, available) {
|
function buildBottomRow(chars, segments, available) {
|
||||||
const tabsWidth = segments.reduce((sum, s) => sum + segmentWidth(s.label), 0);
|
const tabsWidth = segments.reduce((sum, s) => sum + segmentWidth(s.label), 0);
|
||||||
const remainder = available - tabsWidth;
|
const remainder = available - tabsWidth;
|
||||||
const extending = remainder > 0;
|
const extending = remainder > 0;
|
||||||
const tabs = segments.map((s, i) => bottomEdge(s.label, i === 0, i === segments.length - 1 && !extending, s.isActive)).join("");
|
const tabs = segments.map((s, i) => bottomEdge(chars, s.label, i === 0, i === segments.length - 1 && !extending, s.isActive)).join("");
|
||||||
return extending ? tabs + "\u2500".repeat(remainder - 1) + "\u256E" : tabs;
|
return extending ? tabs + chars.horizontal.repeat(remainder - 1) + chars.topRight : tabs;
|
||||||
}
|
}
|
||||||
function fitCount(items, start, available) {
|
function fitCount(items, start, available) {
|
||||||
const hiddenBefore = start;
|
const hiddenBefore = start;
|
||||||
@@ -102,6 +101,7 @@ function Tabs(props) {
|
|||||||
const accent = () => props.accentColor ?? theme.primary;
|
const accent = () => props.accentColor ?? theme.primary;
|
||||||
const muted = () => props.mutedColor ?? theme.muted;
|
const muted = () => props.mutedColor ?? theme.muted;
|
||||||
const borderColor = () => props.focused ? accent() : muted();
|
const borderColor = () => props.focused ? accent() : muted();
|
||||||
|
const chars = BorderChars[theme.borderStyle];
|
||||||
return (() => {
|
return (() => {
|
||||||
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text");
|
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text");
|
||||||
_$insertNode(_el$, _el$2);
|
_$insertNode(_el$, _el$2);
|
||||||
@@ -112,7 +112,8 @@ function Tabs(props) {
|
|||||||
remeasureNextFrame();
|
remeasureNextFrame();
|
||||||
}, _el$);
|
}, _el$);
|
||||||
_$setProp(_el$, "flexDirection", "column");
|
_$setProp(_el$, "flexDirection", "column");
|
||||||
_$insert(_el$2, () => segments().map((s) => topEdge(s.label)).join(""));
|
_$setProp(_el$2, "selectable", false);
|
||||||
|
_$insert(_el$2, () => segments().map((s) => topEdge(chars, s.label)).join(""));
|
||||||
_$setProp(_el$3, "flexDirection", "row");
|
_$setProp(_el$3, "flexDirection", "row");
|
||||||
_$insert(_el$3, _$createComponent(For, {
|
_$insert(_el$3, _$createComponent(For, {
|
||||||
get each() {
|
get each() {
|
||||||
@@ -120,32 +121,36 @@ function Tabs(props) {
|
|||||||
},
|
},
|
||||||
children: (s) => [(() => {
|
children: (s) => [(() => {
|
||||||
var _el$5 = _$createElement("text");
|
var _el$5 = _$createElement("text");
|
||||||
_$insertNode(_el$5, _$createTextNode(`\u2502`));
|
_$setProp(_el$5, "selectable", false);
|
||||||
|
_$insert(_el$5, () => chars.vertical);
|
||||||
_$effect((_$p) => _$setProp(_el$5, "fg", borderColor(), _$p));
|
_$effect((_$p) => _$setProp(_el$5, "fg", borderColor(), _$p));
|
||||||
return _el$5;
|
return _el$5;
|
||||||
})(), (() => {
|
})(), (() => {
|
||||||
var _el$7 = _$createElement("text");
|
var _el$6 = _$createElement("text");
|
||||||
_$insert(_el$7, () => ` ${s.label} `);
|
_$setProp(_el$6, "selectable", false);
|
||||||
|
_$insert(_el$6, () => ` ${s.label} `);
|
||||||
_$effect((_p$) => {
|
_$effect((_p$) => {
|
||||||
var _v$3 = s.isActive ? accent() : muted(), _v$4 = s.isActive ? TextAttributes.BOLD : undefined, _v$5 = theme.mouse && s.value !== undefined ? () => props.onChange(s.value) : undefined;
|
var _v$3 = s.isActive ? accent() : muted(), _v$4 = s.isActive ? TextAttributes.BOLD : undefined, _v$5 = theme.mouse && s.value !== undefined ? () => props.onChange(s.value) : undefined;
|
||||||
_v$3 !== _p$.e && (_p$.e = _$setProp(_el$7, "fg", _v$3, _p$.e));
|
_v$3 !== _p$.e && (_p$.e = _$setProp(_el$6, "fg", _v$3, _p$.e));
|
||||||
_v$4 !== _p$.t && (_p$.t = _$setProp(_el$7, "attributes", _v$4, _p$.t));
|
_v$4 !== _p$.t && (_p$.t = _$setProp(_el$6, "attributes", _v$4, _p$.t));
|
||||||
_v$5 !== _p$.a && (_p$.a = _$setProp(_el$7, "onMouseDown", _v$5, _p$.a));
|
_v$5 !== _p$.a && (_p$.a = _$setProp(_el$6, "onMouseDown", _v$5, _p$.a));
|
||||||
return _p$;
|
return _p$;
|
||||||
}, {
|
}, {
|
||||||
e: undefined,
|
e: undefined,
|
||||||
t: undefined,
|
t: undefined,
|
||||||
a: undefined
|
a: undefined
|
||||||
});
|
});
|
||||||
return _el$7;
|
return _el$6;
|
||||||
})(), (() => {
|
})(), (() => {
|
||||||
var _el$8 = _$createElement("text");
|
var _el$7 = _$createElement("text");
|
||||||
_$insertNode(_el$8, _$createTextNode(`\u2502`));
|
_$setProp(_el$7, "selectable", false);
|
||||||
_$effect((_$p) => _$setProp(_el$8, "fg", borderColor(), _$p));
|
_$insert(_el$7, () => chars.vertical);
|
||||||
return _el$8;
|
_$effect((_$p) => _$setProp(_el$7, "fg", borderColor(), _$p));
|
||||||
|
return _el$7;
|
||||||
})()]
|
})()]
|
||||||
}));
|
}));
|
||||||
_$insert(_el$4, () => buildBottomRow(segments(), width()));
|
_$setProp(_el$4, "selectable", false);
|
||||||
|
_$insert(_el$4, () => buildBottomRow(chars, segments(), width()));
|
||||||
_$effect((_p$) => {
|
_$effect((_p$) => {
|
||||||
var _v$ = borderColor(), _v$2 = borderColor();
|
var _v$ = borderColor(), _v$2 = borderColor();
|
||||||
_v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e));
|
_v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e));
|
||||||
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// @bun
|
||||||
|
import {
|
||||||
|
theme
|
||||||
|
} from "./chunk-57mam43k.js";
|
||||||
|
|
||||||
|
// src/components/MinSizeGuard.tsx
|
||||||
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
||||||
|
import { effect as _$effect } from "@opentui/solid";
|
||||||
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
||||||
|
import { insert as _$insert } from "@opentui/solid";
|
||||||
|
import { setProp as _$setProp } from "@opentui/solid";
|
||||||
|
import { createElement as _$createElement } from "@opentui/solid";
|
||||||
|
import { memo as _$memo } from "@opentui/solid";
|
||||||
|
import { useTerminalDimensions } from "@opentui/solid";
|
||||||
|
import { Show } from "solid-js";
|
||||||
|
function MinSizeGuard(props) {
|
||||||
|
const dimensions = useTerminalDimensions();
|
||||||
|
const minWidth = () => props.minWidth ?? 80;
|
||||||
|
const minHeight = () => props.minHeight ?? 24;
|
||||||
|
const tooSmall = () => dimensions().width < minWidth() || dimensions().height < minHeight();
|
||||||
|
return [_$memo(() => props.children), _$createComponent(Show, {
|
||||||
|
get when() {
|
||||||
|
return tooSmall();
|
||||||
|
},
|
||||||
|
get children() {
|
||||||
|
var _el$ = _$createElement("box"), _el$2 = _$createElement("text");
|
||||||
|
_$insertNode(_el$, _el$2);
|
||||||
|
_$setProp(_el$, "position", "absolute");
|
||||||
|
_$setProp(_el$, "top", 0);
|
||||||
|
_$setProp(_el$, "left", 0);
|
||||||
|
_$setProp(_el$, "alignItems", "center");
|
||||||
|
_$setProp(_el$, "justifyContent", "center");
|
||||||
|
_$setProp(_el$, "zIndex", 9999);
|
||||||
|
_$insert(_el$2, () => `Terminal too small
|
||||||
|
Minimum size: ${minWidth()}x${minHeight()} \u2014 current: ${dimensions().width}x${dimensions().height}`);
|
||||||
|
_$effect((_p$) => {
|
||||||
|
var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backgroundColor ?? theme.background, _v$4 = props.textColor ?? theme.muted;
|
||||||
|
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
||||||
|
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t));
|
||||||
|
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$3, _p$.a));
|
||||||
|
_v$4 !== _p$.o && (_p$.o = _$setProp(_el$2, "fg", _v$4, _p$.o));
|
||||||
|
return _p$;
|
||||||
|
}, {
|
||||||
|
e: undefined,
|
||||||
|
t: undefined,
|
||||||
|
a: undefined,
|
||||||
|
o: undefined
|
||||||
|
});
|
||||||
|
return _el$;
|
||||||
|
}
|
||||||
|
})];
|
||||||
|
}
|
||||||
|
|
||||||
|
export { MinSizeGuard };
|
||||||
Vendored
-60
@@ -1,60 +0,0 @@
|
|||||||
// @bun
|
|
||||||
import {
|
|
||||||
theme
|
|
||||||
} from "./chunk-57mam43k.js";
|
|
||||||
|
|
||||||
// src/components/MinSizeGuard.tsx
|
|
||||||
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
||||||
import { effect as _$effect } from "@opentui/solid";
|
|
||||||
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
||||||
import { insert as _$insert } from "@opentui/solid";
|
|
||||||
import { setProp as _$setProp } from "@opentui/solid";
|
|
||||||
import { createElement as _$createElement } from "@opentui/solid";
|
|
||||||
import { useTerminalDimensions } from "@opentui/solid";
|
|
||||||
import { Match, Switch } from "solid-js";
|
|
||||||
function MinSizeGuard(props) {
|
|
||||||
const dimensions = useTerminalDimensions();
|
|
||||||
const minWidth = () => props.minWidth ?? 80;
|
|
||||||
const minHeight = () => props.minHeight ?? 24;
|
|
||||||
const tooSmall = () => dimensions().width < minWidth() || dimensions().height < minHeight();
|
|
||||||
return _$createComponent(Switch, {
|
|
||||||
get children() {
|
|
||||||
return [_$createComponent(Match, {
|
|
||||||
get when() {
|
|
||||||
return tooSmall();
|
|
||||||
},
|
|
||||||
get children() {
|
|
||||||
var _el$ = _$createElement("box"), _el$2 = _$createElement("text");
|
|
||||||
_$insertNode(_el$, _el$2);
|
|
||||||
_$setProp(_el$, "alignItems", "center");
|
|
||||||
_$setProp(_el$, "justifyContent", "center");
|
|
||||||
_$insert(_el$2, () => `Terminal too small
|
|
||||||
Minimum size: ${minWidth()}x${minHeight()} \u2014 current: ${dimensions().width}x${dimensions().height}`);
|
|
||||||
_$effect((_p$) => {
|
|
||||||
var _v$ = dimensions().width, _v$2 = dimensions().height, _v$3 = props.backgroundColor ?? theme.background, _v$4 = props.textColor ?? theme.muted;
|
|
||||||
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
|
||||||
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$2, _p$.t));
|
|
||||||
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$3, _p$.a));
|
|
||||||
_v$4 !== _p$.o && (_p$.o = _$setProp(_el$2, "fg", _v$4, _p$.o));
|
|
||||||
return _p$;
|
|
||||||
}, {
|
|
||||||
e: undefined,
|
|
||||||
t: undefined,
|
|
||||||
a: undefined,
|
|
||||||
o: undefined
|
|
||||||
});
|
|
||||||
return _el$;
|
|
||||||
}
|
|
||||||
}), _$createComponent(Match, {
|
|
||||||
get when() {
|
|
||||||
return !tooSmall();
|
|
||||||
},
|
|
||||||
get children() {
|
|
||||||
return props.children;
|
|
||||||
}
|
|
||||||
})];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export { MinSizeGuard };
|
|
||||||
Vendored
+128
@@ -0,0 +1,128 @@
|
|||||||
|
// @bun
|
||||||
|
import {
|
||||||
|
presets,
|
||||||
|
theme
|
||||||
|
} from "./chunk-57mam43k.js";
|
||||||
|
|
||||||
|
// src/components/Sidebar.tsx
|
||||||
|
import { use as _$use } from "@opentui/solid";
|
||||||
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
||||||
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
||||||
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
||||||
|
import { effect as _$effect } from "@opentui/solid";
|
||||||
|
import { insert as _$insert } from "@opentui/solid";
|
||||||
|
import { setProp as _$setProp } from "@opentui/solid";
|
||||||
|
import { createElement as _$createElement } from "@opentui/solid";
|
||||||
|
import { TextAttributes } from "@opentui/core";
|
||||||
|
import { Show } from "solid-js";
|
||||||
|
function itemIndexAtScreenY(el, screenY) {
|
||||||
|
const internals = el;
|
||||||
|
if (!internals.linesPerItem)
|
||||||
|
return null;
|
||||||
|
const localY = screenY - el.screenY;
|
||||||
|
if (localY < 0)
|
||||||
|
return null;
|
||||||
|
const index = internals.scrollOffset + Math.floor(localY / internals.linesPerItem);
|
||||||
|
return index >= 0 && index < el.options.length ? index : null;
|
||||||
|
}
|
||||||
|
function Sidebar(props) {
|
||||||
|
let select;
|
||||||
|
const handleMouseDown = (event) => {
|
||||||
|
if (!select)
|
||||||
|
return;
|
||||||
|
const index = itemIndexAtScreenY(select, event.y);
|
||||||
|
if (index !== null)
|
||||||
|
select.setSelectedIndex(index);
|
||||||
|
};
|
||||||
|
const handleMouseScroll = (event) => {
|
||||||
|
if (!select || !event.scroll)
|
||||||
|
return;
|
||||||
|
const steps = Math.max(1, event.scroll.delta);
|
||||||
|
if (event.scroll.direction === "down")
|
||||||
|
select.moveDown(steps);
|
||||||
|
else if (event.scroll.direction === "up")
|
||||||
|
select.moveUp(steps);
|
||||||
|
};
|
||||||
|
return (() => {
|
||||||
|
var _el$ = _$createElement("box"), _el$5 = _$createElement("select");
|
||||||
|
_$insertNode(_el$, _el$5);
|
||||||
|
_$setProp(_el$, "border", true);
|
||||||
|
_$setProp(_el$, "flexDirection", "column");
|
||||||
|
_$insert(_el$, _$createComponent(Show, {
|
||||||
|
get when() {
|
||||||
|
return props.title;
|
||||||
|
},
|
||||||
|
get children() {
|
||||||
|
return [(() => {
|
||||||
|
var _el$2 = _$createElement("text");
|
||||||
|
_$insert(_el$2, () => props.title);
|
||||||
|
_$effect((_$p) => _$setProp(_el$2, "attributes", TextAttributes.BOLD, _$p));
|
||||||
|
return _el$2;
|
||||||
|
})(), (() => {
|
||||||
|
var _el$3 = _$createElement("text");
|
||||||
|
_$insertNode(_el$3, _$createTextNode(` `));
|
||||||
|
return _el$3;
|
||||||
|
})()];
|
||||||
|
}
|
||||||
|
}), _el$5);
|
||||||
|
_$use((el) => {
|
||||||
|
select = el ?? undefined;
|
||||||
|
props.ref?.(el && {
|
||||||
|
moveUp: () => el.moveUp(),
|
||||||
|
moveDown: () => el.moveDown(),
|
||||||
|
selectCurrent: () => el.selectCurrent(),
|
||||||
|
focus: () => el.focus()
|
||||||
|
});
|
||||||
|
}, _el$5);
|
||||||
|
_$setProp(_el$5, "flexGrow", 1);
|
||||||
|
_$setProp(_el$5, "showScrollIndicator", true);
|
||||||
|
_$setProp(_el$5, "onChange", (_index, option) => {
|
||||||
|
if (!option)
|
||||||
|
return;
|
||||||
|
props.onSelect(option);
|
||||||
|
});
|
||||||
|
_$setProp(_el$5, "onSelect", (_index, option) => {
|
||||||
|
if (!option)
|
||||||
|
return;
|
||||||
|
props.onConfirm?.(option);
|
||||||
|
});
|
||||||
|
_$effect((_p$) => {
|
||||||
|
var _v$ = props.width ?? 24, _v$2 = theme.borderStyle, _v$3 = props.focused ? props.accentColor ?? theme.primary : props.mutedColor ?? theme.muted, _v$4 = props.focused, _v$5 = props.items, _v$6 = theme.mouse ? handleMouseDown : undefined, _v$7 = theme.mouse ? handleMouseScroll : undefined, _v$8 = props.backgroundColor ?? "transparent", _v$9 = props.textColor ?? presets.select.textColor, _v$0 = props.focusedBackgroundColor ?? "transparent", _v$1 = props.focusedTextColor ?? presets.select.focusedTextColor, _v$10 = props.selectedBackgroundColor ?? presets.select.selectedBackgroundColor, _v$11 = props.selectedTextColor ?? presets.select.selectedTextColor, _v$12 = props.descriptionColor ?? presets.select.descriptionColor, _v$13 = props.selectedDescriptionColor ?? presets.select.selectedDescriptionColor;
|
||||||
|
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
||||||
|
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "borderStyle", _v$2, _p$.t));
|
||||||
|
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "borderColor", _v$3, _p$.a));
|
||||||
|
_v$4 !== _p$.o && (_p$.o = _$setProp(_el$5, "focused", _v$4, _p$.o));
|
||||||
|
_v$5 !== _p$.i && (_p$.i = _$setProp(_el$5, "options", _v$5, _p$.i));
|
||||||
|
_v$6 !== _p$.n && (_p$.n = _$setProp(_el$5, "onMouseDown", _v$6, _p$.n));
|
||||||
|
_v$7 !== _p$.s && (_p$.s = _$setProp(_el$5, "onMouseScroll", _v$7, _p$.s));
|
||||||
|
_v$8 !== _p$.h && (_p$.h = _$setProp(_el$5, "backgroundColor", _v$8, _p$.h));
|
||||||
|
_v$9 !== _p$.r && (_p$.r = _$setProp(_el$5, "textColor", _v$9, _p$.r));
|
||||||
|
_v$0 !== _p$.d && (_p$.d = _$setProp(_el$5, "focusedBackgroundColor", _v$0, _p$.d));
|
||||||
|
_v$1 !== _p$.l && (_p$.l = _$setProp(_el$5, "focusedTextColor", _v$1, _p$.l));
|
||||||
|
_v$10 !== _p$.u && (_p$.u = _$setProp(_el$5, "selectedBackgroundColor", _v$10, _p$.u));
|
||||||
|
_v$11 !== _p$.c && (_p$.c = _$setProp(_el$5, "selectedTextColor", _v$11, _p$.c));
|
||||||
|
_v$12 !== _p$.w && (_p$.w = _$setProp(_el$5, "descriptionColor", _v$12, _p$.w));
|
||||||
|
_v$13 !== _p$.m && (_p$.m = _$setProp(_el$5, "selectedDescriptionColor", _v$13, _p$.m));
|
||||||
|
return _p$;
|
||||||
|
}, {
|
||||||
|
e: undefined,
|
||||||
|
t: undefined,
|
||||||
|
a: undefined,
|
||||||
|
o: undefined,
|
||||||
|
i: undefined,
|
||||||
|
n: undefined,
|
||||||
|
s: undefined,
|
||||||
|
h: undefined,
|
||||||
|
r: undefined,
|
||||||
|
d: undefined,
|
||||||
|
l: undefined,
|
||||||
|
u: undefined,
|
||||||
|
c: undefined,
|
||||||
|
w: undefined,
|
||||||
|
m: undefined
|
||||||
|
});
|
||||||
|
return _el$;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Sidebar };
|
||||||
Vendored
-78
@@ -1,78 +0,0 @@
|
|||||||
// @bun
|
|
||||||
import {
|
|
||||||
theme
|
|
||||||
} from "./chunk-57mam43k.js";
|
|
||||||
|
|
||||||
// src/components/Sidebar.tsx
|
|
||||||
import { effect as _$effect } from "@opentui/solid";
|
|
||||||
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
||||||
import { use as _$use } from "@opentui/solid";
|
|
||||||
import { insert as _$insert } from "@opentui/solid";
|
|
||||||
import { setProp as _$setProp } from "@opentui/solid";
|
|
||||||
import { createElement as _$createElement } from "@opentui/solid";
|
|
||||||
import { TextAttributes } from "@opentui/core";
|
|
||||||
function Sidebar(props) {
|
|
||||||
return (() => {
|
|
||||||
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("select");
|
|
||||||
_$insertNode(_el$, _el$2);
|
|
||||||
_$insertNode(_el$, _el$3);
|
|
||||||
_$setProp(_el$, "border", true);
|
|
||||||
_$setProp(_el$, "flexDirection", "column");
|
|
||||||
_$insert(_el$2, () => props.title);
|
|
||||||
_$use((el) => {
|
|
||||||
props.ref?.(el && {
|
|
||||||
moveUp: () => el.moveUp(),
|
|
||||||
moveDown: () => el.moveDown(),
|
|
||||||
selectCurrent: () => el.selectCurrent()
|
|
||||||
});
|
|
||||||
}, _el$3);
|
|
||||||
_$setProp(_el$3, "flexGrow", 1);
|
|
||||||
_$setProp(_el$3, "showScrollIndicator", true);
|
|
||||||
_$setProp(_el$3, "onChange", (_index, option) => {
|
|
||||||
if (!option)
|
|
||||||
return;
|
|
||||||
props.onSelect(option);
|
|
||||||
});
|
|
||||||
_$setProp(_el$3, "onSelect", (_index, option) => {
|
|
||||||
if (!option)
|
|
||||||
return;
|
|
||||||
props.onConfirm?.(option);
|
|
||||||
});
|
|
||||||
_$effect((_p$) => {
|
|
||||||
var _v$ = props.width ?? 24, _v$2 = theme.borderStyle, _v$3 = props.focused ? props.accentColor ?? theme.primary : props.mutedColor ?? theme.muted, _v$4 = TextAttributes.BOLD, _v$5 = props.focused, _v$6 = props.items, _v$7 = props.backgroundColor, _v$8 = props.textColor, _v$9 = props.focusedBackgroundColor, _v$0 = props.focusedTextColor, _v$1 = props.selectedBackgroundColor, _v$10 = props.selectedTextColor, _v$11 = props.descriptionColor, _v$12 = props.selectedDescriptionColor;
|
|
||||||
_v$ !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$, _p$.e));
|
|
||||||
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "borderStyle", _v$2, _p$.t));
|
|
||||||
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "borderColor", _v$3, _p$.a));
|
|
||||||
_v$4 !== _p$.o && (_p$.o = _$setProp(_el$2, "attributes", _v$4, _p$.o));
|
|
||||||
_v$5 !== _p$.i && (_p$.i = _$setProp(_el$3, "focused", _v$5, _p$.i));
|
|
||||||
_v$6 !== _p$.n && (_p$.n = _$setProp(_el$3, "options", _v$6, _p$.n));
|
|
||||||
_v$7 !== _p$.s && (_p$.s = _$setProp(_el$3, "backgroundColor", _v$7, _p$.s));
|
|
||||||
_v$8 !== _p$.h && (_p$.h = _$setProp(_el$3, "textColor", _v$8, _p$.h));
|
|
||||||
_v$9 !== _p$.r && (_p$.r = _$setProp(_el$3, "focusedBackgroundColor", _v$9, _p$.r));
|
|
||||||
_v$0 !== _p$.d && (_p$.d = _$setProp(_el$3, "focusedTextColor", _v$0, _p$.d));
|
|
||||||
_v$1 !== _p$.l && (_p$.l = _$setProp(_el$3, "selectedBackgroundColor", _v$1, _p$.l));
|
|
||||||
_v$10 !== _p$.u && (_p$.u = _$setProp(_el$3, "selectedTextColor", _v$10, _p$.u));
|
|
||||||
_v$11 !== _p$.c && (_p$.c = _$setProp(_el$3, "descriptionColor", _v$11, _p$.c));
|
|
||||||
_v$12 !== _p$.w && (_p$.w = _$setProp(_el$3, "selectedDescriptionColor", _v$12, _p$.w));
|
|
||||||
return _p$;
|
|
||||||
}, {
|
|
||||||
e: undefined,
|
|
||||||
t: undefined,
|
|
||||||
a: undefined,
|
|
||||||
o: undefined,
|
|
||||||
i: undefined,
|
|
||||||
n: undefined,
|
|
||||||
s: undefined,
|
|
||||||
h: undefined,
|
|
||||||
r: undefined,
|
|
||||||
d: undefined,
|
|
||||||
l: undefined,
|
|
||||||
u: undefined,
|
|
||||||
c: undefined,
|
|
||||||
w: undefined
|
|
||||||
});
|
|
||||||
return _el$;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
export { Sidebar };
|
|
||||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
HelpModal
|
HelpModal
|
||||||
} from "../chunk-ydf2rnsn.js";
|
} from "../chunk-2n7bvge9.js";
|
||||||
import"../chunk-840y6ygm.js";
|
import"../chunk-4j2gzwtd.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
MinSizeGuard
|
MinSizeGuard
|
||||||
} from "../chunk-syn54rcq.js";
|
} from "../chunk-nr74cgcr.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
Modal
|
Modal
|
||||||
} from "../chunk-840y6ygm.js";
|
} from "../chunk-4j2gzwtd.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
Sidebar
|
Sidebar
|
||||||
} from "../chunk-wkg33t3z.js";
|
} from "../chunk-vve1k0ax.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
import {
|
import {
|
||||||
Tabs,
|
Tabs,
|
||||||
stepTabValue
|
stepTabValue
|
||||||
} from "../chunk-d2tt920p.js";
|
} from "../chunk-4jy6s3k0.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
import {
|
||||||
HelpModal
|
HelpModal
|
||||||
} from "../chunk-ydf2rnsn.js";
|
} from "../chunk-2n7bvge9.js";
|
||||||
import"../chunk-840y6ygm.js";
|
import"../chunk-4j2gzwtd.js";
|
||||||
import {
|
import {
|
||||||
HelpBar
|
HelpBar
|
||||||
} from "../chunk-dv2w3sfk.js";
|
} from "../chunk-dv2w3sfk.js";
|
||||||
|
|||||||
Vendored
+8
-8
@@ -1,10 +1,7 @@
|
|||||||
// @bun
|
// @bun
|
||||||
import {
|
|
||||||
ProgressBar
|
|
||||||
} from "../chunk-ae0jkf2z.js";
|
|
||||||
import {
|
import {
|
||||||
Sidebar
|
Sidebar
|
||||||
} from "../chunk-wkg33t3z.js";
|
} from "../chunk-vve1k0ax.js";
|
||||||
import {
|
import {
|
||||||
SignalBars
|
SignalBars
|
||||||
} from "../chunk-xab9ag99.js";
|
} from "../chunk-xab9ag99.js";
|
||||||
@@ -14,19 +11,22 @@ import {
|
|||||||
import {
|
import {
|
||||||
Toggle
|
Toggle
|
||||||
} from "../chunk-zs53wnet.js";
|
} from "../chunk-zs53wnet.js";
|
||||||
|
import {
|
||||||
|
MinSizeGuard
|
||||||
|
} from "../chunk-nr74cgcr.js";
|
||||||
import {
|
import {
|
||||||
Tabs,
|
Tabs,
|
||||||
stepTabValue
|
stepTabValue
|
||||||
} from "../chunk-d2tt920p.js";
|
} from "../chunk-4jy6s3k0.js";
|
||||||
import {
|
import {
|
||||||
Modal
|
Modal
|
||||||
} from "../chunk-840y6ygm.js";
|
} from "../chunk-4j2gzwtd.js";
|
||||||
import {
|
import {
|
||||||
Badge
|
Badge
|
||||||
} from "../chunk-shxcerba.js";
|
} from "../chunk-shxcerba.js";
|
||||||
import {
|
import {
|
||||||
MinSizeGuard
|
ProgressBar
|
||||||
} from "../chunk-syn54rcq.js";
|
} from "../chunk-ae0jkf2z.js";
|
||||||
import"../chunk-57mam43k.js";
|
import"../chunk-57mam43k.js";
|
||||||
import"../chunk-ergc99dh.js";
|
import"../chunk-ergc99dh.js";
|
||||||
import"../chunk-7f8jagy5.js";
|
import"../chunk-7f8jagy5.js";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ColorInput } from "@opentui/core";
|
import type { ColorInput } from "@opentui/core";
|
||||||
import { useTerminalDimensions } from "@opentui/solid";
|
import { useTerminalDimensions } from "@opentui/solid";
|
||||||
import { Match, Switch, type ParentProps } from "solid-js";
|
import { Show, type ParentProps } from "solid-js";
|
||||||
import { theme } from "../index.ts";
|
import { theme } from "../index.ts";
|
||||||
|
|
||||||
export interface MinSizeGuardProps extends ParentProps {
|
export interface MinSizeGuardProps extends ParentProps {
|
||||||
@@ -17,21 +17,25 @@ export function MinSizeGuard(props: MinSizeGuardProps) {
|
|||||||
const tooSmall = () => dimensions().width < minWidth() || dimensions().height < minHeight();
|
const tooSmall = () => dimensions().width < minWidth() || dimensions().height < minHeight();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<>
|
||||||
<Match when={tooSmall()}>
|
{props.children}
|
||||||
|
<Show when={tooSmall()}>
|
||||||
<box
|
<box
|
||||||
|
position="absolute"
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
width={dimensions().width}
|
width={dimensions().width}
|
||||||
height={dimensions().height}
|
height={dimensions().height}
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
backgroundColor={props.backgroundColor ?? theme.background}
|
backgroundColor={props.backgroundColor ?? theme.background}
|
||||||
|
zIndex={9999}
|
||||||
>
|
>
|
||||||
<text fg={props.textColor ?? theme.muted}>
|
<text fg={props.textColor ?? theme.muted}>
|
||||||
{`Terminal too small\nMinimum size: ${minWidth()}x${minHeight()} — current: ${dimensions().width}x${dimensions().height}`}
|
{`Terminal too small\nMinimum size: ${minWidth()}x${minHeight()} — current: ${dimensions().width}x${dimensions().height}`}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Show>
|
||||||
<Match when={!tooSmall()}>{props.children}</Match>
|
</>
|
||||||
</Switch>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type ColorInput, RGBA } from "@opentui/core";
|
import { type ColorInput, type MouseEvent, RGBA } from "@opentui/core";
|
||||||
import { Portal, useTerminalDimensions } from "@opentui/solid";
|
import { Portal, useTerminalDimensions } from "@opentui/solid";
|
||||||
import { Show, type ParentProps } from "solid-js";
|
import { Show, type ParentProps } from "solid-js";
|
||||||
import { theme } from "../index.ts";
|
import { theme } from "../index.ts";
|
||||||
@@ -41,6 +41,7 @@ export function Modal(props: ModalProps) {
|
|||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
|
onMouseDown={theme.mouse ? (event: MouseEvent) => event.stopPropagation() : undefined}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</box>
|
</box>
|
||||||
|
|||||||
+44
-11
@@ -1,14 +1,25 @@
|
|||||||
import { type ColorInput, type SelectOption, TextAttributes } from "@opentui/core";
|
import { type ColorInput, type MouseEvent, type SelectOption, type SelectRenderable, TextAttributes } from "@opentui/core";
|
||||||
import { theme } from "../index.ts";
|
import { Show } from "solid-js";
|
||||||
|
import { presets, theme } from "../index.ts";
|
||||||
|
|
||||||
export interface SidebarHandle {
|
export interface SidebarHandle {
|
||||||
moveUp(): void;
|
moveUp(): void;
|
||||||
moveDown(): void;
|
moveDown(): void;
|
||||||
selectCurrent(): void;
|
selectCurrent(): void;
|
||||||
|
focus(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemIndexAtScreenY(el: SelectRenderable, screenY: number): number | null {
|
||||||
|
const internals = el as unknown as { scrollOffset: number; linesPerItem: number };
|
||||||
|
if (!internals.linesPerItem) return null;
|
||||||
|
const localY = screenY - el.screenY;
|
||||||
|
if (localY < 0) return null;
|
||||||
|
const index = internals.scrollOffset + Math.floor(localY / internals.linesPerItem);
|
||||||
|
return index >= 0 && index < el.options.length ? index : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SidebarProps {
|
export interface SidebarProps {
|
||||||
title: string;
|
title?: string;
|
||||||
items: SelectOption[];
|
items: SelectOption[];
|
||||||
width?: number;
|
width?: number;
|
||||||
focused?: boolean;
|
focused?: boolean;
|
||||||
@@ -30,6 +41,21 @@ export interface SidebarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Sidebar(props: SidebarProps) {
|
export function Sidebar(props: SidebarProps) {
|
||||||
|
let select: SelectRenderable | undefined;
|
||||||
|
|
||||||
|
const handleMouseDown = (event: MouseEvent) => {
|
||||||
|
if (!select) return;
|
||||||
|
const index = itemIndexAtScreenY(select, event.y);
|
||||||
|
if (index !== null) select.setSelectedIndex(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseScroll = (event: MouseEvent) => {
|
||||||
|
if (!select || !event.scroll) return;
|
||||||
|
const steps = Math.max(1, event.scroll.delta);
|
||||||
|
if (event.scroll.direction === "down") select.moveDown(steps);
|
||||||
|
else if (event.scroll.direction === "up") select.moveUp(steps);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
width={props.width ?? 24}
|
width={props.width ?? 24}
|
||||||
@@ -38,14 +64,19 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
borderColor={props.focused ? (props.accentColor ?? theme.primary) : (props.mutedColor ?? theme.muted)}
|
borderColor={props.focused ? (props.accentColor ?? theme.primary) : (props.mutedColor ?? theme.muted)}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
>
|
>
|
||||||
|
<Show when={props.title}>
|
||||||
<text attributes={TextAttributes.BOLD}>{props.title}</text>
|
<text attributes={TextAttributes.BOLD}>{props.title}</text>
|
||||||
|
<text> </text>
|
||||||
|
</Show>
|
||||||
<select
|
<select
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
|
select = el ?? undefined;
|
||||||
props.ref?.(
|
props.ref?.(
|
||||||
el && {
|
el && {
|
||||||
moveUp: () => el.moveUp(),
|
moveUp: () => el.moveUp(),
|
||||||
moveDown: () => el.moveDown(),
|
moveDown: () => el.moveDown(),
|
||||||
selectCurrent: () => el.selectCurrent(),
|
selectCurrent: () => el.selectCurrent(),
|
||||||
|
focus: () => el.focus(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
@@ -53,14 +84,16 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
focused={props.focused}
|
focused={props.focused}
|
||||||
showScrollIndicator
|
showScrollIndicator
|
||||||
options={props.items}
|
options={props.items}
|
||||||
backgroundColor={props.backgroundColor}
|
onMouseDown={theme.mouse ? handleMouseDown : undefined}
|
||||||
textColor={props.textColor}
|
onMouseScroll={theme.mouse ? handleMouseScroll : undefined}
|
||||||
focusedBackgroundColor={props.focusedBackgroundColor}
|
backgroundColor={props.backgroundColor ?? "transparent"}
|
||||||
focusedTextColor={props.focusedTextColor}
|
textColor={props.textColor ?? presets.select.textColor}
|
||||||
selectedBackgroundColor={props.selectedBackgroundColor}
|
focusedBackgroundColor={props.focusedBackgroundColor ?? "transparent"}
|
||||||
selectedTextColor={props.selectedTextColor}
|
focusedTextColor={props.focusedTextColor ?? presets.select.focusedTextColor}
|
||||||
descriptionColor={props.descriptionColor}
|
selectedBackgroundColor={props.selectedBackgroundColor ?? presets.select.selectedBackgroundColor}
|
||||||
selectedDescriptionColor={props.selectedDescriptionColor}
|
selectedTextColor={props.selectedTextColor ?? presets.select.selectedTextColor}
|
||||||
|
descriptionColor={props.descriptionColor ?? presets.select.descriptionColor}
|
||||||
|
selectedDescriptionColor={props.selectedDescriptionColor ?? presets.select.selectedDescriptionColor}
|
||||||
onChange={(_index, option) => {
|
onChange={(_index, option) => {
|
||||||
if (!option) return;
|
if (!option) return;
|
||||||
props.onSelect(option);
|
props.onSelect(option);
|
||||||
|
|||||||
+30
-14
@@ -1,4 +1,4 @@
|
|||||||
import { type ColorInput, CliRenderEvents, TextAttributes, type BoxRenderable } from "@opentui/core";
|
import { type BorderCharacters, type BoxRenderable, type ColorInput, BorderChars, CliRenderEvents, TextAttributes } from "@opentui/core";
|
||||||
import { onResize, useRenderer } from "@opentui/solid";
|
import { onResize, useRenderer } from "@opentui/solid";
|
||||||
import { createMemo, createSignal, For } from "solid-js";
|
import { createMemo, createSignal, For } from "solid-js";
|
||||||
import { theme } from "../index.ts";
|
import { theme } from "../index.ts";
|
||||||
@@ -31,27 +31,31 @@ function segmentWidth(label: string): number {
|
|||||||
return innerWidth(label) + 2;
|
return innerWidth(label) + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function topEdge(label: string): string {
|
function topEdge(chars: BorderCharacters, label: string): string {
|
||||||
return `╭${"─".repeat(innerWidth(label))}╮`;
|
return `${chars.topLeft}${chars.horizontal.repeat(innerWidth(label))}${chars.topRight}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bottomEdge(label: string, isFirst: boolean, isLast: boolean, isActive: boolean): string {
|
function bottomEdge(chars: BorderCharacters, label: string, isFirst: boolean, isLast: boolean, isActive: boolean): string {
|
||||||
const left = isFirst ? (isActive ? "│" : "├") : isActive ? "╯" : "┴";
|
const left = isFirst ? (isActive ? chars.vertical : chars.leftT) : isActive ? chars.bottomRight : chars.bottomT;
|
||||||
const right = isLast ? (isActive ? "│" : "┤") : isActive ? "╰" : "┴";
|
const right = isLast ? (isActive ? chars.vertical : chars.rightT) : isActive ? chars.bottomLeft : chars.bottomT;
|
||||||
const fill = isActive ? " " : "─";
|
const fill = isActive ? " " : chars.horizontal;
|
||||||
return left + fill.repeat(innerWidth(label)) + right;
|
return left + fill.repeat(innerWidth(label)) + right;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildBottomRow(segments: { label: string; isActive: boolean }[], available: number): string {
|
function buildBottomRow(
|
||||||
|
chars: BorderCharacters,
|
||||||
|
segments: { label: string; isActive: boolean }[],
|
||||||
|
available: number,
|
||||||
|
): string {
|
||||||
const tabsWidth = segments.reduce((sum, s) => sum + segmentWidth(s.label), 0);
|
const tabsWidth = segments.reduce((sum, s) => sum + segmentWidth(s.label), 0);
|
||||||
const remainder = available - tabsWidth;
|
const remainder = available - tabsWidth;
|
||||||
const extending = remainder > 0;
|
const extending = remainder > 0;
|
||||||
|
|
||||||
const tabs = segments
|
const tabs = segments
|
||||||
.map((s, i) => bottomEdge(s.label, i === 0, i === segments.length - 1 && !extending, s.isActive))
|
.map((s, i) => bottomEdge(chars, s.label, i === 0, i === segments.length - 1 && !extending, s.isActive))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
return extending ? tabs + "─".repeat(remainder - 1) + "╮" : tabs;
|
return extending ? tabs + chars.horizontal.repeat(remainder - 1) + chars.topRight : tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fitCount(items: TabItem[], start: number, available: number): number {
|
function fitCount(items: TabItem[], start: number, available: number): number {
|
||||||
@@ -117,6 +121,7 @@ export function Tabs(props: TabsProps) {
|
|||||||
const muted = () => props.mutedColor ?? theme.muted;
|
const muted = () => props.mutedColor ?? theme.muted;
|
||||||
|
|
||||||
const borderColor = () => (props.focused ? accent() : muted());
|
const borderColor = () => (props.focused ? accent() : muted());
|
||||||
|
const chars = BorderChars[theme.borderStyle];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
@@ -126,25 +131,36 @@ export function Tabs(props: TabsProps) {
|
|||||||
remeasureNextFrame();
|
remeasureNextFrame();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={borderColor()}>{segments().map((s) => topEdge(s.label)).join("")}</text>
|
<text selectable={false} fg={borderColor()}>
|
||||||
|
{segments()
|
||||||
|
.map((s) => topEdge(chars, s.label))
|
||||||
|
.join("")}
|
||||||
|
</text>
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<For each={segments()}>
|
<For each={segments()}>
|
||||||
{(s) => (
|
{(s) => (
|
||||||
<>
|
<>
|
||||||
<text fg={borderColor()}>│</text>
|
<text selectable={false} fg={borderColor()}>
|
||||||
|
{chars.vertical}
|
||||||
|
</text>
|
||||||
<text
|
<text
|
||||||
|
selectable={false}
|
||||||
fg={s.isActive ? accent() : muted()}
|
fg={s.isActive ? accent() : muted()}
|
||||||
attributes={s.isActive ? TextAttributes.BOLD : undefined}
|
attributes={s.isActive ? TextAttributes.BOLD : undefined}
|
||||||
onMouseDown={theme.mouse && s.value !== undefined ? () => props.onChange(s.value!) : undefined}
|
onMouseDown={theme.mouse && s.value !== undefined ? () => props.onChange(s.value!) : undefined}
|
||||||
>
|
>
|
||||||
{` ${s.label} `}
|
{` ${s.label} `}
|
||||||
</text>
|
</text>
|
||||||
<text fg={borderColor()}>│</text>
|
<text selectable={false} fg={borderColor()}>
|
||||||
|
{chars.vertical}
|
||||||
|
</text>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
<text fg={borderColor()}>{buildBottomRow(segments(), width())}</text>
|
<text selectable={false} fg={borderColor()}>
|
||||||
|
{buildBottomRow(chars, segments(), width())}
|
||||||
|
</text>
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user