chore: format

This commit is contained in:
Lluis Agusti
2026-01-20 18:56:39 +07:00
parent f51e50fe10
commit 451191c73c
7 changed files with 92 additions and 80 deletions

View File

@@ -34,7 +34,11 @@ export function CopilotShell({ children }: Props) {
} = useCopilotShell();
if (!isLoggedIn) {
return <div className="flex h-full items-center justify-center"><LoadingSpinner size="large" /></div>;
return (
<div className="flex h-full items-center justify-center">
<LoadingSpinner size="large" />
</div>
);
}
return (

View File

@@ -28,7 +28,7 @@ export function useCopilotShell() {
const { isLoggedIn } = useSupabase();
const isMobile =
breakpoint === "base" || breakpoint === "sm" || breakpoint === "md";
const isOnHomepage = pathname === "/copilot";
const paramSessionId = searchParams.get("sessionId");
@@ -55,7 +55,7 @@ export function useCopilotShell() {
});
const storedSessionId = storage.get(Key.CHAT_SESSION_ID) ?? null;
const currentSessionId = getCurrentSessionId(searchParams, storedSessionId)
const currentSessionId = getCurrentSessionId(searchParams, storedSessionId);
const { data: currentSessionData, isLoading: isCurrentSessionLoading } =
useGetV2GetSession(currentSessionId || "", {
@@ -109,7 +109,7 @@ export function useCopilotShell() {
}
const visibleSessions = filterVisibleSessions(accumulatedSessions);
const autoSelect = shouldAutoSelectSession(
areAllSessionsLoaded,
hasAutoSelectedRef.current,
@@ -192,7 +192,7 @@ export function useCopilotShell() {
currentSessionData,
hasAutoSelectedSession,
);
function handleSelectSession(sessionId: string) {
router.push(`/copilot/chat?sessionId=${sessionId}`);
if (isMobile) handleCloseDrawer();
@@ -215,7 +215,8 @@ export function useCopilotShell() {
isMobile,
isDrawerOpen,
isLoggedIn,
hasActiveSession: Boolean(currentSessionId) && (!isOnHomepage || paramSessionId),
hasActiveSession:
Boolean(currentSessionId) && (!isOnHomepage || paramSessionId),
isLoading: isSessionsLoading || !areAllSessionsLoaded,
sessions,
currentSessionId: sidebarSelectedSessionId,

View File

@@ -24,7 +24,9 @@ export default function CopilotPage() {
} = useCopilotHome();
useEffect(() => {
const textarea = document.getElementById("copilot-prompt") as HTMLTextAreaElement;
const textarea = document.getElementById(
"copilot-prompt",
) as HTMLTextAreaElement;
if (!textarea) return;
textarea.style.height = "auto";
const lineHeight = parseInt(
@@ -46,10 +48,10 @@ export default function CopilotPage() {
const isLoading = isUserLoading;
return (
<div className="flex h-full flex-1 items-center justify-center overflow-y-auto px-6 py-10 bg-[#f8f8f9]">
<div className="w-full text-center">
<div className="flex h-full flex-1 items-center justify-center overflow-y-auto bg-[#f8f8f9] px-6 py-10">
<div className="w-full text-center">
{isLoading ? (
<div className="max-w-2xl mx-auto">
<div className="mx-auto max-w-2xl">
<Skeleton className="mx-auto mb-3 h-8 w-64" />
<Skeleton className="mx-auto mb-8 h-6 w-80" />
<div className="mb-8">
@@ -63,13 +65,16 @@ export default function CopilotPage() {
</div>
) : (
<>
<div className="max-w-2xl mx-auto">
<Text variant="h3" className="mb-3 text-zinc-700 !text-[1.375rem]">
Hey, <span className="text-violet-600">{greetingName}</span>
</Text>
<Text variant="h3" className="mb-8 !font-normal">
What do you want to automate?
</Text>
<div className="mx-auto max-w-2xl">
<Text
variant="h3"
className="mb-3 !text-[1.375rem] text-zinc-700"
>
Hey, <span className="text-violet-600">{greetingName}</span>
</Text>
<Text variant="h3" className="mb-8 !font-normal">
What do you want to automate?
</Text>
<form onSubmit={handleSubmit} className="mb-6">
<div className="relative">
@@ -84,7 +89,7 @@ export default function CopilotPage() {
rows={1}
placeholder='You can search or just ask - e.g. "create a blog post outline"'
wrapperClassName="mb-0"
className="!py-5 !rounded-full pr-12 !text-[1rem] border-transparent [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]"
className="!rounded-full border-transparent !py-5 pr-12 !text-[1rem] [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
/>
<Button
type="submit"
@@ -99,14 +104,14 @@ export default function CopilotPage() {
</div>
</form>
</div>
<div className="flex flex-nowrap items-center justify-center gap-3 overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
<div className="flex flex-nowrap items-center justify-center gap-3 overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
{quickActions.map((action) => (
<Button
key={action}
variant="outline"
size="small"
onClick={() => handleQuickAction(action)}
className="border-zinc-600 text-zinc-600 text-[1rem] !py-2 !px-4 h-auto shrink-0"
className="h-auto shrink-0 border-zinc-600 !px-4 !py-2 text-[1rem] text-zinc-600"
>
{action}
</Button>

View File

@@ -11,10 +11,7 @@ import {
import { useFlags } from "launchdarkly-react-client-sdk";
import { useRouter } from "next/navigation";
import { useEffect, useMemo, useState } from "react";
import {
getGreetingName,
getQuickActions,
} from "./helpers";
import { getGreetingName, getQuickActions } from "./helpers";
export function useCopilotHome() {
const router = useRouter();
@@ -28,8 +25,8 @@ export function useCopilotHome() {
const isLaunchDarklyConfigured = envEnabled && Boolean(clientId);
const isFlagReady =
!isLaunchDarklyConfigured || flags[Flag.CHAT] !== undefined;
const greetingName = useMemo(
const greetingName = useMemo(
function getName() {
return getGreetingName(user);
},

View File

@@ -29,7 +29,8 @@ export function ChatContainer({
const { capturePageContext } = usePageContext();
const hasSentInitialRef = useRef(false);
const breakpoint = useBreakpoint();
const isMobile = breakpoint === "base" || breakpoint === "sm" || breakpoint === "md";
const isMobile =
breakpoint === "base" || breakpoint === "sm" || breakpoint === "md";
// Wrap sendMessage to automatically capture page context
const sendMessageWithContext = useCallback(
@@ -73,12 +74,16 @@ export function ChatContainer({
</div>
{/* Input - Fixed at bottom */}
<div className="relative pb-4 pt-2 px-3">
<div className="relative px-3 pb-4 pt-2">
<div className="pointer-events-none absolute top-[-18px] z-10 h-6 w-full bg-gradient-to-b from-transparent to-[#f8f8f9]" />
<ChatInput
onSend={sendMessageWithContext}
disabled={isStreaming || !sessionId}
placeholder={isMobile ? "You can search or just ask" : "You can search or just ask — e.g. “create a blog post outline”"}
placeholder={
isMobile
? "You can search or just ask"
: "You can search or just ask — e.g. “create a blog post outline”"
}
/>
</div>
</div>

View File

@@ -7,7 +7,7 @@ import {
ArrowsClockwiseIcon,
CheckCircleIcon,
CheckIcon,
CopyIcon
CopyIcon,
} from "@phosphor-icons/react";
import { useRouter } from "next/navigation";
import { useCallback, useState } from "react";
@@ -269,7 +269,7 @@ export function ChatMessage({
onClick={handleTryAgain}
aria-label="Try again"
>
<ArrowsClockwiseIcon className="size-4 text-zinc-600" />
<ArrowsClockwiseIcon className="size-4 text-zinc-600" />
</Button>
)}
{(isUser || isFinalMessage) && (

View File

@@ -35,7 +35,7 @@ export function MessageList({
<div className="relative flex min-h-0 flex-1 flex-col">
{/* Top fade shadow */}
<div className="pointer-events-none absolute top-0 z-10 h-8 w-full bg-gradient-to-b from-[#f8f8f9] to-transparent" />
<div
ref={messagesContainerRef}
className={cn(
@@ -45,67 +45,67 @@ export function MessageList({
)}
>
<div className="mx-auto flex min-w-0 flex-col hyphens-auto break-words py-4">
{/* Render all persisted messages */}
{(() => {
const lastAssistantMessageIndex = findLastMessageIndex(
messages,
(msg) => msg.type === "message" && msg.role === "assistant",
);
{/* Render all persisted messages */}
{(() => {
const lastAssistantMessageIndex = findLastMessageIndex(
messages,
(msg) => msg.type === "message" && msg.role === "assistant",
);
const lastToolResponseIndex = findLastMessageIndex(
messages,
(msg) => msg.type === "tool_response",
);
const lastToolResponseIndex = findLastMessageIndex(
messages,
(msg) => msg.type === "tool_response",
);
return messages.map((message, index) => {
// Skip agent_output tool_responses that should be rendered inside assistant messages
if (shouldSkipAgentOutput(message, messages[index - 1])) {
return null;
}
return messages.map((message, index) => {
// Skip agent_output tool_responses that should be rendered inside assistant messages
if (shouldSkipAgentOutput(message, messages[index - 1])) {
return null;
}
// Render last tool_response as AIChatBubble
if (
message.type === "tool_response" &&
index === lastToolResponseIndex
) {
return (
<LastToolResponse
key={index}
message={message}
prevMessage={messages[index - 1]}
/>
);
}
// Render last tool_response as AIChatBubble
if (
message.type === "tool_response" &&
index === lastToolResponseIndex
) {
return (
<LastToolResponse
<MessageItem
key={index}
message={message}
prevMessage={messages[index - 1]}
messages={messages}
index={index}
lastAssistantMessageIndex={lastAssistantMessageIndex}
onSendMessage={onSendMessage}
/>
);
}
});
})()}
return (
<MessageItem
key={index}
message={message}
messages={messages}
index={index}
lastAssistantMessageIndex={lastAssistantMessageIndex}
onSendMessage={onSendMessage}
/>
);
});
})()}
{/* Render thinking message when streaming but no chunks yet */}
{isStreaming && streamingChunks.length === 0 && <ThinkingMessage />}
{/* Render thinking message when streaming but no chunks yet */}
{isStreaming && streamingChunks.length === 0 && <ThinkingMessage />}
{/* Render streaming message if active */}
{isStreaming && streamingChunks.length > 0 && (
<StreamingMessage
chunks={streamingChunks}
onComplete={onStreamComplete}
/>
)}
{/* Render streaming message if active */}
{isStreaming && streamingChunks.length > 0 && (
<StreamingMessage
chunks={streamingChunks}
onComplete={onStreamComplete}
/>
)}
{/* Invisible div to scroll to */}
<div ref={messagesEndRef} />
{/* Invisible div to scroll to */}
<div ref={messagesEndRef} />
</div>
</div>
{/* Bottom fade shadow */}
<div className="pointer-events-none absolute bottom-0 z-10 h-8 w-full bg-gradient-to-t from-[#f8f8f9] to-transparent" />
</div>