actual-tui-plugins
Sebastian Herrlinger 2026-03-05 00:09:17 +01:00
parent a7400a77ea
commit 38f38973b0
6 changed files with 38 additions and 18 deletions

View File

@ -3,14 +3,15 @@ import mytheme from "../themes/mytheme.json" with { type: "json" }
const slot = (label) => ({
id: "workspace-smoke",
slots: {
home_hint() {
return <text> [plugin:{label}]</text>
home_logo() {
return <text>plugin logo:{label}</text>
},
home_footer() {
return <text> theme:workspace-plugin-smoke</text>
},
session_footer(_ctx, props) {
return <text> session:{props.session_id.slice(0, 8)}</text>
sidebar_top(_ctx, props) {
return (
<text>
plugin:{label} session:{props.session_id.slice(0, 8)}
</text>
)
},
},
})

View File

@ -4,6 +4,7 @@ import {
type TuiSlotContext,
type TuiSlotMap,
type TuiSlots,
type SlotMode,
} from "@opencode-ai/plugin/tui"
import { createSlot, createSolidSlotRegistry, type JSX, type SolidPlugin } from "@opentui/solid"
import type { CliRenderer } from "@opentui/core"
@ -17,10 +18,29 @@ import { Instance } from "@/project/instance"
import { resolvePluginTarget, uniqueModuleEntries } from "@/plugin/shared"
import { registerThemes } from "./context/theme"
type Slot = <K extends keyof TuiSlotMap>(props: { name: K } & TuiSlotMap[K]) => JSX.Element | null
type SlotInput<K extends keyof TuiSlotMap> = {
name: K
mode?: SlotMode
slotMode?: SlotMode
children?: JSX.Element
} & TuiSlotMap[K]
type SlotProps<K extends keyof TuiSlotMap> = {
name: K
mode?: SlotMode
children?: JSX.Element
} & TuiSlotMap[K]
type Slot = <K extends keyof TuiSlotMap>(props: SlotInput<K>) => JSX.Element | null
type InitInput = Omit<TuiPluginInput<CliRenderer>, "slots">
function empty<K extends keyof TuiSlotMap>(_props: { name: K } & TuiSlotMap[K]) {
function normalize<K extends keyof TuiSlotMap>(props: SlotInput<K>): SlotProps<K> {
const { slotMode, ...rest } = props
if (!slotMode || rest.mode) return rest as SlotProps<K>
return { ...rest, mode: slotMode } as SlotProps<K>
}
function empty<K extends keyof TuiSlotMap>(_props: SlotInput<K>) {
return null
}
@ -79,7 +99,7 @@ export namespace TuiPlugin {
)
const slot = createSlot<TuiSlotMap, TuiSlotContext>(reg)
view = (props) => slot(props)
view = (props) => slot(normalize(props))
return {
register(pluginSlot) {
if (!isTuiSlotPlugin(pluginSlot)) return () => {}

View File

@ -73,7 +73,6 @@ export function Home() {
</Switch>
</text>
</Show>
{TuiPlugin.Slot({ name: "home_hint" })}
</box>
)
@ -113,7 +112,9 @@ export function Home() {
<box flexGrow={1} minHeight={0} />
<box height={4} minHeight={0} flexShrink={1} />
<box flexShrink={0}>
<Logo />
<TuiPlugin.Slot name="home_logo" slotMode="replace">
<Logo />
</TuiPlugin.Slot>
</box>
<box height={1} minHeight={0} flexShrink={1} />
<box width="100%" maxWidth={75} zIndex={1000} paddingTop={1} flexShrink={0}>
@ -152,7 +153,6 @@ export function Home() {
</Show>
</box>
<box flexGrow={1} />
{TuiPlugin.Slot({ name: "home_footer" })}
<box flexShrink={0}>
<text fg={theme.textMuted}>{Installation.VERSION}</text>
</box>

View File

@ -80,7 +80,6 @@ import { DialogExportOptions } from "../../ui/dialog-export-options"
import { formatTranscript } from "../../util/transcript"
import { UI } from "@/cli/ui.ts"
import { useTuiConfig } from "../../context/tui-config"
import { TuiPlugin } from "../../plugin"
addDefaultParsers(parsers.parsers)
@ -1178,7 +1177,6 @@ export function Session() {
}}
sessionID={route.sessionID}
/>
{TuiPlugin.Slot({ name: "session_footer", session_id: route.sessionID })}
</box>
</Show>
<Toast />

View File

@ -11,6 +11,7 @@ import { useKeybind } from "../../context/keybind"
import { useDirectory } from "../../context/directory"
import { useKV } from "../../context/kv"
import { TodoItem } from "../../component/todo-item"
import { TuiPlugin } from "../../plugin"
export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
const sync = useSync()
@ -90,6 +91,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
}}
>
<box flexShrink={0} gap={1} paddingRight={1}>
{TuiPlugin.Slot({ name: "sidebar_top", session_id: props.sessionID })}
<box paddingRight={1}>
<text fg={theme.text}>
<b>{session().title}</b>

View File

@ -23,9 +23,8 @@ export type ThemeJson = {
}
export type TuiSlotMap = {
home_hint: {}
home_footer: {}
session_footer: {
home_logo: {}
sidebar_top: {
session_id: string
}
}