frontend: separate views
This commit is contained in:
+33
-2
@@ -17,6 +17,7 @@ import {
|
||||
Outlet,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
useMatch,
|
||||
matchPath,
|
||||
} from 'react-router-dom';
|
||||
import './styles.css';
|
||||
@@ -397,6 +398,13 @@ const AppLayout = () => {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [activeTagFilters, setActiveTagFilters] = useState([]);
|
||||
const [activeCorrespondentFilters, setActiveCorrespondentFilters] = useState([]);
|
||||
const documentsRouteMatch = useMatch('/documents');
|
||||
const documentsFolderRouteMatch = useMatch('/documents/folder/:folderId');
|
||||
const tagsRouteMatch = useMatch('/tags');
|
||||
const correspondentsRouteMatch = useMatch('/correspondents');
|
||||
const isDocumentsRoute = Boolean(documentsRouteMatch || documentsFolderRouteMatch);
|
||||
const isTagsRoute = Boolean(tagsRouteMatch);
|
||||
const isCorrespondentsRoute = Boolean(correspondentsRouteMatch);
|
||||
const toggleTagFilter = useCallback((tagId) => {
|
||||
if (!tagId) return;
|
||||
setActiveTagFilters((previous) =>
|
||||
@@ -4239,11 +4247,9 @@ const AppLayout = () => {
|
||||
onFolderDragStart: handleFolderDragStart,
|
||||
onFolderDragEnd: handleFolderDragEnd,
|
||||
draggedFolderId,
|
||||
onShowTags: () => navigate('/tags'),
|
||||
tags,
|
||||
activeTagIds: activeTagFilters,
|
||||
onToggleTagFilter: toggleTagFilter,
|
||||
onShowCorrespondents: () => navigate('/correspondents'),
|
||||
correspondents,
|
||||
activeCorrespondentIds: activeCorrespondentFilters,
|
||||
onToggleCorrespondentFilter: toggleCorrespondentFilter,
|
||||
@@ -4489,6 +4495,31 @@ const AppLayout = () => {
|
||||
)}
|
||||
</div>
|
||||
<div className="app-bar__right">
|
||||
<div className="app-bar__links">
|
||||
<button
|
||||
type="button"
|
||||
className={`app-bar__link${isDocumentsRoute ? ' active' : ''}`}
|
||||
onClick={() => navigate('/documents')}
|
||||
>
|
||||
Documents
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`app-bar__link${isTagsRoute ? ' active' : ''}`}
|
||||
onClick={() => navigate('/tags')}
|
||||
>
|
||||
Tags
|
||||
<span className="app-bar__link-count">{tags.length}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`app-bar__link${isCorrespondentsRoute ? ' active' : ''}`}
|
||||
onClick={() => navigate('/correspondents')}
|
||||
>
|
||||
Correspondents
|
||||
<span className="app-bar__link-count">{correspondents.length}</span>
|
||||
</button>
|
||||
</div>
|
||||
{status && (
|
||||
<div className="app-bar__status">
|
||||
<StatusBanner status={status} />
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useMatch } from 'react-router-dom';
|
||||
import {
|
||||
ChevronIcon,
|
||||
FolderIcon,
|
||||
TagIcon,
|
||||
TrashIcon,
|
||||
CorrespondentIcon,
|
||||
EditIcon,
|
||||
} from '../ui/icons';
|
||||
import { ChevronIcon, FolderIcon, TrashIcon, EditIcon } from '../ui/icons';
|
||||
import { getTagColorStyle } from '../utils/colors';
|
||||
|
||||
const FolderNode = ({
|
||||
@@ -137,21 +129,13 @@ const Sidebar = ({
|
||||
onFolderDragStart,
|
||||
onFolderDragEnd,
|
||||
draggedFolderId,
|
||||
onShowTags,
|
||||
tags = [],
|
||||
activeTagIds = [],
|
||||
onToggleTagFilter,
|
||||
onShowCorrespondents,
|
||||
correspondents = [],
|
||||
activeCorrespondentIds = [],
|
||||
onToggleCorrespondentFilter,
|
||||
}) => {
|
||||
const handleShowTags = onShowTags || (() => {});
|
||||
const tagsRouteMatch = useMatch('/tags');
|
||||
const isTagsRoute = Boolean(tagsRouteMatch);
|
||||
const handleShowCorrespondents = onShowCorrespondents || (() => {});
|
||||
const correspondentsRouteMatch = useMatch('/correspondents');
|
||||
const isCorrespondentsRoute = Boolean(correspondentsRouteMatch);
|
||||
const sortedCorrespondents = useMemo(
|
||||
() =>
|
||||
[...correspondents].sort((a, b) =>
|
||||
@@ -224,21 +208,6 @@ const Sidebar = ({
|
||||
<h3>Tags</h3>
|
||||
<span className="meta">{tags.length}</span>
|
||||
</div>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`sidebar-item${isTagsRoute ? ' active' : ''}`}
|
||||
onClick={handleShowTags}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
handleShowTags();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TagIcon className="sidebar-item__icon" />
|
||||
<span>All tags</span>
|
||||
</span>
|
||||
<div className="sidebar-tag-cloud" role="list">
|
||||
{tags.length ? (
|
||||
tags.map((tag) => {
|
||||
@@ -269,25 +238,6 @@ const Sidebar = ({
|
||||
<h3>Correspondents</h3>
|
||||
<span className="meta">{correspondents.length}</span>
|
||||
</div>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={`sidebar-item${isCorrespondentsRoute ? ' active' : ''}`}
|
||||
onClick={() => {
|
||||
onToggleCorrespondentFilter?.(null);
|
||||
handleShowCorrespondents();
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
onToggleCorrespondentFilter?.(null);
|
||||
handleShowCorrespondents();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CorrespondentIcon className="sidebar-item__icon" />
|
||||
<span>All correspondents</span>
|
||||
</span>
|
||||
<ul className="sidebar-correspondent-list">
|
||||
{sortedCorrespondents.length ? (
|
||||
sortedCorrespondents.map((correspondent) => {
|
||||
|
||||
@@ -306,6 +306,47 @@ button.icon-button.ghost:hover:not([disabled]) {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.app-bar__links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.app-bar__link {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font: inherit;
|
||||
padding: 0.3rem 0.65rem;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.app-bar__link:hover {
|
||||
background: var(--sidebar-hover-bg);
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.app-bar__link:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.app-bar__link.active {
|
||||
background: var(--sidebar-active-bg);
|
||||
color: var(--fg);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.app-bar__link-count {
|
||||
font-size: 0.75rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.app-main {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
|
||||
Reference in New Issue
Block a user