This commit is contained in:
yezhwi 2026-05-20 03:01:16 +08:00 committed by GitHub
commit 4bdffabaed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 70 additions and 46 deletions

View file

@ -0,0 +1,25 @@
import { Footer } from "@/components/landing/footer";
import { Header } from "@/components/landing/header";
import { Hero } from "@/components/landing/hero";
import { CaseStudySection } from "@/components/landing/sections/case-study-section";
import { CommunitySection } from "@/components/landing/sections/community-section";
import { SandboxSection } from "@/components/landing/sections/sandbox-section";
import { SkillsSection } from "@/components/landing/sections/skills-section";
import { WhatsNewSection } from "@/components/landing/sections/whats-new-section";
export default function LandingPage() {
return (
<div className="min-h-screen w-full bg-[#0a0a0a]">
<Header />
<main className="flex w-full flex-col">
<Hero />
<CaseStudySection />
<SkillsSection />
<SandboxSection />
<WhatsNewSection />
<CommunitySection />
</main>
<Footer />
</div>
);
}

View file

@ -18,7 +18,7 @@ export default async function RootLayout({
const locale = await detectLocaleServer();
return (
<html lang={locale} suppressContentEditableWarning suppressHydrationWarning>
<body>
<body suppressHydrationWarning>
<ThemeProvider attribute="class" enableSystem disableTransitionOnChange>
<I18nProvider initialLocale={locale}>{children}</I18nProvider>
</ThemeProvider>

View file

@ -1,25 +1,5 @@
import { Footer } from "@/components/landing/footer";
import { Header } from "@/components/landing/header";
import { Hero } from "@/components/landing/hero";
import { CaseStudySection } from "@/components/landing/sections/case-study-section";
import { CommunitySection } from "@/components/landing/sections/community-section";
import { SandboxSection } from "@/components/landing/sections/sandbox-section";
import { SkillsSection } from "@/components/landing/sections/skills-section";
import { WhatsNewSection } from "@/components/landing/sections/whats-new-section";
import { redirect } from "next/navigation";
export default function LandingPage() {
return (
<div className="min-h-screen w-full bg-[#0a0a0a]">
<Header />
<main className="flex w-full flex-col">
<Hero />
<CaseStudySection />
<SkillsSection />
<SandboxSection />
<WhatsNewSection />
<CommunitySection />
</main>
<Footer />
</div>
);
export default function HomePage() {
redirect("/workspace");
}

View file

@ -335,7 +335,9 @@ export default function Galaxy({
ctn.removeEventListener("mousemove", handleMouseMove);
ctn.removeEventListener("mouseleave", handleMouseLeave);
}
ctn.removeChild(gl.canvas);
if (gl.canvas.parentNode === ctn) {
ctn.removeChild(gl.canvas);
}
gl.getExtension("WEBGL_lose_context")?.loseContext();
};
}, [

View file

@ -130,7 +130,9 @@ const ParticleCard: React.FC<{
duration: 0.3,
ease: "back.in(1.7)",
onComplete: () => {
particle.parentNode?.removeChild(particle);
if (particle.parentNode) {
particle.parentNode.removeChild(particle);
}
},
});
});
@ -482,7 +484,9 @@ const GlobalSpotlight: React.FC<{
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseleave", handleMouseLeave);
spotlightRef.current?.parentNode?.removeChild(spotlightRef.current);
if (spotlightRef.current?.parentNode) {
spotlightRef.current.parentNode.removeChild(spotlightRef.current);
}
};
}, [gridRef, disableAnimations, enabled, spotlightRadius, glowColor]);

View file

@ -40,17 +40,28 @@ export function getMessageGroups(messages: Message[]): MessageGroup[] {
const groups: MessageGroup[] = [];
// Returns the last group if it can still accept tool messages
// (i.e. it's an in-flight processing group, not a terminal human/assistant group).
// Returns the nearest prior group that can still accept tool messages.
// This intentionally scans backwards instead of only checking the last group,
// because an AI message can now render both:
// 1. an in-flight processing group for tool calls, and
// 2. a normal assistant bubble for user-visible text.
// In that case, the assistant bubble is appended after the processing group,
// and later tool messages still belong to that earlier processing group.
function lastOpenGroup() {
const last = groups[groups.length - 1];
if (
last &&
last.type !== "human" &&
last.type !== "assistant" &&
last.type !== "assistant:clarification"
) {
return last;
for (let i = groups.length - 1; i >= 0; i -= 1) {
const group = groups[i];
if (!group) {
continue;
}
if (group.type === "human") {
return null;
}
if (
group.type !== "assistant" &&
group.type !== "assistant:clarification"
) {
return group;
}
}
return null;
}
@ -79,11 +90,6 @@ export function getMessageGroups(messages: Message[]): MessageGroup[] {
const open = lastOpenGroup();
if (open) {
open.messages.push(message);
} else {
console.error(
"Unexpected tool message outside a processing group",
message,
);
}
}
continue;
@ -116,9 +122,14 @@ export function getMessageGroups(messages: Message[]): MessageGroup[] {
}
}
// Not an else-if: a message with reasoning + content (but no tool calls) goes
// into the processing group above AND gets its own assistant bubble here.
if (hasContent(message) && !hasToolCalls(message)) {
// Not an else-if: intermediate assistant messages can contain both
// user-facing text and tool calls. We still want to show that text as a
// normal assistant bubble instead of rendering only the tool timeline.
if (
hasContent(message) &&
!hasPresentFiles(message) &&
!hasSubagent(message)
) {
groups.push({ id: message.id, type: "assistant", messages: [message] });
}
}

View file

@ -120,7 +120,9 @@ export function downloadAsFile(
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
if (a.parentNode === document.body) {
document.body.removeChild(a);
}
URL.revokeObjectURL(url);
}