diff --git a/.gitignore b/.gitignore index b947077..c2658d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ node_modules/ -dist/ diff --git a/dist/chunk-2px9e43p.js b/dist/chunk-2px9e43p.js new file mode 100644 index 0000000..abd798f --- /dev/null +++ b/dist/chunk-2px9e43p.js @@ -0,0 +1,26 @@ +// @bun +// src/context/helper.tsx +import { createComponent as _$createComponent } from "@opentui/solid"; +import { createContext, useContext } from "solid-js"; +function createSimpleContext(input) { + const ctx = createContext(); + return { + provider: (props) => { + const value = input.init(props); + return _$createComponent(ctx.Provider, { + value, + get children() { + return props.children; + } + }); + }, + use() { + const value = useContext(ctx); + if (!value) + throw new Error(`${input.name} context must be used within its provider`); + return value; + } + }; +} + +export { createSimpleContext }; diff --git a/dist/chunk-57mam43k.js b/dist/chunk-57mam43k.js new file mode 100644 index 0000000..3880d51 --- /dev/null +++ b/dist/chunk-57mam43k.js @@ -0,0 +1,45 @@ +// @bun +import { + buildPresets +} from "./chunk-ergc99dh.js"; +import { + configPath, + readYamlFile +} from "./chunk-7f8jagy5.js"; +import { + mergeConfig, + normalizeColors, + resolveBorderStyle +} from "./chunk-hcq62p48.js"; + +// src/index.ts +import { join } from "path"; +function buildTheme() { + const defaultConfigPath = join(import.meta.dir, "default.yaml"); + const base = readYamlFile(defaultConfigPath) ?? {}; + const user = readYamlFile(configPath()) ?? {}; + const merged = mergeConfig(base, user); + const colors = normalizeColors(merged.colors); + return { + ...colors, + background: colors.base00, + subtleBg: colors.base01, + selection: colors.base02, + subtle: colors.base03, + muted: colors.base04, + text: colors.base05, + primary: colors.base0d, + success: colors.base0b, + warning: colors.base09, + error: colors.base08, + nerdFonts: merged.nerdFonts, + emojiFonts: merged.emojiFonts, + reducedMotion: merged.reducedMotion, + mouse: merged.mouse, + borderStyle: resolveBorderStyle(merged.border) + }; +} +var theme = buildTheme(); +var presets = buildPresets(theme); + +export { theme, presets }; diff --git a/dist/chunk-7f8jagy5.js b/dist/chunk-7f8jagy5.js new file mode 100644 index 0000000..094e75d --- /dev/null +++ b/dist/chunk-7f8jagy5.js @@ -0,0 +1,22 @@ +// @bun +// src/yaml.ts +import { existsSync, readFileSync } from "fs"; +import { homedir } from "os"; +import { join } from "path"; +import { parse as parseYAML } from "yaml"; +function configPath() { + const configDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config"); + return join(configDir, "ilovetui", "config.yaml"); +} +function readYamlFile(path) { + if (!existsSync(path)) + return; + try { + return parseYAML(readFileSync(path, "utf8")) ?? undefined; + } catch (err) { + console.error(`ilovetui: failed to parse ${path}, ignoring it.`, err); + return; + } +} + +export { configPath, readYamlFile }; diff --git a/dist/chunk-840y6ygm.js b/dist/chunk-840y6ygm.js new file mode 100644 index 0000000..b18ab61 --- /dev/null +++ b/dist/chunk-840y6ygm.js @@ -0,0 +1,69 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/Modal.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 { RGBA } from "@opentui/core"; +import { Portal, useTerminalDimensions } from "@opentui/solid"; +import { Show } from "solid-js"; +function Modal(props) { + const dimensions = useTerminalDimensions(); + return _$createComponent(Portal, { + get children() { + return _$createComponent(Show, { + get when() { + return props.open; + }, + get children() { + var _el$ = _$createElement("box"), _el$2 = _$createElement("box"); + _$insertNode(_el$, _el$2); + _$setProp(_el$, "position", "absolute"); + _$setProp(_el$, "top", 0); + _$setProp(_el$, "left", 0); + _$setProp(_el$, "alignItems", "center"); + _$setProp(_el$, "zIndex", 2000); + _$setProp(_el$2, "border", true); + _$setProp(_el$2, "flexDirection", "column"); + _$setProp(_el$2, "paddingLeft", 2); + _$setProp(_el$2, "paddingRight", 2); + _$setProp(_el$2, "paddingTop", 1); + _$setProp(_el$2, "paddingBottom", 1); + _$insert(_el$2, () => props.children); + _$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; + _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$, "paddingTop", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "backgroundColor", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$, "onMouseDown", _v$5, _p$.i)); + _v$6 !== _p$.n && (_p$.n = _$setProp(_el$2, "width", _v$6, _p$.n)); + _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$9 !== _p$.r && (_p$.r = _$setProp(_el$2, "backgroundColor", _v$9, _p$.r)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined, + n: undefined, + s: undefined, + h: undefined, + r: undefined + }); + return _el$; + } + }); + } + }); +} + +export { Modal }; diff --git a/dist/chunk-ae0jkf2z.js b/dist/chunk-ae0jkf2z.js new file mode 100644 index 0000000..919448d --- /dev/null +++ b/dist/chunk-ae0jkf2z.js @@ -0,0 +1,58 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/ProgressBar.tsx +import { effect as _$effect } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { parseColor, RGBA } from "@opentui/core"; +import { createMemo, For } from "solid-js"; +function sampleGradient(stops, t) { + if (stops.length === 1) + return stops[0]; + const clamped = Math.min(Math.max(t, 0), 1); + const segment = clamped * (stops.length - 1); + const i = Math.min(Math.floor(segment), stops.length - 2); + const localT = segment - i; + const [ar, ag, ab, aa] = parseColor(stops[i]).toInts(); + const [br, bg, bb, ba] = parseColor(stops[i + 1]).toInts(); + return RGBA.fromInts(Math.round(ar + (br - ar) * localT), Math.round(ag + (bg - ag) * localT), Math.round(ab + (bb - ab) * localT), Math.round(aa + (ba - aa) * localT)); +} +function ProgressBar(props) { + const width = () => props.width ?? 20; + const stops = createMemo(() => Array.isArray(props.color) ? props.color : [props.color ?? theme.primary]); + const filled = createMemo(() => Math.round(width() * Math.min(Math.max(props.value, 0), 100) / 100)); + const cells = createMemo(() => Array.from({ + length: width() + }, (_, i) => i)); + return (() => { + var _el$ = _$createElement("box"); + _$setProp(_el$, "flexDirection", "row"); + _$insert(_el$, _$createComponent(For, { + get each() { + return cells(); + }, + children: (i) => { + const isFilled = () => i < filled(); + const t = width() > 1 ? i / (width() - 1) : 0; + return (() => { + var _el$2 = _$createElement("text"); + _$insert(_el$2, (() => { + var _c$ = _$memo(() => !!isFilled()); + return () => _c$() ? props.fillChar ?? "\u2588" : props.trackChar ?? "\u2591"; + })()); + _$effect((_$p) => _$setProp(_el$2, "fg", isFilled() ? sampleGradient(stops(), t) : props.trackColor ?? theme.muted, _$p)); + return _el$2; + })(); + } + })); + return _el$; + })(); +} + +export { ProgressBar }; diff --git a/dist/chunk-cyvpvpws.js b/dist/chunk-cyvpvpws.js new file mode 100644 index 0000000..25a10f1 --- /dev/null +++ b/dist/chunk-cyvpvpws.js @@ -0,0 +1,9 @@ +// @bun +// src/context/help.ts +import { createSignal } from "solid-js"; +var [helpOpen, setHelpOpen] = createSignal(false); +function toggleHelp() { + setHelpOpen((open) => !open); +} + +export { helpOpen, toggleHelp }; diff --git a/dist/chunk-d2tt920p.js b/dist/chunk-d2tt920p.js new file mode 100644 index 0000000..9668401 --- /dev/null +++ b/dist/chunk-d2tt920p.js @@ -0,0 +1,162 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/Tabs.tsx +import { createTextNode as _$createTextNode } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { use as _$use } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { CliRenderEvents, TextAttributes } from "@opentui/core"; +import { onResize, useRenderer } from "@opentui/solid"; +import { createMemo, createSignal, For } from "solid-js"; +function stepTabValue(items, value, delta) { + const index = items.findIndex((t) => t.value === value); + if (index === -1) + return value; + return items[(index + delta + items.length) % items.length].value; +} +function innerWidth(label) { + return label.length + 2; +} +function segmentWidth(label) { + return innerWidth(label) + 2; +} +function topEdge(label) { + return `\u256D${"\u2500".repeat(innerWidth(label))}\u256E`; +} +function bottomEdge(label, isFirst, isLast, isActive) { + const left = isFirst ? isActive ? "\u2502" : "\u251C" : isActive ? "\u256F" : "\u2534"; + const right = isLast ? isActive ? "\u2502" : "\u2524" : isActive ? "\u2570" : "\u2534"; + const fill = isActive ? " " : "\u2500"; + return left + fill.repeat(innerWidth(label)) + right; +} +function buildBottomRow(segments, available) { + const tabsWidth = segments.reduce((sum, s) => sum + segmentWidth(s.label), 0); + const remainder = available - tabsWidth; + const extending = remainder > 0; + const tabs = segments.map((s, i) => bottomEdge(s.label, i === 0, i === segments.length - 1 && !extending, s.isActive)).join(""); + return extending ? tabs + "\u2500".repeat(remainder - 1) + "\u256E" : tabs; +} +function fitCount(items, start, available) { + const hiddenBefore = start; + let used = 0; + let count = 0; + for (let i = start;i < items.length; i++) { + const width = segmentWidth(items[i].label); + const hiddenAfter = items.length - start - count - 1; + const totalHidden = hiddenBefore + hiddenAfter; + const reserve = totalHidden > 0 ? segmentWidth(`+${totalHidden}`) : 0; + if (used + width + reserve > available) + break; + used += width; + count++; + } + return Math.max(count, 1); +} +function Tabs(props) { + const renderer = useRenderer(); + const [width, setWidth] = createSignal(0); + let container; + const measure = () => { + if (!container) + return; + setWidth(container.width); + }; + const remeasureNextFrame = () => renderer.once(CliRenderEvents.FRAME, measure); + onResize(remeasureNextFrame); + const segments = createMemo(() => { + const items = props.items; + const activeIndex = Math.max(0, items.findIndex((t) => t.value === props.value)); + let start = 0; + let count = fitCount(items, start, width()); + if (activeIndex >= start + count) { + start = activeIndex; + count = fitCount(items, start, width()); + } + const shownItems = items.slice(start, start + count); + const shown = shownItems.map((item) => ({ + value: item.value, + label: item.label, + isActive: item.value === props.value + })); + const hidden = items.length - count; + if (hidden > 0) { + const used = shownItems.reduce((sum, item) => sum + segmentWidth(item.label), 0); + const tag = `+${hidden}`; + if (shown.length === 0 || used + segmentWidth(tag) <= width()) { + shown.push({ + value: undefined, + label: tag, + isActive: false + }); + } + } + return shown; + }); + const accent = () => props.accentColor ?? theme.primary; + const muted = () => props.mutedColor ?? theme.muted; + const borderColor = () => props.focused ? accent() : muted(); + return (() => { + var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text"); + _$insertNode(_el$, _el$2); + _$insertNode(_el$, _el$3); + _$insertNode(_el$, _el$4); + _$use((el) => { + container = el; + remeasureNextFrame(); + }, _el$); + _$setProp(_el$, "flexDirection", "column"); + _$insert(_el$2, () => segments().map((s) => topEdge(s.label)).join("")); + _$setProp(_el$3, "flexDirection", "row"); + _$insert(_el$3, _$createComponent(For, { + get each() { + return segments(); + }, + children: (s) => [(() => { + var _el$5 = _$createElement("text"); + _$insertNode(_el$5, _$createTextNode(`\u2502`)); + _$effect((_$p) => _$setProp(_el$5, "fg", borderColor(), _$p)); + return _el$5; + })(), (() => { + var _el$7 = _$createElement("text"); + _$insert(_el$7, () => ` ${s.label} `); + _$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; + _v$3 !== _p$.e && (_p$.e = _$setProp(_el$7, "fg", _v$3, _p$.e)); + _v$4 !== _p$.t && (_p$.t = _$setProp(_el$7, "attributes", _v$4, _p$.t)); + _v$5 !== _p$.a && (_p$.a = _$setProp(_el$7, "onMouseDown", _v$5, _p$.a)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined + }); + return _el$7; + })(), (() => { + var _el$8 = _$createElement("text"); + _$insertNode(_el$8, _$createTextNode(`\u2502`)); + _$effect((_$p) => _$setProp(_el$8, "fg", borderColor(), _$p)); + return _el$8; + })()] + })); + _$insert(_el$4, () => buildBottomRow(segments(), width())); + _$effect((_p$) => { + var _v$ = borderColor(), _v$2 = borderColor(); + _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$4, "fg", _v$2, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$; + })(); +} + +export { stepTabValue, Tabs }; diff --git a/dist/chunk-dv2w3sfk.js b/dist/chunk-dv2w3sfk.js new file mode 100644 index 0000000..da295de --- /dev/null +++ b/dist/chunk-dv2w3sfk.js @@ -0,0 +1,121 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/HelpBar.tsx +import { createTextNode as _$createTextNode } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { use as _$use } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { CliRenderEvents, TextAttributes } from "@opentui/core"; +import { onResize, useRenderer } from "@opentui/solid"; +import { formatCommandBindings } from "@opentui/keymap/extras"; +import { useKeymapSelector } from "@opentui/keymap/solid"; +import { createMemo, createSignal, For } from "solid-js"; +var KEY_DISPLAY = { + up: "\u2191", + down: "\u2193", + left: "\u2190", + right: "\u2192", + enter: "Enter", + escape: "Esc" +}; +var SEPARATOR = " "; +var ELLIPSIS = "\u2026"; +function HelpBar(props = {}) { + const accent = () => props.accentColor ?? theme.primary; + const muted = () => props.mutedColor ?? theme.muted; + const renderer = useRenderer(); + const [width, setWidth] = createSignal(0); + let container; + const measure = () => { + if (!container) + return; + setWidth(container.width); + }; + const remeasureNextFrame = () => renderer.once(CliRenderEvents.FRAME, measure); + onResize(remeasureNextFrame); + const entries = useKeymapSelector((keymap) => keymap.getCommandEntries({ + visibility: "active" + }).filter((entry) => entry.command.shortHelp === true).map((entry) => ({ + command: entry.command.name, + keys: formatCommandBindings(entry.bindings, { + keyNameAliases: KEY_DISPLAY + }) ?? "", + label: typeof entry.command.desc === "string" ? entry.command.desc : entry.command.name + }))); + const visible = createMemo(() => { + const available = width() - 2; + const shown = []; + let used = 0; + for (const entry of entries()) { + const sepWidth = shown.length > 0 ? SEPARATOR.length : 0; + const entryWidth = entry.keys.length + 1 + entry.label.length; + if (used + sepWidth + entryWidth <= available) { + used += sepWidth + entryWidth; + shown.push(entry); + continue; + } + const remaining = available - used - sepWidth; + const prefix = `${entry.keys} `; + if (remaining > prefix.length + ELLIPSIS.length) { + const labelBudget = remaining - prefix.length - ELLIPSIS.length; + shown.push({ + ...entry, + label: `${entry.label.slice(0, labelBudget)}${ELLIPSIS}` + }); + } + break; + } + return shown; + }); + return (() => { + var _el$ = _$createElement("box"); + _$use((el) => { + container = el; + remeasureNextFrame(); + }, _el$); + _$setProp(_el$, "flexDirection", "row"); + _$setProp(_el$, "paddingLeft", 1); + _$setProp(_el$, "paddingRight", 1); + _$setProp(_el$, "overflow", "hidden"); + _$insert(_el$, _$createComponent(For, { + get each() { + return visible(); + }, + children: (entry, i) => [_$memo(() => _$memo(() => i() > 0)() && (() => { + var _el$4 = _$createElement("text"); + _$insertNode(_el$4, _$createTextNode(` `)); + _$effect((_$p) => _$setProp(_el$4, "fg", muted(), _$p)); + return _el$4; + })()), (() => { + var _el$2 = _$createElement("text"); + _$insert(_el$2, () => entry.keys); + _$effect((_p$) => { + var _v$ = accent(), _v$2 = TextAttributes.BOLD; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "attributes", _v$2, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$2; + })(), (() => { + var _el$3 = _$createElement("text"); + _$insert(_el$3, () => ` ${entry.label}`); + _$effect((_$p) => _$setProp(_el$3, "fg", muted(), _$p)); + return _el$3; + })()] + })); + return _el$; + })(); +} + +export { HelpBar }; diff --git a/dist/chunk-ergc99dh.js b/dist/chunk-ergc99dh.js new file mode 100644 index 0000000..81e30fb --- /dev/null +++ b/dist/chunk-ergc99dh.js @@ -0,0 +1,40 @@ +// @bun +// src/presets.ts +function buildPresets(theme) { + const select = { + backgroundColor: theme.background, + textColor: theme.text, + focusedBackgroundColor: theme.subtleBg, + focusedTextColor: theme.text, + selectedBackgroundColor: theme.selection, + selectedTextColor: theme.primary, + descriptionColor: theme.muted, + selectedDescriptionColor: theme.text + }; + const tabSelect = { + backgroundColor: theme.background, + textColor: theme.text, + focusedBackgroundColor: theme.subtleBg, + focusedTextColor: theme.text, + selectedBackgroundColor: theme.selection, + selectedTextColor: theme.primary, + selectedDescriptionColor: theme.text + }; + const input = { + backgroundColor: theme.background, + textColor: theme.text, + focusedBackgroundColor: theme.subtleBg, + focusedTextColor: theme.text, + placeholderColor: theme.muted + }; + const box = { + border: true, + borderStyle: theme.borderStyle, + borderColor: theme.subtle, + focusedBorderColor: theme.primary, + backgroundColor: theme.background + }; + return { select, tabSelect, input, textarea: input, box }; +} + +export { buildPresets }; diff --git a/dist/chunk-g7p0f33m.js b/dist/chunk-g7p0f33m.js new file mode 100644 index 0000000..f07e036 --- /dev/null +++ b/dist/chunk-g7p0f33m.js @@ -0,0 +1,77 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; +import { + dismiss, + notifications +} from "./chunk-y6txxzxk.js"; + +// src/components/NotificationHost.tsx +import { effect as _$effect } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { Portal } from "@opentui/solid"; +import { For } from "solid-js"; +var KIND_LABEL = { + info: "Info", + success: "Success", + warning: "Warning", + error: "Error" +}; +function NotificationHost(props = {}) { + const defaultColor = () => ({ + info: theme.primary, + success: theme.success, + warning: theme.warning, + error: theme.error + }); + const colorFor = (kind) => props.colors?.[kind] ?? defaultColor()[kind]; + return _$createComponent(Portal, { + get children() { + var _el$ = _$createElement("box"); + _$setProp(_el$, "position", "absolute"); + _$setProp(_el$, "top", 1); + _$setProp(_el$, "right", 1); + _$setProp(_el$, "flexDirection", "column"); + _$setProp(_el$, "zIndex", 1000); + _$insert(_el$, _$createComponent(For, { + get each() { + return notifications(); + }, + children: (toast) => (() => { + var _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"); + _$insertNode(_el$2, _el$3); + _$insertNode(_el$2, _el$4); + _$setProp(_el$2, "border", true); + _$setProp(_el$2, "marginBottom", 1); + _$insert(_el$3, () => toast.title ?? KIND_LABEL[toast.kind]); + _$insert(_el$4, () => toast.message); + _$effect((_p$) => { + var _v$ = theme.borderStyle, _v$2 = colorFor(toast.kind), _v$3 = props.width ?? 32, _v$4 = theme.mouse ? () => dismiss(toast.id) : undefined, _v$5 = colorFor(toast.kind); + _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "borderStyle", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "borderColor", _v$2, _p$.t)); + _v$3 !== _p$.a && (_p$.a = _$setProp(_el$2, "width", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$2, "onMouseDown", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$3, "fg", _v$5, _p$.i)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined + }); + return _el$2; + })() + })); + return _el$; + } + }); +} + +export { NotificationHost }; diff --git a/dist/chunk-hcq62p48.js b/dist/chunk-hcq62p48.js new file mode 100644 index 0000000..c5a9fbc --- /dev/null +++ b/dist/chunk-hcq62p48.js @@ -0,0 +1,60 @@ +// @bun +// src/config.ts +var COLOR_KEYS = [ + "base00", + "base01", + "base02", + "base03", + "base04", + "base05", + "base06", + "base07", + "base08", + "base09", + "base0a", + "base0b", + "base0c", + "base0d", + "base0e", + "base0f" +]; +function mergeColors(base, user) { + const merged = {}; + for (const key of COLOR_KEYS) { + merged[key] = user[key] || base[key] || ""; + } + return merged; +} +function mergeConfig(base, user) { + return { + nerdFonts: user.nerd_fonts ?? base.nerd_fonts ?? false, + emojiFonts: user.emoji_fonts ?? base.emoji_fonts ?? false, + reducedMotion: user.reduced_motion ?? base.reduced_motion ?? false, + mouse: user.mouse ?? base.mouse ?? true, + border: user.border || base.border || "rounded", + colors: mergeColors(base.colors ?? {}, user.colors ?? {}) + }; +} +function normalizeColor(hex) { + const trimmed = hex.trim(); + if (trimmed && !trimmed.startsWith("#")) + return `#${trimmed}`; + return trimmed; +} +function normalizeColors(colors) { + const out = {}; + for (const key of COLOR_KEYS) + out[key] = normalizeColor(colors[key]); + return out; +} +var OPENTUI_BORDER_STYLES = [ + "single", + "double", + "rounded", + "heavy" +]; +function resolveBorderStyle(name) { + return OPENTUI_BORDER_STYLES.includes(name) ? name : "rounded"; +} + +export { COLOR_KEYS, mergeColors, mergeConfig, normalizeColor, normalizeColors, resolveBorderStyle }; diff --git a/dist/chunk-shxcerba.js b/dist/chunk-shxcerba.js new file mode 100644 index 0000000..fcb3486 --- /dev/null +++ b/dist/chunk-shxcerba.js @@ -0,0 +1,80 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/Badge.tsx +import { insertNode as _$insertNode } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { effect as _$effect } 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 Badge(props) { + const textColor = () => props.textColor ?? theme.background; + const backgroundColor = () => props.backgroundColor ?? theme.background; + const attributes = () => props.bold === false ? undefined : TextAttributes.BOLD; + const nerdFonts = () => props.withNerdfont ?? theme.nerdFonts; + return (() => { + var _el$ = _$createElement("box"), _el$3 = _$createElement("text"); + _$insertNode(_el$, _el$3); + _$setProp(_el$, "flexDirection", "row"); + _$insert(_el$, _$createComponent(Show, { + get when() { + return nerdFonts(); + }, + get children() { + var _el$2 = _$createElement("text"); + _$effect((_p$) => { + var _v$ = props.color, _v$2 = backgroundColor(); + _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "bg", _v$2, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$2; + } + }), _el$3); + _$insert(_el$3, (() => { + var _c$ = _$memo(() => !!nerdFonts()); + return () => _c$() ? props.label : ` ${props.label} `; + })()); + _$insert(_el$, _$createComponent(Show, { + get when() { + return nerdFonts(); + }, + get children() { + var _el$4 = _$createElement("text"); + _$effect((_p$) => { + var _v$3 = props.color, _v$4 = backgroundColor(); + _v$3 !== _p$.e && (_p$.e = _$setProp(_el$4, "fg", _v$3, _p$.e)); + _v$4 !== _p$.t && (_p$.t = _$setProp(_el$4, "bg", _v$4, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$4; + } + }), null); + _$effect((_p$) => { + var _v$5 = textColor(), _v$6 = props.color, _v$7 = attributes(); + _v$5 !== _p$.e && (_p$.e = _$setProp(_el$3, "fg", _v$5, _p$.e)); + _v$6 !== _p$.t && (_p$.t = _$setProp(_el$3, "bg", _v$6, _p$.t)); + _v$7 !== _p$.a && (_p$.a = _$setProp(_el$3, "attributes", _v$7, _p$.a)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined + }); + return _el$; + })(); +} + +export { Badge }; diff --git a/dist/chunk-syn54rcq.js b/dist/chunk-syn54rcq.js new file mode 100644 index 0000000..305f23f --- /dev/null +++ b/dist/chunk-syn54rcq.js @@ -0,0 +1,60 @@ +// @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 }; diff --git a/dist/chunk-wkg33t3z.js b/dist/chunk-wkg33t3z.js new file mode 100644 index 0000000..9be64e3 --- /dev/null +++ b/dist/chunk-wkg33t3z.js @@ -0,0 +1,78 @@ +// @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 }; diff --git a/dist/chunk-xab9ag99.js b/dist/chunk-xab9ag99.js new file mode 100644 index 0000000..32096c0 --- /dev/null +++ b/dist/chunk-xab9ag99.js @@ -0,0 +1,32 @@ +// @bun +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/SignalBars.tsx +import { effect as _$effect } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { For } from "solid-js"; +var BARS = ["\u2581", "\u2583", "\u2585", "\u2587"]; +function SignalBars(props) { + const level = () => Math.floor(props.signal * BARS.length / 100); + return (() => { + var _el$ = _$createElement("box"); + _$setProp(_el$, "flexDirection", "row"); + _$insert(_el$, _$createComponent(For, { + each: BARS, + children: (bar, i) => (() => { + var _el$2 = _$createElement("text"); + _$insert(_el$2, bar); + _$effect((_$p) => _$setProp(_el$2, "fg", i() < level() ? props.filledColor : props.emptyColor ?? theme.muted, _$p)); + return _el$2; + })() + })); + return _el$; + })(); +} + +export { SignalBars }; diff --git a/dist/chunk-y6txxzxk.js b/dist/chunk-y6txxzxk.js new file mode 100644 index 0000000..c5fdb1d --- /dev/null +++ b/dist/chunk-y6txxzxk.js @@ -0,0 +1,21 @@ +// @bun +// src/context/notifications.ts +import { createSignal } from "solid-js"; +var DEFAULT_DURATION = 3000; +var [notifications, setNotifications] = createSignal([]); +var nextId = 0; +function notify(message, options = {}) { + const id = options.id ?? `toast-${nextId++}`; + const toast = { id, title: options.title, message, kind: options.kind ?? "info" }; + setNotifications((prev) => [...prev.filter((n) => n.id !== id), toast]); + const duration = options.duration ?? DEFAULT_DURATION; + if (duration > 0) { + setTimeout(() => dismiss(id), duration); + } + return id; +} +function dismiss(id) { + setNotifications((prev) => prev.filter((n) => n.id !== id)); +} + +export { notifications, notify, dismiss }; diff --git a/dist/chunk-ydf2rnsn.js b/dist/chunk-ydf2rnsn.js new file mode 100644 index 0000000..28f1caa --- /dev/null +++ b/dist/chunk-ydf2rnsn.js @@ -0,0 +1,76 @@ +// @bun +import { + Modal +} from "./chunk-840y6ygm.js"; +import { + helpOpen, + toggleHelp +} from "./chunk-cyvpvpws.js"; + +// src/components/HelpModal.tsx +import { createComponent as _$createComponent } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { setProp as _$setProp } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { createTextNode as _$createTextNode } from "@opentui/solid"; +import { insertNode as _$insertNode } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { TextAttributes } from "@opentui/core"; +import { formatCommandBindings } from "@opentui/keymap/extras"; +import { useKeymapSelector } from "@opentui/keymap/solid"; +var KEY_DISPLAY = { + up: "\u2191", + down: "\u2193", + left: "\u2190", + right: "\u2192", + enter: "Enter", + escape: "Esc" +}; +function HelpModal(props = {}) { + const entries = useKeymapSelector((keymap) => keymap.getCommandEntries({ + visibility: "active" + }).map((entry) => ({ + command: entry.command.name, + keys: formatCommandBindings(entry.bindings, { + keyNameAliases: KEY_DISPLAY + }) ?? "", + label: typeof entry.command.desc === "string" ? entry.command.desc : entry.command.name + }))); + return _$createComponent(Modal, { + get open() { + return helpOpen(); + }, + onDismiss: toggleHelp, + get accentColor() { + return props.accentColor; + }, + get backgroundColor() { + return props.backgroundColor; + }, + get backdropColor() { + return props.backdropColor; + }, + get width() { + return props.width; + }, + get children() { + return [(() => { + var _el$ = _$createElement("text"); + _$insertNode(_el$, _$createTextNode(`Keybindings`)); + _$effect((_$p) => _$setProp(_el$, "attributes", TextAttributes.BOLD, _$p)); + return _el$; + })(), (() => { + var _el$3 = _$createElement("text"); + _$insertNode(_el$3, _$createTextNode(` `)); + return _el$3; + })(), (() => { + var _el$5 = _$createElement("text"); + _$insert(_el$5, () => entries().map((entry) => `${entry.keys.padEnd(10)}${entry.label}`).join(` +`)); + return _el$5; + })()]; + } + }); +} + +export { HelpModal }; diff --git a/dist/chunk-zs53wnet.js b/dist/chunk-zs53wnet.js new file mode 100644 index 0000000..07e93b5 --- /dev/null +++ b/dist/chunk-zs53wnet.js @@ -0,0 +1,61 @@ +// @bun +import { + Badge +} from "./chunk-shxcerba.js"; +import { + theme +} from "./chunk-57mam43k.js"; + +// src/components/Toggle.tsx +import { setProp as _$setProp } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { insert as _$insert } from "@opentui/solid"; +import { createComponent as _$createComponent } from "@opentui/solid"; +import { memo as _$memo } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import { TextAttributes } from "@opentui/core"; +import { Show } from "solid-js"; +function Toggle(props) { + const onColor = () => props.onColor ?? theme.success; + const offColor = () => props.offColor ?? theme.muted; + const nerdFonts = () => props.withNerdfont ?? theme.nerdFonts; + return (() => { + var _el$ = _$createElement("box"); + _$insert(_el$, _$createComponent(Show, { + get when() { + return nerdFonts(); + }, + get fallback() { + return (() => { + var _el$2 = _$createElement("text"); + _$insert(_el$2, () => props.on ? "on" : "off"); + _$effect((_p$) => { + var _v$ = props.on ? onColor() : offColor(), _v$2 = TextAttributes.BOLD; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "attributes", _v$2, _p$.t)); + return _p$; + }, { + e: undefined, + t: undefined + }); + return _el$2; + })(); + }, + get children() { + return _$createComponent(Badge, { + get label() { + return props.on ? " \u25CF" : "\u25CF "; + }, + get color() { + return _$memo(() => !!props.on)() ? onColor() : offColor(); + }, + withNerdfont: true + }); + } + })); + _$effect((_$p) => _$setProp(_el$, "onMouseDown", theme.mouse ? props.onToggle : undefined, _$p)); + return _el$; + })(); +} + +export { Toggle }; diff --git a/dist/components/Badge.js b/dist/components/Badge.js new file mode 100644 index 0000000..265e01e --- /dev/null +++ b/dist/components/Badge.js @@ -0,0 +1,11 @@ +// @bun +import { + Badge +} from "../chunk-shxcerba.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + Badge +}; diff --git a/dist/components/HelpBar.js b/dist/components/HelpBar.js new file mode 100644 index 0000000..36e92b4 --- /dev/null +++ b/dist/components/HelpBar.js @@ -0,0 +1,11 @@ +// @bun +import { + HelpBar +} from "../chunk-dv2w3sfk.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + HelpBar +}; diff --git a/dist/components/HelpModal.js b/dist/components/HelpModal.js new file mode 100644 index 0000000..cca0435 --- /dev/null +++ b/dist/components/HelpModal.js @@ -0,0 +1,13 @@ +// @bun +import { + HelpModal +} from "../chunk-ydf2rnsn.js"; +import"../chunk-840y6ygm.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +import"../chunk-cyvpvpws.js"; +export { + HelpModal +}; diff --git a/dist/components/MinSizeGuard.js b/dist/components/MinSizeGuard.js new file mode 100644 index 0000000..a3c53e7 --- /dev/null +++ b/dist/components/MinSizeGuard.js @@ -0,0 +1,11 @@ +// @bun +import { + MinSizeGuard +} from "../chunk-syn54rcq.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + MinSizeGuard +}; diff --git a/dist/components/Modal.js b/dist/components/Modal.js new file mode 100644 index 0000000..2ccca98 --- /dev/null +++ b/dist/components/Modal.js @@ -0,0 +1,11 @@ +// @bun +import { + Modal +} from "../chunk-840y6ygm.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + Modal +}; diff --git a/dist/components/NotificationHost.js b/dist/components/NotificationHost.js new file mode 100644 index 0000000..4976421 --- /dev/null +++ b/dist/components/NotificationHost.js @@ -0,0 +1,12 @@ +// @bun +import { + NotificationHost +} from "../chunk-g7p0f33m.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +import"../chunk-y6txxzxk.js"; +export { + NotificationHost +}; diff --git a/dist/components/ProgressBar.js b/dist/components/ProgressBar.js new file mode 100644 index 0000000..6dccc4d --- /dev/null +++ b/dist/components/ProgressBar.js @@ -0,0 +1,11 @@ +// @bun +import { + ProgressBar +} from "../chunk-ae0jkf2z.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + ProgressBar +}; diff --git a/dist/components/Sidebar.js b/dist/components/Sidebar.js new file mode 100644 index 0000000..384a273 --- /dev/null +++ b/dist/components/Sidebar.js @@ -0,0 +1,11 @@ +// @bun +import { + Sidebar +} from "../chunk-wkg33t3z.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + Sidebar +}; diff --git a/dist/components/SignalBars.js b/dist/components/SignalBars.js new file mode 100644 index 0000000..a5f7762 --- /dev/null +++ b/dist/components/SignalBars.js @@ -0,0 +1,11 @@ +// @bun +import { + SignalBars +} from "../chunk-xab9ag99.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + SignalBars +}; diff --git a/dist/components/Spinner.js b/dist/components/Spinner.js new file mode 100644 index 0000000..c90e0cc --- /dev/null +++ b/dist/components/Spinner.js @@ -0,0 +1,39 @@ +// @bun +import { + theme +} from "../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; + +// src/components/Spinner.tsx +import { setProp as _$setProp } from "@opentui/solid"; +import { effect as _$effect } from "@opentui/solid"; +import { createElement as _$createElement } from "@opentui/solid"; +import"opentui-spinner/solid"; +function Spinner(props) { + return (() => { + var _el$ = _$createElement("spinner"); + _$effect((_p$) => { + var { name: _v$, frames: _v$2, interval: _v$3 } = props, _v$4 = props.autoplay ?? !theme.reducedMotion, _v$5 = props.color ?? theme.primary, _v$6 = props.backgroundColor; + _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "name", _v$, _p$.e)); + _v$2 !== _p$.t && (_p$.t = _$setProp(_el$, "frames", _v$2, _p$.t)); + _v$3 !== _p$.a && (_p$.a = _$setProp(_el$, "interval", _v$3, _p$.a)); + _v$4 !== _p$.o && (_p$.o = _$setProp(_el$, "autoplay", _v$4, _p$.o)); + _v$5 !== _p$.i && (_p$.i = _$setProp(_el$, "color", _v$5, _p$.i)); + _v$6 !== _p$.n && (_p$.n = _$setProp(_el$, "backgroundColor", _v$6, _p$.n)); + return _p$; + }, { + e: undefined, + t: undefined, + a: undefined, + o: undefined, + i: undefined, + n: undefined + }); + return _el$; + })(); +} +export { + Spinner +}; diff --git a/dist/components/Tabs.js b/dist/components/Tabs.js new file mode 100644 index 0000000..312935b --- /dev/null +++ b/dist/components/Tabs.js @@ -0,0 +1,13 @@ +// @bun +import { + Tabs, + stepTabValue +} from "../chunk-d2tt920p.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + stepTabValue, + Tabs +}; diff --git a/dist/components/Toggle.js b/dist/components/Toggle.js new file mode 100644 index 0000000..8c37d98 --- /dev/null +++ b/dist/components/Toggle.js @@ -0,0 +1,12 @@ +// @bun +import { + Toggle +} from "../chunk-zs53wnet.js"; +import"../chunk-shxcerba.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +export { + Toggle +}; diff --git a/dist/components/help.js b/dist/components/help.js new file mode 100644 index 0000000..018d516 --- /dev/null +++ b/dist/components/help.js @@ -0,0 +1,17 @@ +// @bun +import { + HelpModal +} from "../chunk-ydf2rnsn.js"; +import"../chunk-840y6ygm.js"; +import { + HelpBar +} from "../chunk-dv2w3sfk.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +import"../chunk-cyvpvpws.js"; +export { + HelpModal, + HelpBar +}; diff --git a/dist/components/index.js b/dist/components/index.js new file mode 100644 index 0000000..1fcf669 --- /dev/null +++ b/dist/components/index.js @@ -0,0 +1,46 @@ +// @bun +import { + ProgressBar +} from "../chunk-ae0jkf2z.js"; +import { + Sidebar +} from "../chunk-wkg33t3z.js"; +import { + SignalBars +} from "../chunk-xab9ag99.js"; +import { + NotificationHost +} from "../chunk-g7p0f33m.js"; +import { + Toggle +} from "../chunk-zs53wnet.js"; +import { + Tabs, + stepTabValue +} from "../chunk-d2tt920p.js"; +import { + Modal +} from "../chunk-840y6ygm.js"; +import { + Badge +} from "../chunk-shxcerba.js"; +import { + MinSizeGuard +} from "../chunk-syn54rcq.js"; +import"../chunk-57mam43k.js"; +import"../chunk-ergc99dh.js"; +import"../chunk-7f8jagy5.js"; +import"../chunk-hcq62p48.js"; +import"../chunk-y6txxzxk.js"; +export { + stepTabValue, + Toggle, + Tabs, + SignalBars, + Sidebar, + ProgressBar, + NotificationHost, + Modal, + MinSizeGuard, + Badge +}; diff --git a/dist/config.js b/dist/config.js new file mode 100644 index 0000000..56da2f9 --- /dev/null +++ b/dist/config.js @@ -0,0 +1,17 @@ +// @bun +import { + COLOR_KEYS, + mergeColors, + mergeConfig, + normalizeColor, + normalizeColors, + resolveBorderStyle +} from "./chunk-hcq62p48.js"; +export { + resolveBorderStyle, + normalizeColors, + normalizeColor, + mergeConfig, + mergeColors, + COLOR_KEYS +}; diff --git a/dist/context/help.js b/dist/context/help.js new file mode 100644 index 0000000..72c67e5 --- /dev/null +++ b/dist/context/help.js @@ -0,0 +1,9 @@ +// @bun +import { + helpOpen, + toggleHelp +} from "../chunk-cyvpvpws.js"; +export { + toggleHelp, + helpOpen +}; diff --git a/dist/context/helper.js b/dist/context/helper.js new file mode 100644 index 0000000..fe134c1 --- /dev/null +++ b/dist/context/helper.js @@ -0,0 +1,7 @@ +// @bun +import { + createSimpleContext +} from "../chunk-2px9e43p.js"; +export { + createSimpleContext +}; diff --git a/dist/context/index.js b/dist/context/index.js new file mode 100644 index 0000000..51fb61b --- /dev/null +++ b/dist/context/index.js @@ -0,0 +1,21 @@ +// @bun +import { + createSimpleContext +} from "../chunk-2px9e43p.js"; +import { + helpOpen, + toggleHelp +} from "../chunk-cyvpvpws.js"; +import { + dismiss, + notifications, + notify +} from "../chunk-y6txxzxk.js"; +export { + toggleHelp, + notify, + notifications, + helpOpen, + dismiss, + createSimpleContext +}; diff --git a/dist/context/notifications.js b/dist/context/notifications.js new file mode 100644 index 0000000..a3b0ae5 --- /dev/null +++ b/dist/context/notifications.js @@ -0,0 +1,11 @@ +// @bun +import { + dismiss, + notifications, + notify +} from "../chunk-y6txxzxk.js"; +export { + notify, + notifications, + dismiss +}; diff --git a/dist/default.yaml b/dist/default.yaml new file mode 100644 index 0000000..6935aa7 --- /dev/null +++ b/dist/default.yaml @@ -0,0 +1,35 @@ +# ilovetui default config +# Copy to ~/.config/ilovetui/config.yaml and edit to customize. + +# Whether components may use Nerd Font glyphs (requires a patched font). +nerd_fonts: true + +# Whether the terminal font can render emoji glyphs. +emoji_fonts: true + +# Disable spinner animation and other motion across all ilovetui-based TUIs. +reduced_motion: false + +# Whether components may register mouse handlers (e.g. click-to-dismiss). +mouse: true + +# Border style used by panels across all ilovetui-based TUIs. +border: rounded + +colors: + base00: "#110F12" # Background + base01: "#1C1920" # Lighter Background / Status Bars + base02: "#1D1A26" # Selection Background + base03: "#514D63" # Comments / Invisibles + base04: "#8E8AA0" # Dark Foreground / Status Bars + base05: "#C2BED6" # Default Foreground + base06: "#D8D5EA" # Light Foreground + base07: "#EAE7F7" # Light Background + base08: "#E07080" # Variables / Errors / Diff Deleted + base09: "#D49070" # Integers / Constants / Booleans + base0a: "#C4B060" # Classes / Warnings / Search Background + base0b: "#80B880" # Strings / Success / Diff Inserted + base0c: "#70B8C0" # Support / Regex / Escape Characters + base0d: "#9E97F8" # Functions / Methods / Headings / Accent + base0e: "#C090E8" # Keywords / Storage / Diff Changed + base0f: "#D080A0" # Embedded / Misc diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..8694ab9 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,15 @@ +// @bun +import { + presets, + theme +} from "./chunk-57mam43k.js"; +import"./chunk-ergc99dh.js"; +import { + configPath +} from "./chunk-7f8jagy5.js"; +import"./chunk-hcq62p48.js"; +export { + theme, + presets, + configPath +}; diff --git a/dist/keymap/provider.js b/dist/keymap/provider.js new file mode 100644 index 0000000..a03d347 --- /dev/null +++ b/dist/keymap/provider.js @@ -0,0 +1,27 @@ +// @bun +// src/keymap/provider.tsx +import { createComponent as _$createComponent } from "@opentui/solid"; +import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui"; +import { registerCommaBindings } from "@opentui/keymap/addons"; +import { KeymapProvider as BaseKeymapProvider } from "@opentui/keymap/solid"; +import { useRenderer } from "@opentui/solid"; +import { onCleanup } from "solid-js"; +import { useKeymap, useBindings, useKeymapSelector, reactiveMatcherFromSignal } from "@opentui/keymap/solid"; +function KeymapProvider(props) { + const renderer = useRenderer(); + const keymap = createDefaultOpenTuiKeymap(renderer); + onCleanup(registerCommaBindings(keymap)); + return _$createComponent(BaseKeymapProvider, { + keymap, + get children() { + return props.children; + } + }); +} +export { + useKeymapSelector, + useKeymap, + useBindings, + reactiveMatcherFromSignal, + KeymapProvider +}; diff --git a/dist/presets.js b/dist/presets.js new file mode 100644 index 0000000..be5317f --- /dev/null +++ b/dist/presets.js @@ -0,0 +1,7 @@ +// @bun +import { + buildPresets +} from "./chunk-ergc99dh.js"; +export { + buildPresets +}; diff --git a/dist/project-config.js b/dist/project-config.js new file mode 100644 index 0000000..1ac3bdc --- /dev/null +++ b/dist/project-config.js @@ -0,0 +1,75 @@ +// @bun +import { + notify +} from "./chunk-y6txxzxk.js"; + +// src/project-config.ts +import { existsSync, readFileSync } from "fs"; +import { homedir } from "os"; +import { join } from "path"; +import { parse as parseYAML } from "yaml"; +import { z } from "zod"; +function userConfigPath(projectName) { + const configHome = process.env.XDG_CONFIG_HOME || join(homedir(), ".config"); + return join(configHome, projectName, "config.yaml"); +} +function readYaml(path) { + return parseYAML(readFileSync(path, "utf-8")); +} +function warn(projectName, path, message) { + const text = `${path}: ${message}`; + console.error(`[${projectName} config] ${text}`); + notify(text, { kind: "warning", duration: 0 }); +} +function loadProjectConfig(options) { + const { projectName, defaultConfigPath, defaultSchema, userSchema } = options; + let rawDefaults; + try { + rawDefaults = readYaml(defaultConfigPath); + } catch (error) { + throw new Error(`Failed to read ${defaultConfigPath}: ${error instanceof Error ? error.message : error}`); + } + const defaultsResult = defaultSchema.safeParse(rawDefaults); + if (!defaultsResult.success) { + throw new Error(`${defaultConfigPath} is invalid: +${z.prettifyError(defaultsResult.error)}`); + } + const path = userConfigPath(projectName); + const user = (() => { + if (!existsSync(path)) + return {}; + let raw; + try { + raw = readYaml(path); + } catch (error) { + warn(projectName, path, error instanceof Error ? error.message : String(error)); + return {}; + } + const result = userSchema.safeParse(raw ?? {}); + if (!result.success) { + warn(projectName, path, z.prettifyError(result.error)); + return {}; + } + return result.data; + })(); + return { defaults: defaultsResult.data, user }; +} +function keybindsSchema(names, required) { + const shape = {}; + for (const name of names) { + shape[name] = required ? z.string().min(1) : z.string().min(1).optional(); + } + return z.object(shape).strict(); +} +function mergeKeybinds(names, defaults, user) { + const merged = {}; + for (const name of names) { + merged[name] = user?.[name] ?? defaults[name]; + } + return merged; +} +export { + mergeKeybinds, + loadProjectConfig, + keybindsSchema +}; diff --git a/dist/solid.js b/dist/solid.js new file mode 100644 index 0000000..0d8f056 --- /dev/null +++ b/dist/solid.js @@ -0,0 +1,43 @@ +// @bun +import { + presets, + theme +} from "./chunk-57mam43k.js"; +import"./chunk-ergc99dh.js"; +import"./chunk-7f8jagy5.js"; +import"./chunk-hcq62p48.js"; + +// src/solid.ts +import { extend } from "@opentui/solid"; +import { + ASCIIFontRenderable, + BoxRenderable, + InputRenderable, + SelectRenderable, + TabSelectRenderable, + TextareaRenderable, + TextRenderable +} from "@opentui/core"; +function withThemeDefaults(Ctor, defaults, after) { + class Themed extends Ctor { + constructor(...args) { + super(...args); + Object.assign(this, defaults); + after?.(this); + } + } + return Themed; +} +var { borderStyle, borderColor, focusedBorderColor } = presets.box; +var boxDefaults = { borderStyle, borderColor, focusedBorderColor }; +extend({ + box: withThemeDefaults(BoxRenderable, boxDefaults, (instance) => { + instance.border = false; + }), + select: withThemeDefaults(SelectRenderable, presets.select), + tab_select: withThemeDefaults(TabSelectRenderable, presets.tabSelect), + input: withThemeDefaults(InputRenderable, presets.input), + textarea: withThemeDefaults(TextareaRenderable, presets.textarea), + text: withThemeDefaults(TextRenderable, { fg: theme.text }), + ascii_font: withThemeDefaults(ASCIIFontRenderable, { color: theme.primary }) +}); diff --git a/dist/yaml.js b/dist/yaml.js new file mode 100644 index 0000000..dc026e1 --- /dev/null +++ b/dist/yaml.js @@ -0,0 +1,9 @@ +// @bun +import { + configPath, + readYamlFile +} from "./chunk-7f8jagy5.js"; +export { + readYamlFile, + configPath +}; diff --git a/package.json b/package.json index c2c78a3..ec30e6e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "files": ["dist", "src"], "scripts": { "build": "bun run scripts/build.ts", - "prepare": "bun run scripts/build.ts", "typecheck": "tsc --noEmit" }, "peerDependencies": {