diff --git a/bin/amc-hook b/bin/amc-hook index 4405b24..cba8939 100755 --- a/bin/amc-hook +++ b/bin/amc-hook @@ -82,10 +82,14 @@ def _extract_questions(hook): "options": [], } for opt in q.get("options", []): - entry["options"].append({ + opt_entry = { "label": opt.get("label", ""), "description": opt.get("description", ""), - }) + } + # Include markdown preview if present + if opt.get("markdown"): + opt_entry["markdown"] = opt.get("markdown") + entry["options"].append(opt_entry) result.append(entry) return result diff --git a/dashboard/components/OptionButton.js b/dashboard/components/OptionButton.js index 190668a..b3018e4 100644 --- a/dashboard/components/OptionButton.js +++ b/dashboard/components/OptionButton.js @@ -1,17 +1,23 @@ import { html } from '../lib/preact.js'; -export function OptionButton({ number, label, description, onClick }) { +export function OptionButton({ number, label, description, selected, onClick, onMouseEnter, onFocus }) { + const selectedStyles = selected + ? 'border-starting/60 bg-starting/15 shadow-sm' + : 'border-selection/70 bg-surface2/55'; + return html` `; diff --git a/dashboard/components/QuestionBlock.js b/dashboard/components/QuestionBlock.js index bf2c977..70df708 100644 --- a/dashboard/components/QuestionBlock.js +++ b/dashboard/components/QuestionBlock.js @@ -1,12 +1,15 @@ -import { html, useState } from '../lib/preact.js'; +import { html, useState, useRef } from '../lib/preact.js'; import { getStatusMeta } from '../utils/status.js'; import { OptionButton } from './OptionButton.js'; +import { renderContent } from '../lib/markdown.js'; export function QuestionBlock({ questions, sessionId, status, onRespond }) { const [freeformText, setFreeformText] = useState(''); const [focused, setFocused] = useState(false); const [sending, setSending] = useState(false); const [error, setError] = useState(null); + const [previewIndex, setPreviewIndex] = useState(0); + const textareaRef = useRef(null); const meta = getStatusMeta(status); if (!questions || questions.length === 0) return null; @@ -15,6 +18,9 @@ export function QuestionBlock({ questions, sessionId, status, onRespond }) { const question = questions[0]; const remainingCount = questions.length - 1; const options = question.options || []; + + // Check if any option has markdown preview content + const hasMarkdownPreviews = options.some(opt => opt.markdown); const handleOptionClick = async (optionLabel) => { if (sending) return; @@ -44,12 +50,111 @@ export function QuestionBlock({ questions, sessionId, status, onRespond }) { console.error('QuestionBlock freeform error:', err); } finally { setSending(false); + // Refocus the textarea after submission + // Use setTimeout to ensure React has re-rendered with disabled=false + setTimeout(() => { + textareaRef.current?.focus(); + }, 0); } } }; + // Side-by-side layout when options have markdown previews + if (hasMarkdownPreviews) { + const currentMarkdown = options[previewIndex]?.markdown || ''; + + return html` +
e.stopPropagation()}> + ${error && html` +
+ ${error} +
+ `} + + + ${question.header && html` + + ${question.header} + + `} + + +

${question.question || question.text}

+ + +
+ +
+ ${options.map((opt, i) => html` + <${OptionButton} + key=${i} + number=${i + 1} + label=${opt.label || opt} + description=${opt.description} + selected=${previewIndex === i} + onMouseEnter=${() => setPreviewIndex(i)} + onFocus=${() => setPreviewIndex(i)} + onClick=${() => handleOptionClick(opt.label || opt)} + /> + `)} +
+ + +
+ ${currentMarkdown + ? (currentMarkdown.trimStart().startsWith('```') + ? renderContent(currentMarkdown) + : html`
${currentMarkdown}
`) + : html`

No preview for this option

` + } +
+
+ + +
+