mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-12-24 20:48:14 +00:00
feat(library): enhance ui & ux
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import DeleteChat from '@/components/DeleteChat';
|
import DeleteChat from '@/components/DeleteChat';
|
||||||
import { cn, formatTimeDifference } from '@/lib/utils';
|
import { formatTimeDifference } from '@/lib/utils';
|
||||||
import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react';
|
import { BookOpenText, ClockIcon, FileText, Globe2Icon } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
@@ -10,7 +10,8 @@ export interface Chat {
|
|||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
focusMode: string;
|
sources: string[];
|
||||||
|
files: { fileId: string; name: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
@@ -37,8 +38,38 @@ const Page = () => {
|
|||||||
fetchChats();
|
fetchChats();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return loading ? (
|
return (
|
||||||
<div className="flex flex-row items-center justify-center min-h-screen">
|
<div>
|
||||||
|
<div className="flex flex-col pt-10 border-b border-light-200/20 dark:border-dark-200/20 pb-6 px-2">
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-3">
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<BookOpenText size={45} className="mb-2.5" />
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<h1
|
||||||
|
className="text-5xl font-normal p-2 pb-0"
|
||||||
|
style={{ fontFamily: 'PP Editorial, serif' }}
|
||||||
|
>
|
||||||
|
Library
|
||||||
|
</h1>
|
||||||
|
<div className="px-2 text-sm text-black/60 dark:text-white/60 text-center lg:text-left">
|
||||||
|
Past chats, sources, and uploads.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-center lg:justify-end gap-2 text-xs text-black/60 dark:text-white/60">
|
||||||
|
<span className="inline-flex items-center gap-1 rounded-full border border-black/20 dark:border-white/20 px-2 py-0.5">
|
||||||
|
<BookOpenText size={14} />
|
||||||
|
{loading
|
||||||
|
? 'Loading…'
|
||||||
|
: `${chats.length} ${chats.length === 1 ? 'chat' : 'chats'}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<div className="flex flex-row items-center justify-center min-h-[60vh]">
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="w-8 h-8 text-light-200 fill-light-secondary dark:text-[#202020] animate-spin dark:fill-[#ffffff3b]"
|
className="w-8 h-8 text-light-200 fill-light-secondary dark:text-[#202020] animate-spin dark:fill-[#ffffff3b]"
|
||||||
@@ -56,47 +87,56 @@ const Page = () => {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : chats.length === 0 ? (
|
||||||
<div>
|
<div className="flex flex-col items-center justify-center min-h-[70vh] px-2 text-center">
|
||||||
<div className="flex flex-col pt-4">
|
<div className="flex items-center justify-center w-12 h-12 rounded-2xl border border-light-200 dark:border-dark-200 bg-light-secondary dark:bg-dark-secondary">
|
||||||
<div className="flex items-center">
|
<BookOpenText className="text-black/70 dark:text-white/70" />
|
||||||
<BookOpenText />
|
|
||||||
<h1 className="text-3xl font-medium p-2">Library</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<hr className="border-t border-[#2B2C2C] my-4 w-full" />
|
<p className="mt-2 text-black/70 dark:text-white/70 text-sm">
|
||||||
</div>
|
|
||||||
{chats.length === 0 && (
|
|
||||||
<div className="flex flex-row items-center justify-center min-h-screen">
|
|
||||||
<p className="text-black/70 dark:text-white/70 text-sm">
|
|
||||||
No chats found.
|
No chats found.
|
||||||
</p>
|
</p>
|
||||||
|
<p className="mt-1 text-black/70 dark:text-white/70 text-sm">
|
||||||
|
<Link href="/" className="text-sky-400">
|
||||||
|
Start a new chat
|
||||||
|
</Link>{' '}
|
||||||
|
to see it listed here.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
{chats.length > 0 && (
|
<div className="pt-6 pb-28 px-2">
|
||||||
<div className="flex flex-col pb-20 lg:pb-2">
|
<div className="rounded-2xl border border-light-200 dark:border-dark-200 overflow-hidden bg-light-primary dark:bg-dark-primary">
|
||||||
{chats.map((chat, i) => (
|
{chats.map((chat, index) => {
|
||||||
|
const sourcesLabel =
|
||||||
|
chat.sources.length === 0
|
||||||
|
? null
|
||||||
|
: chat.sources.length <= 2
|
||||||
|
? chat.sources
|
||||||
|
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
||||||
|
.join(', ')
|
||||||
|
: `${chat.sources
|
||||||
|
.slice(0, 2)
|
||||||
|
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
||||||
|
.join(', ')} + ${chat.sources.length - 2}`;
|
||||||
|
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
key={chat.id}
|
||||||
'flex flex-col space-y-4 py-6',
|
className={
|
||||||
i !== chats.length - 1
|
'group flex flex-col gap-2 p-4 hover:bg-light-secondary dark:hover:bg-dark-secondary transition-colors duration-200 ' +
|
||||||
? 'border-b border-white-200 dark:border-dark-200'
|
(index !== chats.length - 1
|
||||||
: '',
|
? 'border-b border-light-200 dark:border-dark-200'
|
||||||
)}
|
: '')
|
||||||
key={i}
|
}
|
||||||
>
|
>
|
||||||
|
<div className="flex items-start justify-between gap-3">
|
||||||
<Link
|
<Link
|
||||||
href={`/c/${chat.id}`}
|
href={`/c/${chat.id}`}
|
||||||
className="text-black dark:text-white lg:text-xl font-medium truncate transition duration-200 hover:text-[#24A0ED] dark:hover:text-[#24A0ED] cursor-pointer"
|
className="flex-1 text-black dark:text-white text-base lg:text-lg font-medium leading-snug line-clamp-2 group-hover:text-[#24A0ED] transition duration-200"
|
||||||
|
title={chat.title}
|
||||||
>
|
>
|
||||||
{chat.title}
|
{chat.title}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex flex-row items-center justify-between w-full">
|
<div className="pt-0.5 shrink-0">
|
||||||
<div className="flex flex-row items-center space-x-1 lg:space-x-1.5 text-black/70 dark:text-white/70">
|
|
||||||
<ClockIcon size={15} />
|
|
||||||
<p className="text-xs">
|
|
||||||
{formatTimeDifference(new Date(), chat.createdAt)} Ago
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<DeleteChat
|
<DeleteChat
|
||||||
chatId={chat.id}
|
chatId={chat.id}
|
||||||
chats={chats}
|
chats={chats}
|
||||||
@@ -104,7 +144,31 @@ const Page = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
|
<div className="flex flex-wrap items-center gap-2 text-black/70 dark:text-white/70">
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs">
|
||||||
|
<ClockIcon size={14} />
|
||||||
|
{formatTimeDifference(new Date(), chat.createdAt)} Ago
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{sourcesLabel && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs border border-black/20 dark:border-white/20 rounded-full px-2 py-0.5">
|
||||||
|
<Globe2Icon size={14} />
|
||||||
|
{sourcesLabel}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{chat.files.length > 0 && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs border border-black/20 dark:border-white/20 rounded-full px-2 py-0.5">
|
||||||
|
<FileText size={14} />
|
||||||
|
{chat.files.length}{' '}
|
||||||
|
{chat.files.length === 1 ? 'file' : 'files'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user