|
|
@@ -1,6 +1,6 @@
|
|
|
import { InputRenderable, RGBA, ScrollBoxRenderable, TextAttributes } from "@opentui/core"
|
|
|
import { Keymap, type KeymapCommand } from "../context/keymap"
|
|
|
-import { useTheme, selectedForeground } from "../context/theme"
|
|
|
+import { useTheme } from "../context/theme"
|
|
|
import { entries, filter, flatMap, groupBy, pipe } from "remeda"
|
|
|
import { batch, createEffect, createMemo, createSignal, For, Show, type JSX, on, onCleanup } from "solid-js"
|
|
|
import { createStore } from "solid-js/store"
|
|
|
@@ -74,6 +74,7 @@ export interface DialogSelectOption<T = any> {
|
|
|
categoryView?: JSX.Element
|
|
|
disabled?: boolean
|
|
|
bg?: RGBA
|
|
|
+ fg?: RGBA
|
|
|
gutter?: () => JSX.Element
|
|
|
margin?: JSX.Element
|
|
|
onSelect?: (ctx: DialogContext) => void
|
|
|
@@ -91,7 +92,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
type VisibleAction = (Action & { label: string }) | FooterHint
|
|
|
|
|
|
const dialog = useDialog()
|
|
|
- const { theme } = useTheme()
|
|
|
+ const { themeV2, mode } = useTheme().contextual("elevated")
|
|
|
const config = useConfig().data
|
|
|
const scrollAcceleration = createMemo(() => getScrollAcceleration(config))
|
|
|
|
|
|
@@ -517,29 +518,44 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
if (!isActionItem(action.item))
|
|
|
return (
|
|
|
<text>
|
|
|
- <span style={{ fg: theme.text }}>
|
|
|
+ <span style={{ fg: themeV2.text.default }}>
|
|
|
<b>{action.item.title}</b>{" "}
|
|
|
</span>
|
|
|
- <span style={{ fg: theme.textMuted }}>{action.item.label}</span>
|
|
|
+ <span style={{ fg: themeV2.text.subdued }}>{action.item.label}</span>
|
|
|
</text>
|
|
|
)
|
|
|
const item = action.item
|
|
|
const active = createMemo(() => isActionFocused(item))
|
|
|
const disabled = createMemo(() => isActionDisabled(item))
|
|
|
- const fg = selectedForeground(theme)
|
|
|
return (
|
|
|
<box
|
|
|
flexDirection="row"
|
|
|
- backgroundColor={active() ? theme.primary : RGBA.fromInts(0, 0, 0, 0)}
|
|
|
+ backgroundColor={active() ? themeV2.background.action.primary.focused : RGBA.fromInts(0, 0, 0, 0)}
|
|
|
onMouseUp={() => trigger(item)}
|
|
|
>
|
|
|
<text
|
|
|
- fg={disabled() ? theme.textMuted : active() ? fg : theme.text}
|
|
|
+ fg={
|
|
|
+ disabled()
|
|
|
+ ? themeV2.text.action.primary.disabled
|
|
|
+ : active()
|
|
|
+ ? themeV2.text.action.primary.focused
|
|
|
+ : themeV2.text.default
|
|
|
+ }
|
|
|
attributes={active() ? TextAttributes.BOLD : undefined}
|
|
|
>
|
|
|
{item.title}
|
|
|
</text>
|
|
|
- <text fg={disabled() ? theme.textMuted : active() ? fg : theme.textMuted}> {item.label}</text>
|
|
|
+ <text
|
|
|
+ fg={
|
|
|
+ disabled()
|
|
|
+ ? themeV2.text.action.primary.disabled
|
|
|
+ : active()
|
|
|
+ ? themeV2.text.action.primary.focused
|
|
|
+ : themeV2.text.subdued
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {" " + item.label}
|
|
|
+ </text>
|
|
|
</box>
|
|
|
)
|
|
|
}
|
|
|
@@ -549,11 +565,11 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
<box paddingLeft={4} paddingRight={4}>
|
|
|
<box flexDirection="row" justifyContent="space-between">
|
|
|
{props.titleView ?? (
|
|
|
- <text fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
|
+ <text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
|
|
{props.title}
|
|
|
</text>
|
|
|
)}
|
|
|
- <text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
|
|
|
+ <text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
|
|
esc
|
|
|
</text>
|
|
|
</box>
|
|
|
@@ -567,9 +583,9 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
props.onFilter?.(e)
|
|
|
})
|
|
|
}}
|
|
|
- focusedBackgroundColor={theme.backgroundPanel}
|
|
|
- cursorColor={theme.primary}
|
|
|
- focusedTextColor={theme.textMuted}
|
|
|
+ focusedBackgroundColor={themeV2.background.formfield.focused}
|
|
|
+ cursorColor={themeV2.text.formfield.focused}
|
|
|
+ focusedTextColor={themeV2.text.formfield.focused}
|
|
|
ref={(r) => {
|
|
|
input = r
|
|
|
input.traits = { status: "FILTER" }
|
|
|
@@ -580,7 +596,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
}, 1)
|
|
|
}}
|
|
|
placeholder={props.placeholder ?? "Search"}
|
|
|
- placeholderColor={theme.textMuted}
|
|
|
+ placeholderColor={themeV2.text.subdued}
|
|
|
/>
|
|
|
</box>
|
|
|
</Show>
|
|
|
@@ -594,14 +610,14 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
fallback={
|
|
|
props.emptyView ?? (
|
|
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
|
|
- <text fg={theme.textMuted}>No items available</text>
|
|
|
+ <text fg={themeV2.text.subdued}>No items available</text>
|
|
|
</box>
|
|
|
)
|
|
|
}
|
|
|
>
|
|
|
{props.noMatchView ?? (
|
|
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
|
|
- <text fg={theme.textMuted}>No results found</text>
|
|
|
+ <text fg={themeV2.text.subdued}>No results found</text>
|
|
|
</box>
|
|
|
)}
|
|
|
</Show>
|
|
|
@@ -623,7 +639,10 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
<Show
|
|
|
when={options[0]?.categoryView}
|
|
|
fallback={
|
|
|
- <text fg={theme.accent} attributes={TextAttributes.BOLD}>
|
|
|
+ <text
|
|
|
+ fg={themeV2.hue.accent[mode() === "light" ? 800 : 200]}
|
|
|
+ attributes={TextAttributes.BOLD}
|
|
|
+ >
|
|
|
{category}
|
|
|
</text>
|
|
|
}
|
|
|
@@ -672,8 +691,8 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
backgroundColor={
|
|
|
active()
|
|
|
? actionFocused()
|
|
|
- ? theme.backgroundElement
|
|
|
- : (option.bg ?? theme.primary)
|
|
|
+ ? themeV2.background.surface.overlay
|
|
|
+ : (option.bg ?? themeV2.background.action.primary.focused)
|
|
|
: RGBA.fromInts(0, 0, 0, 0)
|
|
|
}
|
|
|
>
|
|
|
@@ -692,6 +711,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
active={active()}
|
|
|
current={current()}
|
|
|
muted={actionFocused()}
|
|
|
+ activeColor={option.fg}
|
|
|
gutter={option.gutter}
|
|
|
/>
|
|
|
</box>
|
|
|
@@ -699,7 +719,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|
|
{(detail) => (
|
|
|
<box paddingLeft={3} paddingRight={3}>
|
|
|
<text
|
|
|
- fg={option.detailsColor ?? theme.textMuted}
|
|
|
+ fg={option.detailsColor ?? themeV2.text.subdued}
|
|
|
wrapMode={option.detailsWrap ? "word" : "none"}
|
|
|
>
|
|
|
{option.detailsWrap
|
|
|
@@ -745,15 +765,15 @@ function Option(props: {
|
|
|
titleWidth?: number
|
|
|
truncateTitle?: boolean | "left"
|
|
|
gutter?: () => JSX.Element
|
|
|
+ activeColor?: RGBA
|
|
|
onMouseOver?: () => void
|
|
|
}) {
|
|
|
- const { theme } = useTheme()
|
|
|
- const fg = selectedForeground(theme)
|
|
|
+ const { themeV2 } = useTheme().contextual("elevated")
|
|
|
const text = createMemo(() => {
|
|
|
- if (props.active && !props.muted) return fg
|
|
|
- if (props.muted && (props.active || props.current)) return theme.textMuted
|
|
|
- if (props.current) return theme.primary
|
|
|
- return theme.text
|
|
|
+ if (props.active && !props.muted) return props.activeColor ?? themeV2.text.action.primary.focused
|
|
|
+ if (props.muted && (props.active || props.current)) return themeV2.text.subdued
|
|
|
+ if (props.current) return themeV2.text.formfield.selected
|
|
|
+ return themeV2.text.default
|
|
|
})
|
|
|
|
|
|
return (
|
|
|
@@ -783,12 +803,14 @@ function Option(props: {
|
|
|
? Locale.truncateLeft(props.title, props.titleWidth ?? 61)
|
|
|
: Locale.truncate(props.title, props.titleWidth ?? 61))}
|
|
|
<Show when={props.description}>
|
|
|
- <span style={{ fg: props.active && !props.muted ? fg : theme.textMuted }}> {props.description}</span>
|
|
|
+ <span style={{ fg: props.active && !props.muted ? text() : themeV2.text.subdued }}>
|
|
|
+ {" " + props.description}
|
|
|
+ </span>
|
|
|
</Show>
|
|
|
</text>
|
|
|
<Show when={props.footer}>
|
|
|
<box flexShrink={0}>
|
|
|
- <text fg={props.active && !props.muted ? fg : theme.textMuted}>{props.footer}</text>
|
|
|
+ <text fg={props.active && !props.muted ? text() : themeV2.text.subdued}>{props.footer}</text>
|
|
|
</box>
|
|
|
</Show>
|
|
|
</>
|