This commit is contained in:
2025-10-29 22:46:44 +01:00
parent 4a116e013c
commit 22f4d42c19
8 changed files with 116 additions and 35 deletions
+1 -1
View File
@@ -2037,7 +2037,7 @@ export const createDesktopSurface = ({ workspaceProps, renderSidebarToggle }) =>
<> <>
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={onRefresh} onClick={onRefresh}
aria-label="Refresh" aria-label="Refresh"
title="Refresh" title="Refresh"
+6 -6
View File
@@ -1002,7 +1002,7 @@ const DetailPanel = ({
<h3 style={{ margin: 0 }}>{displayName}</h3> <h3 style={{ margin: 0 }}>{displayName}</h3>
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={startTitleEdit} onClick={startTitleEdit}
aria-label="Edit title" aria-label="Edit title"
title="Edit title" title="Edit title"
@@ -1236,7 +1236,7 @@ const DetailPanel = ({
<div className="panel-actions"> <div className="panel-actions">
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={onClose} onClick={onClose}
aria-label="Close detail panel" aria-label="Close detail panel"
title="Close detail panel" title="Close detail panel"
@@ -1246,7 +1246,7 @@ const DetailPanel = ({
{singleDoc ? ( {singleDoc ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
onOpenPreview(singleDoc.id); onOpenPreview(singleDoc.id);
@@ -1262,7 +1262,7 @@ const DetailPanel = ({
{isBulkSelection && onBulkReanalyze ? ( {isBulkSelection && onBulkReanalyze ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
onBulkReanalyze(bulkDocumentIds); onBulkReanalyze(bulkDocumentIds);
@@ -1289,7 +1289,7 @@ const DetailPanel = ({
{showOcrAction ? ( {showOcrAction ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
openOcr(); openOcr();
@@ -1303,7 +1303,7 @@ const DetailPanel = ({
{singleDoc ? ( {singleDoc ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
onRegenerateThumbnails(singleDoc.id); onRegenerateThumbnails(singleDoc.id);
+5 -5
View File
@@ -820,7 +820,7 @@ const DocumentsTable = ({
{folder.id !== 'root' && onFolderRename && ( {folder.id !== 'root' && onFolderRename && (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
title="Rename" title="Rename"
aria-label={`Rename folder ${folder.name}`} aria-label={`Rename folder ${folder.name}`}
onClick={(event) => { onClick={(event) => {
@@ -977,7 +977,7 @@ const DocumentsTable = ({
{onDocumentRename && ( {onDocumentRename && (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
title="Rename" title="Rename"
aria-label={`Rename document ${doc.title || doc.original_name}`} aria-label={`Rename document ${doc.title || doc.original_name}`}
onClick={(event) => { onClick={(event) => {
@@ -1090,7 +1090,7 @@ export const createDocumentsTableHeaderActions = ({
</span> </span>
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={onRequestCreateFolder} onClick={onRequestCreateFolder}
disabled={creatingFolder} disabled={creatingFolder}
aria-label={creatingFolder ? 'Creating folder…' : 'Create folder'} aria-label={creatingFolder ? 'Creating folder…' : 'Create folder'}
@@ -1100,7 +1100,7 @@ export const createDocumentsTableHeaderActions = ({
</button> </button>
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={onRefresh} onClick={onRefresh}
aria-label="Refresh" aria-label="Refresh"
title="Refresh" title="Refresh"
@@ -1152,7 +1152,7 @@ export const createDocumentsSurface = ({
? ( ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={onNavigateParent} onClick={onNavigateParent}
aria-label="Go to parent folder" aria-label="Go to parent folder"
title="Go to parent folder" title="Go to parent folder"
+6 -1
View File
@@ -5148,9 +5148,11 @@ const AppLayout = () => {
tags, tags,
activeTagIds: activeTagFilters, activeTagIds: activeTagFilters,
onToggleTagFilter: toggleTagFilter, onToggleTagFilter: toggleTagFilter,
onCreateTag: (label) => handleTagCreate({ label }),
correspondents, correspondents,
activeCorrespondentIds: activeCorrespondentFilters, activeCorrespondentIds: activeCorrespondentFilters,
onToggleCorrespondentFilter: toggleCorrespondentFilter, onToggleCorrespondentFilter: toggleCorrespondentFilter,
onCreateCorrespondent: (name) => handleCorrespondentCreate({ name }),
appStatus, appStatus,
loading, loading,
previewActive, previewActive,
@@ -5197,6 +5199,8 @@ const AppLayout = () => {
tenantName, tenantName,
toggleCorrespondentFilter, toggleCorrespondentFilter,
toggleTagFilter, toggleTagFilter,
handleTagCreate,
handleCorrespondentCreate,
], ],
); );
@@ -5333,6 +5337,7 @@ const AppLayout = () => {
skeuoWorkspaceProps, skeuoWorkspaceProps,
ensurePreviewData, ensurePreviewData,
ensureAssetUrl, ensureAssetUrl,
resolveApiPath,
getDocumentAsset, getDocumentAsset,
notifyApiError, notifyApiError,
openTagsModal, openTagsModal,
@@ -5606,7 +5611,7 @@ const DocumentsRoute = () => {
return ( return (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={expandSidebar} onClick={expandSidebar}
aria-label="Expand sidebar" aria-label="Expand sidebar"
title="Expand sidebar" title="Expand sidebar"
+3 -3
View File
@@ -137,7 +137,7 @@ export const createPreviewWorkspaceHeaderActions = ({
{hasOcr ? ( {hasOcr ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={handleOcrClick} onClick={handleOcrClick}
aria-label="View OCR text" aria-label="View OCR text"
title="View OCR text" title="View OCR text"
@@ -147,7 +147,7 @@ export const createPreviewWorkspaceHeaderActions = ({
) : null} ) : null}
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={() => onRegenerate(document.id)} onClick={() => onRegenerate(document.id)}
aria-label="Re-run analysis" aria-label="Re-run analysis"
title="Re-run analysis" title="Re-run analysis"
@@ -179,7 +179,7 @@ export const createPreviewSurface = ({
? ( ? (
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={() => onClose?.()} onClick={() => onClose?.()}
aria-label="Close preview" aria-label="Close preview"
title="Close preview" title="Close preview"
+74 -16
View File
@@ -9,6 +9,7 @@ import {
ChevronDownIcon, ChevronDownIcon,
SettingsIcon, SettingsIcon,
CheckIcon, CheckIcon,
PlusIcon,
} from '../ui/icons'; } from '../ui/icons';
import { getTagColorStyle } from '../utils/colors'; import { getTagColorStyle } from '../utils/colors';
@@ -82,7 +83,7 @@ const FolderNode = ({
<div className="folder-row__actions"> <div className="folder-row__actions">
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
if (!onRename) return; if (!onRename) return;
@@ -103,7 +104,7 @@ const FolderNode = ({
</button> </button>
<button <button
type="button" type="button"
className="icon-button ghost" className="icon-button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
onDelete(node.id); onDelete(node.id);
@@ -146,6 +147,8 @@ const Sidebar = ({
onToggleCorrespondentFilter, onToggleCorrespondentFilter,
onManageTags, onManageTags,
onManageCorrespondents, onManageCorrespondents,
onCreateTag,
onCreateCorrespondent,
searchQuery = '', searchQuery = '',
onSearchChange, onSearchChange,
onSearchSubmit, onSearchSubmit,
@@ -175,6 +178,37 @@ const Sidebar = ({
const activeTagSet = new Set(activeTagIds); const activeTagSet = new Set(activeTagIds);
const handleManageTags = onManageTags || (() => {}); const handleManageTags = onManageTags || (() => {});
const handleManageCorrespondents = onManageCorrespondents || (() => {}); const handleManageCorrespondents = onManageCorrespondents || (() => {});
const handleCreateTag = useCallback(async () => {
const input = window.prompt('New tag name');
if (!input) {
return;
}
const trimmed = input.trim();
if (!trimmed) {
return;
}
try {
await onCreateTag?.(trimmed);
} catch (error) {
console.error('[sidebar] failed to create tag', error);
}
}, [onCreateTag]);
const handleCreateCorrespondent = useCallback(async () => {
const input = window.prompt('New correspondent name');
if (!input) {
return;
}
const trimmed = input.trim();
if (!trimmed) {
return;
}
try {
await onCreateCorrespondent?.(trimmed);
} catch (error) {
console.error('[sidebar] failed to create correspondent', error);
}
}, [onCreateCorrespondent]);
const handleSearchInputChange = useCallback( const handleSearchInputChange = useCallback(
(event) => { (event) => {
onSearchChange?.(event.target.value); onSearchChange?.(event.target.value);
@@ -408,14 +442,26 @@ const Sidebar = ({
</div> </div>
<div className="sidebar-section"> <div className="sidebar-section">
<div className="sidebar-section__header"> <div className="sidebar-section__header">
<button <h3>Tags</h3>
type="button" <div className="sidebar-section__actions">
className="sidebar-section__title" <button
onClick={handleManageTags} type="button"
> className="icon-button"
<h3>Tags</h3> onClick={handleCreateTag}
aria-label="Create tag"
>
<PlusIcon size={16} />
</button>
<button
type="button"
className="icon-button"
onClick={handleManageTags}
aria-label="Manage tags"
>
<SettingsIcon size={16} />
</button>
<span className="meta">{tags.length}</span> <span className="meta">{tags.length}</span>
</button> </div>
</div> </div>
<div <div
className={`sidebar-tag-cloud${ className={`sidebar-tag-cloud${
@@ -460,14 +506,26 @@ const Sidebar = ({
</div> </div>
<div className="sidebar-section"> <div className="sidebar-section">
<div className="sidebar-section__header"> <div className="sidebar-section__header">
<button <h3>Correspondents</h3>
type="button" <div className="sidebar-section__actions">
className="sidebar-section__title" <button
onClick={handleManageCorrespondents} type="button"
> className="icon-button"
<h3>Correspondents</h3> onClick={handleCreateCorrespondent}
aria-label="Create correspondent"
>
<PlusIcon size={16} />
</button>
<button
type="button"
className="icon-button"
onClick={handleManageCorrespondents}
aria-label="Manage correspondents"
>
<SettingsIcon size={16} />
</button>
<span className="meta">{correspondents.length}</span> <span className="meta">{correspondents.length}</span>
</button> </div>
</div> </div>
<ul className="sidebar-correspondent-list"> <ul className="sidebar-correspondent-list">
{sortedCorrespondents.map((correspondent) => { {sortedCorrespondents.map((correspondent) => {
+11 -3
View File
@@ -1406,6 +1406,17 @@ button.danger:hover:not([disabled]) {
font-weight: 600; font-weight: 600;
} }
.sidebar-section__actions {
display: inline-flex;
align-items: center;
gap: 0.35rem;
}
.sidebar-section__actions .meta {
font-size: 0.75rem;
color: var(--muted);
}
.sidebar-item { .sidebar-item {
background: transparent; background: transparent;
padding: 0.16rem 0.26rem; padding: 0.16rem 0.26rem;
@@ -1511,7 +1522,6 @@ button.danger:hover:not([disabled]) {
.sidebar-correspondent-item:hover { .sidebar-correspondent-item:hover {
background: var(--sidebar-hover-bg); background: var(--sidebar-hover-bg);
box-shadow: 0 1px 3px var(--shadow-soft);
color: var(--fg); color: var(--fg);
} }
@@ -1522,7 +1532,6 @@ button.danger:hover:not([disabled]) {
.sidebar-correspondent-item.active { .sidebar-correspondent-item.active {
background: var(--sidebar-active-bg); background: var(--sidebar-active-bg);
box-shadow: 0 0 0 1px var(--sidebar-active-pill-border);
color: var(--fg); color: var(--fg);
} }
@@ -1917,7 +1926,6 @@ button.danger:hover:not([disabled]) {
text-decoration: underline; text-decoration: underline;
text-decoration-thickness: 1.5px; text-decoration-thickness: 1.5px;
background-color: transparent; background-color: transparent;
box-shadow: none;
} }
.doc-correspondent-link:not(.is-static):focus-visible { .doc-correspondent-link:not(.is-static):focus-visible {
+10
View File
@@ -23,6 +23,7 @@ import {
IconX, IconX,
IconSettings, IconSettings,
IconCheck, IconCheck,
IconPlus,
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import FolderSvg from '../assets/folder.svg'; import FolderSvg from '../assets/folder.svg';
@@ -206,6 +207,15 @@ export const SettingsIcon = ({ className, size = '1em', stroke = 1.6, ...rest })
/> />
); );
export const PlusIcon = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconPlus
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const CheckIcon = ({ className, size = '1em', stroke = 1.6, ...rest }) => ( export const CheckIcon = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconCheck <IconCheck
className={composeClassName('icon', className)} className={composeClassName('icon', className)}