enhanced ext editor in worknote page

This commit is contained in:
laxmanhalaki 2025-10-23 19:40:12 +05:30
parent da1d0538e9
commit 47a5a436aa
3 changed files with 303 additions and 52 deletions

View File

@ -1,4 +1,4 @@
import { useState } from 'react'; import { useState, useEffect } from 'react';
import { Bell, Settings, User, Plus, Search, Home, FileText, CheckCircle, LogOut, PanelLeft, PanelLeftClose } from 'lucide-react'; import { Bell, Settings, User, Plus, Search, Home, FileText, CheckCircle, LogOut, PanelLeft, PanelLeftClose } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
@ -14,7 +14,7 @@ interface PageLayoutProps {
} }
export function PageLayout({ children, currentPage = 'dashboard', onNavigate, onNewRequest }: PageLayoutProps) { export function PageLayout({ children, currentPage = 'dashboard', onNavigate, onNewRequest }: PageLayoutProps) {
const [sidebarOpen, setSidebarOpen] = useState(true); const [sidebarOpen, setSidebarOpen] = useState(false);
const menuItems = [ const menuItems = [
{ id: 'dashboard', label: 'Dashboard', icon: Home }, { id: 'dashboard', label: 'Dashboard', icon: Home },
@ -27,11 +27,52 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
setSidebarOpen(!sidebarOpen); setSidebarOpen(!sidebarOpen);
}; };
// Handle responsive behavior: sidebar open on desktop, closed on mobile
useEffect(() => {
const handleResize = () => {
// 768px is the md breakpoint in Tailwind
if (window.innerWidth >= 768) {
setSidebarOpen(true); // Always open on desktop
} else {
setSidebarOpen(false); // Closed by default on mobile
}
};
// Set initial state
handleResize();
// Add event listener
window.addEventListener('resize', handleResize);
// Cleanup
return () => window.removeEventListener('resize', handleResize);
}, []);
return ( return (
<div className="min-h-screen flex w-full bg-background"> <div className="min-h-screen flex w-full bg-background">
{/* Sidebar */} {/* Mobile Overlay */}
<div className={`${sidebarOpen ? 'w-64' : 'w-0'} transition-all duration-300 ease-in-out overflow-hidden flex-shrink-0`}> {sidebarOpen && (
<div className="w-64 h-full border-r border-gray-800 bg-black"> <div
className="fixed inset-0 bg-black/50 z-40 md:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}
{/* Sidebar - Hidden on mobile by default, toggleable on desktop */}
<aside className={`
fixed md:relative
inset-y-0 left-0
w-64
transform transition-transform duration-300 ease-in-out
${sidebarOpen ? 'translate-x-0' : '-translate-x-full'}
md:translate-x-0
${sidebarOpen ? 'md:w-64' : 'md:w-0 md:-translate-x-full'}
z-50 md:z-auto
flex-shrink-0
border-r border-gray-800 bg-black
overflow-y-auto
`}>
<div className="w-64 h-full">
<div className="p-4 border-b border-gray-800"> <div className="p-4 border-b border-gray-800">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-10 h-10 bg-re-green rounded-lg flex items-center justify-center shrink-0"> <div className="w-10 h-10 bg-re-green rounded-lg flex items-center justify-center shrink-0">
@ -48,7 +89,13 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
{menuItems.map((item) => ( {menuItems.map((item) => (
<button <button
key={item.id} key={item.id}
onClick={() => onNavigate?.(item.id)} onClick={() => {
onNavigate?.(item.id);
// Close sidebar on mobile after navigation
if (window.innerWidth < 768) {
setSidebarOpen(false);
}
}}
className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors ${ className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors ${
currentPage === item.id currentPage === item.id
? 'bg-re-green text-white font-medium' ? 'bg-re-green text-white font-medium'
@ -74,7 +121,7 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
</div> </div>
</div> </div>
</div> </div>
</div> </aside>
{/* Main Content Area */} {/* Main Content Area */}
<div className="flex-1 flex flex-col min-w-0"> <div className="flex-1 flex flex-col min-w-0">

View File

@ -305,7 +305,9 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const [messages, setMessages] = useState<Message[]>(INITIAL_MESSAGES); const [messages, setMessages] = useState<Message[]>(INITIAL_MESSAGES);
const [showSidebar, setShowSidebar] = useState(false); const [showSidebar, setShowSidebar] = useState(false);
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
// Get request info // Get request info
const requestInfo = useMemo(() => { const requestInfo = useMemo(() => {
@ -334,27 +336,117 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
}, [messages]); }, [messages]);
const handleSendMessage = () => { const handleSendMessage = () => {
if (message.trim()) { if (message.trim() || selectedFiles.length > 0) {
const attachments = selectedFiles.map(file => ({
name: file.name,
url: URL.createObjectURL(file),
type: file.type.split('/')[1] || 'file'
}));
const newMessage: Message = { const newMessage: Message = {
id: Date.now().toString(), id: Date.now().toString(),
user: { name: 'You', avatar: 'YO', role: 'Current User' }, user: { name: 'You', avatar: 'YO', role: 'Current User' },
content: message, content: message,
timestamp: new Date().toLocaleString(), timestamp: new Date().toLocaleString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
hour12: true
}),
mentions: extractMentions(message), mentions: extractMentions(message),
isHighPriority: message.includes('!important') || message.includes('urgent') isHighPriority: message.includes('!important') || message.includes('urgent'),
attachments: attachments.length > 0 ? attachments : undefined
}; };
setMessages(prev => [...prev, newMessage]); setMessages(prev => [...prev, newMessage]);
setMessage(''); setMessage('');
setSelectedFiles([]);
} }
}; };
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
const filesArray = Array.from(e.target.files);
setSelectedFiles(prev => [...prev, ...filesArray]);
}
};
const handleRemoveFile = (index: number) => {
setSelectedFiles(prev => prev.filter((_, i) => i !== index));
// Reset file input to allow reselecting the same file
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
const handleEmojiSelect = (emoji: string) => {
setMessage(prev => prev + emoji);
setShowEmojiPicker(false);
};
const handleAttachmentClick = () => {
fileInputRef.current?.click();
};
// Emoji picker data - Expanded collection
const emojiList = [
// Smileys & Emotions
'😊', '😂', '🤣', '😁', '😃', '😄', '😅', '😆', '😉', '😌',
'😍', '🥰', '😘', '😗', '😙', '😚', '🙂', '🤗', '🤩', '🤔',
'🤨', '😐', '😑', '😶', '🙄', '😏', '😒', '🙃', '😬', '🤐',
'😴', '😪', '😵', '🤯', '🤪', '😜', '😝', '😛', '🤤', '😋',
'😎', '🤓', '🧐', '😕', '😟', '🙁', '☹️', '😮', '😯', '😲',
'😳', '🥺', '😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱',
'😖', '😣', '😞', '😓', '😩', '😫', '🥱', '😤', '😡', '😠',
'🤬', '😈', '👿', '💀', '☠️', '💩', '🤡', '👹', '👺', '👻',
// Gestures & Body
'👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤌', '🤏', '✌️', '🤞',
'🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍',
'👎', '✊', '👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝',
'🙏', '💪', '🦾', '🦿', '🦵', '🦶', '👂', '🦻', '👃', '🧠',
// Hearts & Love
'❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔',
'❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '❤️‍🔥',
// Work & Office
'💼', '📊', '📈', '📉', '💻', '⌨️', '🖥️', '🖨️', '🖱️', '💾',
'💿', '📱', '☎️', '📞', '📟', '📠', '📧', '✉️', '📨', '📩',
'📮', '📪', '📫', '📬', '📭', '📄', '📃', '📑', '📝', '✏️',
'✒️', '🖊️', '🖋️', '📏', '📐', '📌', '📍', '🗂️', '📁', '📂',
// Success & Achievement
'✅', '✔️', '☑️', '🎯', '🎖️', '🏆', '🥇', '🥈', '🥉', '⭐',
'🌟', '✨', '💫', '🔥', '💥', '⚡', '💯', '🎉', '🎊', '🎈',
// Alerts & Symbols
'⚠️', '🚫', '❌', '⛔', '🚷', '🚯', '🚱', '🚳', '🔞', '📵',
'❗', '❓', '❕', '❔', '‼️', '⁉️', '💢', '💬', '💭', '🗯️',
// Time & Calendar
'⏰', '⏱️', '⏲️', '⏳', '⌛', '📅', '📆', '🗓️', '📇', '🕐',
'🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚',
// Actions & Arrows
'🚀', '🎯', '🎲', '🎰', '🧩', '🔍', '🔎', '🔑', '🗝️', '🔒',
'🔓', '🔐', '🔏', '🔔', '🔕', '📣', '📢', '💡', '🔦', '🏮',
'', '', '✖️', '➗', '♾️', '‼️', '⁉️', '❓', '❔', '❕',
'🔄', '🔃', '🔂', '▶️', '⏸️', '⏯️', '⏹️', '⏺️', '⏭️', '⏮️',
'⏩', '⏪', '⏫', '⏬', '◀️', '🔼', '🔽', '➡️', '⬅️', '⬆️',
'⬇️', '↗️', '↘️', '↙️', '↖️', '↕️', '↔️', '↪️', '↩️', '⤴️'
];
const extractMentions = (text: string): string[] => { const extractMentions = (text: string): string[] => {
const mentionRegex = /@([\w\s]+)(?=\s|$|[.,!?])/g; const mentionRegex = /@([\w\s]+)(?=\s|$|[.,!?])/g;
const mentions = []; const mentions: string[] = [];
let match; let match;
while ((match = mentionRegex.exec(text)) !== null) { while ((match = mentionRegex.exec(text)) !== null) {
if (match[1]) {
mentions.push(match[1].trim()); mentions.push(match[1].trim());
} }
}
return mentions; return mentions;
}; };
@ -392,8 +484,8 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
return ( return (
<div className="h-screen max-h-screen flex flex-col bg-gray-50 overflow-hidden"> <div className="h-screen max-h-screen flex flex-col bg-gray-50 overflow-hidden">
{/* Header */} {/* Header - Fixed at top */}
<div className="bg-white border-b border-gray-200 px-3 sm:px-6 py-4"> <div className="bg-white border-b border-gray-200 px-3 sm:px-6 py-4 flex-shrink-0">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2 sm:gap-4 min-w-0 flex-1"> <div className="flex items-center gap-2 sm:gap-4 min-w-0 flex-1">
<Button variant="ghost" size="icon" onClick={onBack} className="shrink-0"> <Button variant="ghost" size="icon" onClick={onBack} className="shrink-0">
@ -456,9 +548,9 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
<div className="flex-1 flex overflow-hidden relative"> <div className="flex-1 flex overflow-hidden relative">
{/* Main Chat Area */} {/* Main Chat Area */}
<div className="flex-1 flex flex-col min-w-0"> <div className="flex-1 flex flex-col min-w-0">
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1 flex flex-col"> <Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1 flex flex-col overflow-hidden">
{/* Tab Navigation */} {/* Tab Navigation - Fixed */}
<div className="bg-white border-b border-gray-200 px-2 sm:px-3 lg:px-6"> <div className="bg-white border-b border-gray-200 px-2 sm:px-3 lg:px-6 flex-shrink-0">
<TabsList className="grid w-full max-w-full sm:max-w-md grid-cols-3 bg-gray-100 h-10"> <TabsList className="grid w-full max-w-full sm:max-w-md grid-cols-3 bg-gray-100 h-10">
<TabsTrigger value="chat" className="flex items-center gap-1 sm:gap-2 text-xs sm:text-sm px-2"> <TabsTrigger value="chat" className="flex items-center gap-1 sm:gap-2 text-xs sm:text-sm px-2">
<MessageSquare className="w-3 h-3 sm:w-4 sm:h-4" /> <MessageSquare className="w-3 h-3 sm:w-4 sm:h-4" />
@ -478,9 +570,9 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
</div> </div>
{/* Chat Tab */} {/* Chat Tab */}
<TabsContent value="chat" className="flex-1 flex flex-col m-0"> <TabsContent value="chat" className="flex-1 flex flex-col m-0 overflow-hidden min-h-0">
{/* Search Bar */} {/* Search Bar - Fixed */}
<div className="bg-white border-b border-gray-200 px-2 sm:px-3 lg:px-6 py-2 sm:py-3"> <div className="bg-white border-b border-gray-200 px-2 sm:px-3 lg:px-6 py-2 sm:py-3 flex-shrink-0">
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" /> <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<Input <Input
@ -492,8 +584,8 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
</div> </div>
</div> </div>
{/* Messages Area */} {/* Messages Area - Fixed height with proper scrolling */}
<div className="flex-1 overflow-y-auto px-2 sm:px-3 lg:px-6 py-2 sm:py-4"> <div className="flex-1 overflow-y-auto overflow-x-hidden px-2 sm:px-3 lg:px-6 py-2 sm:py-4 min-h-0">
<div className="space-y-3 sm:space-y-6 max-w-full"> <div className="space-y-3 sm:space-y-6 max-w-full">
{filteredMessages.map((msg) => ( {filteredMessages.map((msg) => (
<div key={msg.id} className={`flex gap-2 sm:gap-3 lg:gap-4 ${msg.isSystem ? 'justify-center' : ''}`}> <div key={msg.id} className={`flex gap-2 sm:gap-3 lg:gap-4 ${msg.isSystem ? 'justify-center' : ''}`}>
@ -617,11 +709,42 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
</div> </div>
</div> </div>
{/* Message Input */} {/* Message Input - Fixed at bottom */}
<div className="bg-white border-t border-gray-200 p-2 sm:p-3 lg:p-6"> <div className="bg-white border-t border-gray-200 p-2 sm:p-3 lg:p-6 flex-shrink-0">
<div className="max-w-full"> <div className="max-w-full">
<div className="flex flex-col gap-2 sm:gap-4"> {/* Hidden File Input */}
<div className="flex-1"> <input
type="file"
ref={fileInputRef}
onChange={handleFileSelect}
className="hidden"
multiple
accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt"
/>
{/* Selected Files Preview - Scrollable if many files */}
{selectedFiles.length > 0 && (
<div className="mb-3 space-y-2 max-h-32 overflow-y-auto pr-2">
{selectedFiles.map((file, index) => (
<div key={index} className="flex items-center gap-2 p-2 bg-blue-50 rounded-lg border border-blue-200">
<span className="text-lg flex-shrink-0">{getFileIcon(file.type.split('/')[1] || 'file')}</span>
<span className="text-sm text-gray-700 flex-1 truncate min-w-0">{file.name}</span>
<span className="text-xs text-gray-500 flex-shrink-0">{(file.size / 1024).toFixed(1)} KB</span>
<Button
variant="ghost"
size="sm"
onClick={() => handleRemoveFile(index)}
className="h-6 w-6 p-0 hover:bg-red-100 flex-shrink-0"
>
<X className="h-3 w-3 text-red-600" />
</Button>
</div>
))}
</div>
)}
{/* Textarea with Emoji Picker */}
<div className="relative mb-2">
<Textarea <Textarea
placeholder="Type your message... Use @username to mention someone" placeholder="Type your message... Use @username to mention someone"
value={message} value={message}
@ -630,44 +753,101 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
className="min-h-[50px] sm:min-h-[60px] resize-none border-gray-200 focus:ring-blue-500 focus:border-blue-500 w-full text-sm" className="min-h-[50px] sm:min-h-[60px] resize-none border-gray-200 focus:ring-blue-500 focus:border-blue-500 w-full text-sm"
rows={2} rows={2}
/> />
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mt-2 gap-2">
<div className="flex items-center gap-1 sm:gap-2 order-2 sm:order-1"> {/* Emoji Picker Popup */}
<Button variant="ghost" size="sm" className="text-gray-500 h-7 w-7 sm:h-8 sm:w-8 p-0"> {showEmojiPicker && (
<Paperclip className="h-3 w-3 sm:h-4 sm:w-4" /> <div className="absolute bottom-full left-0 mb-2 bg-white border border-gray-200 rounded-lg shadow-xl p-3 z-50 w-full sm:w-96 max-h-80 overflow-y-auto">
<div className="flex items-center justify-between mb-3 sticky top-0 bg-white pb-2 border-b">
<span className="text-sm font-semibold text-gray-700">Pick an emoji</span>
<Button
variant="ghost"
size="sm"
onClick={() => setShowEmojiPicker(false)}
className="h-6 w-6 p-0"
>
<X className="h-3 w-3" />
</Button> </Button>
<Button variant="ghost" size="sm" className="text-gray-500 h-7 w-7 sm:h-8 sm:w-8 p-0"> </div>
<Smile className="h-3 w-3 sm:h-4 sm:w-4" /> <div className="grid grid-cols-8 sm:grid-cols-10 gap-1">
{emojiList.map((emoji, index) => (
<button
key={index}
onClick={() => handleEmojiSelect(emoji)}
className="text-xl sm:text-2xl hover:bg-gray-100 rounded p-1 transition-colors flex items-center justify-center"
title={emoji}
>
{emoji}
</button>
))}
</div>
</div>
)}
</div>
{/* Action Buttons Row - Always visible */}
<div className="flex items-center justify-between gap-2 flex-shrink-0">
{/* Left side - Action buttons */}
<div className="flex items-center gap-1 sm:gap-2 flex-shrink-0">
<Button
variant="ghost"
size="sm"
className="text-gray-500 h-8 w-8 p-0 hover:bg-blue-50 hover:text-blue-600 flex-shrink-0"
onClick={handleAttachmentClick}
title="Attach file"
>
<Paperclip className="h-4 w-4" />
</Button> </Button>
<Button variant="ghost" size="sm" className="text-gray-500 h-7 w-7 sm:h-8 sm:w-8 p-0 hidden sm:flex"> <Button
variant="ghost"
size="sm"
className="text-gray-500 h-8 w-8 p-0 hover:bg-blue-50 hover:text-blue-600 flex-shrink-0"
onClick={() => setShowEmojiPicker(!showEmojiPicker)}
title="Add emoji"
>
<Smile className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
className="text-gray-500 h-8 w-8 p-0 hidden sm:flex hover:bg-blue-50 hover:text-blue-600 flex-shrink-0"
onClick={() => setMessage(prev => prev + '@')}
title="Mention someone"
>
<AtSign className="h-4 w-4" /> <AtSign className="h-4 w-4" />
</Button> </Button>
<Button variant="ghost" size="sm" className="text-gray-500 h-7 w-7 sm:h-8 sm:w-8 p-0 hidden sm:flex"> <Button
variant="ghost"
size="sm"
className="text-gray-500 h-8 w-8 p-0 hidden sm:flex hover:bg-blue-50 hover:text-blue-600 flex-shrink-0"
onClick={() => setMessage(prev => prev + '#')}
title="Add hashtag"
>
<Hash className="h-4 w-4" /> <Hash className="h-4 w-4" />
</Button> </Button>
</div> </div>
<div className="flex items-center gap-2 order-1 sm:order-2">
<span className="text-xs text-gray-500 hidden sm:inline"> {/* Right side - Character count and Send button */}
<div className="flex items-center gap-2 ml-auto flex-shrink-0">
<span className="text-xs text-gray-500 hidden md:inline whitespace-nowrap">
{message.length}/2000 {message.length}/2000
</span> </span>
<Button <Button
onClick={handleSendMessage} onClick={handleSendMessage}
disabled={!message.trim()} disabled={!message.trim() && selectedFiles.length === 0}
className="bg-blue-600 hover:bg-blue-700 min-w-0 h-8 sm:h-9" className="bg-blue-600 hover:bg-blue-700 h-8 sm:h-9 px-3 sm:px-4 disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0"
size="sm" size="sm"
> >
<Send className="h-3 w-3 sm:h-4 sm:w-4 sm:mr-2" /> <Send className="h-4 w-4 sm:mr-2" />
<span className="hidden sm:inline ml-1">Send</span> <span className="hidden sm:inline">Send</span>
</Button> </Button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</TabsContent> </TabsContent>
{/* Files Tab */} {/* Files Tab */}
<TabsContent value="files" className="flex-1 p-2 sm:p-3 lg:p-6 m-0"> <TabsContent value="files" className="flex-1 p-2 sm:p-3 lg:p-6 m-0 pt-0">
<div className="max-w-full"> <div className="max-w-full">
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 sm:mb-6 gap-3"> <div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 sm:mb-6 gap-3">
<h3 className="text-base sm:text-lg font-semibold text-gray-900">Shared Files</h3> <h3 className="text-base sm:text-lg font-semibold text-gray-900">Shared Files</h3>
@ -714,7 +894,7 @@ export function WorkNoteChat({ requestId, onBack }: WorkNoteChatProps) {
</TabsContent> </TabsContent>
{/* Activity Tab */} {/* Activity Tab */}
<TabsContent value="activity" className="flex-1 p-2 sm:p-3 lg:p-6 m-0"> <TabsContent value="activity" className="flex-1 p-2 sm:p-3 lg:p-6 m-0 pt-0">
<div className="max-w-full"> <div className="max-w-full">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 sm:mb-6">Recent Activity</h3> <h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-4 sm:mb-6">Recent Activity</h3>
<div className="space-y-3 sm:space-y-4"> <div className="space-y-3 sm:space-y-4">

View File

@ -604,6 +604,30 @@
[data-slot="dialog-content"] { [data-slot="dialog-content"] {
background-color: rgb(255 255 255) !important; background-color: rgb(255 255 255) !important;
} }
/* Custom scrollbar for better UX */
.overflow-y-auto::-webkit-scrollbar {
width: 6px;
}
.overflow-y-auto::-webkit-scrollbar-track {
background: transparent;
}
.overflow-y-auto::-webkit-scrollbar-thumb {
background: rgb(203 213 225);
border-radius: 3px;
}
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
background: rgb(148 163 184);
}
/* Firefox scrollbar */
.overflow-y-auto {
scrollbar-width: thin;
scrollbar-color: rgb(203 213 225) transparent;
}
} }
html { html {