mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-04 22:02:16 +02:00
feat(web): improve comment panel and trigger UI
This commit is contained in:
parent
d99722cfdc
commit
f008acecfc
8 changed files with 56 additions and 24 deletions
|
|
@ -157,5 +157,33 @@ button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar styles */
|
||||||
|
.scrollbar-thin {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: hsl(var(--muted-foreground) / 0.2) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin:hover {
|
||||||
|
scrollbar-color: hsl(var(--muted-foreground) / 0.4) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Webkit scrollbar styles */
|
||||||
|
.scrollbar-thin::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
|
background-color: hsl(var(--muted-foreground) / 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: hsl(var(--muted-foreground) / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
@source '../node_modules/@llamaindex/chat-ui/**/*.{ts,tsx}';
|
@source '../node_modules/@llamaindex/chat-ui/**/*.{ts,tsx}';
|
||||||
@source '../node_modules/streamdown/dist/*.js';
|
@source '../node_modules/streamdown/dist/*.js';
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import { transformComment, transformMember } from "./utils";
|
||||||
export function CommentPanelContainer({
|
export function CommentPanelContainer({
|
||||||
messageId,
|
messageId,
|
||||||
isOpen,
|
isOpen,
|
||||||
maxHeight = 400,
|
maxHeight,
|
||||||
}: CommentPanelContainerProps) {
|
}: CommentPanelContainerProps) {
|
||||||
const { data: commentsData, isLoading: isCommentsLoading } = useComments({
|
const { data: commentsData, isLoading: isCommentsLoading } = useComments({
|
||||||
messageId,
|
messageId,
|
||||||
|
|
@ -70,7 +70,6 @@ export function CommentPanelContainer({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommentPanel
|
<CommentPanel
|
||||||
messageId={messageId}
|
|
||||||
threads={commentThreads}
|
threads={commentThreads}
|
||||||
members={members}
|
members={members}
|
||||||
membersLoading={isMembersLoading}
|
membersLoading={isMembersLoading}
|
||||||
|
|
@ -84,4 +83,3 @@ export function CommentPanelContainer({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
export interface CommentPanelContainerProps {
|
export interface CommentPanelContainerProps {
|
||||||
messageId: number;
|
messageId: number;
|
||||||
searchSpaceId: number;
|
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose?: () => void;
|
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,3 @@ export function transformMember(membership: Membership): MemberOption {
|
||||||
avatarUrl: membership.user_avatar_url ?? null,
|
avatarUrl: membership.user_avatar_url ?? null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export function CommentPanel({
|
||||||
onEditComment,
|
onEditComment,
|
||||||
onDeleteComment,
|
onDeleteComment,
|
||||||
isSubmitting = false,
|
isSubmitting = false,
|
||||||
maxHeight = 400,
|
maxHeight,
|
||||||
}: CommentPanelProps) {
|
}: CommentPanelProps) {
|
||||||
const [isComposerOpen, setIsComposerOpen] = useState(false);
|
const [isComposerOpen, setIsComposerOpen] = useState(false);
|
||||||
|
|
||||||
|
|
@ -44,13 +44,17 @@ export function CommentPanel({
|
||||||
const hasThreads = threads.length > 0;
|
const hasThreads = threads.length > 0;
|
||||||
const showEmptyState = !hasThreads && !isComposerOpen;
|
const showEmptyState = !hasThreads && !isComposerOpen;
|
||||||
|
|
||||||
|
// Ensure minimum usable height for empty state + composer button
|
||||||
|
const minHeight = 180;
|
||||||
|
const effectiveMaxHeight = maxHeight ? Math.max(maxHeight, minHeight) : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-80 flex-col rounded-lg border bg-card">
|
<div
|
||||||
|
className="flex w-85 flex-col rounded-lg border bg-card"
|
||||||
|
style={effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : undefined}
|
||||||
|
>
|
||||||
{hasThreads && (
|
{hasThreads && (
|
||||||
<div
|
<div className="min-h-0 flex-1 overflow-y-auto scrollbar-thin">
|
||||||
className="overflow-y-auto"
|
|
||||||
style={{ maxHeight }}
|
|
||||||
>
|
|
||||||
<div className="space-y-4 p-4">
|
<div className="space-y-4 p-4">
|
||||||
{threads.map((thread) => (
|
{threads.map((thread) => (
|
||||||
<CommentThread
|
<CommentThread
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import type { CommentThreadData } from "../comment-thread/types";
|
||||||
import type { MemberOption } from "../member-mention-picker/types";
|
import type { MemberOption } from "../member-mention-picker/types";
|
||||||
|
|
||||||
export interface CommentPanelProps {
|
export interface CommentPanelProps {
|
||||||
messageId: number;
|
|
||||||
threads: CommentThreadData[];
|
threads: CommentThreadData[];
|
||||||
members: MemberOption[];
|
members: MemberOption[];
|
||||||
membersLoading?: boolean;
|
membersLoading?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,32 @@ import { Button } from "@/components/ui/button";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { CommentTriggerProps } from "./types";
|
import type { CommentTriggerProps } from "./types";
|
||||||
|
|
||||||
export function CommentTrigger({ commentCount, isOpen, onClick }: CommentTriggerProps) {
|
export function CommentTrigger({ commentCount, isOpen, onClick, disabled }: CommentTriggerProps) {
|
||||||
const hasComments = commentCount > 0;
|
const hasComments = commentCount > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant={isOpen ? "secondary" : "ghost"}
|
variant={hasComments ? "outline" : isOpen ? "secondary" : "ghost"}
|
||||||
size="sm"
|
size="icon"
|
||||||
|
disabled={disabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-8 gap-1.5 px-2 transition-opacity",
|
"relative size-10 rounded-full transition-all duration-200",
|
||||||
isOpen ? "text-foreground" : "text-muted-foreground",
|
hasComments
|
||||||
!hasComments && !isOpen && "opacity-0 group-hover:opacity-100"
|
? "border-primary/50 bg-primary/5 text-primary hover:bg-primary/10 hover:border-primary"
|
||||||
|
: isOpen
|
||||||
|
? "text-foreground"
|
||||||
|
: "text-muted-foreground hover:text-foreground",
|
||||||
|
!hasComments && !isOpen && "opacity-0 group-hover:opacity-100",
|
||||||
|
disabled && "cursor-not-allowed opacity-50"
|
||||||
)}
|
)}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<MessageSquare className={cn("size-4", isOpen && "fill-current")} />
|
<MessageSquare className={cn("size-5", (hasComments || isOpen) && "fill-current")} />
|
||||||
{hasComments && (
|
{hasComments && (
|
||||||
<span className="min-w-5 text-xs font-medium">{commentCount}</span>
|
<span className="absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-foreground">
|
||||||
|
{commentCount > 9 ? "9+" : commentCount}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@ export interface CommentTriggerProps {
|
||||||
commentCount: number;
|
commentCount: number;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue