mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-03 12:52:39 +02:00
feat: replace Loader2 with Spinner component for consistent loading indicators
This commit is contained in:
parent
9215118bab
commit
2d17d1a1b6
34 changed files with 113 additions and 105 deletions
|
|
@ -7,12 +7,13 @@ import {
|
|||
useAssistantApi,
|
||||
useAssistantState,
|
||||
} from "@assistant-ui/react";
|
||||
import { FileText, Loader2, Paperclip, PlusIcon, Upload, XIcon } from "lucide-react";
|
||||
import { FileText, Paperclip, PlusIcon, Upload, XIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { type FC, type PropsWithChildren, useEffect, useRef, useState } from "react";
|
||||
import { useShallow } from "zustand/shallow";
|
||||
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Dialog, DialogContent, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
|
@ -135,7 +136,7 @@ const AttachmentThumb: FC = () => {
|
|||
if (isProcessing) {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center bg-muted">
|
||||
<Loader2 className="size-6 animate-spin text-muted-foreground" />
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -213,7 +214,7 @@ const AttachmentUI: FC = () => {
|
|||
>
|
||||
{isProcessing ? (
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
Processing...
|
||||
</span>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
"use client";
|
||||
|
||||
import { Loader2 } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
interface ChatSessionStatusProps {
|
||||
isAiResponding: boolean;
|
||||
|
|
@ -43,7 +43,7 @@ export const ChatSessionStatus: FC<ChatSessionStatusProps> = ({
|
|||
className
|
||||
)}
|
||||
>
|
||||
<Loader2 className="size-3.5 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
<span>Currently responding to {displayName}</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
"use client";
|
||||
|
||||
import { useAtomValue } from "jotai";
|
||||
import { Cable, Loader2 } from "lucide-react";
|
||||
import { Cable } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import type { FC } from "react";
|
||||
import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms";
|
||||
import { currentUserAtom } from "@/atoms/user/user-query.atoms";
|
||||
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tabs, TabsContent } from "@/components/ui/tabs";
|
||||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
import { useConnectorsElectric } from "@/hooks/use-connectors-electric";
|
||||
|
|
@ -174,7 +175,7 @@ export const ConnectorIndicator: FC = () => {
|
|||
onClick={() => handleOpenChange(true)}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner size="sm" />
|
||||
) : (
|
||||
<>
|
||||
<Cable className="size-4 stroke-[1.5px]" />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"use client";
|
||||
|
||||
import { IconBrandYoutube } from "@tabler/icons-react";
|
||||
import { FileText, Loader2 } from "lucide-react";
|
||||
import { FileText } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
@ -111,7 +112,7 @@ export const ConnectorCard: FC<ConnectorCardProps> = ({
|
|||
</div>
|
||||
{isIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
Syncing
|
||||
</p>
|
||||
) : isConnected ? (
|
||||
|
|
@ -151,7 +152,7 @@ export const ConnectorCard: FC<ConnectorCardProps> = ({
|
|||
disabled={isConnecting || !isEnabled}
|
||||
>
|
||||
{isConnecting ? (
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
) : !isEnabled ? (
|
||||
"Unavailable"
|
||||
) : isConnected ? (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"use client";
|
||||
|
||||
import { ArrowLeft, Loader2 } from "lucide-react";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { type FC, useMemo } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { EnumConnectorName } from "@/contracts/enums/connector";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
import { getConnectorTypeDisplay } from "@/lib/connectors/utils";
|
||||
|
|
@ -139,7 +140,7 @@ export const ConnectorConnectView: FC<ConnectorConnectViewProps> = ({
|
|||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
Connecting
|
||||
</>
|
||||
) : connectorType === "MCP_CONNECTOR" ? (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"use client";
|
||||
|
||||
import { ArrowLeft, Info, Loader2, RefreshCw, Trash2 } from "lucide-react";
|
||||
import { ArrowLeft, Info, RefreshCw, Trash2 } from "lucide-react";
|
||||
import { type FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
@ -311,7 +312,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
|||
>
|
||||
{isDisconnecting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
Disconnecting
|
||||
</>
|
||||
) : (
|
||||
|
|
@ -347,7 +348,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
|||
>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
Saving
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"use client";
|
||||
|
||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
||||
import { ArrowLeft, Check, Info } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { type FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
import { getConnectorTypeDisplay } from "@/lib/connectors/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
@ -216,7 +217,7 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
|||
>
|
||||
{isStartingIndexing ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
Starting...
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
"use client";
|
||||
|
||||
import { ArrowRight, Cable, Loader2 } from "lucide-react";
|
||||
import { ArrowRight, Cable } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { FC } from "react";
|
||||
import { useState } from "react";
|
||||
import { getDocumentTypeLabel } from "@/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
|
|
@ -209,7 +210,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
<p className="text-[14px] font-semibold leading-tight truncate">{title}</p>
|
||||
{isAnyIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
Syncing
|
||||
</p>
|
||||
) : (
|
||||
|
|
@ -270,7 +271,7 @@ export const ActiveConnectorsTab: FC<ActiveConnectorsTabProps> = ({
|
|||
</div>
|
||||
{isIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
Syncing
|
||||
</p>
|
||||
) : !isMCPConnector ? (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"use client";
|
||||
|
||||
import { differenceInDays, differenceInMinutes, format, isToday, isYesterday } from "date-fns";
|
||||
import { ArrowLeft, Loader2, Plus, Server } from "lucide-react";
|
||||
import { ArrowLeft, Plus, Server } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
import type { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||
|
|
@ -143,7 +144,7 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
>
|
||||
<div className="flex h-5 w-5 items-center justify-center rounded-md bg-primary/10 shrink-0">
|
||||
{isConnecting ? (
|
||||
<Loader2 className="size-3 animate-spin text-primary" />
|
||||
<Spinner size="xs" className="text-primary" />
|
||||
) : (
|
||||
<Plus className="size-3 text-primary" />
|
||||
)}
|
||||
|
|
@ -207,7 +208,7 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
</p>
|
||||
{isIndexing ? (
|
||||
<p className="text-[11px] text-primary mt-1 flex items-center gap-1.5">
|
||||
<Loader2 className="size-3 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
Syncing
|
||||
</p>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
import { TagInput, type Tag as TagType } from "emblor";
|
||||
import { useAtom } from "jotai";
|
||||
import { ArrowLeft, Loader2 } from "lucide-react";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { type FC, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { createDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||
|
|
@ -222,7 +223,7 @@ export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ searchSpaceId,
|
|||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
{t("processing")}
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import type { CommentActionsProps } from "./types";
|
||||
|
|
@ -23,7 +24,7 @@ export function CommentActions({ canEdit, canDelete, onEdit, onDelete }: Comment
|
|||
size="icon"
|
||||
className="size-7 opacity-100 md:opacity-0 md:group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<MoreHorizontal className="size-4" />
|
||||
<MoreHorizontal className="size-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
|
|
@ -33,8 +34,9 @@ export function CommentActions({ canEdit, canDelete, onEdit, onDelete }: Comment
|
|||
Edit
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{canEdit && canDelete && <DropdownMenuSeparator />}
|
||||
{canDelete && (
|
||||
<DropdownMenuItem onClick={onDelete} className="text-destructive">
|
||||
<DropdownMenuItem onClick={onDelete} className="text-destructive focus:text-destructive">
|
||||
<Trash2 className="mr-2 size-4" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { MemberMentionItem } from "./member-mention-item";
|
||||
import type { MemberMentionPickerProps } from "./types";
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ export function MemberMentionPicker({
|
|||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center py-6">
|
||||
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import {
|
|||
FolderOpen,
|
||||
HardDrive,
|
||||
Image,
|
||||
Loader2,
|
||||
Presentation,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useComposioDriveFolders } from "@/hooks/use-composio-drive-folders";
|
||||
import { connectorsApiService } from "@/lib/apis/connectors-api.service";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
@ -253,7 +253,7 @@ export function ComposioDriveFolderTree({
|
|||
aria-label={isExpanded ? `Collapse ${item.name}` : `Expand ${item.name}`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loader2 className="h-2.5 w-2.5 sm:h-3 sm:w-3 animate-spin" />
|
||||
<Spinner size="xs" className="h-2.5 w-2.5 sm:h-3 sm:w-3" />
|
||||
) : isExpanded ? (
|
||||
<ChevronDown className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
) : (
|
||||
|
|
@ -344,7 +344,7 @@ export function ComposioDriveFolderTree({
|
|||
|
||||
{isLoadingRoot && (
|
||||
<div className="flex items-center justify-center py-4 sm:py-8">
|
||||
<Loader2 className="h-4 w-4 sm:h-6 sm:w-6 animate-spin text-muted-foreground" />
|
||||
<Spinner size="sm" className="sm:h-6 sm:w-6 text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import {
|
|||
FolderOpen,
|
||||
HardDrive,
|
||||
Image,
|
||||
Loader2,
|
||||
Presentation,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useGoogleDriveFolders } from "@/hooks/use-google-drive-folders";
|
||||
import { connectorsApiService } from "@/lib/apis/connectors-api.service";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
@ -253,7 +253,7 @@ export function GoogleDriveFolderTree({
|
|||
aria-label={isExpanded ? `Collapse ${item.name}` : `Expand ${item.name}`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loader2 className="h-2.5 w-2.5 sm:h-3 sm:w-3 animate-spin" />
|
||||
<Spinner size="xs" className="h-2.5 w-2.5 sm:h-3 sm:w-3" />
|
||||
) : isExpanded ? (
|
||||
<ChevronDown className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
) : (
|
||||
|
|
@ -344,7 +344,7 @@ export function GoogleDriveFolderTree({
|
|||
|
||||
{isLoadingRoot && (
|
||||
<div className="flex items-center justify-center py-4 sm:py-8">
|
||||
<Loader2 className="h-4 w-4 sm:h-6 sm:w-6 animate-spin text-muted-foreground" />
|
||||
<Spinner size="sm" className="sm:h-6 sm:w-6 text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { Loader2, Plus, Search } from "lucide-react";
|
||||
import { Plus, Search } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
|
@ -26,6 +26,7 @@ import {
|
|||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { trackSearchSpaceCreated } from "@/lib/posthog/events";
|
||||
|
||||
const formSchema = z.object({
|
||||
|
|
@ -145,7 +146,7 @@ export function CreateSearchSpaceDialog({ open, onOpenChange }: CreateSearchSpac
|
|||
<Button type="submit" disabled={isSubmitting} className="w-full sm:w-auto h-9 sm:h-10 text-sm">
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="mr-1.5 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-1.5" />
|
||||
{t("creating")}
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|||
import { format } from "date-fns";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
Loader2,
|
||||
MessageCircleMore,
|
||||
MoreHorizontal,
|
||||
RotateCcwIcon,
|
||||
|
|
@ -30,6 +29,7 @@ import {
|
|||
import { Input } from "@/components/ui/input";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import {
|
||||
deleteThread,
|
||||
|
|
@ -304,7 +304,7 @@ export function AllPrivateChatsSidebar({
|
|||
<div className="flex-1 overflow-y-auto overflow-x-hidden p-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8 text-sm text-destructive">
|
||||
|
|
@ -365,7 +365,7 @@ export function AllPrivateChatsSidebar({
|
|||
disabled={isBusy}
|
||||
>
|
||||
{isDeleting ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
) : (
|
||||
<MoreHorizontal className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|||
import { format } from "date-fns";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
Loader2,
|
||||
MessageCircleMore,
|
||||
MoreHorizontal,
|
||||
RotateCcwIcon,
|
||||
|
|
@ -30,6 +29,7 @@ import {
|
|||
import { Input } from "@/components/ui/input";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import {
|
||||
deleteThread,
|
||||
|
|
@ -304,7 +304,7 @@ export function AllSharedChatsSidebar({
|
|||
<div className="flex-1 overflow-y-auto overflow-x-hidden p-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
<Spinner size="md" className="text-muted-foreground" />
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-8 text-sm text-destructive">
|
||||
|
|
@ -365,7 +365,7 @@ export function AllSharedChatsSidebar({
|
|||
disabled={isBusy}
|
||||
>
|
||||
{isDeleting ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
<Spinner size="xs" />
|
||||
) : (
|
||||
<MoreHorizontal className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import { Check } from "lucide-react";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { NavItem } from "../../types/layout.types";
|
||||
|
|
@ -40,9 +39,6 @@ export function NavSection({ items, onItemClick, isCollapsed = false }: NavSecti
|
|||
{...joyrideAttr}
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
{item.isActive && (
|
||||
<Check className="absolute bottom-0.5 right-0.5 h-3 w-3 text-primary" />
|
||||
)}
|
||||
{item.badge && (
|
||||
<span className="absolute top-0.5 right-0.5 inline-flex items-center justify-center min-w-[14px] h-[14px] px-0.5 rounded-full bg-red-500 text-white text-[9px] font-medium">
|
||||
{item.badge}
|
||||
|
|
@ -73,9 +69,6 @@ export function NavSection({ items, onItemClick, isCollapsed = false }: NavSecti
|
|||
>
|
||||
<Icon className="h-4 w-4 shrink-0" />
|
||||
<span className="flex-1 truncate">{item.title}</span>
|
||||
{item.isActive && (
|
||||
<Check className="h-4 w-4 shrink-0 text-primary" />
|
||||
)}
|
||||
{item.badge && (
|
||||
<span className="inline-flex items-center justify-center min-w-4 h-4 px-1 rounded-full bg-red-500 text-white text-[10px] font-medium">
|
||||
{item.badge}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
Cloud,
|
||||
Edit3,
|
||||
Globe,
|
||||
Loader2,
|
||||
Plus,
|
||||
Settings2,
|
||||
Sparkles,
|
||||
|
|
@ -36,6 +35,7 @@ import {
|
|||
CommandSeparator,
|
||||
} from "@/components/ui/command";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type {
|
||||
GlobalNewLLMConfig,
|
||||
NewLLMConfigPublic,
|
||||
|
|
@ -179,7 +179,7 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp
|
|||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||
<Spinner size="sm" className="text-muted-foreground" />
|
||||
<span className="text-muted-foreground hidden md:inline">Loading</span>
|
||||
</>
|
||||
) : currentConfig ? (
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
Bot,
|
||||
CheckCircle,
|
||||
FileText,
|
||||
Loader2,
|
||||
RefreshCw,
|
||||
RotateCcw,
|
||||
Save,
|
||||
|
|
@ -32,6 +31,7 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
const ROLE_DESCRIPTIONS = {
|
||||
agent: {
|
||||
|
|
@ -206,7 +206,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
|
|||
<Card>
|
||||
<CardContent className="flex items-center justify-center py-8 md:py-12">
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Loader2 className="w-4 h-4 md:w-5 md:h-5 animate-spin" />
|
||||
<Spinner size="sm" className="md:h-5 md:w-5" />
|
||||
<span className="text-xs md:text-sm">
|
||||
{configsLoading && preferencesLoading
|
||||
? "Loading configurations and preferences..."
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {
|
|||
Clock,
|
||||
Edit3,
|
||||
FileText,
|
||||
Loader2,
|
||||
MessageSquareQuote,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
|
|
@ -49,6 +48,7 @@ import {
|
|||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { NewLLMConfig } from "@/contracts/types/new-llm-config.types";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
|
|||
<Card>
|
||||
<CardContent className="flex items-center justify-center py-10 md:py-16">
|
||||
<div className="flex flex-col items-center gap-2 md:gap-3">
|
||||
<Loader2 className="h-6 w-6 md:h-8 md:w-8 animate-spin text-muted-foreground" />
|
||||
<Spinner size="md" className="md:h-8 md:w-8 text-muted-foreground" />
|
||||
<span className="text-xs md:text-sm text-muted-foreground">
|
||||
Loading configurations...
|
||||
</span>
|
||||
|
|
@ -484,7 +484,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
|
|||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
Deleting
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
ChevronDown,
|
||||
ChevronsUpDown,
|
||||
Key,
|
||||
Loader2,
|
||||
MessageSquareQuote,
|
||||
Rocket,
|
||||
Sparkles,
|
||||
|
|
@ -48,6 +47,7 @@ import {
|
|||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { getModelsByProvider } from "@/contracts/enums/llm-models";
|
||||
|
|
@ -592,7 +592,7 @@ export function LLMConfigForm({
|
|||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="h-3.5 w-3.5 sm:h-4 sm:w-4 animate-spin" />
|
||||
<Spinner size="sm" />
|
||||
{mode === "edit" ? "Updating..." : "Creating"}
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
"use client";
|
||||
|
||||
import { useAtom } from "jotai";
|
||||
import { CheckCircle2, FileType, Info, Loader2, Tag, Upload, X } from "lucide-react";
|
||||
import { CheckCircle2, FileType, Info, Tag, Upload, X } from "lucide-react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { toast } from "sonner";
|
||||
import { uploadDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
|
|
@ -424,7 +425,7 @@ export function DocumentUploadTab({
|
|||
>
|
||||
{isUploading ? (
|
||||
<span className="flex items-center gap-2">
|
||||
<Loader2 className="h-4 w-4 sm:h-5 sm:w-5 animate-spin" />
|
||||
<Spinner size="sm" />
|
||||
{t("uploading")}
|
||||
</span>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
"use client";
|
||||
|
||||
import { makeAssistantToolUI } from "@assistant-ui/react";
|
||||
import { AlertCircleIcon, Loader2Icon, MicIcon } from "lucide-react";
|
||||
import { AlertCircleIcon, MicIcon } from "lucide-react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { Audio } from "@/components/tool-ui/audio";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { baseApiService } from "@/lib/apis/base-api.service";
|
||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||
import { clearActivePodcastTaskId, setActivePodcastTaskId } from "@/lib/chat/podcast-state";
|
||||
|
|
@ -97,8 +98,8 @@ function PodcastGeneratingState({ title }: { title: string }) {
|
|||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-foreground text-lg">{title}</h3>
|
||||
<div className="mt-2 flex items-center gap-2 text-muted-foreground">
|
||||
<Loader2Icon className="size-4 animate-spin" />
|
||||
<span className="text-sm">Generating podcast. This may take a few minutes</span>
|
||||
<Spinner size="sm" />
|
||||
<span className="text-sm">Generating podcast. This may take a few minutes.</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="h-1.5 w-full overflow-hidden rounded-full bg-primary/10">
|
||||
|
|
@ -144,7 +145,7 @@ function AudioLoadingState({ title }: { title: string }) {
|
|||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-foreground">{title}</h3>
|
||||
<div className="mt-2 flex items-center gap-2 text-muted-foreground">
|
||||
<Loader2Icon className="size-4 animate-spin" />
|
||||
<Spinner size="sm" />
|
||||
<span className="text-sm">Loading audio...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
"use client";
|
||||
|
||||
import { ExternalLinkIcon, ImageIcon, Loader2 } from "lucide-react";
|
||||
import { ExternalLinkIcon, ImageIcon } from "lucide-react";
|
||||
import NextImage from "next/image";
|
||||
import { Component, type ReactNode, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
|
|
@ -184,7 +185,7 @@ export function ImageLoading({ title = "Loading image..." }: { title?: string })
|
|||
<Card className="w-full max-w-md overflow-hidden">
|
||||
<div className="aspect-[4/3] bg-muted flex items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<Loader2 className="size-8 text-muted-foreground animate-spin" />
|
||||
<Spinner size="lg" className="text-muted-foreground" />
|
||||
<p className="text-muted-foreground text-sm">{title}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
"use client";
|
||||
|
||||
import { ExternalLinkIcon, Globe, ImageIcon, LinkIcon, Loader2 } from "lucide-react";
|
||||
import { ExternalLinkIcon, Globe, ImageIcon, LinkIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { Component, type ReactNode } from "react";
|
||||
import { z } from "zod";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
|
|
@ -299,18 +300,17 @@ export function MediaCard({
|
|||
|
||||
{/* Response Actions */}
|
||||
{responseActions && responseActions.length > 0 && (
|
||||
<div
|
||||
className="mt-4 flex items-center justify-end gap-2 border-t pt-3"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="mt-4 flex items-center justify-end gap-2 border-t pt-3">
|
||||
{responseActions.map((action) => (
|
||||
<Tooltip key={action.id}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={action.variant || "secondary"}
|
||||
size="sm"
|
||||
onClick={() => onResponseAction?.(action.id)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onResponseAction?.(action.id);
|
||||
}}
|
||||
>
|
||||
{action.label}
|
||||
</Button>
|
||||
|
|
@ -337,7 +337,7 @@ export function MediaCardLoading({ title = "Loading preview..." }: { title?: str
|
|||
return (
|
||||
<Card className="w-full max-w-md overflow-hidden">
|
||||
<div className="aspect-[2/1] bg-muted animate-pulse flex items-center justify-center">
|
||||
<Loader2 className="size-8 text-muted-foreground animate-spin" />
|
||||
<Spinner size="lg" className="text-muted-foreground" />
|
||||
</div>
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import { makeAssistantToolUI, useAssistantState } from "@assistant-ui/react";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
|
|
@ -11,6 +10,7 @@ import {
|
|||
registerPlanOwner,
|
||||
updatePlanStateAtom,
|
||||
} from "@/atoms/chat/plan-state.atom";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Plan, PlanErrorBoundary, parseSerializablePlan, TodoStatusSchema } from "./plan";
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -46,7 +46,7 @@ function WriteTodosLoading() {
|
|||
return (
|
||||
<div className="my-4 w-full max-w-xl rounded-2xl border bg-card/60 px-5 py-4 shadow-sm">
|
||||
<div className="flex items-center gap-3">
|
||||
<Loader2 className="size-5 animate-spin text-primary" />
|
||||
<Spinner size="md" className="text-primary" />
|
||||
<span className="text-sm text-muted-foreground">Creating plan...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue