mike/frontend/src/app/components/assistant/InitialView.tsx

99 lines
4 KiB
TypeScript

"use client";
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { useAuth } from "@/contexts/AuthContext";
import { useUserProfile } from "@/contexts/UserProfileContext";
import { MikeIcon } from "@/components/chat/mike-icon";
import { ChatInput } from "./ChatInput";
import { SelectAssistantProjectModal } from "./SelectAssistantProjectModal";
import type { Message } from "../shared/types";
interface InitialViewProps {
onSubmit: (message: Message) => void;
}
const ICON_SIZE = 30;
const GAP = 12; // gap-4 = 1rem = 16px
export function InitialView({ onSubmit }: InitialViewProps) {
const { user } = useAuth();
const { profile } = useUserProfile();
const [loaded, setLoaded] = useState(false);
const [projectModalOpen, setProjectModalOpen] = useState(false);
const [iconOffset, setIconOffset] = useState(0);
const [textOffset, setTextOffset] = useState(0);
const textRef = useRef<HTMLHeadingElement>(null);
const username =
profile?.displayName?.trim() || user?.email?.split("@")[0] || "there";
useLayoutEffect(() => {
if (!profile || !textRef.current) return;
const h1Width = textRef.current.offsetWidth;
setIconOffset((h1Width + GAP) / 2);
setTextOffset((ICON_SIZE + GAP) / 2);
}, [profile]);
useEffect(() => {
if (!iconOffset) return;
const t = setTimeout(() => setLoaded(true), 100);
return () => clearTimeout(t);
}, [iconOffset]);
return (
<div className="flex flex-col h-full w-full px-6">
<div className="flex-1 flex flex-col items-center justify-center">
<div className="flex-col items-center w-full max-w-4xl relative px-0 xl:px-8">
<div className="mb-10 relative flex items-center justify-center">
<div
className="absolute h-[30px] w-[30px] top-[-14px]"
style={{
left: "50%",
transform: loaded
? `translateX(calc(-50% - ${iconOffset}px))`
: "translateX(-50%)",
transition:
"transform 900ms cubic-bezier(0.25, 0.46, 0.45, 0.94)",
}}
>
<MikeIcon size={ICON_SIZE} />
</div>
<h1
ref={textRef}
className="absolute text-4xl font-serif font-light text-gray-900 whitespace-nowrap"
style={{
left: "50%",
transform: loaded
? `translateX(calc(-50% + ${textOffset}px))`
: "translateX(-50%)",
opacity: loaded ? 1 : 0,
transition:
"transform 900ms cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 800ms ease-in-out 300ms",
}}
>
Hi, {username}
</h1>
</div>
<ChatInput
onSubmit={onSubmit}
onCancel={() => {}}
isLoading={false}
onProjectsClick={() => setProjectModalOpen(true)}
/>
<div className="text-center">
<p className="text-xs py-3 mb-3 text-gray-500">
AI can make mistakes. Answers are not legal advice.
</p>
</div>
</div>
</div>
<SelectAssistantProjectModal
open={projectModalOpen}
onClose={() => setProjectModalOpen(false)}
/>
</div>
);
}