mirror of
https://github.com/anotherhadi/ilovetui.git
synced 2026-10-05 19:08:25 +02:00
+45
-12
@@ -1,14 +1,25 @@
|
||||
import { type ColorInput, type SelectOption, TextAttributes } from "@opentui/core";
|
||||
import { theme } from "../index.ts";
|
||||
import { type ColorInput, type MouseEvent, type SelectOption, type SelectRenderable, TextAttributes } from "@opentui/core";
|
||||
import { Show } from "solid-js";
|
||||
import { presets, theme } from "../index.ts";
|
||||
|
||||
export interface SidebarHandle {
|
||||
moveUp(): void;
|
||||
moveDown(): 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 {
|
||||
title: string;
|
||||
title?: string;
|
||||
items: SelectOption[];
|
||||
width?: number;
|
||||
focused?: boolean;
|
||||
@@ -30,6 +41,21 @@ export interface 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 (
|
||||
<box
|
||||
width={props.width ?? 24}
|
||||
@@ -38,14 +64,19 @@ export function Sidebar(props: SidebarProps) {
|
||||
borderColor={props.focused ? (props.accentColor ?? theme.primary) : (props.mutedColor ?? theme.muted)}
|
||||
flexDirection="column"
|
||||
>
|
||||
<text attributes={TextAttributes.BOLD}>{props.title}</text>
|
||||
<Show when={props.title}>
|
||||
<text attributes={TextAttributes.BOLD}>{props.title}</text>
|
||||
<text> </text>
|
||||
</Show>
|
||||
<select
|
||||
ref={(el) => {
|
||||
select = el ?? undefined;
|
||||
props.ref?.(
|
||||
el && {
|
||||
moveUp: () => el.moveUp(),
|
||||
moveDown: () => el.moveDown(),
|
||||
selectCurrent: () => el.selectCurrent(),
|
||||
focus: () => el.focus(),
|
||||
},
|
||||
);
|
||||
}}
|
||||
@@ -53,14 +84,16 @@ export function Sidebar(props: SidebarProps) {
|
||||
focused={props.focused}
|
||||
showScrollIndicator
|
||||
options={props.items}
|
||||
backgroundColor={props.backgroundColor}
|
||||
textColor={props.textColor}
|
||||
focusedBackgroundColor={props.focusedBackgroundColor}
|
||||
focusedTextColor={props.focusedTextColor}
|
||||
selectedBackgroundColor={props.selectedBackgroundColor}
|
||||
selectedTextColor={props.selectedTextColor}
|
||||
descriptionColor={props.descriptionColor}
|
||||
selectedDescriptionColor={props.selectedDescriptionColor}
|
||||
onMouseDown={theme.mouse ? handleMouseDown : undefined}
|
||||
onMouseScroll={theme.mouse ? handleMouseScroll : undefined}
|
||||
backgroundColor={props.backgroundColor ?? "transparent"}
|
||||
textColor={props.textColor ?? presets.select.textColor}
|
||||
focusedBackgroundColor={props.focusedBackgroundColor ?? "transparent"}
|
||||
focusedTextColor={props.focusedTextColor ?? presets.select.focusedTextColor}
|
||||
selectedBackgroundColor={props.selectedBackgroundColor ?? presets.select.selectedBackgroundColor}
|
||||
selectedTextColor={props.selectedTextColor ?? presets.select.selectedTextColor}
|
||||
descriptionColor={props.descriptionColor ?? presets.select.descriptionColor}
|
||||
selectedDescriptionColor={props.selectedDescriptionColor ?? presets.select.selectedDescriptionColor}
|
||||
onChange={(_index, option) => {
|
||||
if (!option) return;
|
||||
props.onSelect(option);
|
||||
|
||||
Reference in New Issue
Block a user