document types

This commit is contained in:
2025-10-31 00:13:16 +01:00
parent 3941ec61d3
commit 813ce24aeb
19 changed files with 1714 additions and 43 deletions
+85
View File
@@ -151,10 +151,15 @@ const Sidebar = ({
correspondents = [],
activeCorrespondentIds = [],
onToggleCorrespondentFilter,
documentTypes = [],
activeDocumentTypeIds = [],
onToggleDocumentTypeFilter,
onManageTags,
onManageCorrespondents,
onManageDocumentTypes,
onCreateTag,
onCreateCorrespondent,
onCreateDocumentType,
searchQuery = '',
onSearchChange,
onSearchSubmit,
@@ -180,10 +185,22 @@ const Sidebar = ({
() => new Set(activeCorrespondentIds || []),
[activeCorrespondentIds],
);
const sortedDocumentTypes = useMemo(
() =>
[...documentTypes].sort((a, b) =>
(a?.name || '').localeCompare(b?.name || '', undefined, { sensitivity: 'base' }),
),
[documentTypes],
);
const activeDocumentTypeSet = useMemo(
() => new Set(activeDocumentTypeIds || []),
[activeDocumentTypeIds],
);
const handleToggleTag = onToggleTagFilter || (() => {});
const activeTagSet = new Set(activeTagIds);
const handleManageTags = onManageTags || (() => {});
const handleManageCorrespondents = onManageCorrespondents || (() => {});
const handleManageDocumentTypes = onManageDocumentTypes || (() => {});
const handleCreateTag = useCallback(async () => {
const input = window.prompt('New tag name');
if (!input) {
@@ -216,6 +233,22 @@ const Sidebar = ({
}
}, [onCreateCorrespondent]);
const handleCreateDocumentType = useCallback(async () => {
const input = window.prompt('New document type name');
if (!input) {
return;
}
const trimmed = input.trim();
if (!trimmed) {
return;
}
try {
await onCreateDocumentType?.(trimmed);
} catch (error) {
console.error('[sidebar] failed to create document type', error);
}
}, [onCreateDocumentType]);
const handleCreateFolder = useCallback(() => {
if (creatingFolder) {
return;
@@ -592,6 +625,58 @@ const Sidebar = ({
})}
</ul>
</div>
<div className="sidebar-section">
<div className="sidebar-section__header">
<h3>Document Types</h3>
<div className="sidebar-section__actions">
<button
type="button"
className="icon-button"
onClick={handleCreateDocumentType}
aria-label="Create document type"
>
<PlusIcon size={16} />
</button>
<button
type="button"
className="icon-button"
onClick={handleManageDocumentTypes}
aria-label="Manage document types"
>
<SettingsIcon size={16} />
</button>
<span className="meta">{documentTypes.length}</span>
</div>
</div>
<ul className="sidebar-correspondent-list">
{sortedDocumentTypes.map((entry) => {
const isActive = activeDocumentTypeSet.has(entry.id);
const className = `sidebar-correspondent-item${isActive ? ' active' : ''}`;
const label = entry.name || 'Untitled';
const handleSelect = () => {
const nextId = isActive ? null : entry.id;
onToggleDocumentTypeFilter?.(nextId);
};
return (
<li key={entry.id}>
<span
className={className}
role="button"
onClick={handleSelect}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
handleSelect();
}
}}
>
{label}
</span>
</li>
);
})}
</ul>
</div>
{typeof neutralHue === 'number' || typeof neutralHue === 'string' ? (
<div className="sidebar-section">
<div className="sidebar-section__header">