mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-22 23:31:12 +02:00
chore: ran linting
This commit is contained in:
parent
5803fe79da
commit
0a26a6c5bb
54 changed files with 1015 additions and 672 deletions
|
|
@ -173,9 +173,7 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
|
|||
<Plus className="size-3 text-primary" />
|
||||
)}
|
||||
</div>
|
||||
<span className="text-xs sm:text-sm font-medium">
|
||||
{buttonText}
|
||||
</span>
|
||||
<span className="text-xs sm:text-sm font-medium">{buttonText}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -337,9 +337,7 @@ export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ searchSpaceId,
|
|||
disabled={isSubmitting || isFetchingPlaylist || videoTags.length === 0}
|
||||
className="relative text-xs sm:text-sm min-w-[140px] disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none"
|
||||
>
|
||||
<span className={isSubmitting ? "opacity-0" : ""}>
|
||||
{t("submit")}
|
||||
</span>
|
||||
<span className={isSubmitting ? "opacity-0" : ""}>{t("submit")}</span>
|
||||
{isSubmitting && <Spinner size="sm" className="absolute" />}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -132,9 +132,7 @@ const DocumentUploadPopupContent: FC<{
|
|||
<div className="flex-1 min-h-0 overflow-y-auto overscroll-contain">
|
||||
<div className="sticky top-0 z-20 bg-muted px-4 sm:px-6 pt-6 sm:pt-8 pb-10">
|
||||
<div className="flex items-center gap-2 mb-1 pr-8 sm:pr-0">
|
||||
<h2 className="text-xl sm:text-3xl font-semibold tracking-tight">
|
||||
Upload Documents
|
||||
</h2>
|
||||
<h2 className="text-xl sm:text-3xl font-semibold tracking-tight">Upload Documents</h2>
|
||||
</div>
|
||||
<p className="text-xs sm:text-base text-muted-foreground/80 line-clamp-1">
|
||||
Upload and sync your documents to your search space
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
import type { ImageMessagePartComponent } from "@assistant-ui/react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { ImageIcon, ImageOffIcon } from "lucide-react";
|
||||
import NextImage from "next/image";
|
||||
import { memo, type PropsWithChildren, useEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { cn } from "@/lib/utils";
|
||||
import NextImage from 'next/image';
|
||||
|
||||
const imageVariants = cva("aui-image-root relative overflow-hidden rounded-lg", {
|
||||
variants: {
|
||||
|
|
@ -88,23 +88,23 @@ function ImagePreview({
|
|||
<ImageOffIcon className="size-8 text-muted-foreground" />
|
||||
</div>
|
||||
) : isDataOrBlobUrl(src) ? (
|
||||
// biome-ignore lint/performance/noImgElement: data/blob URLs need plain img
|
||||
<img
|
||||
ref={imgRef}
|
||||
src={src}
|
||||
alt={alt}
|
||||
className={cn("block h-auto w-full object-contain", !loaded && "invisible", className)}
|
||||
onLoad={(e) => {
|
||||
if (typeof src === "string") setLoadedSrc(src);
|
||||
onLoad?.(e);
|
||||
}}
|
||||
onError={(e) => {
|
||||
if (typeof src === "string") setErrorSrc(src);
|
||||
onError?.(e);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
// biome-ignore lint/performance/noImgElement: data/blob URLs need plain img
|
||||
<img
|
||||
ref={imgRef}
|
||||
src={src}
|
||||
alt={alt}
|
||||
className={cn("block h-auto w-full object-contain", !loaded && "invisible", className)}
|
||||
onLoad={(e) => {
|
||||
if (typeof src === "string") setLoadedSrc(src);
|
||||
onLoad?.(e);
|
||||
}}
|
||||
onError={(e) => {
|
||||
if (typeof src === "string") setErrorSrc(src);
|
||||
onError?.(e);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
// biome-ignore lint/performance/noImgElement: intentional for dynamic external URLs
|
||||
// <img
|
||||
// ref={imgRef}
|
||||
|
|
@ -122,22 +122,22 @@ function ImagePreview({
|
|||
// {...props}
|
||||
// />
|
||||
<NextImage
|
||||
fill
|
||||
src={src || ""}
|
||||
alt={alt}
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 60vw"
|
||||
className={cn("block object-contain", !loaded && "invisible", className)}
|
||||
onLoad={() => {
|
||||
if (typeof src === "string") setLoadedSrc(src);
|
||||
onLoad?.();
|
||||
}}
|
||||
onError={() => {
|
||||
if (typeof src === "string") setErrorSrc(src);
|
||||
onError?.();
|
||||
}}
|
||||
unoptimized={false}
|
||||
{...props}
|
||||
/>
|
||||
fill
|
||||
src={src || ""}
|
||||
alt={alt}
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 60vw"
|
||||
className={cn("block object-contain", !loaded && "invisible", className)}
|
||||
onLoad={() => {
|
||||
if (typeof src === "string") setLoadedSrc(src);
|
||||
onLoad?.();
|
||||
}}
|
||||
onError={() => {
|
||||
if (typeof src === "string") setErrorSrc(src);
|
||||
onError?.();
|
||||
}}
|
||||
unoptimized={false}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -162,8 +162,8 @@ type ImageZoomProps = PropsWithChildren<{
|
|||
alt?: string;
|
||||
}>;
|
||||
function isDataOrBlobUrl(src: string | undefined): boolean {
|
||||
if (!src || typeof src !== "string") return false;
|
||||
return src.startsWith("data:") || src.startsWith("blob:");
|
||||
if (!src || typeof src !== "string") return false;
|
||||
return src.startsWith("data:") || src.startsWith("blob:");
|
||||
}
|
||||
function ImageZoom({ src, alt = "Image preview", children }: ImageZoomProps) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
|
@ -216,38 +216,38 @@ function ImageZoom({ src, alt = "Image preview", children }: ImageZoomProps) {
|
|||
>
|
||||
{/** biome-ignore lint/performance/noImgElement: <explanation> */}
|
||||
{isDataOrBlobUrl(src) ? (
|
||||
// biome-ignore lint/performance/noImgElement: data/blob URLs need plain img
|
||||
<img
|
||||
data-slot="image-zoom-content"
|
||||
src={src}
|
||||
alt={alt}
|
||||
className="aui-image-zoom-content fade-in zoom-in-95 max-h-[90vh] max-w-[90vw] animate-in object-contain duration-200"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
// biome-ignore lint/performance/noImgElement: data/blob URLs need plain img
|
||||
<img
|
||||
data-slot="image-zoom-content"
|
||||
src={src}
|
||||
alt={alt}
|
||||
className="aui-image-zoom-content fade-in zoom-in-95 max-h-[90vh] max-w-[90vw] animate-in object-contain duration-200"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<NextImage
|
||||
data-slot="image-zoom-content"
|
||||
fill
|
||||
src={src}
|
||||
alt={alt}
|
||||
sizes="90vw"
|
||||
className="aui-image-zoom-content fade-in zoom-in-95 object-contain duration-200"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}}
|
||||
unoptimized={false}
|
||||
/>
|
||||
)}
|
||||
data-slot="image-zoom-content"
|
||||
fill
|
||||
src={src}
|
||||
alt={alt}
|
||||
sizes="90vw"
|
||||
className="aui-image-zoom-content fade-in zoom-in-95 object-contain duration-200"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}}
|
||||
unoptimized={false}
|
||||
/>
|
||||
)}
|
||||
</button>,
|
||||
document.body
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -241,9 +241,7 @@ const ThreadListItemComponent = memo(function ThreadListItemComponent({
|
|||
<MessageSquareIcon className="size-4 shrink-0 text-muted-foreground" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="truncate text-sm font-medium">{thread.title || "New Chat"}</p>
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
{relativeTime}
|
||||
</p>
|
||||
<p className="truncate text-xs text-muted-foreground">{relativeTime}</p>
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|||
);
|
||||
|
||||
const serializedResult = useMemo(
|
||||
() => (result !== undefined && typeof result !== "string" ? JSON.stringify(result, null, 2) : null),
|
||||
() =>
|
||||
result !== undefined && typeof result !== "string" ? JSON.stringify(result, null, 2) : null,
|
||||
[result]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -300,15 +300,15 @@ export function CommentComposer({
|
|||
|
||||
<div className={cn("flex items-center gap-2", !compact && "justify-end")}>
|
||||
{onCancel && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onCancel}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onCancel}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
|
|
@ -317,11 +317,7 @@ export function CommentComposer({
|
|||
disabled={!canSubmit}
|
||||
className={cn(!canSubmit && "opacity-50", compact && "size-8 shrink-0 rounded-full")}
|
||||
>
|
||||
{compact ? (
|
||||
<ArrowUp className="size-4" />
|
||||
) : (
|
||||
submitLabel
|
||||
)}
|
||||
{compact ? <ArrowUp className="size-4" /> : submitLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -207,9 +207,15 @@ export const DocumentNode = React.memo(function DocumentNode({
|
|||
);
|
||||
})()}
|
||||
|
||||
<Tooltip delayDuration={600} open={titleTooltipOpen} onOpenChange={handleTitleTooltipOpenChange}>
|
||||
<Tooltip
|
||||
delayDuration={600}
|
||||
open={titleTooltipOpen}
|
||||
onOpenChange={handleTitleTooltipOpenChange}
|
||||
>
|
||||
<TooltipTrigger asChild>
|
||||
<span ref={titleRef} className="flex-1 min-w-0 truncate">{doc.title}</span>
|
||||
<span ref={titleRef} className="flex-1 min-w-0 truncate">
|
||||
{doc.title}
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="max-w-xs break-words">
|
||||
{doc.title}
|
||||
|
|
@ -276,10 +282,7 @@ export const DocumentNode = React.memo(function DocumentNode({
|
|||
Versions
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
disabled={isProcessing}
|
||||
onClick={() => onDelete(doc)}
|
||||
>
|
||||
<DropdownMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -321,10 +324,7 @@ export const DocumentNode = React.memo(function DocumentNode({
|
|||
Versions
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
<ContextMenuItem
|
||||
disabled={isProcessing}
|
||||
onClick={() => onDelete(doc)}
|
||||
>
|
||||
<ContextMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
|
|
|
|||
|
|
@ -97,7 +97,10 @@ export function FolderTreeView({
|
|||
const handleCancelRename = useCallback(() => setRenamingFolderId(null), [setRenamingFolderId]);
|
||||
|
||||
const effectiveActiveTypes = useMemo(() => {
|
||||
if (activeTypes.includes("FILE" as DocumentTypeEnum) && !activeTypes.includes("LOCAL_FOLDER_FILE" as DocumentTypeEnum)) {
|
||||
if (
|
||||
activeTypes.includes("FILE" as DocumentTypeEnum) &&
|
||||
!activeTypes.includes("LOCAL_FOLDER_FILE" as DocumentTypeEnum)
|
||||
) {
|
||||
return [...activeTypes, "LOCAL_FOLDER_FILE" as DocumentTypeEnum];
|
||||
}
|
||||
return activeTypes;
|
||||
|
|
@ -110,7 +113,9 @@ export function FolderTreeView({
|
|||
function check(folderId: number): boolean {
|
||||
if (match[folderId] !== undefined) return match[folderId];
|
||||
const childDocs = (docsByFolder[folderId] ?? []).some(
|
||||
(d) => effectiveActiveTypes.length === 0 || effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||
(d) =>
|
||||
effectiveActiveTypes.length === 0 ||
|
||||
effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||
);
|
||||
if (childDocs) {
|
||||
match[folderId] = true;
|
||||
|
|
@ -201,7 +206,9 @@ export function FolderTreeView({
|
|||
? childFolders.filter((f) => hasDescendantMatch[f.id])
|
||||
: childFolders;
|
||||
const childDocs = (docsByFolder[key] ?? []).filter(
|
||||
(d) => effectiveActiveTypes.length === 0 || effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||
(d) =>
|
||||
effectiveActiveTypes.length === 0 ||
|
||||
effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||
);
|
||||
|
||||
const nodes: React.ReactNode[] = [];
|
||||
|
|
@ -223,7 +230,7 @@ export function FolderTreeView({
|
|||
depth={depth}
|
||||
isExpanded={isExpanded}
|
||||
isRenaming={renamingFolderId === f.id}
|
||||
selectionState={folderSelectionStates[f.id] ?? "none"}
|
||||
selectionState={folderSelectionStates[f.id] ?? "none"}
|
||||
processingState={folderProcessingStates[f.id] ?? "idle"}
|
||||
onToggleSelect={onToggleFolderSelect}
|
||||
onToggleExpand={onToggleExpand}
|
||||
|
|
|
|||
|
|
@ -158,17 +158,18 @@ export function PlateEditor({
|
|||
// When not forced read-only, the user can toggle between editing/viewing.
|
||||
const canToggleMode = !readOnly;
|
||||
|
||||
const contextProviderValue = useMemo(()=> ({
|
||||
onSave,
|
||||
hasUnsavedChanges,
|
||||
isSaving,
|
||||
canToggleMode,
|
||||
}), [onSave, hasUnsavedChanges, isSaving, canToggleMode]);
|
||||
const contextProviderValue = useMemo(
|
||||
() => ({
|
||||
onSave,
|
||||
hasUnsavedChanges,
|
||||
isSaving,
|
||||
canToggleMode,
|
||||
}),
|
||||
[onSave, hasUnsavedChanges, isSaving, canToggleMode]
|
||||
);
|
||||
|
||||
return (
|
||||
<EditorSaveContext.Provider
|
||||
value={contextProviderValue}
|
||||
>
|
||||
<EditorSaveContext.Provider value={contextProviderValue}>
|
||||
<Plate
|
||||
editor={editor}
|
||||
// Only pass readOnly as a controlled prop when forced (permanently read-only).
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
import Image from 'next/image';
|
||||
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import Image from "next/image";
|
||||
import { ExpandedGifOverlay, useExpandedGif } from "@/components/ui/expanded-gif-overlay";
|
||||
|
||||
const useCases = [
|
||||
|
|
@ -83,13 +83,13 @@ function UseCaseCard({
|
|||
className="w-full rounded-xl object-cover transition-transform duration-500 group-hover:scale-[1.02]"
|
||||
/>
|
||||
<div className="relative w-full h-48">
|
||||
<Image
|
||||
src={src}
|
||||
alt={title}
|
||||
fill
|
||||
className="rounded-xl object-cover transition-transform duration-500 group-hover:scale-[1.02]"
|
||||
unoptimized={src.endsWith('.gif')}
|
||||
/>
|
||||
<Image
|
||||
src={src}
|
||||
alt={title}
|
||||
fill
|
||||
className="rounded-xl object-cover transition-transform duration-500 group-hover:scale-[1.02]"
|
||||
unoptimized={src.endsWith(".gif")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
|
|
|
|||
|
|
@ -370,7 +370,8 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
|
|||
url: "#announcements",
|
||||
icon: Megaphone,
|
||||
isActive: isAnnouncementsSidebarOpen,
|
||||
badge: announcementUnreadCount > 0 ? formatInboxCount(announcementUnreadCount) : undefined,
|
||||
badge:
|
||||
announcementUnreadCount > 0 ? formatInboxCount(announcementUnreadCount) : undefined,
|
||||
},
|
||||
] as (NavItem | null)[]
|
||||
).filter((item): item is NavItem => item !== null),
|
||||
|
|
|
|||
|
|
@ -376,24 +376,24 @@ export function AllPrivateChatsSidebarContent({
|
|||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
) : (
|
||||
<Tooltip delayDuration={600}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleThreadClick(thread.id)}
|
||||
disabled={isBusy}
|
||||
className="flex items-center gap-2 flex-1 min-w-0 text-left overflow-hidden"
|
||||
>
|
||||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" align="start">
|
||||
<p>
|
||||
{t("updated") || "Updated"}:{" "}
|
||||
{format(new Date(thread.updatedAt), "MMM d, yyyy 'at' h:mm a")}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip delayDuration={600}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleThreadClick(thread.id)}
|
||||
disabled={isBusy}
|
||||
className="flex items-center gap-2 flex-1 min-w-0 text-left overflow-hidden"
|
||||
>
|
||||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" align="start">
|
||||
<p>
|
||||
{t("updated") || "Updated"}:{" "}
|
||||
{format(new Date(thread.updatedAt), "MMM d, yyyy 'at' h:mm a")}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<DropdownMenu
|
||||
|
|
|
|||
|
|
@ -375,24 +375,24 @@ export function AllSharedChatsSidebarContent({
|
|||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
) : (
|
||||
<Tooltip delayDuration={600}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleThreadClick(thread.id)}
|
||||
disabled={isBusy}
|
||||
className="flex items-center gap-2 flex-1 min-w-0 text-left overflow-hidden"
|
||||
>
|
||||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" align="start">
|
||||
<p>
|
||||
{t("updated") || "Updated"}:{" "}
|
||||
{format(new Date(thread.updatedAt), "MMM d, yyyy 'at' h:mm a")}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip delayDuration={600}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleThreadClick(thread.id)}
|
||||
disabled={isBusy}
|
||||
className="flex items-center gap-2 flex-1 min-w-0 text-left overflow-hidden"
|
||||
>
|
||||
<span className="truncate">{thread.title || "New Chat"}</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" align="start">
|
||||
<p>
|
||||
{t("updated") || "Updated"}:{" "}
|
||||
{format(new Date(thread.updatedAt), "MMM d, yyyy 'at' h:mm a")}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<DropdownMenu
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import { createCodePlugin } from "@streamdown/code";
|
|||
import { createMathPlugin } from "@streamdown/math";
|
||||
import { Streamdown, type StreamdownProps } from "streamdown";
|
||||
import "katex/dist/katex.min.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from 'next/image';
|
||||
import { is } from "drizzle-orm";
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const code = createCodePlugin({
|
||||
themes: ["nord", "nord"],
|
||||
|
|
@ -130,30 +130,31 @@ export function MarkdownViewer({ content, className, maxLength }: MarkdownViewer
|
|||
),
|
||||
hr: ({ ...props }) => <hr className="my-4 border-muted" {...props} />,
|
||||
img: ({ src, alt, width: _w, height: _h, ...props }) => {
|
||||
const isDataOrUnknownUrl = typeof src === "string" && (src.startsWith("data:") || !src.startsWith("http"));
|
||||
const isDataOrUnknownUrl =
|
||||
typeof src === "string" && (src.startsWith("data:") || !src.startsWith("http"));
|
||||
|
||||
return isDataOrUnknownUrl ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
className="max-w-full h-auto my-4 rounded"
|
||||
alt={alt || "markdown image"}
|
||||
src={src}
|
||||
loading="lazy"
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="max-w-full h-auto my-4 rounded"
|
||||
alt={alt || "markdown image"}
|
||||
src={typeof src === "string" ? src : ""}
|
||||
width={_w || 800}
|
||||
height={_h || 600}
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 60vw"
|
||||
unoptimized={isDataOrUnknownUrl}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
return isDataOrUnknownUrl ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
className="max-w-full h-auto my-4 rounded"
|
||||
alt={alt || "markdown image"}
|
||||
src={src}
|
||||
loading="lazy"
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="max-w-full h-auto my-4 rounded"
|
||||
alt={alt || "markdown image"}
|
||||
src={typeof src === "string" ? src : ""}
|
||||
width={_w || 800}
|
||||
height={_h || 600}
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 60vw"
|
||||
unoptimized={isDataOrUnknownUrl}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
table: ({ ...props }) => (
|
||||
<div className="overflow-x-auto my-4 rounded-lg border border-border w-full">
|
||||
<table className="w-full divide-y divide-border" {...props} />
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import { Globe, KeyRound, Monitor, Receipt, Sparkles, User } from "lucide-react"
|
|||
import { useTranslations } from "next-intl";
|
||||
import { ApiKeyContent } from "@/app/dashboard/[search_space_id]/user-settings/components/ApiKeyContent";
|
||||
import { CommunityPromptsContent } from "@/app/dashboard/[search_space_id]/user-settings/components/CommunityPromptsContent";
|
||||
import { DesktopContent } from "@/app/dashboard/[search_space_id]/user-settings/components/DesktopContent";
|
||||
import { ProfileContent } from "@/app/dashboard/[search_space_id]/user-settings/components/ProfileContent";
|
||||
import { PromptsContent } from "@/app/dashboard/[search_space_id]/user-settings/components/PromptsContent";
|
||||
import { PurchaseHistoryContent } from "@/app/dashboard/[search_space_id]/user-settings/components/PurchaseHistoryContent";
|
||||
import { DesktopContent } from "@/app/dashboard/[search_space_id]/user-settings/components/DesktopContent";
|
||||
import { userSettingsDialogAtom } from "@/atoms/settings/settings-dialog.atoms";
|
||||
import { SettingsDialog } from "@/components/settings/settings-dialog";
|
||||
|
||||
|
|
|
|||
|
|
@ -471,13 +471,13 @@ export function DocumentUploadTab({
|
|||
</button>
|
||||
))
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="flex flex-col items-center gap-4 py-12 px-4 cursor-pointer w-full bg-transparent border-none"
|
||||
onClick={() => {
|
||||
if (!isElectron) fileInputRef.current?.click();
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="flex flex-col items-center gap-4 py-12 px-4 cursor-pointer w-full bg-transparent border-none"
|
||||
onClick={() => {
|
||||
if (!isElectron) fileInputRef.current?.click();
|
||||
}}
|
||||
>
|
||||
<Upload className="h-10 w-10 text-muted-foreground" />
|
||||
<div className="text-center space-y-1.5">
|
||||
<p className="text-base font-medium">
|
||||
|
|
@ -485,10 +485,15 @@ export function DocumentUploadTab({
|
|||
</p>
|
||||
<p className="text-sm text-muted-foreground">{t("file_size_limit")}</p>
|
||||
</div>
|
||||
{/* biome-ignore lint/a11y/useSemanticElements: wrapper to stop click propagation to parent button */}
|
||||
<div className="w-full mt-1" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} role="group">
|
||||
{renderBrowseButton({ fullWidth: true })}
|
||||
</div>
|
||||
{/* biome-ignore lint/a11y/useSemanticElements: wrapper to stop click propagation to parent button */}
|
||||
<div
|
||||
className="w-full mt-1"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
role="group"
|
||||
>
|
||||
{renderBrowseButton({ fullWidth: true })}
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -684,17 +689,17 @@ export function DocumentUploadTab({
|
|||
</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-3 pb-3">
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{supportedExtensions.map((ext) => (
|
||||
<Badge
|
||||
key={ext}
|
||||
variant="secondary"
|
||||
className="rounded border-0 bg-neutral-200/80 dark:bg-neutral-700/60 text-muted-foreground text-[10px] px-2 py-0.5 font-normal"
|
||||
>
|
||||
{ext}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{supportedExtensions.map((ext) => (
|
||||
<Badge
|
||||
key={ext}
|
||||
variant="secondary"
|
||||
className="rounded border-0 bg-neutral-200/80 dark:bg-neutral-700/60 text-muted-foreground text-[10px] px-2 py-0.5 font-normal"
|
||||
>
|
||||
{ext}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import { Code2, Database, ExternalLink, File, FileText, Globe, Newspaper } from "lucide-react";
|
||||
import NextImage from "next/image";
|
||||
import * as React from "react";
|
||||
import { openSafeNavigationHref, resolveSafeNavigationHref } from "../shared/media";
|
||||
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";
|
||||
import { Citation } from "./citation";
|
||||
import type { CitationType, CitationVariant, SerializableCitation } from "./schema";
|
||||
import NextImage from 'next/image';
|
||||
|
||||
|
||||
const TYPE_ICONS: Record<CitationType, LucideIcon> = {
|
||||
webpage: Globe,
|
||||
|
|
@ -264,9 +263,9 @@ function OverflowItem({ citation, onClick }: OverflowItemProps) {
|
|||
className="size-4.5 rounded-full object-cover"
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
) : (
|
||||
<TypeIcon className="text-muted-foreground size-3" aria-hidden="true" />
|
||||
)}
|
||||
)}
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="group-hover:decoration-foreground/30 truncate text-sm font-medium group-hover:underline group-hover:underline-offset-2">
|
||||
{citation.title}
|
||||
|
|
@ -341,18 +340,18 @@ function StackedCitations({ id, citations, className, onNavigate }: StackedCitat
|
|||
style={{ zIndex: maxIcons - index }}
|
||||
>
|
||||
{citation.favicon ? (
|
||||
<NextImage
|
||||
src={citation.favicon}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
width={18}
|
||||
height={18}
|
||||
className="size-4.5 rounded-full object-cover"
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<TypeIcon className="text-muted-foreground size-3" aria-hidden="true" />
|
||||
)}
|
||||
<NextImage
|
||||
src={citation.favicon}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
width={18}
|
||||
height={18}
|
||||
className="size-4.5 rounded-full object-cover"
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<TypeIcon className="text-muted-foreground size-3" aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import { Code2, Database, ExternalLink, File, FileText, Globe, Newspaper } from "lucide-react";
|
||||
import NextImage from "next/image";
|
||||
import * as React from "react";
|
||||
import { openSafeNavigationHref, sanitizeHref } from "../shared/media";
|
||||
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";
|
||||
import type { CitationType, CitationVariant, SerializableCitation } from "./schema";
|
||||
import NextImage from 'next/image';
|
||||
|
||||
const FALLBACK_LOCALE = "en-US";
|
||||
|
||||
|
|
@ -115,18 +115,18 @@ export function Citation(props: CitationProps) {
|
|||
};
|
||||
|
||||
const iconElement = favicon ? (
|
||||
<NextImage
|
||||
src={favicon}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
width={16}
|
||||
height={16}
|
||||
className="bg-muted size-3.5 shrink-0 rounded object-cover"
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<TypeIcon className="size-3.5 shrink-0 opacity-60" aria-hidden="true" />
|
||||
);
|
||||
<NextImage
|
||||
src={favicon}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
width={16}
|
||||
height={16}
|
||||
className="bg-muted size-3.5 shrink-0 rounded object-cover"
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<TypeIcon className="size-3.5 shrink-0 opacity-60" aria-hidden="true" />
|
||||
);
|
||||
|
||||
const { open, handleMouseEnter, handleMouseLeave } = useHoverPopover();
|
||||
|
||||
|
|
|
|||
|
|
@ -202,7 +202,10 @@ const Tabs = forwardRef<
|
|||
},
|
||||
[onValueChange, value]
|
||||
);
|
||||
const contextValue = useMemo(() => ({ activeValue, onValueChange: handleValueChange }), [activeValue, handleValueChange]);
|
||||
const contextValue = useMemo(
|
||||
() => ({ activeValue, onValueChange: handleValueChange }),
|
||||
[activeValue, handleValueChange]
|
||||
);
|
||||
return (
|
||||
<TabsContext.Provider value={contextValue}>
|
||||
<div ref={ref} className={cn("tabs-container", className)} {...props}>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
import { useMemo } from "react";
|
||||
import { toggleVariants } from "@/components/ui/toggle";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const ToggleGroupContext = React.createContext<
|
||||
VariantProps<typeof toggleVariants> & {
|
||||
|
|
@ -28,8 +28,8 @@ function ToggleGroup({
|
|||
VariantProps<typeof toggleVariants> & {
|
||||
spacing?: number;
|
||||
}) {
|
||||
const contextValue = useMemo(() => ({variant, size, spacing }), [variant, size, spacing]);
|
||||
|
||||
const contextValue = useMemo(() => ({ variant, size, spacing }), [variant, size, spacing]);
|
||||
|
||||
return (
|
||||
<ToggleGroupPrimitive.Root
|
||||
data-slot="toggle-group"
|
||||
|
|
@ -43,9 +43,7 @@ function ToggleGroup({
|
|||
)}
|
||||
{...props}
|
||||
>
|
||||
<ToggleGroupContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ToggleGroupContext.Provider>
|
||||
<ToggleGroupContext.Provider value={contextValue}>{children}</ToggleGroupContext.Provider>
|
||||
</ToggleGroupPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue