8f994460ad
- Merge the comments side-panel header into the Open/Resolved tab row, then drop the now-redundant "Comments" title; the panel keeps its accessible name via the AppShell.Aside aria-label. - Overlay the close (X) button on the right of the tab row and nudge it up 4px to align with the tab labels; the tab list stays full-width so its bottom border line is preserved. The toc/details tabs keep their existing shared header and scroll area unchanged. - Quote block (.textSelection): increase top margin (2px -> 8px) so it no longer sticks to the timestamp when it is the first block, and add margin-left: 6px so the quote's left bar lines up with the comment body text left edge.
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { ActionIcon, Box, Group, ScrollArea, Title, Tooltip } from "@mantine/core";
|
|
import { IconX } from "@tabler/icons-react";
|
|
import CommentListWithTabs from "@/features/comment/components/comment-list-with-tabs.tsx";
|
|
import { useAtom } from "jotai";
|
|
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
|
import React, { ReactNode, useEffect } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { TableOfContents } from "@/features/editor/components/table-of-contents/table-of-contents.tsx";
|
|
import { useAtomValue } from "jotai";
|
|
import { pageEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
|
|
import { PageDetailsAside } from "@/features/page-details/components/page-details-aside.tsx";
|
|
import { ASIDE_PANEL_ID } from "@/hooks/use-toggle-aside.tsx";
|
|
|
|
export default function Aside() {
|
|
const [{ tab, isAsideOpen }, setAsideState] = useAtom(asideStateAtom);
|
|
const { t } = useTranslation();
|
|
const pageEditor = useAtomValue(pageEditorAtom);
|
|
const closeAside = () => setAsideState((s) => ({ ...s, isAsideOpen: false }));
|
|
|
|
useEffect(() => {
|
|
if (!isAsideOpen) return;
|
|
document.getElementById(ASIDE_PANEL_ID)?.focus();
|
|
}, [isAsideOpen, tab]);
|
|
|
|
let title: string;
|
|
let component: ReactNode;
|
|
|
|
switch (tab) {
|
|
case "comments":
|
|
component = <CommentListWithTabs onClose={closeAside} />;
|
|
title = "Comments";
|
|
break;
|
|
case "toc":
|
|
component = <TableOfContents editor={pageEditor} />;
|
|
title = "Table of contents";
|
|
break;
|
|
case "details":
|
|
component = <PageDetailsAside />;
|
|
title = "Details";
|
|
break;
|
|
default:
|
|
component = null;
|
|
title = null;
|
|
}
|
|
|
|
return (
|
|
<Box p={0} style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
|
{component &&
|
|
(tab === "comments" ? (
|
|
component
|
|
) : (
|
|
<>
|
|
<Group justify="space-between" wrap="nowrap" mb="sm">
|
|
<Title order={2} size="h6" fw={500}>
|
|
{t(title)}
|
|
</Title>
|
|
<Tooltip label={t("Close")} withArrow>
|
|
<ActionIcon
|
|
variant="subtle"
|
|
color="gray"
|
|
onClick={closeAside}
|
|
aria-label={t("Close")}
|
|
>
|
|
<IconX size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</Group>
|
|
<ScrollArea
|
|
style={{ height: "85vh" }}
|
|
scrollbarSize={5}
|
|
type="scroll"
|
|
>
|
|
<div style={{ paddingBottom: "200px" }}>{component}</div>
|
|
</ScrollArea>
|
|
</>
|
|
))}
|
|
</Box>
|
|
);
|
|
}
|