diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index 4c25005..67b49ec 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -501,11 +501,11 @@ export function SettingsModal({ className = '' }: { className?: string }) { onClick={() => { void requestOpenSettings(); }} - className={`inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase hover:text-accent transition-transform transition-colors duration-200 ease-out hover:scale-[1.08] ${className}`} + className={`inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase hover:text-accent transition-transform transition-colors duration-200 ease-out hover:scale-[1.01] ${className}`} aria-label="Settings" tabIndex={0} > - + @@ -1447,7 +1447,7 @@ function SettingsChangelogPanel({
{enableUserSignups && ( - @@ -49,7 +49,7 @@ export function UserMenu({ className = '' }: { className?: string }) {
)} - {fallbackViewMode === 'icons' && ( - - setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) - } - onDropOnFolder={handleDropOnFolder} - onMergeIntoFolder={handleMergeIntoFolder} - /> - )} - {fallbackViewMode === 'list' && ( - { - setSortBy(b); - setSortDirection(d); - }} - collapsedFolders={collapsedFolders} - onToggleCollapse={toggleFolderCollapse} - onDeleteFolder={handleDeleteFolder} - onDeleteDoc={(doc) => - setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) - } - onDropOnFolder={handleDropOnFolder} - onMergeIntoFolder={handleMergeIntoFolder} - /> - )} - {fallbackViewMode === 'columns' && ( - - setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) - } - onDropOnFolder={handleDropOnFolder} - onMergeIntoFolder={handleMergeIntoFolder} - /> - )} - {fallbackViewMode === 'gallery' && ( - - setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) - } - onDropOnFolder={handleDropOnFolder} - onMergeIntoFolder={handleMergeIntoFolder} - /> - )} + + {fallbackViewMode === 'icons' && ( + + setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) + } + onDropOnFolder={handleDropOnFolder} + onMergeIntoFolder={handleMergeIntoFolder} + /> + )} + {fallbackViewMode === 'list' && ( + { + setSortBy(b); + setSortDirection(d); + }} + collapsedFolders={collapsedFolders} + onToggleCollapse={toggleFolderCollapse} + onDeleteFolder={handleDeleteFolder} + onDeleteDoc={(doc) => + setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) + } + onDropOnFolder={handleDropOnFolder} + onMergeIntoFolder={handleMergeIntoFolder} + /> + )} + {fallbackViewMode === 'columns' && ( + + setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) + } + onDropOnFolder={handleDropOnFolder} + onMergeIntoFolder={handleMergeIntoFolder} + /> + )} + {fallbackViewMode === 'gallery' && ( + + setDocumentToDelete({ id: doc.id, name: doc.name, type: doc.type }) + } + onDropOnFolder={handleDropOnFolder} + onMergeIntoFolder={handleMergeIntoFolder} + /> + )} + )} -
- {isGenerating ? '…' : typeLabel} +
+ {isGenerating + ? '…' + : `${typeLabel} • ${ + doc.size >= 1024 * 1024 * 1024 + ? `${(doc.size / 1024 / 1024 / 1024).toFixed(2)} GB` + : doc.size >= 1024 * 1024 + ? `${(doc.size / 1024 / 1024).toFixed(2)} MB` + : `${(doc.size / 1024).toFixed(1)} KB` + }`}
); diff --git a/src/components/doclist/views/ColumnsView.tsx b/src/components/doclist/views/ColumnsView.tsx index 0af734b..0142433 100644 --- a/src/components/doclist/views/ColumnsView.tsx +++ b/src/components/doclist/views/ColumnsView.tsx @@ -216,7 +216,12 @@ export function ColumnsView({ {selected.doc.name}

- {selected.doc.type.toUpperCase()} • {(selected.doc.size / 1024 / 1024).toFixed(2)} MB + {selected.doc.type.toUpperCase()} •{' '} + {selected.doc.size >= 1024 * 1024 * 1024 + ? `${(selected.doc.size / 1024 / 1024 / 1024).toFixed(2)} GB` + : selected.doc.size >= 1024 * 1024 + ? `${(selected.doc.size / 1024 / 1024).toFixed(2)} MB` + : `${(selected.doc.size / 1024).toFixed(1)} KB`}

= { sm: 'text-[10px]', - md: 'text-[12px]', - lg: 'text-[13px]', - xl: 'text-[14px]', + md: 'text-[11px]', + lg: 'text-[12px]', + xl: 'text-[13px]', + }; + + const bottomPaddingClasses: Record = { + sm: 'px-[7px] py-[4px]', + md: 'px-[8px] py-[5px]', + lg: 'px-[9px] py-[5px]', + xl: 'px-[10px] py-[6px]', + }; + + const linkPaddingClasses: Record = { + sm: 'px-[2px] py-[2px]', + md: 'px-[2px] py-[2px]', + lg: 'px-[2px] py-[2px]', + xl: 'px-[2px] py-[2px]', + }; + + const gapClasses: Record = { + sm: 'gap-1', + md: 'gap-1.5', + lg: 'gap-2', + xl: 'gap-2', + }; + + const fileIconClasses: Record = { + sm: 'w-3 h-3', + md: 'w-3.5 h-3.5', + lg: 'w-3.5 h-3.5', + xl: 'w-4 h-4', + }; + + const trashBtnClasses: Record = { + sm: 'ml-0.5 h-[18px] w-[18px] rounded-sm', + md: 'ml-0.5 h-[21px] w-[21px] rounded-sm', + lg: 'ml-1 h-[23px] w-[23px] rounded', + xl: 'ml-1.5 h-[25px] w-[25px] rounded', + }; + + const trashIconClasses: Record = { + sm: 'w-[10px] h-[10px]', + md: 'w-[11px] h-[11px]', + lg: 'w-[12px] h-[12px]', + xl: 'w-[13px] h-[13px]', }; return ( @@ -140,49 +181,40 @@ export function DocumentTile({ > -
+
- + {doc.type === 'pdf' ? ( - + ) : doc.type === 'epub' ? ( - + ) : ( - + )} - - - {doc.name} - - - {(doc.size / 1024 / 1024).toFixed(2)} MB - + + {doc.name} {showDeleteButton && (
diff --git a/src/components/doclist/views/ListView.tsx b/src/components/doclist/views/ListView.tsx index 1233184..e6bc86a 100644 --- a/src/components/doclist/views/ListView.tsx +++ b/src/components/doclist/views/ListView.tsx @@ -36,6 +36,9 @@ function formatDate(ms: number): string { function formatSize(bytes: number): string { const mb = bytes / 1024 / 1024; + if (mb >= 1024) { + return `${(mb / 1024).toFixed(2)} GB`; + } return mb >= 1 ? `${mb.toFixed(2)} MB` : `${(bytes / 1024).toFixed(1)} KB`; } diff --git a/src/components/doclist/window/FinderSidebar.tsx b/src/components/doclist/window/FinderSidebar.tsx index 5298520..7de467b 100644 --- a/src/components/doclist/window/FinderSidebar.tsx +++ b/src/components/doclist/window/FinderSidebar.tsx @@ -47,7 +47,7 @@ function SidebarRow({ type="button" onClick={onClick} className={ - 'group w-full flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border transform transition-all duration-200 ease-out text-left hover:scale-[1.02] ' + + 'group w-full flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border transform transition-all duration-200 ease-out text-left hover:scale-[1.01] ' + (active ? 'border-accent bg-offbase text-accent' : 'border-transparent text-foreground hover:border-accent hover:bg-offbase hover:text-accent') + diff --git a/src/components/doclist/window/FinderToolbar.tsx b/src/components/doclist/window/FinderToolbar.tsx index d929043..e40761f 100644 --- a/src/components/doclist/window/FinderToolbar.tsx +++ b/src/components/doclist/window/FinderToolbar.tsx @@ -58,10 +58,9 @@ const ICON_SIZES: Array<{ value: IconSize; label: string }> = [ // Match SettingsModal / UserMenu trigger sizing exactly so all bar buttons share one rhythm. const TOOLBAR_BTN = - 'inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-out hover:scale-[1.02]'; + 'inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-out hover:scale-[1.01]'; const TOOLBAR_BTN_INACTIVE = 'border-offbase text-foreground hover:text-accent hover:border-accent hover:bg-offbase'; -const TOOLBAR_BTN_ACTIVE = 'border-accent text-accent bg-offbase'; // Pill-grouped segmented control. Outer pill carries the border; inner segments are // borderless and rely on bg/text color to show active/hover. Sized so the whole pill diff --git a/src/components/documents/DocumentUploader.tsx b/src/components/documents/DocumentUploader.tsx index efe1afb..2ff1766 100644 --- a/src/components/documents/DocumentUploader.tsx +++ b/src/components/documents/DocumentUploader.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useCallback } from 'react'; +import { useState, useCallback, type ReactNode } from 'react'; import { useDropzone } from 'react-dropzone'; import { UploadIcon } from '@/components/icons/Icons'; import { useDocuments } from '@/contexts/DocumentContext'; @@ -10,10 +10,11 @@ import { useFeatureFlag } from '@/contexts/RuntimeConfigContext'; interface DocumentUploaderProps { className?: string; - variant?: 'default' | 'compact'; + variant?: 'default' | 'compact' | 'overlay'; + children?: ReactNode; } -export function DocumentUploader({ className = '', variant = 'default' }: DocumentUploaderProps) { +export function DocumentUploader({ className = '', variant = 'default', children }: DocumentUploaderProps) { const enableDocx = useFeatureFlag('enableDocxConversion'); const { addPDFDocument: addPDF, @@ -71,11 +72,13 @@ export function DocumentUploader({ className = '', variant = 'default' }: Docume } : {}) }, multiple: true, - disabled: isUploading || isConverting + disabled: isUploading || isConverting, + noClick: variant === 'overlay', + noKeyboard: variant === 'overlay' }); const containerBase = `group w-full rounded transform transition-all duration-200 ease-in-out ${ - variant === 'compact' ? 'hover:scale-[1.02]' : '' + variant === 'compact' ? 'hover:scale-[1.01]' : '' } ${ isUploading || isConverting ? 'cursor-not-allowed opacity-50' : 'cursor-pointer' } ${className}`; @@ -95,6 +98,32 @@ export function DocumentUploader({ className = '', variant = 'default' }: Docume const paddingClass = variant === 'compact' ? 'py-1 px-2 rounded-md' : 'py-5 px-3 rounded-lg'; + if (variant === 'overlay') { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { onClick, onKeyDown, ...rootProps } = getRootProps(); + return ( +
+ + {children} + {isDragActive && ( +
+
+ +

+ Drop files here to upload +

+

+ {enableDocx + ? 'Accepts PDF, EPUB, TXT, MD, or DOCX' + : 'Accepts PDF, EPUB, TXT, or MD'} +

+
+
+ )} +
+ ); + } + return (