fix: many minor fixes

This commit is contained in:
Henry Li
2026-01-25 21:57:57 +08:00
parent ae0e7de3b7
commit 598fed797f
4 changed files with 83 additions and 38 deletions

View File

@@ -34,6 +34,14 @@ export async function GET(
headers, headers,
}); });
} }
if (artifactPath.endsWith(".mp4")) {
return new Response(fs.readFileSync(artifactPath), {
status: 200,
headers: {
"Content-Type": "video/mp4",
},
});
}
return new Response(fs.readFileSync(artifactPath), { status: 200 }); return new Response(fs.readFileSync(artifactPath), { status: 200 });
} }
} }

View File

@@ -93,6 +93,13 @@ export default function ChatPage() {
thread.values.artifacts, thread.values.artifacts,
]); ]);
const artifactPanelOpen = useMemo(() => {
if (env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true") {
return artifactsOpen && artifacts?.length > 0;
}
return artifactsOpen;
}, [artifactsOpen, artifacts]);
const [todoListCollapsed, setTodoListCollapsed] = useState( const [todoListCollapsed, setTodoListCollapsed] = useState(
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true", env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true",
); );
@@ -119,8 +126,8 @@ export default function ChatPage() {
<ResizablePanelGroup orientation="horizontal"> <ResizablePanelGroup orientation="horizontal">
<ResizablePanel <ResizablePanel
className="relative" className="relative"
defaultSize={artifactsOpen && artifacts?.length > 0 ? 46 : 100} defaultSize={artifactPanelOpen ? 46 : 100}
minSize={artifactsOpen && artifacts?.length > 0 ? 30 : 100} minSize={artifactPanelOpen ? 30 : 100}
> >
<div className="relative flex size-full min-h-0 justify-between"> <div className="relative flex size-full min-h-0 justify-between">
<header <header
@@ -215,9 +222,7 @@ export default function ChatPage() {
<ResizableHandle <ResizableHandle
className={cn( className={cn(
"opacity-33 hover:opacity-100", "opacity-33 hover:opacity-100",
!artifactsOpen && !artifactPanelOpen && "pointer-events-none opacity-0",
artifacts?.length > 0 &&
"pointer-events-none opacity-0",
)} )}
/> />
<ResizablePanel <ResizablePanel
@@ -225,16 +230,14 @@ export default function ChatPage() {
"transition-all duration-300 ease-in-out", "transition-all duration-300 ease-in-out",
!artifactsOpen && "opacity-0", !artifactsOpen && "opacity-0",
)} )}
defaultSize={artifactsOpen && artifacts?.length > 0 ? 64 : 0} defaultSize={artifactPanelOpen ? 64 : 0}
minSize={0} minSize={0}
maxSize={artifactsOpen && artifacts?.length > 0 ? undefined : 0} maxSize={artifactPanelOpen ? undefined : 0}
> >
<div <div
className={cn( className={cn(
"h-full p-4 transition-transform duration-300 ease-in-out", "h-full p-4 transition-transform duration-300 ease-in-out",
artifactsOpen && artifacts?.length > 0 artifactPanelOpen ? "translate-x-0" : "translate-x-full",
? "translate-x-0"
: "translate-x-full",
)} )}
> >
{selectedArtifact ? ( {selectedArtifact ? (

View File

@@ -1,40 +1,48 @@
import { SparklesIcon } from "lucide-react"; import Link from "next/link";
import SpotlightCard from "@/components/ui/spotlight-card"; import { Card } from "@/components/ui/card";
import { pathOfThread } from "@/core/threads/utils";
import { cn } from "@/lib/utils";
import { Section } from "../section"; import { Section } from "../section";
export function CaseStudySection({ className }: { className?: string }) { export function CaseStudySection({ className }: { className?: string }) {
const caseStudies = [ const caseStudies = [
{ {
title: "2025 Survey", threadId: "7cfa5f8f-a2f8-47ad-acbd-da7137baf990",
title: "Forecast 2026 Agent Trends and Opportunities",
description: description:
"A 12,000-word research report analyzing 47 papers on brain-inspired chips, covering Intel Loihi 2, IBM NorthPole, and SynSense's edge AI solutions.", "Create a webpage with a Deep Research report forecasting the agent technology trends and opportunities in 2026.",
}, },
{ {
title: "Indie Hacker's SaaS Landing Page", threadId: "4f3e55ee-f853-43db-bfb3-7d1a411f03cb",
title: 'Generate a Video Based On the Novel "Pride and Prejudice"',
description: description:
"A fully responsive landing page with hero section, pricing table, testimonials, and Stripe integration — shipped in one conversation.", 'Search the specific scene from the novel "Pride and Prejudice", then generate a video as well as a reference image based on the scenes.',
}, },
{ {
title: "Transformer Architecture Explained", threadId: "21cfea46-34bd-4aa6-9e1f-3009452fbeb9",
title: "Doraemon Explains the MOE Architecture",
description: description:
"A 25-slide presentation breaking down self-attention, positional encoding, and KV-cache with hand-drawn style diagrams for a university lecture.", "Generate a Doraemon comic strip explaining the MOE architecture to the teenagers who are interested in AI.",
}, },
{ {
title: "DeerDeer Explains RAG", threadId: "ad76c455-5bf9-4335-8517-fc03834ab828",
title: "An Exploratory Data Analysis of the Titanic Dataset",
description: description:
"A series of 12 illustrations featuring a curious deer mascot explaining Retrieval-Augmented Generation through a library adventure story.", "Explore the Titanic dataset and identify the key factors that influenced survival rates with visualizations and insights.",
}, },
{ {
title: "AI Weekly: Your Tech Podcast", threadId: "d3e5adaf-084c-4dd5-9d29-94f1d6bccd98",
title: "Watch Y Combinator's Video then Conduct a Deep Research",
description: description:
"A 20-minute podcast episode where two AI hosts debate whether AI agents will replace traditional SaaS, based on 5 articles you provided.", "Watch the given Y Combinator's YouTube video and conduct a deep research on the YC's tips for technical startup founders.",
}, },
{ {
title: "How Diffusion Models Work", threadId: "3823e443-4e2b-4679-b496-a9506eae462b",
title: "Collect and Summarize Dr. Fei Fei Li's Podcasts",
description: description:
"A 3-minute animated explainer video visualizing the denoising process, from pure noise to a generated image, with voiceover narration.", "Collect all the podcast appearances of Dr. Fei Fei Li in the last 6 months, then summarize them into a comprehensive report.",
}, },
]; ];
return ( return (
@@ -43,23 +51,46 @@ export function CaseStudySection({ className }: { className?: string }) {
title="Case Studies" title="Case Studies"
subtitle="See how DeerFlow is used in the wild" subtitle="See how DeerFlow is used in the wild"
> >
<div className="mt-8 grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3"> <div className="container-md mt-8 grid grid-cols-1 gap-4 px-20 md:grid-cols-2 lg:grid-cols-3">
{caseStudies.map((caseStudy) => ( {caseStudies.map((caseStudy) => (
<SpotlightCard className="h-64" key={caseStudy.title}> <Link
<div className="flex h-full w-full flex-col items-center justify-center"> key={caseStudy.title}
<div className="flex w-75 flex-col gap-4"> href={pathOfThread(caseStudy.threadId)}
<div> target="_blank"
<SparklesIcon className="text-primary size-8" /> >
</div> <Card className="group/card relative h-64 overflow-hidden">
<div className="flex flex-col gap-2"> <div
<h3 className="text-2xl font-bold">{caseStudy.title}</h3> className="absolute inset-0 z-0 bg-cover bg-center bg-no-repeat transition-all duration-300 group-hover/card:scale-110 group-hover/card:brightness-90"
<p className="text-muted-foreground text-sm"> style={{
{caseStudy.description} backgroundImage: `url(/images/${caseStudy.threadId}.jpg)`,
</p> }}
></div>
<div
className={cn(
"flex h-full w-full translate-y-[calc(100%-60px)] flex-col items-center",
"transition-all duration-300",
"group-hover/card:translate-y-[calc(100%-128px)]",
)}
>
<div
className="flex w-full flex-col p-4"
style={{
background:
"linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%)",
}}
>
<div className="flex flex-col gap-2">
<h3 className="flex h-14 items-center text-xl font-bold text-shadow-black">
{caseStudy.title}
</h3>
<p className="box-shadow-black overflow-hidden text-sm text-white/85 text-shadow-black">
{caseStudy.description}
</p>
</div>
</div> </div>
</div> </div>
</div> </Card>
</SpotlightCard> </Link>
))} ))}
</div> </div>
</Section> </Section>

View File

@@ -11,9 +11,11 @@ interface Position {
interface SpotlightCardProps extends React.PropsWithChildren { interface SpotlightCardProps extends React.PropsWithChildren {
className?: string; className?: string;
spotlightColor?: `rgba(${number}, ${number}, ${number}, ${number})`; spotlightColor?: `rgba(${number}, ${number}, ${number}, ${number})`;
style?: React.CSSProperties;
} }
const SpotlightCard: React.FC<SpotlightCardProps> = ({ const SpotlightCard: React.FC<SpotlightCardProps> = ({
style,
children, children,
className = "", className = "",
spotlightColor = "rgba(255, 255, 255, 0.25)", spotlightColor = "rgba(255, 255, 255, 0.25)",
@@ -37,6 +39,7 @@ const SpotlightCard: React.FC<SpotlightCardProps> = ({
ref={divRef} ref={divRef}
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
className={`card-spotlight ${className}`} className={`card-spotlight ${className}`}
style={style}
> >
{children} {children}
</div> </div>