@@ -204,11 +205,12 @@ const MobileCitationDrawer: FC = () => {
{citations.map((citation) => (
-
-
+
))}
@@ -506,9 +508,10 @@ export const AssistantMessage: FC = () => {
>
{/* Fixed trigger slot prevents any vertical reflow when visibility changes */}
-
+
{/* Desktop floating comment panel — overlays on top of chat content */}
diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx
index 153e0d54d..31212b0d2 100644
--- a/surfsense_web/components/assistant-ui/thread.tsx
+++ b/surfsense_web/components/assistant-ui/thread.tsx
@@ -161,14 +161,16 @@ const PremiumQuotaPinnedAlert: FC = () => {
-
+
);
@@ -280,9 +282,11 @@ const ConnectToolsBanner: FC<{ isThreadEmpty: boolean }> = ({ isThreadEmpty }) =
return (
-
-
);
@@ -326,14 +332,16 @@ const PendingScreenImageStrip: FC = () => {
>
{/* biome-ignore lint/performance/noImgElement: data URL thumbnails from capture */}
- setUrls((prev) => prev.filter((_, i) => i !== index))}
- className="absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-background/90 text-muted-foreground shadow-sm transition-opacity hover:text-accent-foreground sm:opacity-0 sm:group-hover:opacity-100"
+ variant="ghost"
+ size="icon"
+ className="absolute right-0.5 top-0.5 size-5 rounded-full bg-background/90 text-muted-foreground shadow-sm transition-opacity hover:bg-background/90 hover:text-accent-foreground sm:opacity-0 sm:group-hover:opacity-100"
aria-label="Remove screenshot"
>
-
+
))}
@@ -352,21 +360,25 @@ const ClipboardChip: FC<{ text: string; onDismiss: () => void }> = ({ text, onDi
From clipboard
{isLong && (
- setExpanded((v) => !v)}
- className="flex items-center text-muted-foreground hover:text-accent-foreground transition-colors"
+ variant="ghost"
+ size="icon"
+ className="size-5 text-muted-foreground hover:bg-transparent hover:text-accent-foreground"
>
{expanded ? : }
-
+
)}
-
-
+
@@ -1173,13 +1185,15 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false
)}
{hasWebSearchTool && (
- toggleTool("web_search")}
className={cn(
- "rounded-full transition-[background-color,border-color,color] flex items-center gap-1 px-2 py-1 border h-8 select-none",
+ "rounded-full transition-[background-color,border-color,color] flex items-center gap-1 px-2 py-1 border h-8 select-none hover:bg-transparent",
isWebSearchEnabled
? "bg-sky-500/15 border-sky-500/60 text-sky-500"
: "bg-transparent border-transparent text-muted-foreground hover:text-accent-foreground"
@@ -1212,7 +1226,7 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false
)}
-
+
)}
{!hasModelConfigured && (
diff --git a/surfsense_web/components/new-chat/document-mention-picker.tsx b/surfsense_web/components/new-chat/document-mention-picker.tsx
index cb61a5f2b..a2b3c138c 100644
--- a/surfsense_web/components/new-chat/document-mention-picker.tsx
+++ b/surfsense_web/components/new-chat/document-mention-picker.tsx
@@ -17,6 +17,7 @@ import {
FOLDER_MENTION_DOCUMENT_TYPE,
type MentionedDocumentInfo,
} from "@/atoms/chat/mentioned-documents.atom";
+import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
import type { Document, SearchDocumentTitlesResponse } from "@/contracts/types/document.types";
@@ -484,7 +485,7 @@ export const DocumentMentionPicker = forwardRef<
const isHighlighted = !isAlreadySelected && selectableIndex === highlightedIndex;
return (
- {
if (el && selectableIndex >= 0) {
@@ -492,6 +493,7 @@ export const DocumentMentionPicker = forwardRef<
}
}}
type="button"
+ variant="ghost"
onClick={() => !isAlreadySelected && handleSelectMention(mention)}
onMouseEnter={() => {
if (!isAlreadySelected && selectableIndex >= 0) {
@@ -500,7 +502,7 @@ export const DocumentMentionPicker = forwardRef<
}}
disabled={isAlreadySelected}
className={cn(
- "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
+ "h-auto w-full justify-start gap-2 px-3 py-2 text-left transition-colors",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent text-accent-foreground"
)}
@@ -511,7 +513,7 @@ export const DocumentMentionPicker = forwardRef<
{doc.title}
-
+
);
})}
>
@@ -541,7 +543,7 @@ export const DocumentMentionPicker = forwardRef<
const isHighlighted = !isAlreadySelected && selectableIndex === highlightedIndex;
return (
- {
if (el && selectableIndex >= 0) {
@@ -549,6 +551,7 @@ export const DocumentMentionPicker = forwardRef<
}
}}
type="button"
+ variant="ghost"
onClick={() => !isAlreadySelected && handleSelectMention(mention)}
onMouseEnter={() => {
if (!isAlreadySelected && selectableIndex >= 0) {
@@ -557,7 +560,7 @@ export const DocumentMentionPicker = forwardRef<
}}
disabled={isAlreadySelected}
className={cn(
- "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
+ "h-auto w-full justify-start gap-2 px-3 py-2 text-left transition-colors",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent text-accent-foreground"
)}
@@ -568,7 +571,7 @@ export const DocumentMentionPicker = forwardRef<
{doc.title}
-
+
);
})}
>
@@ -595,7 +598,7 @@ export const DocumentMentionPicker = forwardRef<
const isHighlighted = !isAlreadySelected && selectableIndex === highlightedIndex;
return (
- {
if (el && selectableIndex >= 0) {
@@ -603,6 +606,7 @@ export const DocumentMentionPicker = forwardRef<
}
}}
type="button"
+ variant="ghost"
onClick={() => !isAlreadySelected && handleSelectMention(folder)}
onMouseEnter={() => {
if (!isAlreadySelected && selectableIndex >= 0) {
@@ -611,7 +615,7 @@ export const DocumentMentionPicker = forwardRef<
}}
disabled={isAlreadySelected}
className={cn(
- "w-full flex items-center gap-2 px-3 py-2 text-left transition-colors rounded-md",
+ "h-auto w-full justify-start gap-2 px-3 py-2 text-left transition-colors",
isAlreadySelected ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
isHighlighted && "bg-accent text-accent-foreground"
)}
@@ -622,7 +626,7 @@ export const DocumentMentionPicker = forwardRef<
{folder.title}
-
+
);
})}
>
diff --git a/surfsense_web/components/new-chat/model-selector.tsx b/surfsense_web/components/new-chat/model-selector.tsx
index a88a8d04e..6f7c946f0 100644
--- a/surfsense_web/components/new-chat/model-selector.tsx
+++ b/surfsense_web/components/new-chat/model-selector.tsx
@@ -853,14 +853,15 @@ export function ModelSelector({
: "opacity-100 translate-y-0 pointer-events-auto"
)}
>
- scrollProviderSidebar("backward")}
- className="flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground/90 hover:text-accent-foreground hover:bg-accent transition-colors"
+ className="h-4 w-4 rounded-sm p-0 text-muted-foreground/90 hover:bg-accent hover:text-accent-foreground"
>
-
+
)}
{isMobile && (
@@ -913,12 +914,13 @@ export function ModelSelector({
))}
- setSelectedProvider(provider)}
tabIndex={-1}
className={cn(
- "relative flex items-center justify-center rounded-md transition-all duration-150",
+ "relative h-auto rounded-md transition-all duration-150",
isMobile ? "p-2 shrink-0" : "p-1.5 w-full",
isActive
? "bg-primary/10 text-primary"
@@ -934,7 +936,7 @@ export function ModelSelector({
className: "size-4",
})
)}
-
+
{isAll ? "All Models" : formatProviderName(provider)}
@@ -954,14 +956,15 @@ export function ModelSelector({
: "opacity-100 translate-y-0 pointer-events-auto"
)}
>
- scrollProviderSidebar("forward")}
- className="flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground/90 hover:text-accent-foreground hover:bg-accent transition-colors"
+ className="h-4 w-4 rounded-sm p-0 text-muted-foreground/90 hover:bg-accent hover:text-accent-foreground"
>
-
+
)}
{isMobile && (
@@ -1175,13 +1178,14 @@ export function ModelSelector({
},
] as const
).map(({ value, icon: Icon, label }) => (
- setActiveTab(value)}
onClick={() => handleTabChange(value)}
className={cn(
- "flex items-center justify-center gap-1.5 text-sm font-medium transition-all duration-200 border-b-[1.5px]",
+ "h-auto rounded-none px-0 py-0 gap-1.5 text-sm font-medium transition-all duration-200 border-b-[1.5px] hover:bg-transparent",
activeTab === value
? "border-foreground dark:border-white text-foreground"
: "border-transparent text-muted-foreground hover:text-accent-foreground"
@@ -1189,7 +1193,7 @@ export function ModelSelector({
>
{label}
-
+
))}
diff --git a/surfsense_web/components/ui/equation-node.tsx b/surfsense_web/components/ui/equation-node.tsx
index 98bcf5f8e..5ceea83e5 100644
--- a/surfsense_web/components/ui/equation-node.tsx
+++ b/surfsense_web/components/ui/equation-node.tsx
@@ -6,6 +6,7 @@ import type { TEquationElement } from "platejs";
import { PlateElement, type PlateElementProps, useSelected } from "platejs/react";
import * as React from "react";
+import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export function EquationElement({ children, ...props }: PlateElementProps) {
@@ -74,20 +75,23 @@ export function EquationElement({ children, ...props }: PlateElementProps
-
Cancel
-
-
+
Done
-
+
)}
@@ -162,20 +166,23 @@ export function InlineEquationElement({ children, ...props }: PlateElementProps<
{...inputProps}
/>
-
Cancel
-
-
+
Done
-
+
)}
diff --git a/surfsense_web/components/ui/hero-carousel.tsx b/surfsense_web/components/ui/hero-carousel.tsx
index 2c1a98f46..53c1febac 100644
--- a/surfsense_web/components/ui/hero-carousel.tsx
+++ b/surfsense_web/components/ui/hero-carousel.tsx
@@ -3,7 +3,8 @@
import { ChevronLeft, ChevronRight } from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useCallback, useEffect, useRef, useState } from "react";
-import { ExpandedGifOverlay, useExpandedGif } from "@/components/ui/expanded-gif-overlay";
+import { Button } from "@/components/ui/button";
+import { ExpandedMediaOverlay, useExpandedMedia } from "@/components/ui/expanded-gif-overlay";
const carouselItems = [
{
@@ -70,7 +71,7 @@ function HeroCarouselCard({
src: string;
onExpandedChange?: (expanded: boolean) => void;
}) {
- const { expanded, open, close } = useExpandedGif();
+ const { expanded, open, close } = useExpandedMedia();
const videoRef = useRef(null);
const [hasLoaded, setHasLoaded] = useState(false);
@@ -147,7 +148,7 @@ function HeroCarouselCard({
- {expanded && }
+ {expanded && }
>
);
@@ -204,22 +205,26 @@ function HeroCarousel() {
-
!isGifExpanded && goToPrev()}
- className="flex size-11 items-center justify-center rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-sm transition-colors hover:bg-neutral-100 touch-manipulation dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
+ className="size-11 rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-sm hover:bg-neutral-100 touch-manipulation dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
aria-label="Previous slide"
>
-
+
- {carouselItems.map((_, i) => (
- (
+ !isGifExpanded && goTo(i)}
- className="flex h-11 min-w-[28px] items-center justify-center touch-manipulation"
+ className="h-11 min-w-[28px] bg-transparent p-0 hover:bg-transparent touch-manipulation"
aria-label={`Go to slide ${i + 1}`}
>
-
+
))}
-
!isGifExpanded && goToNext()}
- className="flex size-11 items-center justify-center rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-sm transition-colors hover:bg-neutral-100 touch-manipulation dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
+ className="size-11 rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-sm hover:bg-neutral-100 touch-manipulation dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700"
aria-label="Next slide"
>
-
+
);