mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-26 17:26:23 +02:00
feat: improve public chat UI and shared components
This commit is contained in:
parent
37adc54d6a
commit
ee65e1377f
14 changed files with 403 additions and 275 deletions
|
|
@ -1,34 +0,0 @@
|
|||
import { formatDistanceToNow } from "date-fns";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
interface PublicChatHeaderProps {
|
||||
title: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export function PublicChatHeader({ title, createdAt }: PublicChatHeaderProps) {
|
||||
const timeAgo = formatDistanceToNow(new Date(createdAt), { addSuffix: true });
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-10 -mx-4 mb-4 border-b bg-background/95 px-4 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||
<div className="mx-auto flex max-w-(--thread-max-width) items-center justify-between py-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/" className="shrink-0">
|
||||
<Image
|
||||
src="/surfsenselogo.png"
|
||||
alt="SurfSense"
|
||||
width={32}
|
||||
height={32}
|
||||
className="rounded"
|
||||
/>
|
||||
</Link>
|
||||
<div className="min-w-0">
|
||||
<h1 className="truncate font-medium">{title}</h1>
|
||||
<p className="text-xs text-muted-foreground">{timeAgo}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { Navbar } from "@/components/homepage/navbar";
|
||||
import { DisplayImageToolUI } from "@/components/tool-ui/display-image";
|
||||
import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast";
|
||||
import { LinkPreviewToolUI } from "@/components/tool-ui/link-preview";
|
||||
|
|
@ -9,7 +10,6 @@ import { ScrapeWebpageToolUI } from "@/components/tool-ui/scrape-webpage";
|
|||
import { usePublicChat } from "@/hooks/use-public-chat";
|
||||
import { usePublicChatRuntime } from "@/hooks/use-public-chat-runtime";
|
||||
import { PublicChatFooter } from "./public-chat-footer";
|
||||
import { PublicChatHeader } from "./public-chat-header";
|
||||
import { PublicThread } from "./public-thread";
|
||||
|
||||
interface PublicChatViewProps {
|
||||
|
|
@ -22,37 +22,43 @@ export function PublicChatView({ shareToken }: PublicChatViewProps) {
|
|||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<Loader2 className="size-8 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
<main className="min-h-screen bg-linear-to-b from-gray-50 to-gray-100 text-gray-900 dark:from-black dark:to-gray-900 dark:text-white overflow-x-hidden">
|
||||
<Navbar />
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<Loader2 className="size-8 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !data) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col items-center justify-center gap-4 px-4 text-center">
|
||||
<h1 className="text-2xl font-semibold">Chat not found</h1>
|
||||
<p className="text-muted-foreground">
|
||||
This chat may have been removed or is no longer public.
|
||||
</p>
|
||||
</div>
|
||||
<main className="min-h-screen bg-linear-to-b from-gray-50 to-gray-100 text-gray-900 dark:from-black dark:to-gray-900 dark:text-white overflow-x-hidden">
|
||||
<Navbar />
|
||||
<div className="flex h-screen flex-col items-center justify-center gap-4 px-4 text-center">
|
||||
<h1 className="text-2xl font-semibold">Chat not found</h1>
|
||||
<p className="text-muted-foreground">
|
||||
This chat may have been removed or is no longer public.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AssistantRuntimeProvider runtime={runtime}>
|
||||
{/* Tool UIs for rendering tool results */}
|
||||
<GeneratePodcastToolUI />
|
||||
<LinkPreviewToolUI />
|
||||
<DisplayImageToolUI />
|
||||
<ScrapeWebpageToolUI />
|
||||
<main className="min-h-screen bg-linear-to-b from-gray-50 to-gray-100 text-gray-900 dark:from-black dark:to-gray-900 dark:text-white overflow-x-hidden">
|
||||
<Navbar />
|
||||
<AssistantRuntimeProvider runtime={runtime}>
|
||||
{/* Tool UIs for rendering tool results */}
|
||||
<GeneratePodcastToolUI />
|
||||
<LinkPreviewToolUI />
|
||||
<DisplayImageToolUI />
|
||||
<ScrapeWebpageToolUI />
|
||||
|
||||
<div className="flex h-screen flex-col bg-background">
|
||||
<PublicThread
|
||||
header={<PublicChatHeader title={data.thread.title} createdAt={data.thread.created_at} />}
|
||||
footer={<PublicChatFooter shareToken={shareToken} />}
|
||||
/>
|
||||
</div>
|
||||
</AssistantRuntimeProvider>
|
||||
<div className="flex h-screen flex-col pt-16">
|
||||
<PublicThread footer={<PublicChatFooter shareToken={shareToken} />} />
|
||||
</div>
|
||||
</AssistantRuntimeProvider>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ import { type FC, type ReactNode, useState } from "react";
|
|||
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
||||
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
||||
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PublicThreadProps {
|
||||
header?: ReactNode;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +21,7 @@ interface PublicThreadProps {
|
|||
* Read-only thread component for public chat viewing.
|
||||
* No composer, no edit capabilities - just message display.
|
||||
*/
|
||||
export const PublicThread: FC<PublicThreadProps> = ({ header, footer }) => {
|
||||
export const PublicThread: FC<PublicThreadProps> = ({ footer }) => {
|
||||
return (
|
||||
<ThreadPrimitive.Root
|
||||
className="aui-root aui-thread-root @container flex h-full min-h-0 flex-col bg-background"
|
||||
|
|
@ -32,8 +30,6 @@ export const PublicThread: FC<PublicThreadProps> = ({ header, footer }) => {
|
|||
}}
|
||||
>
|
||||
<ThreadPrimitive.Viewport className="aui-thread-viewport relative flex flex-1 min-h-0 flex-col overflow-y-auto px-4 pt-4">
|
||||
{header}
|
||||
|
||||
<ThreadPrimitive.Messages
|
||||
components={{
|
||||
UserMessage: PublicUserMessage,
|
||||
|
|
@ -159,10 +155,8 @@ const PublicAssistantActionBar: FC = () => {
|
|||
return (
|
||||
<ActionBarPrimitive.Root
|
||||
autohide="not-last"
|
||||
className={cn(
|
||||
"aui-assistant-action-bar-root -ml-1 flex gap-1 text-muted-foreground",
|
||||
"opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
)}
|
||||
autohideFloat="single-branch"
|
||||
className="aui-assistant-action-bar-root -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm"
|
||||
>
|
||||
<ActionBarPrimitive.Copy asChild>
|
||||
<TooltipIconButton tooltip="Copy">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue