aboutsummaryrefslogtreecommitdiff
path: root/apps/web/components/editor/toc.tsx
blob: 4f5a3abbdb0d41977c9240d63a2d9e91b3b2d8c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { useEditor } from "novel";
import { motion } from "framer-motion";

type tContent = {
	id: string;
	textContent: string;
	level: number;
	isActive: boolean;
	itemIndex: number;
	isScrolledOver: boolean;
	pos: number;
};

export const ToCItem = ({
	item,
	onItemClick,
}: {
	item: tContent;
	onItemClick: (pos: number) => void;
}) => {
	return (
		<div
			className={`text-sm ${
				item.level === 2 ? "pl-2" : item.level === 3 ? "pl-4" : "pl-0"
			}`}
		>
			<div
				onClick={() => onItemClick(item.pos)}
				className={`cursor-pointer text-base font-medium py-1 px-2 w-full hover:bg-[#2b3238] transition-colors rounded-sm ${item.isActive && "text-blue-500"}`}
			>
				{item.textContent}
			</div>
		</div>
	);
};

export const ToC = ({ items }: { items: tContent[] }) => {
	if (items.length < 2) {
		return;
	}

	return (
		<div className="fixed right-0 top-1/4 -translate-y-1/2 mr-12">
			<div className="items-end space-y-3 py-2 max-h-[60vh] overflow-hidden">
				{items.map((item, i) => (
					<ToCItemStick key={item.id} item={item} />
				))}
			</div>
			<motion.div
				initial={{ x: 15, opacity: 0 }}
				whileHover={{ x: 5, opacity: 1 }}
				transition={{ ease: "easeOut", duration: 0.15 }}
				className="absolute top-0 right-0 space-y-3 min-w-72 max-w-72"
			>
				<Container items={items} />
			</motion.div>
		</div>
	);
};

function Container({ items }: { items: tContent[] }) {
	const { editor } = useEditor();

	const onItemClick = (pos: number) => {
		console.log(pos);
		if (editor) {
			editor.commands.focus(pos ? pos : 1, { scrollIntoView: true });
		}
	};

	return (
		<div className="bg-[#1F2428] rounded-xl overflow-auto max-h-[60vh] px-4 py-6">
			{items.map((item, i) => (
				<ToCItem onItemClick={onItemClick} key={item.id} item={item} />
			))}
		</div>
	);
}

export function ToCItemStick({ item }: { item: tContent }) {
	return (
		<div
			className={`h-[0.125rem] bg-gray-500 rounded-xl ml-auto ${
				item.level === 1 ? "w-6" : item.level === 2 ? "w-4" : "w-3"
			}`}
		></div>
	);
}