Biome: fixes for compontents directory

This commit is contained in:
Utkarsh-Patel-13 2025-07-27 10:41:15 -07:00
parent 758603b275
commit 2950573271
69 changed files with 478 additions and 648 deletions

View file

@ -1,5 +1,4 @@
"use client"; "use client";
import { cn } from "@/lib/utils";
import { import {
IconBrandDiscord, IconBrandDiscord,
IconBrandGithub, IconBrandGithub,
@ -8,6 +7,7 @@ import {
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import Link from "next/link"; import Link from "next/link";
import type React from "react"; import type React from "react";
import { cn } from "@/lib/utils";
export function Footer() { export function Footer() {
const pages = [ const pages = [
@ -32,8 +32,8 @@ export function Footer() {
</div> </div>
<ul className="transition-colors flex sm:flex-row flex-col hover:text-text-neutral-800 text-neutral-600 dark:text-neutral-300 list-none gap-4"> <ul className="transition-colors flex sm:flex-row flex-col hover:text-text-neutral-800 text-neutral-600 dark:text-neutral-300 list-none gap-4">
{pages.map((page, idx) => ( {pages.map((page) => (
<li key={"pages" + idx} className="list-none"> <li key={`pages-${page.title}`} className="list-none">
<Link className="transition-colors hover:text-text-neutral-800" href={page.href}> <Link className="transition-colors hover:text-text-neutral-800" href={page.href}>
{page.title} {page.title}
</Link> </Link>

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import Link from "next/link";
import React from "react";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export const Logo = ({ className }: { className?: string }) => { export const Logo = ({ className }: { className?: string }) => {

View file

@ -1,9 +1,7 @@
"use client"; "use client";
import { cn } from "@/lib/utils"; import { IconBrandDiscord, IconBrandGithub, IconFileTypeDoc } from "@tabler/icons-react";
import { IconFileTypeDoc, IconBrandGithub, IconBrandDiscord } from "@tabler/icons-react";
import Link from "next/link"; import Link from "next/link";
import React from "react"; import { cn } from "@/lib/utils";
import { motion } from "framer-motion";
import { Logo } from "./Logo"; import { Logo } from "./Logo";
export function ModernHeroWithGradients() { export function ModernHeroWithGradients() {
@ -88,6 +86,7 @@ const TopLines = () => {
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className="aspect-square pointer-events-none absolute inset-x-0 top-0 h-[100px] w-full md:h-[200px]" className="aspect-square pointer-events-none absolute inset-x-0 top-0 h-[100px] w-full md:h-[200px]"
> >
<title>Top Lines</title>
<line <line
y1="-0.5" y1="-0.5"
x2="406" x2="406"
@ -212,6 +211,7 @@ const BottomLines = () => {
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className="aspect-square pointer-events-none absolute inset-x-0 -bottom-20 z-20 h-[150px] w-full md:h-[300px]" className="aspect-square pointer-events-none absolute inset-x-0 -bottom-20 z-20 h-[150px] w-full md:h-[300px]"
> >
<title>Bottom Lines</title>
<line x1="139.5" y1="418" x2="139.5" y2="12" stroke="url(#paint0_linear_0_1)" /> <line x1="139.5" y1="418" x2="139.5" y2="12" stroke="url(#paint0_linear_0_1)" />
<line x1="172.5" y1="418" x2="172.5" y2="12" stroke="url(#paint1_linear_0_1)" /> <line x1="172.5" y1="418" x2="172.5" y2="12" stroke="url(#paint1_linear_0_1)" />
<line x1="205.5" y1="418" x2="205.5" y2="12" stroke="url(#paint2_linear_0_1)" /> <line x1="205.5" y1="418" x2="205.5" y2="12" stroke="url(#paint2_linear_0_1)" />
@ -344,6 +344,7 @@ const SideLines = () => {
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className="pointer-events-none absolute inset-0 z-30 h-full w-full" className="pointer-events-none absolute inset-0 z-30 h-full w-full"
> >
<title>Side Lines</title>
<path <path
d="M268 115L181.106 6.97176C178.069 3.19599 173.485 1 168.639 1H0" d="M268 115L181.106 6.97176C178.069 3.19599 173.485 1 168.639 1H0"
stroke="url(#paint0_linear_337_46)" stroke="url(#paint0_linear_337_46)"
@ -451,6 +452,7 @@ const BottomGradient = ({ className }: { className?: string }) => {
className className
)} )}
> >
<title>Bottom Gradient</title>
<path <path
d="M118.499 0H532.468L635.375 38.6161L665 194.625L562.093 346H0L24.9473 121.254L118.499 0Z" d="M118.499 0H532.468L635.375 38.6161L665 194.625L562.093 346H0L24.9473 121.254L118.499 0Z"
fill="url(#paint0_radial_254_132)" fill="url(#paint0_radial_254_132)"
@ -487,6 +489,7 @@ const TopGradient = ({ className }: { className?: string }) => {
className className
)} )}
> >
<title>Top Gradient</title>
<path <path
d="M807 110.119L699.5 -117.546L8.5 -154L-141 246.994L-7 952L127 782.111L279 652.114L513 453.337L807 110.119Z" d="M807 110.119L699.5 -117.546L8.5 -154L-141 246.994L-7 952L127 782.111L279 652.114L513 453.337L807 110.119Z"
fill="url(#paint0_radial_254_135)" fill="url(#paint0_radial_254_135)"
@ -527,7 +530,7 @@ const TopGradient = ({ className }: { className?: string }) => {
); );
}; };
const DarkModeGradient = ({ className }: { className?: string } = {}) => { const DarkModeGradient = () => {
return ( return (
<div className="hidden dark:block"> <div className="hidden dark:block">
<div className="absolute -left-48 -top-48 h-[800px] w-[800px] rounded-full bg-purple-900/20 blur-[180px]"></div> <div className="absolute -left-48 -top-48 h-[800px] w-[800px] rounded-full bg-purple-900/20 blur-[180px]"></div>

View file

@ -1,13 +1,12 @@
"use client"; "use client";
import { cn } from "@/lib/utils"; import { IconMenu2, IconUser, IconX } from "@tabler/icons-react";
import { IconMenu2, IconX, IconBrandGoogleFilled, IconUser } from "@tabler/icons-react"; import { AnimatePresence, motion, useMotionValueEvent, useScroll } from "framer-motion";
import { motion, AnimatePresence, useScroll, useMotionValueEvent } from "framer-motion";
import Link from "next/link"; import Link from "next/link";
import type React from "react";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { Button } from "./ui/button"; import { cn } from "@/lib/utils";
import { Logo } from "./Logo"; import { Logo } from "./Logo";
import { ThemeTogglerComponent } from "./theme/theme-toggle"; import { ThemeTogglerComponent } from "./theme/theme-toggle";
import { Button } from "./ui/button";
interface NavbarProps { interface NavbarProps {
navItems: { navItems: {
@ -109,7 +108,7 @@ const DesktopNav = ({ navItems, visible }: NavbarProps) => {
> >
{navItems.map((navItem, idx) => ( {navItems.map((navItem, idx) => (
<motion.div <motion.div
key={`nav-item-${idx}`} key={`nav-item-${navItem.name}`}
onHoverStart={() => setHoveredIndex(idx)} onHoverStart={() => setHoveredIndex(idx)}
className="relative" className="relative"
> >
@ -194,7 +193,6 @@ const MobileNav = ({ navItems, visible }: NavbarProps) => {
}; };
return ( return (
<>
<motion.div <motion.div
animate={{ animate={{
backdropFilter: "blur(16px)", backdropFilter: "blur(16px)",
@ -262,9 +260,9 @@ const MobileNav = ({ navItems, visible }: NavbarProps) => {
}} }}
className="flex rounded-3xl absolute top-16 dark:bg-black/80 bg-white/90 backdrop-blur-xl backdrop-saturate-[1.8] inset-x-0 z-50 flex-col items-start justify-start gap-4 w-full px-6 py-8" className="flex rounded-3xl absolute top-16 dark:bg-black/80 bg-white/90 backdrop-blur-xl backdrop-saturate-[1.8] inset-x-0 z-50 flex-col items-start justify-start gap-4 w-full px-6 py-8"
> >
{navItems.map((navItem: { link: string; name: string }, idx: number) => ( {navItems.map((navItem: { link: string; name: string }) => (
<Link <Link
key={`link=${idx}`} key={`link-${navItem.name}`}
href={navItem.link} href={navItem.link}
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
className="relative dark:text-white/90 text-gray-800 hover:text-gray-900 dark:hover:text-white transition-colors" className="relative dark:text-white/90 text-gray-800 hover:text-gray-900 dark:hover:text-white transition-colors"
@ -284,6 +282,5 @@ const MobileNav = ({ navItems, visible }: NavbarProps) => {
)} )}
</AnimatePresence> </AnimatePresence>
</motion.div> </motion.div>
</>
); );
}; };

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
interface TokenHandlerProps { interface TokenHandlerProps {
redirectPath?: string; // Path to redirect after storing token redirectPath?: string; // Path to redirect after storing token

View file

@ -1,8 +1,9 @@
"use client"; "use client";
import { BadgeCheck, ChevronsUpDown, LogOut, Settings } from "lucide-react"; import { BadgeCheck, LogOut, Settings } from "lucide-react";
import { useRouter } from "next/navigation";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -12,8 +13,6 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { useRouter, useParams } from "next/navigation";
export function UserDropdown({ export function UserDropdown({
user, user,

View file

@ -1,11 +1,11 @@
"use client"; "use client";
import { cn } from "@/lib/utils";
import { Manrope } from "next/font/google";
import React, { useRef, useEffect, useReducer, useMemo } from "react";
import { RoughNotation, RoughNotationGroup } from "react-rough-notation";
import { useInView } from "framer-motion"; import { useInView } from "framer-motion";
import { Manrope } from "next/font/google";
import { useEffect, useMemo, useReducer, useRef } from "react";
import { RoughNotation, RoughNotationGroup } from "react-rough-notation";
import { useSidebar } from "@/components/ui/sidebar"; import { useSidebar } from "@/components/ui/sidebar";
import { cn } from "@/lib/utils";
// Font configuration - could be moved to a global font config file // Font configuration - could be moved to a global font config file
const manrope = Manrope({ const manrope = Manrope({
@ -115,7 +115,7 @@ export function AnimatedEmptyState() {
}, TIMING.SIDEBAR_TRANSITION); }, TIMING.SIDEBAR_TRANSITION);
return () => clearTimeout(stabilizeTimer); return () => clearTimeout(stabilizeTimer);
}, [sidebarState]); }, []);
// Handle highlight visibility based on layout stability and viewport visibility // Handle highlight visibility based on layout stability and viewport visibility
useEffect(() => { useEffect(() => {

View file

@ -1,13 +1,14 @@
"use client"; "use client";
import type React from "react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { ExternalLink } from "lucide-react"; import { ExternalLink } from "lucide-react";
import type React from "react";
import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
export const CitationDisplay: React.FC<{ index: number; node: any }> = ({ index, node }) => { export const CitationDisplay: React.FC<{ index: number; node: any }> = ({ index, node }) => {
const truncateText = (text: string, maxLength: number = 200) => { const truncateText = (text: string, maxLength: number = 200) => {
if (text.length <= maxLength) return text; if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + "..."; return `${text.substring(0, maxLength)}...`;
}; };
const handleUrlClick = (e: React.MouseEvent, url: string) => { const handleUrlClick = (e: React.MouseEvent, url: string) => {
@ -26,13 +27,15 @@ export const CitationDisplay: React.FC<{ index: number; node: any }> = ({ index,
<PopoverContent className="w-80 p-4 space-y-3 relative" align="start"> <PopoverContent className="w-80 p-4 space-y-3 relative" align="start">
{/* External Link Button - Top Right */} {/* External Link Button - Top Right */}
{node?.url && ( {node?.url && (
<button <Button
size="icon"
variant="ghost"
onClick={(e) => handleUrlClick(e, node.url)} onClick={(e) => handleUrlClick(e, node.url)}
className="absolute top-3 right-3 inline-flex items-center justify-center w-6 h-6 text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-200 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded transition-colors" className="absolute top-3 right-3 inline-flex items-center justify-center w-6 h-6 text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-200 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded transition-colors"
title="Open in new tab" title="Open in new tab"
> >
<ExternalLink size={14} /> <ExternalLink size={14} />
</button> </Button>
)} )}
{/* Heading */} {/* Heading */}

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { SuggestedQuestions } from "@llamaindex/chat-ui/widgets";
import { getAnnotationData, type Message, useChatUI } from "@llamaindex/chat-ui"; import { getAnnotationData, type Message, useChatUI } from "@llamaindex/chat-ui";
import { SuggestedQuestions } from "@llamaindex/chat-ui/widgets";
import { import {
Accordion, Accordion,
AccordionContent, AccordionContent,
@ -14,7 +14,7 @@ export const ChatFurtherQuestions: React.FC<{ message: Message }> = ({ message }
const { append, requestData } = useChatUI(); const { append, requestData } = useChatUI();
if (annotations.length !== 1 || annotations[0].length === 0) { if (annotations.length !== 1 || annotations[0].length === 0) {
return <></>; return null;
} }
return ( return (

View file

@ -1,15 +1,24 @@
"use client"; "use client";
import { ChatInput } from "@llamaindex/chat-ui"; import { ChatInput } from "@llamaindex/chat-ui";
import { FolderOpen, Check, Zap, Brain } from "lucide-react"; import { Brain, Check, FolderOpen, Zap } from "lucide-react";
import { useParams } from "next/navigation";
import React, { Suspense, useCallback, useState } from "react";
import type { ResearchMode } from "@/components/chat";
import {
ConnectorButton as ConnectorButtonComponent,
getConnectorIcon,
} from "@/components/chat/ConnectorComponents";
import { DocumentsDataTable } from "@/components/chat/DocumentsDataTable";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogFooter,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
DialogFooter,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { import {
Select, Select,
@ -18,19 +27,9 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge"; import { type Document, useDocuments } from "@/hooks/use-documents";
import { Suspense, useState, useCallback } from "react";
import { useParams } from "next/navigation";
import { useDocuments, type Document } from "@/hooks/use-documents";
import { DocumentsDataTable } from "@/components/chat/DocumentsDataTable";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import {
getConnectorIcon,
ConnectorButton as ConnectorButtonComponent,
} from "@/components/chat/ConnectorComponents";
import type { ResearchMode } from "@/components/chat";
import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs"; import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs";
import React from "react"; import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
const DocumentSelector = React.memo( const DocumentSelector = React.memo(
({ ({
@ -188,24 +187,17 @@ const ConnectorSelector = React.memo(
const isSelected = selectedConnectors.includes(connector.type); const isSelected = selectedConnectors.includes(connector.type);
return ( return (
<div <Button
key={connector.id} key={connector.id}
className={`flex items-center gap-2 p-2 rounded-md border cursor-pointer transition-colors ${ className={`flex items-center gap-2 p-2 rounded-md border cursor-pointer transition-colors`}
isSelected
? "border-primary bg-primary/10"
: "border-border hover:border-primary/50 hover:bg-muted"
}`}
onClick={() => handleConnectorToggle(connector.type)} onClick={() => handleConnectorToggle(connector.type)}
role="checkbox" variant={isSelected ? "default" : "outline"}
aria-checked={isSelected} size="sm"
tabIndex={0} type="button"
> >
<div className="flex-shrink-0 w-6 h-6 flex items-center justify-center rounded-full bg-muted">
{getConnectorIcon(connector.type)} {getConnectorIcon(connector.type)}
</div>
<span className="flex-1 text-sm font-medium">{connector.name}</span> <span className="flex-1 text-sm font-medium">{connector.name}</span>
{isSelected && <Check className="h-4 w-4 text-primary" />} </Button>
</div>
); );
}) })
)} )}

View file

@ -1,11 +1,10 @@
"use client"; "use client";
import React from "react"; import { type ChatHandler, ChatSection as LlamaIndexChatSection } from "@llamaindex/chat-ui";
import { ChatSection as LlamaIndexChatSection, type ChatHandler } from "@llamaindex/chat-ui";
import type { Document } from "@/hooks/use-documents";
import { ChatInputUI } from "@/components/chat/ChatInputGroup";
import type { ResearchMode } from "@/components/chat"; import type { ResearchMode } from "@/components/chat";
import { ChatInputUI } from "@/components/chat/ChatInputGroup";
import { ChatMessagesUI } from "@/components/chat/ChatMessages"; import { ChatMessagesUI } from "@/components/chat/ChatMessages";
import type { Document } from "@/hooks/use-documents";
interface ChatInterfaceProps { interface ChatInterfaceProps {
handler: ChatHandler; handler: ChatHandler;

View file

@ -1,17 +1,17 @@
"use client"; "use client";
import React from "react";
import { import {
ChatMessage as LlamaIndexChatMessage, ChatMessage as LlamaIndexChatMessage,
ChatMessages as LlamaIndexChatMessages, ChatMessages as LlamaIndexChatMessages,
type Message, type Message,
useChatUI, useChatUI,
} from "@llamaindex/chat-ui"; } from "@llamaindex/chat-ui";
import TerminalDisplay from "@/components/chat/ChatTerminal"; import { useEffect, useRef } from "react";
import ChatSourcesDisplay from "@/components/chat/ChatSources"; import { AnimatedEmptyState } from "@/components/chat/AnimatedEmptyState";
import { CitationDisplay } from "@/components/chat/ChatCitation"; import { CitationDisplay } from "@/components/chat/ChatCitation";
import { ChatFurtherQuestions } from "@/components/chat/ChatFurtherQuestions"; import { ChatFurtherQuestions } from "@/components/chat/ChatFurtherQuestions";
import { AnimatedEmptyState } from "@/components/chat/AnimatedEmptyState"; import ChatSourcesDisplay from "@/components/chat/ChatSources";
import TerminalDisplay from "@/components/chat/ChatTerminal";
import { languageRenderers } from "@/components/chat/CodeBlock"; import { languageRenderers } from "@/components/chat/CodeBlock";
export function ChatMessagesUI() { export function ChatMessagesUI() {
@ -37,13 +37,13 @@ export function ChatMessagesUI() {
} }
function ChatMessageUI({ message, isLast }: { message: Message; isLast: boolean }) { function ChatMessageUI({ message, isLast }: { message: Message; isLast: boolean }) {
const bottomRef = React.useRef<HTMLDivElement>(null); const bottomRef = useRef<HTMLDivElement>(null);
React.useEffect(() => { useEffect(() => {
if (isLast && bottomRef.current) { if (isLast && bottomRef.current) {
bottomRef.current.scrollIntoView({ behavior: "smooth" }); bottomRef.current.scrollIntoView({ behavior: "smooth" });
} }
}, [message]); }, [isLast]);
return ( return (
<LlamaIndexChatMessage message={message} isLast={isLast} className="flex flex-col "> <LlamaIndexChatMessage message={message} isLast={isLast} className="flex flex-col ">

View file

@ -1,8 +1,12 @@
"use client"; "use client";
import { useState } from "react";
import { getAnnotationData, type Message } from "@llamaindex/chat-ui"; import { getAnnotationData, type Message } from "@llamaindex/chat-ui";
import { IconBrandGithub } from "@tabler/icons-react";
import { ExternalLink, FileText, Globe } from "lucide-react";
import { useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -11,10 +15,6 @@ import {
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { ExternalLink, FileText, Globe } from "lucide-react";
import { IconBrandGithub } from "@tabler/icons-react";
interface Source { interface Source {
id: string; id: string;
@ -44,10 +44,6 @@ interface SourceNode {
metadata: NodeMetadata; metadata: NodeMetadata;
} }
interface NodesResponse {
nodes: SourceNode[];
}
function getSourceIcon(type: string) { function getSourceIcon(type: string) {
switch (type) { switch (type) {
case "USER_SELECTED_GITHUB_CONNECTOR": case "USER_SELECTED_GITHUB_CONNECTOR":

View file

@ -1,16 +1,26 @@
"use client"; "use client";
import React from "react";
import { getAnnotationData, type Message } from "@llamaindex/chat-ui"; import { getAnnotationData, type Message } from "@llamaindex/chat-ui";
import { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
export default function TerminalDisplay({ message, open }: { message: Message; open: boolean }) { export default function TerminalDisplay({ message, open }: { message: Message; open: boolean }) {
const [isCollapsed, setIsCollapsed] = React.useState(!open); const [isCollapsed, setIsCollapsed] = useState(!open);
const bottomRef = React.useRef<HTMLDivElement>(null); const bottomRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (bottomRef.current) {
bottomRef.current.scrollTo({
top: bottomRef.current.scrollHeight,
behavior: "smooth",
});
}
}, []);
// Get the last assistant message that's not being typed // Get the last assistant message that's not being typed
if (!message) { if (!message) {
return <></>; return null;
} }
interface TerminalInfo { interface TerminalInfo {
@ -22,24 +32,17 @@ export default function TerminalDisplay({ message, open }: { message: Message; o
const events = getAnnotationData(message, "TERMINAL_INFO") as TerminalInfo[]; const events = getAnnotationData(message, "TERMINAL_INFO") as TerminalInfo[];
if (events.length === 0) { if (events.length === 0) {
return <></>; return null;
} }
React.useEffect(() => {
if (bottomRef.current) {
bottomRef.current.scrollTo({
top: bottomRef.current.scrollHeight,
behavior: "smooth",
});
}
}, [events]);
return ( return (
<div className="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden font-mono text-sm shadow-lg"> <div className="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden font-mono text-sm shadow-lg">
{/* Terminal Header */} {/* Terminal Header */}
<div <Button
className="bg-gray-800 px-4 py-2 flex items-center gap-2 border-b border-gray-700 cursor-pointer hover:bg-gray-750 transition-colors" className="w-full bg-gray-800 px-4 py-2 flex items-center gap-2 border-b border-gray-700 cursor-pointer hover:bg-gray-750 transition-colors"
onClick={() => setIsCollapsed(!isCollapsed)} onClick={() => setIsCollapsed(!isCollapsed)}
variant="ghost"
type="button"
> >
<div className="flex gap-2"> <div className="flex gap-2">
<div className="w-3 h-3 rounded-full bg-red-500"></div> <div className="w-3 h-3 rounded-full bg-red-500"></div>
@ -52,6 +55,7 @@ export default function TerminalDisplay({ message, open }: { message: Message; o
<div className="text-gray-400"> <div className="text-gray-400">
{isCollapsed ? ( {isCollapsed ? (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<title>Collapse</title>
<path <path
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
@ -61,6 +65,7 @@ export default function TerminalDisplay({ message, open }: { message: Message; o
</svg> </svg>
) : ( ) : (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<title>Expand</title>
<path <path
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
@ -70,7 +75,7 @@ export default function TerminalDisplay({ message, open }: { message: Message; o
</svg> </svg>
)} )}
</div> </div>
</div> </Button>
{/* Terminal Content */} {/* Terminal Content */}
{!isCollapsed && ( {!isCollapsed && (

View file

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { ExternalLink } from "lucide-react"; import { ExternalLink } from "lucide-react";
import { memo, useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { import {
@ -20,8 +20,7 @@ type CitationProps = {
/** /**
* Citation component to handle individual citations * Citation component to handle individual citations
*/ */
export const Citation = React.memo( export const Citation = memo(({ citationId, citationText, position, source }: CitationProps) => {
({ citationId, citationText, position, source }: CitationProps) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const citationKey = `citation-${citationId}-${position}`; const citationKey = `citation-${citationId}-${position}`;
@ -69,8 +68,7 @@ export const Citation = React.memo(
</DropdownMenu> </DropdownMenu>
</span> </span>
); );
} });
);
Citation.displayName = "Citation"; Citation.displayName = "Citation";
@ -85,10 +83,10 @@ export const renderTextWithCitations = (
const citationRegex = /\[(\d+)\]/g; const citationRegex = /\[(\d+)\]/g;
const parts = []; const parts = [];
let lastIndex = 0; let lastIndex = 0;
let match; let match: RegExpExecArray | null = citationRegex.exec(text);
let position = 0; let position = 0;
while ((match = citationRegex.exec(text)) !== null) { while (match !== null) {
// Add text before the citation // Add text before the citation
if (match.index > lastIndex) { if (match.index > lastIndex) {
parts.push(text.substring(lastIndex, match.index)); parts.push(text.substring(lastIndex, match.index));
@ -108,6 +106,7 @@ export const renderTextWithCitations = (
lastIndex = match.index + match[0].length; lastIndex = match.index + match[0].length;
position++; position++;
match = citationRegex.exec(text);
} }
// Add any remaining text after the last citation // Add any remaining text after the last citation

View file

@ -1,10 +1,10 @@
"use client"; "use client";
import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneLight, oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { Check, Copy } from "lucide-react"; import { Check, Copy } from "lucide-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark, oneLight } from "react-syntax-highlighter/dist/cjs/styles/prism";
// Constants for styling and configuration // Constants for styling and configuration
const COPY_TIMEOUT = 2000; const COPY_TIMEOUT = 2000;
@ -41,14 +41,14 @@ interface CodeBlockProps {
language: string; language: string;
} }
type LanguageRenderer = (props: { code: string }) => React.JSX.Element type LanguageRenderer = (props: { code: string }) => React.JSX.Element;
interface SyntaxStyle { interface SyntaxStyle {
[key: string]: React.CSSProperties; [key: string]: React.CSSProperties;
} }
// Memoized fallback component for SSR/hydration // Memoized fallback component for SSR/hydration
const FallbackCodeBlock = React.memo(({ children }: { children: string }) => ( const FallbackCodeBlock = memo(({ children }: { children: string }) => (
<div className="bg-muted p-4 rounded-md"> <div className="bg-muted p-4 rounded-md">
<pre className="m-0 p-0 border-0"> <pre className="m-0 p-0 border-0">
<code className="text-xs font-mono border-0 leading-6">{children}</code> <code className="text-xs font-mono border-0 leading-6">{children}</code>
@ -59,7 +59,7 @@ const FallbackCodeBlock = React.memo(({ children }: { children: string }) => (
FallbackCodeBlock.displayName = "FallbackCodeBlock"; FallbackCodeBlock.displayName = "FallbackCodeBlock";
// Code block component with syntax highlighting and copy functionality // Code block component with syntax highlighting and copy functionality
export const CodeBlock = React.memo<CodeBlockProps>(({ children, language }) => { export const CodeBlock = memo<CodeBlockProps>(({ children, language }) => {
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const { resolvedTheme, theme } = useTheme(); const { resolvedTheme, theme } = useTheme();
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);

View file

@ -1,28 +1,28 @@
import type React from "react";
import {
ChevronDown,
Plus,
Search,
Globe,
Sparkles,
Microscope,
Telescope,
File,
Link,
Webhook,
MessageCircle,
FileText,
} from "lucide-react";
import { import {
IconBrandDiscord,
IconBrandGithub,
IconBrandNotion, IconBrandNotion,
IconBrandSlack, IconBrandSlack,
IconBrandYoutube, IconBrandYoutube,
IconBrandGithub,
IconLayoutKanban, IconLayoutKanban,
IconLinkPlus, IconLinkPlus,
IconBrandDiscord,
IconTicket, IconTicket,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import {
ChevronDown,
File,
FileText,
Globe,
Link,
MessageCircle,
Microscope,
Plus,
Search,
Sparkles,
Telescope,
Webhook,
} from "lucide-react";
import type React from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import type { Connector, ResearchMode } from "./types"; import type { Connector, ResearchMode } from "./types";
@ -238,7 +238,7 @@ export const ResearchModeControl = ({ value, onChange }: ResearchModeControlProp
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{/* Main Q/A vs Report Toggle */} {/* Main Q/A vs Report Toggle */}
<div className="flex h-8 rounded-md border border-border overflow-hidden"> <div className="flex h-8 rounded-md border border-border overflow-hidden">
<button <Button
className={`flex h-full items-center gap-1 px-3 text-xs font-medium transition-colors whitespace-nowrap ${ className={`flex h-full items-center gap-1 px-3 text-xs font-medium transition-colors whitespace-nowrap ${
isQnaMode isQnaMode
? "bg-primary text-primary-foreground" ? "bg-primary text-primary-foreground"
@ -249,8 +249,8 @@ export const ResearchModeControl = ({ value, onChange }: ResearchModeControlProp
> >
<MessageCircle className="h-3 w-3" /> <MessageCircle className="h-3 w-3" />
<span>Q/A</span> <span>Q/A</span>
</button> </Button>
<button <Button
className={`flex h-full items-center gap-1 px-3 text-xs font-medium transition-colors whitespace-nowrap ${ className={`flex h-full items-center gap-1 px-3 text-xs font-medium transition-colors whitespace-nowrap ${
isReportMode isReportMode
? "bg-primary text-primary-foreground" ? "bg-primary text-primary-foreground"
@ -261,14 +261,14 @@ export const ResearchModeControl = ({ value, onChange }: ResearchModeControlProp
> >
<FileText className="h-3 w-3" /> <FileText className="h-3 w-3" />
<span>Report</span> <span>Report</span>
</button> </Button>
</div> </div>
{/* Report Sub-options (only show when in Report mode) */} {/* Report Sub-options (only show when in Report mode) */}
{isReportMode && ( {isReportMode && (
<div className="flex h-8 rounded-md border border-border overflow-hidden"> <div className="flex h-8 rounded-md border border-border overflow-hidden">
{reportSubOptions.map((option) => ( {reportSubOptions.map((option) => (
<button <Button
key={option.value} key={option.value}
className={`flex h-full items-center gap-1 px-2 text-xs font-medium transition-colors whitespace-nowrap ${ className={`flex h-full items-center gap-1 px-2 text-xs font-medium transition-colors whitespace-nowrap ${
getCurrentReportMode() === option.value getCurrentReportMode() === option.value
@ -280,7 +280,7 @@ export const ResearchModeControl = ({ value, onChange }: ResearchModeControlProp
> >
{option.icon} {option.icon}
<span>{option.label}</span> <span>{option.label}</span>
</button> </Button>
))} ))}
</div> </div>
)} )}

View file

@ -1,6 +1,5 @@
"use client"; "use client";
import * as React from "react";
import { import {
type ColumnDef, type ColumnDef,
type ColumnFiltersState, type ColumnFiltersState,
@ -14,9 +13,11 @@ import {
type VisibilityState, type VisibilityState,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { ArrowUpDown, Calendar, FileText, Search } from "lucide-react"; import { ArrowUpDown, Calendar, FileText, Search } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -24,7 +25,6 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import { import {
Table, Table,
TableBody, TableBody,
@ -33,7 +33,6 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { Badge } from "@/components/ui/badge";
import type { Document, DocumentType } from "@/hooks/use-documents"; import type { Document, DocumentType } from "@/hooks/use-documents";
interface DocumentsDataTableProps { interface DocumentsDataTableProps {
@ -206,13 +205,13 @@ export function DocumentsDataTable({
onDone, onDone,
initialSelectedDocuments = [], initialSelectedDocuments = [],
}: DocumentsDataTableProps) { }: DocumentsDataTableProps) {
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({}); const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
const [documentTypeFilter, setDocumentTypeFilter] = React.useState<DocumentType | "ALL">("ALL"); const [documentTypeFilter, setDocumentTypeFilter] = useState<DocumentType | "ALL">("ALL");
// Memoize initial row selection to prevent infinite loops // Memoize initial row selection to prevent infinite loops
const initialRowSelection = React.useMemo(() => { const initialRowSelection = useMemo(() => {
if (!documents.length || !initialSelectedDocuments.length) return {}; if (!documents.length || !initialSelectedDocuments.length) return {};
const selection: Record<string, boolean> = {}; const selection: Record<string, boolean> = {};
@ -222,24 +221,24 @@ export function DocumentsDataTable({
return selection; return selection;
}, [documents, initialSelectedDocuments]); }, [documents, initialSelectedDocuments]);
const [rowSelection, setRowSelection] = React.useState<Record<string, boolean>>({}); const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
// Only update row selection when initialRowSelection actually changes and is not empty // Only update row selection when initialRowSelection actually changes and is not empty
React.useEffect(() => { useEffect(() => {
const hasChanges = JSON.stringify(rowSelection) !== JSON.stringify(initialRowSelection); const hasChanges = JSON.stringify(rowSelection) !== JSON.stringify(initialRowSelection);
if (hasChanges && Object.keys(initialRowSelection).length > 0) { if (hasChanges && Object.keys(initialRowSelection).length > 0) {
setRowSelection(initialRowSelection); setRowSelection(initialRowSelection);
} }
}, [initialRowSelection]); }, [initialRowSelection, rowSelection]);
// Initialize row selection on mount // Initialize row selection on mount
React.useEffect(() => { useEffect(() => {
if (Object.keys(rowSelection).length === 0 && Object.keys(initialRowSelection).length > 0) { if (Object.keys(rowSelection).length === 0 && Object.keys(initialRowSelection).length > 0) {
setRowSelection(initialRowSelection); setRowSelection(initialRowSelection);
} }
}, []); }, [initialRowSelection, rowSelection]);
const filteredDocuments = React.useMemo(() => { const filteredDocuments = useMemo(() => {
if (documentTypeFilter === "ALL") return documents; if (documentTypeFilter === "ALL") return documents;
return documents.filter((doc) => doc.document_type === documentTypeFilter); return documents.filter((doc) => doc.document_type === documentTypeFilter);
}, [documents, documentTypeFilter]); }, [documents, documentTypeFilter]);
@ -260,11 +259,11 @@ export function DocumentsDataTable({
state: { sorting, columnFilters, columnVisibility, rowSelection }, state: { sorting, columnFilters, columnVisibility, rowSelection },
}); });
React.useEffect(() => { useEffect(() => {
const selectedRows = table.getFilteredSelectedRowModel().rows; const selectedRows = table.getFilteredSelectedRowModel().rows;
const selectedDocuments = selectedRows.map((row) => row.original); const selectedDocuments = selectedRows.map((row) => row.original);
onSelectionChange(selectedDocuments); onSelectionChange(selectedDocuments);
}, [rowSelection, onSelectionChange, table]); }, [onSelectionChange, table]);
const handleClearAll = () => setRowSelection({}); const handleClearAll = () => setRowSelection({});

View file

@ -47,7 +47,7 @@ export const useScrollIndicators = (
// Add resize listener to update indicators when window size changes // Add resize listener to update indicators when window size changes
window.addEventListener("resize", updateIndicators); window.addEventListener("resize", updateIndicators);
return () => window.removeEventListener("resize", updateIndicators); return () => window.removeEventListener("resize", updateIndicators);
}, []); }, [updateIndicators]);
return updateIndicators; return updateIndicators;
}; };

View file

@ -1,4 +1,5 @@
import type React from "react"; import type React from "react";
import { Button } from "@/components/ui/button";
type SegmentedControlProps<T extends string> = { type SegmentedControlProps<T extends string> = {
value: T; value: T;
@ -21,7 +22,7 @@ function SegmentedControl<T extends string>({
return ( return (
<div className="flex h-7 rounded-md border border-border overflow-hidden"> <div className="flex h-7 rounded-md border border-border overflow-hidden">
{options.map((option) => ( {options.map((option) => (
<button <Button
key={option.value} key={option.value}
className={`flex h-full items-center gap-1 px-2 text-xs transition-colors ${ className={`flex h-full items-center gap-1 px-2 text-xs transition-colors ${
value === option.value ? "bg-primary text-primary-foreground" : "hover:bg-muted" value === option.value ? "bg-primary text-primary-foreground" : "hover:bg-muted"
@ -31,7 +32,7 @@ function SegmentedControl<T extends string>({
> >
{option.icon} {option.icon}
<span>{option.label}</span> <span>{option.label}</span>
</button> </Button>
))} ))}
</div> </div>
); );

View file

@ -1,4 +1,4 @@
import type { Source, Connector } from "./types"; import type { Connector, Source } from "./types";
/** /**
* Function to get sources for the main view * Function to get sources for the main view

View file

@ -1,8 +1,9 @@
// Export all components and utilities from the chat folder // Export all components and utilities from the chat folder
export { default as SegmentedControl } from "./SegmentedControl";
export * from "./ConnectorComponents";
export * from "./Citation"; export * from "./Citation";
export * from "./SourceUtils";
export * from "./ScrollUtils";
export * from "./CodeBlock"; export * from "./CodeBlock";
export * from "./ConnectorComponents";
export * from "./ScrollUtils";
export { default as SegmentedControl } from "./SegmentedControl";
export * from "./SourceUtils";
export * from "./types"; export * from "./types";

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import { useEffect, useRef, useState } from "react";
import type { RefObject } from "react";
import { Button } from "./ui/button";
import { Copy, CopyCheck } from "lucide-react"; import { Copy, CopyCheck } from "lucide-react";
import type { RefObject } from "react";
import { useEffect, useRef, useState } from "react";
import { Button } from "./ui/button";
export default function CopyButton({ ref }: { ref: RefObject<HTMLDivElement | null> }) { export default function CopyButton({ ref }: { ref: RefObject<HTMLDivElement | null> }) {
const [copy, setCopy] = useState(false); const [copy, setCopy] = useState(false);

View file

@ -1,4 +1,7 @@
import { FileText } from "lucide-react";
import type React from "react"; import type React from "react";
import { MarkdownViewer } from "@/components/markdown-viewer";
import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -6,9 +9,6 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { MarkdownViewer } from "@/components/markdown-viewer";
import { FileText } from "lucide-react";
interface DocumentViewerProps { interface DocumentViewerProps {
title: string; title: string;

View file

@ -1,6 +1,7 @@
import React from "react"; "use client";
import { Skeleton } from "@/components/ui/skeleton";
import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
export function EditConnectorLoadingSkeleton() { export function EditConnectorLoadingSkeleton() {
return ( return (

View file

@ -1,6 +1,7 @@
import React from "react"; "use client";
import type { Control } from "react-hook-form"; import type { Control } from "react-hook-form";
import { FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"; import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
// Assuming EditConnectorFormValues is defined elsewhere or passed as generic // Assuming EditConnectorFormValues is defined elsewhere or passed as generic

View file

@ -1,19 +1,19 @@
import { CircleAlert, Edit, KeyRound, Loader2 } from "lucide-react";
import type React from "react"; import type React from "react";
import type { UseFormReturn } from "react-hook-form"; import type { UseFormReturn } from "react-hook-form";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { import {
FormControl,
FormDescription,
FormField, FormField,
FormItem, FormItem,
FormLabel, FormLabel,
FormControl,
FormDescription,
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Edit, KeyRound, Loader2, CircleAlert } from "lucide-react";
// Types needed from parent // Types needed from parent
interface GithubRepo { interface GithubRepo {

View file

@ -1,15 +1,16 @@
import React from "react"; "use client";
import { KeyRound } from "lucide-react";
import type { Control } from "react-hook-form"; import type { Control } from "react-hook-form";
import { import {
FormControl,
FormDescription,
FormField, FormField,
FormItem, FormItem,
FormLabel, FormLabel,
FormControl,
FormDescription,
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { KeyRound } from "lucide-react";
// Assuming EditConnectorFormValues is defined elsewhere or passed as generic // Assuming EditConnectorFormValues is defined elsewhere or passed as generic
interface EditSimpleTokenFormProps { interface EditSimpleTokenFormProps {

View file

@ -1,4 +1,7 @@
import { FileJson } from "lucide-react";
import React from "react"; import React from "react";
import { defaultStyles, JsonView } from "react-json-view-lite";
import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -6,9 +9,6 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { FileJson } from "lucide-react";
import { JsonView, defaultStyles } from "react-json-view-lite";
import "react-json-view-lite/dist/index.css"; import "react-json-view-lite/dist/index.css";
interface JsonMetadataViewerProps { interface JsonMetadataViewerProps {

View file

@ -1,15 +1,17 @@
import React, { useMemo, useState, useEffect, useRef } from "react"; import { Check, Copy } from "lucide-react";
import Image from "next/image";
import { useTheme } from "next-themes";
import React, { useEffect, useMemo, useRef, useState } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark, oneLight } from "react-syntax-highlighter/dist/cjs/styles/prism";
import rehypeRaw from "rehype-raw"; import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize"; import rehypeSanitize from "rehype-sanitize";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Citation } from "./chat/Citation"; import { Citation } from "./chat/Citation";
import type { Source } from "./chat/types"; import type { Source } from "./chat/types";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneLight, oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { Check, Copy } from "lucide-react";
import { useTheme } from "next-themes";
import CopyButton from "./copy-button"; import CopyButton from "./copy-button";
interface MarkdownViewerProps { interface MarkdownViewerProps {
@ -112,7 +114,13 @@ export function MarkdownViewer({
), ),
hr: ({ node, ...props }: any) => <hr className="my-4 border-muted" {...props} />, hr: ({ node, ...props }: any) => <hr className="my-4 border-muted" {...props} />,
img: ({ node, ...props }: any) => ( img: ({ node, ...props }: any) => (
<img className="max-w-full h-auto my-4 rounded" {...props} /> <Image
className="max-w-full h-auto my-4 rounded"
alt="markdown image"
height={100}
width={100}
{...props}
/>
), ),
table: ({ node, ...props }: any) => ( table: ({ node, ...props }: any) => (
<div className="overflow-x-auto my-4"> <div className="overflow-x-auto my-4">
@ -186,7 +194,8 @@ const CodeBlock = ({ children, language }: { children: string; language: string
return ( return (
<div className="relative my-4 group"> <div className="relative my-4 group">
<div className="absolute right-2 top-2 z-10"> <div className="absolute right-2 top-2 z-10">
<button <Button
variant="ghost"
onClick={handleCopy} onClick={handleCopy}
className="p-1.5 rounded-md bg-background/80 hover:bg-background border border-border flex items-center justify-center transition-colors" className="p-1.5 rounded-md bg-background/80 hover:bg-background border border-border flex items-center justify-center transition-colors"
aria-label="Copy code" aria-label="Copy code"
@ -196,7 +205,7 @@ const CodeBlock = ({ children, language }: { children: string; language: string
) : ( ) : (
<Copy size={14} className="text-muted-foreground" /> <Copy size={14} className="text-muted-foreground" />
)} )}
</button> </Button>
</div> </div>
{mounted ? ( {mounted ? (
<SyntaxHighlighter <SyntaxHighlighter
@ -297,10 +306,10 @@ const processCitationsInText = (
const citationRegex = /\[(\d+)\]/g; const citationRegex = /\[(\d+)\]/g;
const parts: React.ReactNode[] = []; const parts: React.ReactNode[] = [];
let lastIndex = 0; let lastIndex = 0;
let match; let match: RegExpExecArray | null = citationRegex.exec(text);
let position = 0; let position = 0;
while ((match = citationRegex.exec(text)) !== null) { while (match !== null) {
// Add text before the citation // Add text before the citation
if (match.index > lastIndex) { if (match.index > lastIndex) {
parts.push(text.substring(lastIndex, match.index)); parts.push(text.substring(lastIndex, match.index));
@ -322,6 +331,7 @@ const processCitationsInText = (
lastIndex = match.index + match[0].length; lastIndex = match.index + match[0].length;
position++; position++;
match = citationRegex.exec(text);
} }
// Add any remaining text after the last citation // Add any remaining text after the last citation

View file

@ -1,8 +1,11 @@
"use client"; "use client";
import type React from "react";
import { useState } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { AlertCircle, Bot, Plus, Trash2 } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
@ -14,12 +17,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { type CreateLLMConfig, useLLMConfigs } from "@/hooks/use-llm-configs";
import { Badge } from "@/components/ui/badge";
import { Plus, Trash2, Bot, AlertCircle } from "lucide-react";
import { useLLMConfigs, type CreateLLMConfig } from "@/hooks/use-llm-configs";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
const LLM_PROVIDERS = [ const LLM_PROVIDERS = [
{ value: "OPENAI", label: "OpenAI", example: "gpt-4o, gpt-4, gpt-3.5-turbo" }, { value: "OPENAI", label: "OpenAI", example: "gpt-4o, gpt-4, gpt-3.5-turbo" },

View file

@ -1,8 +1,12 @@
"use client"; "use client";
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { AlertCircle, Bot, Brain, CheckCircle, Zap } from "lucide-react";
import { useEffect, useState } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -10,10 +14,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { Brain, Zap, Bot, AlertCircle, CheckCircle } from "lucide-react";
import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs"; import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs";
import { Alert, AlertDescription } from "@/components/ui/alert";
const ROLE_DESCRIPTIONS = { const ROLE_DESCRIPTIONS = {
long_context: { long_context: {
@ -163,7 +164,7 @@ export function AssignRolesStep({ onPreferencesUpdated }: AssignRolesStepProps)
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium">Assign LLM Configuration:</label> <Label className="text-sm font-medium">Assign LLM Configuration:</Label>
<Select <Select
value={currentAssignment?.toString() || ""} value={currentAssignment?.toString() || ""}
onValueChange={(value) => handleRoleAssignment(`${key}_llm_id`, value)} onValueChange={(value) => handleRoleAssignment(`${key}_llm_id`, value)}
@ -224,7 +225,7 @@ export function AssignRolesStep({ onPreferencesUpdated }: AssignRolesStepProps)
<div className="flex items-center gap-2 text-sm text-muted-foreground"> <div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>Progress:</span> <span>Progress:</span>
<div className="flex gap-1"> <div className="flex gap-1">
{Object.keys(ROLE_DESCRIPTIONS).map((key, index) => ( {Object.keys(ROLE_DESCRIPTIONS).map((key, _index) => (
<div <div
key={key} key={key}
className={`w-2 h-2 rounded-full ${ className={`w-2 h-2 rounded-full ${

View file

@ -1,10 +1,9 @@
"use client"; "use client";
import React from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { ArrowRight, Bot, Brain, CheckCircle, Sparkles, Zap } from "lucide-react";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { CheckCircle, Bot, Brain, Zap, Sparkles, ArrowRight } from "lucide-react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs"; import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs";
const ROLE_ICONS = { const ROLE_ICONS = {

View file

@ -1,15 +1,12 @@
"use client"; "use client";
import { useState } from "react"; import { zodResolver } from "@hookform/resolvers/zod";
import { motion } from "framer-motion"; import { motion, type Variants } from "framer-motion";
import { cn } from "@/lib/utils";
import { MoveLeftIcon, Plus, Search, Trash2 } from "lucide-react"; import { MoveLeftIcon, Plus, Search, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation";
import { Input } from "@/components/ui/input"; import { useState } from "react";
import { Label } from "@/components/ui/label"; import { useForm } from "react-hook-form";
import { Separator } from "@/components/ui/separator"; import * as z from "zod";
import { Tilt } from "@/components/ui/tilt";
import { Spotlight } from "@/components/ui/spotlight";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
@ -21,9 +18,7 @@ import {
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
} from "@/components/ui/alert-dialog"; } from "@/components/ui/alert-dialog";
import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@/components/ui/button";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { import {
Form, Form,
FormControl, FormControl,
@ -33,7 +28,11 @@ import {
FormLabel, FormLabel,
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { useRouter } from "next/navigation"; import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Spotlight } from "@/components/ui/spotlight";
import { Tilt } from "@/components/ui/tilt";
import { cn } from "@/lib/utils";
// Define the form schema with Zod // Define the form schema with Zod
const searchSpaceFormSchema = z.object({ const searchSpaceFormSchema = z.object({
@ -97,7 +96,7 @@ export function SearchSpaceForm({
}, },
}; };
const itemVariants = { const itemVariants: Variants = {
hidden: { y: 20, opacity: 0 }, hidden: { y: 20, opacity: 0 },
visible: { visible: {
y: 0, y: 0,
@ -128,7 +127,8 @@ export function SearchSpaceForm({
: "Create a new search space to organize your documents, chats, and podcasts."} : "Create a new search space to organize your documents, chats, and podcasts."}
</p> </p>
</div> </div>
<button <Button
variant="ghost"
className="group relative rounded-full p-3 bg-background/80 hover:bg-muted border border-border hover:border-primary/20 shadow-sm hover:shadow-md transition-all duration-200 backdrop-blur-sm" className="group relative rounded-full p-3 bg-background/80 hover:bg-muted border border-border hover:border-primary/20 shadow-sm hover:shadow-md transition-all duration-200 backdrop-blur-sm"
onClick={() => { onClick={() => {
router.push("/dashboard"); router.push("/dashboard");
@ -139,7 +139,7 @@ export function SearchSpaceForm({
className="text-muted-foreground group-hover:text-foreground transition-colors duration-200" className="text-muted-foreground group-hover:text-foreground transition-colors duration-200"
/> />
<div className="absolute inset-0 rounded-full bg-gradient-to-r from-blue-500/10 to-purple-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" /> <div className="absolute inset-0 rounded-full bg-gradient-to-r from-blue-500/10 to-purple-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</button> </Button>
</motion.div> </motion.div>
<motion.div className="w-full" variants={itemVariants}> <motion.div className="w-full" variants={itemVariants}>

View file

@ -1,8 +1,25 @@
"use client"; "use client";
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import {
AlertCircle,
Bot,
Brain,
CheckCircle,
Loader2,
RefreshCw,
RotateCcw,
Save,
Settings2,
Zap,
} from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -10,23 +27,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Brain,
Zap,
Bot,
AlertCircle,
CheckCircle,
Settings2,
RefreshCw,
Save,
RotateCcw,
Loader2,
} from "lucide-react";
import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs"; import { useLLMConfigs, useLLMPreferences } from "@/hooks/use-llm-configs";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { toast } from "sonner";
const ROLE_DESCRIPTIONS = { const ROLE_DESCRIPTIONS = {
long_context: { long_context: {
@ -405,7 +406,7 @@ export function LLMRoleManager() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium">Assign LLM Configuration:</label> <Label className="text-sm font-medium">Assign LLM Configuration:</Label>
<Select <Select
value={currentAssignment?.toString() || "unassigned"} value={currentAssignment?.toString() || "unassigned"}
onValueChange={(value) => handleRoleAssignment(`${key}_llm_id`, value)} onValueChange={(value) => handleRoleAssignment(`${key}_llm_id`, value)}
@ -494,7 +495,7 @@ export function LLMRoleManager() {
<div className="flex items-center gap-2 text-sm text-muted-foreground"> <div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>Progress:</span> <span>Progress:</span>
<div className="flex gap-1"> <div className="flex gap-1">
{Object.keys(ROLE_DESCRIPTIONS).map((key, index) => ( {Object.keys(ROLE_DESCRIPTIONS).map((key) => (
<div <div
key={key} key={key}
className={`w-2 h-2 rounded-full ${ className={`w-2 h-2 rounded-full ${

View file

@ -1,10 +1,33 @@
"use client"; "use client";
import type React from "react"; import { AnimatePresence, motion } from "framer-motion";
import { useState, useEffect } from "react"; import {
import { motion, AnimatePresence } from "framer-motion"; AlertCircle,
Bot,
CheckCircle,
Clock,
Edit3,
Eye,
EyeOff,
Loader2,
Plus,
RefreshCw,
Settings2,
Trash2,
} from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { import {
@ -14,37 +37,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge"; import { type CreateLLMConfig, type LLMConfig, useLLMConfigs } from "@/hooks/use-llm-configs";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
Plus,
Trash2,
Bot,
AlertCircle,
Edit3,
Settings2,
Eye,
EyeOff,
CheckCircle,
Clock,
AlertTriangle,
RefreshCw,
Loader2,
} from "lucide-react";
import {
useLLMConfigs,
type CreateLLMConfig,
UpdateLLMConfig,
type LLMConfig,
} from "@/hooks/use-llm-configs";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
const LLM_PROVIDERS = [ const LLM_PROVIDERS = [
{ {
@ -179,7 +172,7 @@ export function ModelConfigManager() {
setIsSubmitting(true); setIsSubmitting(true);
let result; let result: LLMConfig | null = null;
if (editingConfig) { if (editingConfig) {
// Update existing config // Update existing config
result = await updateLLMConfig(editingConfig.id, formData); result = await updateLLMConfig(editingConfig.id, formData);

View file

@ -1,7 +1,9 @@
"use client"; "use client";
import { Trash2 } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { AppSidebar } from "@/components/sidebar/app-sidebar"; import { AppSidebar } from "@/components/sidebar/app-sidebar";
import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -10,8 +12,6 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Trash2 } from "lucide-react";
import { apiClient } from "@/lib/api"; // Import the API client import { apiClient } from "@/lib/api"; // Import the API client
interface Chat { interface Chat {

View file

@ -1,23 +1,23 @@
"use client"; "use client";
import * as React from "react";
import { import {
AlertCircle,
BookOpen, BookOpen,
Cable, Cable,
ExternalLink,
FileStack, FileStack,
Undo2, FileText,
Info,
type LucideIcon,
MessageCircleMore, MessageCircleMore,
Podcast,
Settings2, Settings2,
SquareLibrary, SquareLibrary,
SquareTerminal, SquareTerminal,
AlertCircle,
Info,
ExternalLink,
Trash2, Trash2,
Podcast, Undo2,
type LucideIcon,
FileText,
} from "lucide-react"; } from "lucide-react";
import { useMemo } from "react";
import { Logo } from "@/components/Logo"; import { Logo } from "@/components/Logo";
import { NavMain } from "@/components/sidebar/nav-main"; import { NavMain } from "@/components/sidebar/nav-main";
@ -26,7 +26,6 @@ import { NavSecondary } from "@/components/sidebar/nav-secondary";
import { import {
Sidebar, Sidebar,
SidebarContent, SidebarContent,
SidebarFooter,
SidebarHeader, SidebarHeader,
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
@ -178,7 +177,7 @@ export function AppSidebar({
...props ...props
}: AppSidebarProps) { }: AppSidebarProps) {
// Process navMain to resolve icon names to components // Process navMain to resolve icon names to components
const processedNavMain = React.useMemo(() => { const processedNavMain = useMemo(() => {
return navMain.map((item) => ({ return navMain.map((item) => ({
...item, ...item,
icon: iconMap[item.icon] || SquareTerminal, // Fallback to SquareTerminal if icon not found icon: iconMap[item.icon] || SquareTerminal, // Fallback to SquareTerminal if icon not found
@ -186,7 +185,7 @@ export function AppSidebar({
}, [navMain]); }, [navMain]);
// Process navSecondary to resolve icon names to components // Process navSecondary to resolve icon names to components
const processedNavSecondary = React.useMemo(() => { const processedNavSecondary = useMemo(() => {
return navSecondary.map((item) => ({ return navSecondary.map((item) => ({
...item, ...item,
icon: iconMap[item.icon] || Undo2, // Fallback to Undo2 if icon not found icon: iconMap[item.icon] || Undo2, // Fallback to Undo2 if icon not found
@ -194,7 +193,7 @@ export function AppSidebar({
}, [navSecondary]); }, [navSecondary]);
// Process RecentChats to resolve icon names to components // Process RecentChats to resolve icon names to components
const processedRecentChats = React.useMemo(() => { const processedRecentChats = useMemo(() => {
return ( return (
RecentChats?.map((item) => ({ RecentChats?.map((item) => ({
...item, ...item,
@ -227,9 +226,6 @@ export function AppSidebar({
{processedRecentChats.length > 0 && <NavProjects chats={processedRecentChats} />} {processedRecentChats.length > 0 && <NavProjects chats={processedRecentChats} />}
<NavSecondary items={processedNavSecondary} className="mt-auto" /> <NavSecondary items={processedNavSecondary} className="mt-auto" />
</SidebarContent> </SidebarContent>
{/* <SidebarFooter>
footer
</SidebarFooter> */}
</Sidebar> </Sidebar>
); );
} }

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { ExternalLink, Folder, MoreHorizontal, Share, Trash2, type LucideIcon } from "lucide-react"; import { ExternalLink, Folder, type LucideIcon, MoreHorizontal, Share, Trash2 } from "lucide-react";
import { useRouter } from "next/navigation";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -18,7 +18,6 @@ import {
SidebarMenuItem, SidebarMenuItem,
useSidebar, useSidebar,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { useRouter } from "next/navigation";
// Map of icon names to their components // Map of icon names to their components
const actionIconMap: Record<string, LucideIcon> = { const actionIconMap: Record<string, LucideIcon> = {

View file

@ -1,14 +1,14 @@
"use client"; "use client";
import type * as React from "react";
import type { LucideIcon } from "lucide-react"; import type { LucideIcon } from "lucide-react";
import type * as React from "react";
import { import {
SidebarGroup, SidebarGroup,
SidebarGroupLabel,
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
SidebarGroupLabel,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
export function NavSecondary({ export function NavSecondary({

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { BadgeCheck, ChevronsUpDown, LogOut, Settings } from "lucide-react"; import { BadgeCheck, ChevronsUpDown, LogOut, Settings } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { import {
DropdownMenu, DropdownMenu,
@ -18,7 +18,6 @@ import {
SidebarMenuItem, SidebarMenuItem,
useSidebar, useSidebar,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { useRouter, useParams } from "next/navigation";
export function NavUser({ export function NavUser({
user, user,

View file

@ -1,8 +1,7 @@
"use client"; "use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import type { ThemeProviderProps } from "next-themes"; import type { ThemeProviderProps } from "next-themes";
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) { export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>; return <NextThemesProvider {...props}>{children}</NextThemesProvider>;

View file

@ -1,22 +1,24 @@
"use client"; "use client";
import * as React from "react";
import { useTheme } from "next-themes";
import { MoonIcon, SunIcon } from "lucide-react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { MoonIcon, SunIcon } from "lucide-react";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
export function ThemeTogglerComponent() { export function ThemeTogglerComponent() {
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
const [isClient, setIsClient] = React.useState(false); const [isClient, setIsClient] = useState(false);
React.useEffect(() => { useEffect(() => {
setIsClient(true); setIsClient(true);
}, []); }, []);
return ( return (
isClient && ( isClient && (
<button <Button
variant="ghost"
onClick={() => { onClick={() => {
theme === "dark" ? setTheme("light") : setTheme("dark"); theme === "dark" ? setTheme("light") : setTheme("dark");
}} }}
@ -63,7 +65,7 @@ export function ThemeTogglerComponent() {
)} )}
<span className="sr-only">Toggle theme</span> <span className="sr-only">Toggle theme</span>
</button> </Button>
) )
); );
} }

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import type * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion"; import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDownIcon } from "lucide-react"; import { ChevronDownIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,10 +1,9 @@
"use client"; "use client";
import type * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import type * as React from "react";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) { function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />; return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const alertVariants = cva( const alertVariants = cva(

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import type * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar"; import * as AvatarPrimitive from "@radix-ui/react-avatar";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,6 +1,6 @@
import type * as React from "react";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,102 +0,0 @@
import type * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "@/lib/utils";
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
return (
<ol
data-slot="breadcrumb-list"
className={cn(
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
className
)}
{...props}
/>
);
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-item"
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
);
}
function BreadcrumbLink({
asChild,
className,
...props
}: React.ComponentProps<"a"> & {
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "a";
return (
<Comp
data-slot="breadcrumb-link"
className={cn("hover:text-foreground transition-colors", className)}
{...props}
/>
);
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
className={cn("text-foreground font-normal", className)}
{...props}
/>
);
}
function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRight />}
</li>
);
}
function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
className={cn("flex size-9 items-center justify-center", className)}
{...props}
>
<MoreHorizontal className="size-4" />
<span className="sr-only">More</span>
</span>
);
}
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
};

View file

@ -1,6 +1,6 @@
import type * as React from "react";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,11 +1,10 @@
"use client"; "use client";
import * as React from "react";
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import * as React from "react";
import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"; import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
import { cn } from "@/lib/utils";
import { Button, buttonVariants } from "@/components/ui/button"; import { Button, buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
function Calendar({ function Calendar({
className, className,

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import type * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "lucide-react"; import { CheckIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog"; import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { cn } from "@/lib/utils";
import { Sparkles } from "lucide-react"; import { Sparkles } from "lucide-react";
import { cn } from "@/lib/utils";
interface DisplayCardProps { interface DisplayCardProps {
className?: string; className?: string;

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import type * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import * as React from "react";
import type * as LabelPrimitive from "@radix-ui/react-label"; import type * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import * as React from "react";
import { import {
Controller, Controller,
type ControllerProps, type ControllerProps,
@ -12,9 +12,8 @@ import {
useFormContext, useFormContext,
useFormState, useFormState,
} from "react-hook-form"; } from "react-hook-form";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
const Form = FormProvider; const Form = FormProvider;

View file

@ -1,56 +0,0 @@
"use client";
import { Label } from "@/components/ui/label";
import { type Tag, TagInput } from "emblor";
import { useState } from "react";
const tags = [
{
id: "1",
text: "Red",
},
];
function InputDemo() {
const [exampleTags, setExampleTags] = useState<Tag[]>(tags);
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null);
return (
<div className="space-y-2 w-[300px]">
<Label htmlFor="input-57">Input with inner tags</Label>
<TagInput
id="input-57"
tags={exampleTags}
setTags={(newTags) => {
setExampleTags(newTags);
}}
placeholder="Add a tag"
styleClasses={{
inlineTagsContainer:
"border-input rounded-lg bg-background shadow-sm shadow-black/5 transition-shadow focus-within:border-ring focus-within:outline-none focus-within:ring-[3px] focus-within:ring-ring/20 p-1 gap-1",
input: "w-full min-w-[80px] focus-visible:outline-none shadow-none px-2 h-7",
tag: {
body: "h-7 relative bg-background border border-input hover:bg-background rounded-md font-medium text-xs ps-2 pe-7 flex",
closeButton:
"absolute -inset-y-px -end-px p-0 rounded-e-lg flex size-7 transition-colors outline-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70 text-muted-foreground/80 hover:text-foreground",
},
}}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
/>
<p className="mt-2 text-xs text-muted-foreground" role="region" aria-live="polite">
Built with{" "}
<a
className="underline hover:text-foreground"
href="https://github.com/JaleelB/emblor"
target="_blank"
rel="noopener nofollow"
>
emblor
</a>
</p>
</div>
);
}
export { InputDemo };

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import type * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label"; import * as LabelPrimitive from "@radix-ui/react-label";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,13 +1,11 @@
import type * as React from "react";
import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"; import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils";
import { type Button, buttonVariants } from "@/components/ui/button"; import { type Button, buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
function Pagination({ className, ...props }: React.ComponentProps<"nav">) { function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
return ( return (
<nav <nav
role="navigation"
aria-label="pagination" aria-label="pagination"
data-slot="pagination" data-slot="pagination"
className={cn("mx-auto flex w-full justify-center", className)} className={cn("mx-auto flex w-full justify-center", className)}

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import type * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover"; import * as PopoverPrimitive from "@radix-ui/react-popover";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import type * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select"; import * as SelectPrimitive from "@radix-ui/react-select";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import type * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator"; import * as SeparatorPrimitive from "@radix-ui/react-separator";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import type * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog"; import * as SheetPrimitive from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react"; import { XIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,12 +1,9 @@
"use client"; "use client";
import * as React from "react";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import { PanelLeftIcon } from "lucide-react"; import { PanelLeftIcon } from "lucide-react";
import * as React from "react";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
@ -19,6 +16,8 @@ import {
} from "@/components/ui/sheet"; } from "@/components/ui/sheet";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
const SIDEBAR_COOKIE_NAME = "sidebar_state"; const SIDEBAR_COOKIE_NAME = "sidebar_state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
@ -86,7 +85,7 @@ function SidebarProvider({
// Helper to toggle the sidebar. // Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => { const toggleSidebar = React.useCallback(() => {
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]); }, [isMobile, setOpen]);
// Adds a keyboard shortcut to toggle the sidebar. // Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => { React.useEffect(() => {
@ -115,7 +114,7 @@ function SidebarProvider({
setOpenMobile, setOpenMobile,
toggleSidebar, toggleSidebar,
}), }),
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] [state, open, setOpen, isMobile, openMobile, toggleSidebar]
); );
return ( return (

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider"; import * as SliderPrimitive from "@radix-ui/react-slider";
import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React, { useRef, useState, useCallback, useEffect } from "react"; import { motion, type SpringOptions, useSpring, useTransform } from "framer-motion";
import { motion, useSpring, useTransform, type SpringOptions } from "framer-motion"; import { useCallback, useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
type SpotlightProps = { type SpotlightProps = {

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs"; import * as TabsPrimitive from "@radix-ui/react-tabs";
import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -1,16 +1,16 @@
"use client"; "use client";
import type React from "react";
import { useRef } from "react";
import { import {
type MotionStyle,
motion, motion,
type SpringOptions,
useMotionTemplate, useMotionTemplate,
useMotionValue, useMotionValue,
useSpring, useSpring,
useTransform, useTransform,
type MotionStyle,
type SpringOptions,
} from "framer-motion"; } from "framer-motion";
import type React from "react";
import { useRef } from "react";
type TiltProps = { type TiltProps = {
children: React.ReactNode; children: React.ReactNode;

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import type * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";