mirror of
https://github.com/MODSetter/SurfSense.git
synced 2025-09-02 18:49:09 +00:00
Biome: fixes for compontents directory
This commit is contained in:
parent
758603b275
commit
2950573271
69 changed files with 478 additions and 648 deletions
|
@ -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>
|
||||||
|
|
|
@ -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 }) => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(() => {
|
||||||
|
|
|
@ -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 */}
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ">
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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({});
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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" },
|
||||||
|
|
|
@ -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 ${
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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}>
|
||||||
|
|
|
@ -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 ${
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> = {
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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} />;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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,
|
|
||||||
};
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 };
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue