mirror of
https://github.com/zadam/trilium.git
synced 2025-12-20 14:24:27 +01:00
chore(toc): reintroduce basic collapse support
This commit is contained in:
parent
87a98201b4
commit
73f1b91d34
@ -1,8 +1,16 @@
|
|||||||
interface IconProps {
|
import clsx from "clsx";
|
||||||
|
import { HTMLAttributes } from "preact";
|
||||||
|
|
||||||
|
interface IconProps extends Pick<HTMLAttributes<HTMLSpanElement>, "className" | "onClick"> {
|
||||||
icon?: string;
|
icon?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Icon({ icon, className }: IconProps) {
|
export default function Icon({ icon, className, ...restProps }: IconProps) {
|
||||||
return <span class={`${icon ?? "bx bx-empty"} ${className ?? ""}`}></span>
|
return (
|
||||||
}
|
<span
|
||||||
|
class={clsx(icon ?? "bx bx-empty", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
82
apps/client/src/widgets/sidebar/TableOfContents.css
Normal file
82
apps/client/src/widgets/sidebar/TableOfContents.css
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
.toc ol {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-inline-start: 0px;
|
||||||
|
transition: max-height 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li.collapsed + ol {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li + ol:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
border-inline-start: 1px solid var(--main-border-color);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
list-style: none;
|
||||||
|
align-items: center;
|
||||||
|
padding-inline-start: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: justify;
|
||||||
|
word-wrap: break-word;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc > ol {
|
||||||
|
--toc-depth-level: 1;
|
||||||
|
}
|
||||||
|
.toc > ol > ol {
|
||||||
|
--toc-depth-level: 2;
|
||||||
|
}
|
||||||
|
.toc > ol > ol > ol {
|
||||||
|
--toc-depth-level: 3;
|
||||||
|
}
|
||||||
|
.toc > ol > ol > ol > ol {
|
||||||
|
--toc-depth-level: 4;
|
||||||
|
}
|
||||||
|
.toc > ol > ol > ol > ol > ol {
|
||||||
|
--toc-depth-level: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc > ol ol::before {
|
||||||
|
inset-inline-start: calc((var(--toc-depth-level) - 2) * 20px + 14px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li {
|
||||||
|
padding-inline-start: calc((var(--toc-depth-level) - 1) * 20px + 4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li .collapse-button {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li.collapsed .collapse-button {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li .item-content {
|
||||||
|
margin-inline-start: 25px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li .collapse-button + .item-content {
|
||||||
|
margin-inline-start: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li:hover {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
@ -1,8 +1,12 @@
|
|||||||
|
import "./TableOfContents.css";
|
||||||
|
|
||||||
import { CKTextEditor, ModelElement } from "@triliumnext/ckeditor5";
|
import { CKTextEditor, ModelElement } from "@triliumnext/ckeditor5";
|
||||||
|
import clsx from "clsx";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import { useActiveNoteContext, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks";
|
import { useActiveNoteContext, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks";
|
||||||
|
import Icon from "../react/Icon";
|
||||||
import RightPanelWidget from "./RightPanelWidget";
|
import RightPanelWidget from "./RightPanelWidget";
|
||||||
|
|
||||||
interface RawHeading {
|
interface RawHeading {
|
||||||
@ -66,19 +70,35 @@ function AbstractTableOfContents({ headings }: {
|
|||||||
headings: RawHeading[];
|
headings: RawHeading[];
|
||||||
}) {
|
}) {
|
||||||
const nestedHeadings = buildHeadingTree(headings);
|
const nestedHeadings = buildHeadingTree(headings);
|
||||||
return nestedHeadings.map(heading => <TableOfContentsHeading heading={heading} />);
|
return (
|
||||||
|
<span className="toc">
|
||||||
|
<ol>
|
||||||
|
{nestedHeadings.map(heading => <TableOfContentsHeading heading={heading} />)}
|
||||||
|
</ol>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TableOfContentsHeading({ heading }: { heading: HeadingsWithNesting }) {
|
function TableOfContentsHeading({ heading }: { heading: HeadingsWithNesting }) {
|
||||||
|
const [ collapsed, setCollapsed ] = useState(false);
|
||||||
return (
|
return (
|
||||||
<li>
|
<>
|
||||||
<span className="title">{heading.text}</span>
|
<li className={clsx(collapsed && "collapsed")}>
|
||||||
|
{heading.children.length > 0 && (
|
||||||
|
<Icon
|
||||||
|
className="collapse-button"
|
||||||
|
icon="bx bx-chevron-down"
|
||||||
|
onClick={() => setCollapsed(!collapsed)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span className="item-content">{heading.text}</span>
|
||||||
|
</li>
|
||||||
{heading.children && (
|
{heading.children && (
|
||||||
<ul>
|
<ol>
|
||||||
{heading.children.map(heading => <TableOfContentsHeading heading={heading} />)}
|
{heading.children.map(heading => <TableOfContentsHeading heading={heading} />)}
|
||||||
</ul>
|
</ol>
|
||||||
)}
|
)}
|
||||||
</li>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user