Merge visual review into full shell and preserve bilingual layout

This commit is contained in:
Codex
2026-09-13 14:55:58 +02:00
69 changed files with 1419 additions and 346 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ export function FallbackWidget({ descriptor, onRespond }: WidgetProps) {
useUnsavedDraft(text);
return (
<div className="rounded-xl border border-border/70 bg-card p-3 shadow-sm space-y-2">
<p className="text-sm text-amber-600">{translate("Unsupported widget (kind: {kind}) — respond manually", { kind: descriptor.widget })}</p>
<p className="text-sm text-warning">{translate("Unsupported widget (kind: {kind}) — respond manually", { kind: descriptor.widget })}</p>
<pre className="text-xs font-mono overflow-auto max-h-48 rounded-lg bg-muted p-2">{JSON.stringify(descriptor, null, 2)}</pre>
<textarea aria-label={translate("Manual response")} className="w-full rounded-lg border border-input bg-card p-2 text-sm shadow-xs outline-none transition-[border-color,box-shadow] focus:border-primary/50 focus:ring-2 focus:ring-ring/20" value={text} onChange={(e) => setText(e.target.value)} />
<button className="rounded-md border border-border/70 px-2 py-1 text-sm shadow-xs transition-colors hover:bg-accent" onClick={() => {
+1 -1
View File
@@ -15,7 +15,7 @@ export function FreetextWidget({ descriptor, onRespond }: WidgetProps) {
return (
<div className="space-y-3 rounded-xl border border-border/70 bg-card p-4 shadow-sm">
{descriptor.title && (
<p className="text-[0.95rem] font-semibold leading-snug text-foreground">
<p className="text-base font-semibold leading-snug text-foreground">
{descriptor.title}
</p>
)}
+1 -1
View File
@@ -1,5 +1,5 @@
import type { WidgetProps } from "./types";
export function InfoWidget({ descriptor }: WidgetProps) {
const color = descriptor.level === "error" ? "text-red-600" : descriptor.level === "warning" ? "text-amber-600" : "text-foreground";
const color = descriptor.level === "error" ? "text-red-600" : descriptor.level === "warning" ? "text-warning" : "text-foreground";
return <p className={`text-sm leading-relaxed ${color}`}>{descriptor.text ?? descriptor.title}</p>;
}
+4 -3
View File
@@ -11,7 +11,7 @@ export function JoinReviewWidget({ descriptor, onRespond }: WidgetProps) {
<div className="space-y-4 rounded-xl border border-border/70 bg-card p-4 shadow-sm">
<div className="space-y-1.5">
{descriptor.title && (
<p className="text-[0.95rem] font-semibold leading-snug text-foreground">
<p className="text-base font-semibold leading-snug text-foreground">
{descriptor.title}
</p>
)}
@@ -45,8 +45,9 @@ export function JoinReviewWidget({ descriptor, onRespond }: WidgetProps) {
)}
{option.rationale && (
<div className="grid gap-1 sm:grid-cols-[5rem_minmax(0,1fr)] sm:gap-3">
<span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
{translate("Rationale")}</span>
<span className="text-xs font-medium text-muted-foreground">
{translate("Rationale")}
</span>
<p className="text-sm leading-relaxed text-muted-foreground">
{option.rationale}
</p>
+9 -7
View File
@@ -29,7 +29,7 @@ export function MultiselectWidget({ descriptor, onRespond }: WidgetProps) {
return (
<div className="space-y-4 rounded-xl border border-border/70 bg-card p-4 shadow-sm">
{descriptor.title && (
<p className="text-[0.95rem] font-semibold leading-snug text-foreground">
<p className="text-base font-semibold leading-snug text-foreground">
{descriptor.title}
</p>
)}
@@ -70,18 +70,20 @@ export function MultiselectWidget({ descriptor, onRespond }: WidgetProps) {
</div>
)}
{o.rationale && (
<div className="mt-3 border-l-2 border-border/70 pl-3 text-xs text-foreground/80">
<div className="mb-1 font-semibold uppercase tracking-wide text-muted-foreground">
{translate("Reason")}</div>
<div className="mt-3 border-l border-border/70 pl-3 text-xs text-foreground/80">
<div className="mb-1 font-semibold text-muted-foreground">
{translate("Reason")}
</div>
<div className="thot-prose leading-relaxed [&>p:first-child]:mt-0 [&>p:last-child]:mb-0">
<ReactMarkdown remarkPlugins={[remarkGfm]}>{o.rationale}</ReactMarkdown>
</div>
</div>
)}
{typeof o.meta?.question_context === "string" && o.meta.question_context && (
<div className="mt-3 border-l-2 border-border/50 pl-3 text-xs text-muted-foreground">
<div className="mb-1 font-semibold uppercase tracking-wide">
{translate("Context question")}</div>
<div className="mt-3 border-l border-border/50 pl-3 text-xs text-muted-foreground">
<div className="mb-1 font-semibold">
{translate("Context question")}
</div>
<div className="thot-prose leading-relaxed [&>p:first-child]:mt-0 [&>p:last-child]:mb-0">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{o.meta.question_context}
@@ -65,7 +65,7 @@ export function SchemaLinkingGateWidget({ descriptor, onRespond }: WidgetProps)
return (
<div className="space-y-4 rounded-xl border border-border/70 bg-card p-4 shadow-sm">
{descriptor.title && (
<p className="text-[0.95rem] font-semibold leading-snug text-foreground">{descriptor.title}</p>
<p className="text-base font-semibold leading-snug text-foreground">{descriptor.title}</p>
)}
<div className="flex flex-col gap-2">
+4 -3
View File
@@ -10,7 +10,7 @@ export function SelectWidget({ descriptor, onRespond }: WidgetProps) {
{(descriptor.title || descriptor.intro) && (
<div className="space-y-1.5">
{descriptor.title && (
<p className="text-[0.95rem] font-semibold leading-snug text-foreground">
<p className="text-base font-semibold leading-snug text-foreground">
{descriptor.title}
</p>
)}
@@ -26,8 +26,9 @@ export function SelectWidget({ descriptor, onRespond }: WidgetProps) {
>
<span>{o.label}</span>
{o.recommended && (
<span className="shrink-0 rounded-md bg-[oklch(var(--success)/0.16)] px-2 py-0.5 text-[0.65rem] font-medium text-[oklch(0.5_0.13_165)]">
{translate("Recommended")}</span>
<span className="shrink-0 rounded-md bg-[oklch(var(--success)/0.16)] px-2 py-0.5 text-xs font-medium text-success">
{translate("Recommended")}
</span>
)}
</button>
))}