mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
// Used for displayMode: 'popup' surfaces (e.g., ask_question)
|
||||
// Supports markdown content parsing and multi-page navigation
|
||||
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
@@ -167,6 +167,23 @@ function SinglePagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
||||
|
||||
const questionId = (surface.initialState as any)?.questionId as string | undefined;
|
||||
|
||||
// Countdown timer for auto-selection
|
||||
const timeoutAt = (surface.initialState as any)?.timeoutAt as string | undefined;
|
||||
const defaultLabel = (surface.initialState as any)?.defaultValue as string | undefined;
|
||||
const [remaining, setRemaining] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!timeoutAt || !defaultLabel) return;
|
||||
const target = new Date(timeoutAt).getTime();
|
||||
const tick = () => {
|
||||
const secs = Math.max(0, Math.ceil((target - Date.now()) / 1000));
|
||||
setRemaining(secs);
|
||||
};
|
||||
tick();
|
||||
const id = setInterval(tick, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, [timeoutAt, defaultLabel]);
|
||||
|
||||
// Extract title, message, and description from surface components
|
||||
const titleComponent = surface.components.find(
|
||||
(c) => c.id === 'title' && 'Text' in (c.component as any)
|
||||
@@ -351,6 +368,15 @@ function SinglePagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Countdown for auto-selection */}
|
||||
{remaining !== null && defaultLabel && (
|
||||
<div className="text-xs text-muted-foreground text-center pt-2">
|
||||
{remaining > 0
|
||||
? `${remaining}s 后将自动选择「${defaultLabel}」`
|
||||
: `即将自动选择「${defaultLabel}」`}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer - Action buttons */}
|
||||
{actionButtons.length > 0 && (
|
||||
<DialogFooter className="pt-4">
|
||||
@@ -383,6 +409,22 @@ function MultiPagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
|
||||
// Countdown timer for auto-selection
|
||||
const timeoutAt = (state as any)?.timeoutAt as string | undefined;
|
||||
const [remaining, setRemaining] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!timeoutAt) return;
|
||||
const target = new Date(timeoutAt).getTime();
|
||||
const tick = () => {
|
||||
const secs = Math.max(0, Math.ceil((target - Date.now()) / 1000));
|
||||
setRemaining(secs);
|
||||
};
|
||||
tick();
|
||||
const id = setInterval(tick, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, [timeoutAt]);
|
||||
|
||||
// "Other" per-page state
|
||||
const [otherSelectedPages, setOtherSelectedPages] = useState<Set<number>>(new Set());
|
||||
const [otherTexts, setOtherTexts] = useState<Map<number, string>>(new Map());
|
||||
@@ -613,6 +655,15 @@ function MultiPagePopup({ surface, onClose }: A2UIPopupCardProps) {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Countdown for auto-selection */}
|
||||
{remaining !== null && (
|
||||
<div className="text-xs text-muted-foreground text-center">
|
||||
{remaining > 0
|
||||
? `${remaining}s 后将自动提交默认选项`
|
||||
: '即将自动提交默认选项'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer - Navigation buttons */}
|
||||
<DialogFooter className="pt-2">
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
|
||||
@@ -127,6 +127,7 @@ export const RadioGroupComponentSchema = z.object({
|
||||
label: TextContentSchema,
|
||||
value: z.string(),
|
||||
description: TextContentSchema.optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
})),
|
||||
selectedValue: TextContentSchema.optional(),
|
||||
onChange: ActionSchema,
|
||||
|
||||
@@ -43,7 +43,9 @@ export const A2UIRadioGroup: ComponentRenderer = ({ component, onAction, resolve
|
||||
return (
|
||||
<RadioGroup value={selectedValue} onValueChange={handleChange} className="space-y-2">
|
||||
{radioConfig.options.map((option, idx) => {
|
||||
const labelText = resolveTextContent(option.label, resolveBinding);
|
||||
const rawLabel = resolveTextContent(option.label, resolveBinding);
|
||||
const labelText = rawLabel.replace(/\s*\(Recommended\)\s*/i, '');
|
||||
const isDefault = (option as any).isDefault === true || /\(Recommended\)/i.test(rawLabel);
|
||||
const descriptionText = option.description
|
||||
? resolveTextContent(option.description, resolveBinding)
|
||||
: undefined;
|
||||
@@ -61,6 +63,11 @@ export const A2UIRadioGroup: ComponentRenderer = ({ component, onAction, resolve
|
||||
className="text-sm font-medium leading-none cursor-pointer"
|
||||
>
|
||||
{labelText}
|
||||
{isDefault && (
|
||||
<span className="ml-2 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-primary/10 text-primary">
|
||||
推荐
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
{descriptionText && (
|
||||
<span className="text-xs text-muted-foreground mt-1">
|
||||
|
||||
Reference in New Issue
Block a user