Skip to content

Commit b1cc68f

Browse files
committed
revert(toc): restore Table of Contents to pre-refactor state
Reverts TOC components to commit 6a52451 (before 2a3eb08 refactor). The refactor caused build issues on Linux due to case-sensitivity. Restored: - RenderToc.tsx, RenderTocs.tsx (root + mobile/) - Original hooks (useActiveHeading, useHandelTocUpdate, etc.) - Original components (ContextMenuItems, DocTitleChatRoom, etc.) - helper.ts Removed: - New TocMobile.tsx, index.ts, types.ts - New hooks (useTocItems, useHeadingActions, useScrollToHeading, etc.) - New components (TocItem, TocContextMenu, DocTitle, etc.)
1 parent 60d569a commit b1cc68f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1340
-2199
lines changed

packages/webapp/src/components/TipTap/extentions/plugins/headingButtonsPlugin.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ const buttonWrapper = (
122122
url.searchParams.set('id', headingId)
123123
window.history.pushState({}, '', url.toString())
124124
copyToClipboard(url.href, () => {
125-
console.info('Link copied to clipboard')
125+
console.log('Link copied to clipboard')
126126
})
127127
editor
128128
.chain()
@@ -154,37 +154,25 @@ const appendButtonsDec = (doc: ProseMirrorNode, editor: TipTapEditor): Decoratio
154154
}
155155

156156
const handleHeadingToggle = (editor: TipTapEditor, { headingId }: EditorEventData): void => {
157-
// Guard: check if editor is available and has a mounted view
158-
// tiptap throws when accessing .view if not mounted, so we need try-catch
159-
let editorDom: Element | null = null
160-
try {
161-
editorDom = editor?.view?.dom
162-
} catch {
163-
console.warn('[HeadingButtons] Editor view not available yet')
164-
return
165-
}
166-
167-
if (!editorDom) {
168-
console.warn('[HeadingButtons] Editor DOM not available')
169-
return
170-
}
157+
const { tr } = editor.state
158+
const headingNodeEl = editor.view.dom.querySelector(
159+
`.ProseMirror .heading[data-id="${headingId}"]`
160+
)
171161

172162
if (isProcessing) return
173163
isProcessing = true
174164

175-
const { tr } = editor.state
176-
const headingNodeEl = editorDom.querySelector(`.ProseMirror .heading[data-id="${headingId}"]`)
177-
178165
if (!headingNodeEl) {
179166
isProcessing = false
180167
return
181168
}
182169

170+
// TODO: I have no idea why this is working like this!
171+
183172
let nodePos
184173
try {
185174
nodePos = editor.view.state.doc.resolve(editor.view.posAtDOM(headingNodeEl))
186-
} catch {
187-
console.warn('[HeadingButtons] Error getting node position')
175+
} catch (error) {
188176
isProcessing = false
189177
return
190178
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React from 'react'
2+
import { CaretRight, ChatLeft } from '@icons'
3+
import { useStore, useChatStore } from '@stores'
4+
import { toggleHeadingSection, handelScroll2Header } from './helper'
5+
import AvatarStack from '@components/AvatarStack'
6+
7+
import usePresentUsers from './hooks/usePresentUsers'
8+
import useActiveHeading from './hooks/useActiveHeading'
9+
import useOpenChatContainer from './hooks/useOpenChatContainer'
10+
import useUnreadMessage from './hooks/useUnreadMessage'
11+
import useOpenChatroomHandler from './hooks/useOpenChatroomHandler'
12+
13+
export const RenderToc = ({ childItems, item, renderTocs }: any) => {
14+
const { headingId } = useChatStore((state) => state.chatRoom)
15+
const {
16+
editor: { instance: editor }
17+
} = useStore((state) => state.settings)
18+
19+
const presentUsers = usePresentUsers(item.id)
20+
const [activeHeading, setActiveHeading] = useActiveHeading()
21+
const unreadMessage = useUnreadMessage(item)
22+
const openChatContainerHandler = useOpenChatContainer()
23+
24+
if (!editor) return
25+
26+
return (
27+
<li
28+
key={item.id}
29+
className={`toc__item relative w-full ${item.open ? '' : 'closed'} `}
30+
data-id={item.id}
31+
data-offsettop={item.offsetTop}>
32+
<a
33+
className={`group relative ${headingId === item.id ? 'active' : ''} ${headingId === item.id && 'activeTocBorder bg-gray-300'}`}
34+
onClick={(e) => handelScroll2Header(e, editor, setActiveHeading, true)}
35+
href={`?${item.id}`}
36+
data-id={item.id}>
37+
<span className="toc__link wrap-anywhere">{item.text}</span>
38+
<span
39+
className={`btnFold tooltip tooltip-top ${item.open ? 'opened' : 'closed'}`}
40+
onClick={() => toggleHeadingSection(item)}
41+
data-tip="Toggle">
42+
<CaretRight size={17} fill="#363636" />
43+
</span>
44+
<span
45+
className="btn_chat tooltip tooltip-top relative ml-auto"
46+
onClick={() => openChatContainerHandler(item)}
47+
data-tip="Chat Room">
48+
{unreadMessage > 0 && (
49+
<div className="badge badge-docsy badge-sm bg-docsy border-docsy absolute top-1/2 z-[1] -translate-y-1/2 scale-90 border border-none text-white">
50+
{unreadMessage > 99 ? '99+' : unreadMessage}
51+
</div>
52+
)}
53+
<ChatLeft
54+
className={`btnChat ${unreadMessage > 0 && 'hidden'} group-hover:fill-docsy cursor-pointer transition-all hover:fill-indigo-900`}
55+
size={18}
56+
/>
57+
</span>
58+
59+
<div className="absolute relative -right-5">
60+
{presentUsers.length > 0 && (
61+
<AvatarStack
62+
size={8}
63+
users={presentUsers}
64+
showStatus={true}
65+
tooltipPosition="tooltip-left"
66+
/>
67+
)}
68+
</div>
69+
</a>
70+
71+
{childItems.length > 0 && (
72+
<ul className={`childrenWrapper ${item.open ? '' : 'hidden'}`}>{renderTocs(childItems)}</ul>
73+
)}
74+
</li>
75+
)
76+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { RenderToc } from './RenderToc'
2+
3+
export const RenderTocs = (items: any) => {
4+
const renderedItems = []
5+
6+
for (let i = 0; i < items.length; ) {
7+
const item = items[i]
8+
const children = []
9+
let j = i + 1
10+
11+
while (j < items.length && items[j].level > item.level) {
12+
children.push(items[j])
13+
j++
14+
}
15+
renderedItems.push(
16+
<RenderToc key={j * i} childItems={children} item={item} renderTocs={RenderTocs} />
17+
)
18+
i = j
19+
}
20+
return renderedItems
21+
}
Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,82 @@
1-
import React, { memo, useRef, useState, useCallback } from 'react'
2-
import { ContextMenu } from '@components/ui/ContextMenu'
1+
import React, { useEffect, useRef, useState } from 'react'
2+
import { useChatStore } from '@stores'
3+
import useHandelTocUpdate from './hooks/useHandelTocUpdate'
4+
import { RenderTocs } from './RenderTocs'
5+
import { DocTitleChatRoomDesktop } from './components/DocTitleChatRoom'
36
import AppendHeadingButton from '@components/pages/document/components/AppendHeadingButton'
4-
import { DocTitle, TocList, TocContextMenu } from './components'
5-
import { useTocItems } from './hooks'
7+
import { ContextMenu } from '@components/ui/ContextMenu'
8+
import ContextMenuItems from './components/ContextMenuItems'
69

7-
interface TocDesktopProps {
8-
className?: string
10+
const removeContextMenuActiveClass = () => {
11+
const tocItems = document.querySelectorAll('.toc__item a.context-menu-active')
12+
tocItems.forEach((item: Element) => {
13+
item.classList.remove('context-menu-active')
14+
})
915
}
1016

11-
const TocDesktop = memo(({ className = '' }: TocDesktopProps) => {
12-
const items = useTocItems()
17+
const TOCDesktop = ({ className }: any) => {
18+
const { headingId } = useChatStore((state) => state.chatRoom)
19+
const [renderedTocs, setRenderedTocs] = useState([])
20+
const { items } = useHandelTocUpdate()
1321
const contextMenuRef = useRef<HTMLDivElement>(null)
14-
const [contextTarget, setContextTarget] = useState<Element | null>(null)
22+
const [contextMenuState, setContextMenuState] = useState<{
23+
tocItem: Element | null
24+
}>({
25+
tocItem: null
26+
})
1527

16-
const handleBeforeContextMenu = useCallback((e: any) => {
17-
const tocItem = e.target.closest('.toc__item') as Element | null
28+
useEffect(() => {
29+
if (!items.length) return
30+
const tocs = RenderTocs(items)
31+
// @ts-ignore
32+
setRenderedTocs(tocs)
33+
}, [items, headingId])
34+
35+
const handleBeforeShow = (e: any) => {
36+
const tocItem = e.target.closest('.toc__item') ?? null
1837
if (!tocItem) return null
38+
setContextMenuState({ tocItem })
1939

20-
// Remove any existing highlight
21-
document.querySelectorAll('.toc__item a.context-menu-active').forEach((el) => {
22-
el.classList.remove('context-menu-active')
23-
})
40+
removeContextMenuActiveClass()
2441

25-
// Highlight current item
2642
const tocId = tocItem.getAttribute('data-id')
43+
44+
// Add CSS class to highlight the toc item
2745
tocItem.querySelector(`a[data-id="${tocId}"]`)?.classList.add('context-menu-active')
2846

29-
setContextTarget(tocItem)
3047
return tocItem
31-
}, [])
32-
33-
const handleContextMenuClose = useCallback(() => {
34-
setContextTarget(null)
35-
document.querySelectorAll('.toc__item a.context-menu-active').forEach((el) => {
36-
el.classList.remove('context-menu-active')
48+
}
49+
const handleContextMenuClose = () => {
50+
setContextMenuState({
51+
tocItem: null
3752
})
38-
}, [])
39-
40-
// Empty state
41-
if (!items.length) {
53+
// Remove CSS class from the toc item
54+
// find all .toc__item and the remove the class
55+
removeContextMenuActiveClass()
56+
}
57+
if (!items.length)
4258
return (
43-
<div className={className} style={{ scrollbarGutter: 'stable' }}>
44-
<DocTitle className="my-1" variant="desktop" />
59+
<div className={`${className}`} style={{ scrollbarGutter: 'stable' }}>
60+
<DocTitleChatRoomDesktop className="my-1" />
4561
</div>
4662
)
47-
}
4863

4964
return (
50-
<div className={className} style={{ scrollbarGutter: 'stable' }} ref={contextMenuRef}>
51-
<DocTitle className="my-1" variant="desktop" />
52-
65+
<div className={`${className}`} style={{ scrollbarGutter: 'stable' }} ref={contextMenuRef}>
66+
<DocTitleChatRoomDesktop className="my-1" />
5367
<ul className="toc__list menu w-full p-0">
5468
<ContextMenu
5569
className="menu bg-base-100 absolute z-20 m-0 rounded-md p-2 shadow-md outline-none"
5670
parrentRef={contextMenuRef}
57-
onBeforeShow={handleBeforeContextMenu}
71+
onBeforeShow={handleBeforeShow}
5872
onClose={handleContextMenuClose}>
59-
<TocContextMenu tocElement={contextTarget} />
73+
<ContextMenuItems tocItem={contextMenuState?.tocItem} />
6074
</ContextMenu>
61-
62-
<TocList items={items} variant="desktop" />
75+
{renderedTocs}
6376
</ul>
64-
6577
<AppendHeadingButton className="mt-4" />
6678
</div>
6779
)
68-
})
69-
70-
TocDesktop.displayName = 'TocDesktop'
80+
}
7181

72-
export default TocDesktop
82+
export default React.memo(TOCDesktop)

packages/webapp/src/components/TipTap/tableOfContents/TocMobile.tsx

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)