样式修改
This commit is contained in:
1 parent
c2c44f8d29
commit
03dff2ce77
17 files changed
+577
-58
No files matched your search
@@ -0,0 +1,34 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface CollapseTransitionProps {
|
||||
open: boolean;
|
||||
className?: string;
|
||||
innerClassName?: string;
|
||||
duration?: number;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function CollapseTransition({
|
||||
open,
|
||||
className,
|
||||
innerClassName,
|
||||
duration = 200,
|
||||
children,
|
||||
}: CollapseTransitionProps) {
|
||||
return (
|
||||
<div
|
||||
aria-hidden={!open}
|
||||
style={{ transitionDuration: `${duration}ms` }}
|
||||
className={cn(
|
||||
'grid overflow-hidden transition-[grid-template-rows,opacity] ease-out',
|
||||
open ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className={cn('min-h-0 overflow-hidden', innerClassName)}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
CheckCircle2, ChevronRight, ChevronDown,
|
||||
CheckCircle2, ChevronRight,
|
||||
ExternalLink, ListTree, FileText,
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -9,6 +9,7 @@ import type { AIMaterial, CompletedIntervention } from '../../types/ai-writing';
|
||||
import { OutlineCard } from './OutlineCard';
|
||||
import { ReviewCard } from './ReviewCard';
|
||||
import { ScoreBar } from './ScoreBar';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface Props {
|
||||
record: CompletedIntervention;
|
||||
@@ -57,19 +58,22 @@ function MaterialCompleted({ record, expanded, onToggle }: { record: CompletedIn
|
||||
)}
|
||||
</span>
|
||||
{count > 0 && (
|
||||
expanded
|
||||
? <ChevronDown className="size-3 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3 text-muted-foreground" />
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{expanded && record.materials && record.materials.length > 0 && (
|
||||
<div className="px-2.5 pb-2.5 pt-1 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
|
||||
{record.materials.map((m) => (
|
||||
<CollapseTransition open={expanded && !!record.materials && record.materials.length > 0}>
|
||||
<div className="px-2.5 pb-2.5 pt-1.5 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
|
||||
{record.materials?.map((m) => (
|
||||
<CompletedMaterialItem key={m.id} material={m} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -102,9 +106,12 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
|
||||
<div className="flex items-start gap-1.5">
|
||||
<span className="flex-1 font-medium leading-snug line-clamp-2">{material.title}</span>
|
||||
{hasDetail && (
|
||||
open
|
||||
? <ChevronDown className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
|
||||
: <ChevronRight className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'mt-0.5 size-3 shrink-0 text-muted-foreground transition-transform duration-200',
|
||||
open && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
@@ -120,7 +127,7 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{open && hasDetail && (
|
||||
<CollapseTransition open={open && hasDetail}>
|
||||
<div className="px-2.5 pb-2 pt-1.5 space-y-1.5 border-t border-border/40">
|
||||
{material.content && (
|
||||
<p className="text-muted-foreground leading-relaxed line-clamp-6">
|
||||
@@ -139,7 +146,7 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -168,17 +175,20 @@ function OutlineCompleted({ record, expanded, onToggle }: { record: CompletedInt
|
||||
<span className="ml-1 text-muted-foreground font-normal">共 {sectionCount} 章节</span>
|
||||
</span>
|
||||
{record.outline && (
|
||||
expanded
|
||||
? <ChevronDown className="size-3 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3 text-muted-foreground" />
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{expanded && record.outline && (
|
||||
<CollapseTransition open={expanded && !!record.outline}>
|
||||
<div className="px-2.5 pb-2.5 pt-1 border-t border-green-200/40 dark:border-green-900/20">
|
||||
<OutlineCard outline={record.outline} readOnly />
|
||||
{record.outline && <OutlineCard outline={record.outline} readOnly />}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -217,17 +227,20 @@ function DraftCompleted({ record, expanded, onToggle }: { record: CompletedInter
|
||||
{wordCount > 0 && <span className="ml-1">({wordCount} 字)</span>}
|
||||
</span>
|
||||
{hasReview && (
|
||||
expanded
|
||||
? <ChevronDown className="size-3 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3 text-muted-foreground" />
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{expanded && record.reviewResult && (
|
||||
<CollapseTransition open={expanded && !!record.reviewResult}>
|
||||
<div className="px-2.5 pb-2.5 pt-1 border-t border-green-200/40 dark:border-green-900/20">
|
||||
<ReviewCard review={record.reviewResult} />
|
||||
{record.reviewResult && <ReviewCard review={record.reviewResult} />}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -259,19 +272,26 @@ function ReviewCompleted({ record, expanded, onToggle }: { record: CompletedInte
|
||||
</span>
|
||||
)}
|
||||
{hasReview && (
|
||||
expanded
|
||||
? <ChevronDown className="size-3 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3 text-muted-foreground" />
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{expanded && record.reviewResult && (
|
||||
<CollapseTransition open={expanded && !!record.reviewResult}>
|
||||
<div className="px-2.5 pb-2.5 pt-1 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
|
||||
<ScoreBar label="事实准确性" score={record.reviewResult.factScore} />
|
||||
<ScoreBar label="逻辑结构" score={record.reviewResult.logicScore} />
|
||||
<ScoreBar label="语言文字" score={record.reviewResult.languageScore} />
|
||||
{record.reviewResult && (
|
||||
<>
|
||||
<ScoreBar label="事实准确性" score={record.reviewResult.factScore} />
|
||||
<ScoreBar label="逻辑结构" score={record.reviewResult.logicScore} />
|
||||
<ScoreBar label="语言文字" score={record.reviewResult.languageScore} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Brain, ChevronDown, ChevronRight } from 'lucide-react';
|
||||
import { Brain, ChevronRight } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { StreamingDraftSection } from '../../types/ai-writing';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface DraftStreamingViewProps {
|
||||
title: string;
|
||||
@@ -40,10 +41,10 @@ function SectionThinking({ thinkingText, isDone }: { thinkingText: string; isDon
|
||||
<Brain className="size-3 text-amber-500 shrink-0" />
|
||||
<span className="text-[11px] font-medium text-amber-600 dark:text-amber-400">思考过程</span>
|
||||
<span className="ml-auto text-amber-400">
|
||||
{open ? <ChevronDown className="size-3" /> : <ChevronRight className="size-3" />}
|
||||
<ChevronRight className={cn('size-3 transition-transform duration-200', open && 'rotate-90')} />
|
||||
</span>
|
||||
</button>
|
||||
{open && (
|
||||
<CollapseTransition open={open}>
|
||||
<pre
|
||||
ref={preRef}
|
||||
className="text-[10px] font-mono leading-relaxed px-2.5 py-2 text-amber-700/70 dark:text-amber-300/60 whitespace-pre-wrap max-h-32 overflow-y-auto italic"
|
||||
@@ -53,7 +54,7 @@ function SectionThinking({ thinkingText, isDone }: { thinkingText: string; isDon
|
||||
<span className="inline-block w-0.5 h-3 bg-amber-400 ml-0.5 align-text-bottom animate-[blink_1s_step-end_infinite]" />
|
||||
)}
|
||||
</pre>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { ChevronRight, ChevronDown, ExternalLink } from 'lucide-react';
|
||||
import { ChevronRight, ExternalLink } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { buildIntranetSourceUrl } from '@/core/config';
|
||||
import type { AIMaterial } from '../../types/ai-writing';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface MaterialItemProps {
|
||||
material: AIMaterial;
|
||||
@@ -52,9 +53,12 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
|
||||
<span className={cn('flex-1 font-medium leading-snug line-clamp-2', !checked && 'text-muted-foreground')}>
|
||||
{material.title}
|
||||
</span>
|
||||
{expanded
|
||||
? <ChevronDown className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
|
||||
: <ChevronRight className="mt-0.5 size-3 shrink-0 text-muted-foreground" />}
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'mt-0.5 size-3 shrink-0 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -83,7 +87,7 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
|
||||
</div>
|
||||
|
||||
{/* 展开内容 */}
|
||||
{expanded && (
|
||||
<CollapseTransition open={expanded}>
|
||||
<div className="px-2.5 pb-2.5 pl-8 space-y-1.5 border-t">
|
||||
<p className="text-muted-foreground leading-relaxed pt-2 line-clamp-6">
|
||||
{material.content.slice(0, 300)}
|
||||
@@ -102,7 +106,7 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { ChevronDown, ChevronRight, FileText } from 'lucide-react';
|
||||
import { ChevronRight, FileText } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { AIMaterial } from '../../types/ai-writing';
|
||||
import { MaterialItem } from './MaterialItem';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface MaterialsCardProps {
|
||||
materials: AIMaterial[];
|
||||
@@ -27,14 +29,17 @@ export function MaterialsCard({ materials, selectedIds, onToggle }: MaterialsCar
|
||||
(共 {materials.length} 条,已选 {selectedIds.size} 条)
|
||||
</span>
|
||||
</span>
|
||||
{expanded
|
||||
? <ChevronDown className="size-3 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3 text-muted-foreground" />}
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{/* 列表 */}
|
||||
{expanded && (
|
||||
<div className="px-2.5 pb-2.5 space-y-1.5 border-t">
|
||||
<CollapseTransition open={expanded}>
|
||||
<div className="px-2.5 pb-2.5 pt-1.5 space-y-1.5 border-t">
|
||||
{materials.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground py-2 text-center">暂无素材</p>
|
||||
) : (
|
||||
@@ -48,7 +53,7 @@ export function MaterialsCard({ materials, selectedIds, onToggle }: MaterialsCar
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { ListTree, Plus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { AIOutline, OutlineSection as OutlineSectionType } from '../../types/ai-writing';
|
||||
import { OutlineSection } from './OutlineSection';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface OutlineCardProps {
|
||||
outline: AIOutline;
|
||||
@@ -69,7 +70,7 @@ export function OutlineCard({ outline, onChange, readOnly = false }: OutlineCard
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{!collapsed && (
|
||||
<CollapseTransition open={!collapsed}>
|
||||
<div className="px-3 py-2.5 space-y-2">
|
||||
{/* 文章标题 */}
|
||||
<div className="flex items-center gap-1.5 text-xs">
|
||||
@@ -137,7 +138,7 @@ export function OutlineCard({ outline, onChange, readOnly = false }: OutlineCard
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { ChevronRight, ChevronDown, Plus, X, GripVertical } from 'lucide-react';
|
||||
import { ChevronRight, Plus, X, GripVertical } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { OutlineSection as OutlineSectionType } from '../../types/ai-writing';
|
||||
import { CollapseTransition } from './CollapseTransition';
|
||||
|
||||
interface OutlineSectionProps {
|
||||
section: OutlineSectionType;
|
||||
@@ -72,9 +73,12 @@ export function OutlineSection({
|
||||
onClick={() => setExpanded((v) => !v)}
|
||||
className="shrink-0"
|
||||
>
|
||||
{expanded
|
||||
? <ChevronDown className="size-3.5 text-muted-foreground" />
|
||||
: <ChevronRight className="size-3.5 text-muted-foreground" />}
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
'size-3.5 text-muted-foreground transition-transform duration-200',
|
||||
expanded && 'rotate-90',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<span className="text-muted-foreground/60 shrink-0 w-4 text-center">{index + 1}.</span>
|
||||
@@ -109,7 +113,7 @@ export function OutlineSection({
|
||||
</div>
|
||||
|
||||
{/* 要点列表 */}
|
||||
{expanded && (
|
||||
<CollapseTransition open={expanded}>
|
||||
<div className="px-8 pb-2.5 space-y-1 border-t">
|
||||
{section.keyPoints.map((kp, i) => (
|
||||
<div key={i} className="flex items-center gap-1.5 pt-1.5">
|
||||
@@ -142,7 +146,7 @@ export function OutlineSection({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</CollapseTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user