Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useTheme } from "@tui/context/theme"
import { DialogPrompt } from "@tui/ui/dialog-prompt"

interface DialogQuestionCommentProps {
question: string
value?: string
onSave: (comment: string) => void
onCancel: () => void
}

export function DialogQuestionComment(props: DialogQuestionCommentProps) {
const { theme } = useTheme()

return (
<DialogPrompt
title={props.question}
description={() => <text fg={theme.textMuted}>Add comment</text>}
placeholder="Optional comment..."
value={props.value}
onConfirm={(value) => props.onSave(value)}
onCancel={() => props.onCancel()}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { createMemo, createSignal, onMount } from "solid-js"
import { useTheme } from "@tui/context/theme"
import { useDialog } from "@tui/ui/dialog"
import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select"
import { DialogQuestionComment } from "./dialog-question-comment"
import { truncate } from "./helpers"
import type { SingleQuestionProps } from "./types"

export function DialogQuestionConfirm(props: SingleQuestionProps) {
const dialog = useDialog()
const { theme } = useTheme()
const [comment, setComment] = createSignal<string | undefined>(props.currentAnswer?.comment)

// Find current selection value
const currentValue = createMemo(() => props.currentAnswer?.value)

onMount(() => {
dialog.setSize("medium")
})

function openComment() {
dialog.push(() => (
<DialogQuestionComment
question={props.item.question}
value={comment()}
onSave={(c) => {
const trimmedComment = c.trim() || undefined
setComment(trimmedComment)
// Update just the comment, merging with existing answer
props.onAnswer({ comment: trimmedComment })
dialog.pop()
}}
onCancel={() => dialog.pop()}
/>
))
}

function confirmSelection(value: boolean) {
props.onAnswer({ value })
dialog.pop()
}

// Yes/No options
const options = createMemo<DialogSelectOption<boolean>[]>(() => [
{
title: "Yes",
value: true,
},
{
title: "No",
value: false,
},
])

return (
<DialogSelect
title={props.item.question}
options={options()}
current={typeof currentValue() === "boolean" ? currentValue() : undefined}
hideSearch={true}
onSelect={(option) => {
if (typeof option.value === "boolean") {
confirmSelection(option.value)
}
}}
beforeFooter={
comment() ? (
<box paddingLeft={4} paddingRight={4}>
<text fg={theme.textMuted}>💬 "{truncate(comment()!, 40)}"</text>
</box>
) : undefined
}
keybind={[
{
keybind: { name: "c", ctrl: false, meta: false, shift: false, super: false, leader: false },
title: "add comment",
onTrigger: () => openComment(),
},
]}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { createMemo, createSignal, onMount } from "solid-js"
import { useTheme } from "@tui/context/theme"
import { useDialog } from "@tui/ui/dialog"
import { DialogMultiSelect, type DialogMultiSelectOption } from "@tui/ui/dialog-multiselect"
import { DialogQuestionComment } from "./dialog-question-comment"
import { truncate } from "./helpers"
import type { SingleQuestionProps } from "./types"

export function DialogQuestionMultiSelect(props: SingleQuestionProps) {
const dialog = useDialog()
const { theme } = useTheme()
const [comment, setComment] = createSignal<string | undefined>(props.currentAnswer?.comment)

// Sort options with recommended first
const sortedOptions = createMemo(() => {
const opts = props.item.options ?? []
return [...opts].sort((a, b) => (b.recommended ? 1 : 0) - (a.recommended ? 1 : 0))
})

onMount(() => {
dialog.setSize("medium")
})

function openComment() {
dialog.push(() => (
<DialogQuestionComment
question={props.item.question}
value={comment()}
onSave={(c) => {
const trimmedComment = c.trim() || undefined
setComment(trimmedComment)
// Update just the comment, merging with existing answer
props.onAnswer({ comment: trimmedComment })
dialog.pop()
}}
onCancel={() => dialog.pop()}
/>
))
}

// Convert options to DialogMultiSelectOption format
const selectOptions = createMemo<DialogMultiSelectOption<string>[]>(() =>
sortedOptions().map((option) => ({
title: option.label,
value: option.value,
footer: option.recommended ? "(Recommended)" : undefined,
})),
)

// Get current values as array
const currentValues = createMemo(() => {
if (Array.isArray(props.currentAnswer?.value)) {
return props.currentAnswer.value
}
return []
})

function confirmSelection(selected: string[]) {
props.onAnswer({ value: selected })
dialog.pop()
}

return (
<DialogMultiSelect
title={props.item.question}
options={selectOptions()}
current={currentValues()}
hideSearch={true}
onSelect={confirmSelection}
beforeFooter={
comment() ? (
<box paddingLeft={4} paddingRight={4}>
<text fg={theme.textMuted}>💬 "{truncate(comment()!, 40)}"</text>
</box>
) : undefined
}
keybind={[
{
keybind: { name: "c", ctrl: false, meta: false, shift: false, super: false, leader: false },
title: "add comment",
onTrigger: () => openComment(),
},
]}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { createMemo, createSignal, onMount } from "solid-js"
import { useTheme } from "@tui/context/theme"
import { useDialog } from "@tui/ui/dialog"
import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select"
import { DialogQuestionComment } from "./dialog-question-comment"
import { truncate } from "./helpers"
import type { SingleQuestionProps } from "./types"

export function DialogQuestionSelect(props: SingleQuestionProps) {
const dialog = useDialog()
const { theme } = useTheme()
const [comment, setComment] = createSignal<string | undefined>(props.currentAnswer?.comment)

// Sort options with recommended first
const sortedOptions = createMemo(() => {
const opts = props.item.options ?? []
return [...opts].sort((a, b) => (b.recommended ? 1 : 0) - (a.recommended ? 1 : 0))
})

// Find current selection value
const currentValue = createMemo(() => props.currentAnswer?.value)

onMount(() => {
dialog.setSize("medium")
})

function openComment() {
dialog.push(() => (
<DialogQuestionComment
question={props.item.question}
value={comment()}
onSave={(c) => {
const trimmedComment = c.trim() || undefined
setComment(trimmedComment)
// Update just the comment, merging with existing answer
props.onAnswer({ comment: trimmedComment })
dialog.pop()
}}
onCancel={() => dialog.pop()}
/>
))
}

function confirmSelection(option: { value: string; label: string; recommended?: boolean }) {
props.onAnswer({ value: option.value })
dialog.pop()
}

// Convert options to DialogSelectOption format
const selectOptions = createMemo<DialogSelectOption<{ value: string; label: string; recommended?: boolean }>[]>(() =>
sortedOptions().map((option) => ({
title: option.label,
value: option,
footer: option.recommended ? "(Recommended)" : undefined,
})),
)

return (
<DialogSelect
title={props.item.question}
options={selectOptions()}
current={sortedOptions().find((o) => o.value === currentValue())}
hideSearch={true}
onSelect={(option) => confirmSelection(option.value)}
beforeFooter={
comment() ? (
<box paddingLeft={4} paddingRight={4}>
<text fg={theme.textMuted}>💬 "{truncate(comment()!, 40)}"</text>
</box>
) : undefined
}
keybind={[
{
keybind: { name: "c", ctrl: false, meta: false, shift: false, super: false, leader: false },
title: "add comment",
onTrigger: () => openComment(),
},
]}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useDialog } from "@tui/ui/dialog"
import { DialogPrompt } from "@tui/ui/dialog-prompt"
import type { SingleQuestionProps } from "./types"

export function DialogQuestionText(props: SingleQuestionProps) {
const dialog = useDialog()
const placeholder = typeof props.item.default === "string" ? props.item.default : "Enter your response..."
const initialValue = typeof props.currentAnswer?.value === "string" ? props.currentAnswer.value : ""

function confirmText(value: string) {
const trimmedValue = value.trim()
props.onAnswer({ value: trimmedValue || null })
dialog.pop()
}

return (
<DialogPrompt
title={props.item.question}
placeholder={placeholder}
value={initialValue}
onConfirm={confirmText}
onCancel={() => props.onCancel()}
/>
)
}
Loading