@tnotesjs/core 0.1.28 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{chunk-4KG6RXFS.js → chunk-5QN44ES5.js} +2946 -1533
- package/dist/{chunk-AGSL3VZE.js → chunk-5Y5IYS6C.js} +7 -0
- package/dist/cli/index.js +343 -40
- package/dist/index.js +1 -1
- package/dist/vitepress/config/index.js +573 -65
- package/package.json +4 -1
- package/templates/sub-repo/.gitattributes +30 -0
- package/templates/sub-repo/.github/workflows/deploy.yml +87 -0
- package/templates/sub-repo/.vitepress/config.mts +12 -0
- package/templates/sub-repo/.vitepress/env.d.ts +10 -0
- package/templates/sub-repo/.vitepress/theme/index.ts +12 -0
- package/templates/sub-repo/.vscode/settings.json +330 -0
- package/templates/sub-repo/.vscode/tnotes.code-snippets +110 -0
- package/templates/sub-repo/public/favicon.ico +0 -0
- package/templates/sub-repo/public/logo.png +0 -0
- package/templates/sub-repo/tsconfig.json +45 -0
- package/vitepress/assets/icons/icon__setting_dark.svg +4 -0
- package/vitepress/assets/icons/icon__setting_light.svg +4 -0
- package/vitepress/assets/icons/index.ts +2 -2
- package/vitepress/client/localSearchIndexBridge.ts +24 -0
- package/vitepress/components/Discussions/Discussions.vue +1 -1
- package/vitepress/components/Footprints/Footprints.vue +90 -25
- package/vitepress/components/Layout/CustomSidebar.vue +489 -117
- package/vitepress/components/Layout/Layout.vue +5 -0
- package/vitepress/components/Layout/NavBarSettingsTrigger.vue +10 -2
- package/vitepress/components/Layout/SidebarItems.vue +517 -342
- package/vitepress/components/Layout/SidebarNavBefore.vue +1 -50
- package/vitepress/components/Layout/SidebarResizeHandle.vue +6 -23
- package/vitepress/components/Layout/composables/docLayoutLogic.ts +59 -0
- package/vitepress/components/Layout/composables/useDocLayout.test.ts +69 -0
- package/vitepress/components/Layout/composables/useDocLayout.ts +128 -0
- package/vitepress/components/Layout/composables/useSidebarDrag.ts +514 -0
- package/vitepress/components/Layout/composables/useSidebarLayout.ts +25 -8
- package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +8 -3
- package/vitepress/components/Layout/sidebarCollapsedState.test.ts +183 -0
- package/vitepress/components/Layout/sidebarCollapsedState.ts +241 -0
- package/vitepress/components/Layout/sidebarDragLogic.test.ts +1146 -0
- package/vitepress/components/Layout/sidebarDragLogic.ts +1307 -0
- package/vitepress/components/Layout/sidebarHitTest.test.ts +572 -0
- package/vitepress/components/Layout/sidebarHitTest.ts +801 -0
- package/vitepress/components/Layout/sidebarItemRenderLogic.test.ts +53 -0
- package/vitepress/components/Layout/sidebarItemRenderLogic.ts +50 -0
- package/vitepress/components/MarkMap/MarkMap.vue +67 -10
- package/vitepress/components/Settings/Settings.vue +78 -74
- package/vitepress/components/SidebarCard/FolderTreeItems.vue +268 -0
- package/vitepress/components/SidebarCard/SidebarCard.vue +125 -274
- package/vitepress/components/constants.ts +18 -6
- package/vitepress/components/sidebar.data.ts +13 -11
- package/vitepress/components/sidebarTreeHelpers.test.ts +142 -0
- package/vitepress/components/sidebarTreeHelpers.ts +168 -0
- package/vitepress/components/utils/vscodePaths.test.ts +41 -0
- package/vitepress/components/utils/vscodePaths.ts +52 -0
- package/vitepress/config/index.ts +2 -0
- package/vitepress/plugins/localSearchIndexBuilder.ts +209 -0
- package/vitepress/plugins/localSearchReindex.test.ts +46 -0
- package/vitepress/plugins/localSearchReindexLogic.ts +50 -0
- package/vitepress/plugins/localSearchReindexPatch.test.ts +30 -0
- package/vitepress/plugins/localSearchReindexPatch.ts +37 -0
- package/vitepress/plugins/localSearchReindexPlugin.ts +318 -0
- package/vitepress/plugins/sidebarStructurePlugin.ts +209 -63
- package/vitepress/theme/index.ts +8 -0
- package/vitepress/theme/styles/base.scss +0 -8
- package/vitepress/theme/styles/components/markmap.scss +23 -2
- package/vitepress/theme/styles/components/swiper.scss +1 -1
- package/vitepress/theme/styles/doc-layout.scss +212 -0
- package/vitepress/theme/styles/index.scss +3 -0
- package/vitepress/theme/styles/layout.scss +60 -10
- package/vitepress/assets/icons/icon__mindmap.svg +0 -1
- package/vitepress/assets/icons/icon__setting.svg +0 -1
- package/vitepress/components/SidebarCard/MindMapView.vue +0 -488
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getSidebarItemRenderMode,
|
|
5
|
+
type SidebarRenderItem,
|
|
6
|
+
} from './sidebarItemRenderLogic'
|
|
7
|
+
|
|
8
|
+
/** introduction:TNotes 笔记书写规范 → 0027 → Giscus folder */
|
|
9
|
+
const giscusFolderAtDepth2: SidebarRenderItem = {
|
|
10
|
+
text: '评论功能的技术实现(Giscus)',
|
|
11
|
+
items: [
|
|
12
|
+
{
|
|
13
|
+
text: '⏰ 评论功能的技术实现(Giscus)',
|
|
14
|
+
link: '/notes/0003. 评论功能的技术实现(Giscus)/README',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('sidebarItemRenderLogic', () => {
|
|
20
|
+
it('renders pure folder at depth 2 when maxDepth is 3 (0027 child)', () => {
|
|
21
|
+
expect(getSidebarItemRenderMode(giscusFolderAtDepth2, 2, 3)).toBe(
|
|
22
|
+
'pure-folder',
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('legacy cutoff depth < maxDepth - 1 would hide depth-2 folders', () => {
|
|
27
|
+
const legacyAllowsGroup = 2 < 3 - 1
|
|
28
|
+
expect(legacyAllowsGroup).toBe(false)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('parent note at depth 1 still renders as group', () => {
|
|
32
|
+
const emojiNote: SidebarRenderItem = {
|
|
33
|
+
text: '✅ emoji 规范',
|
|
34
|
+
link: '/notes/0027. emoji 规范/README',
|
|
35
|
+
items: [giscusFolderAtDepth2],
|
|
36
|
+
}
|
|
37
|
+
expect(getSidebarItemRenderMode(emojiNote, 1, 3)).toBe('parent-note')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('leaf note at depth 3 renders when maxDepth is 3', () => {
|
|
41
|
+
const leaf: SidebarRenderItem = {
|
|
42
|
+
text: '⏰ 0003',
|
|
43
|
+
link: '/notes/0003. x/README',
|
|
44
|
+
}
|
|
45
|
+
expect(getSidebarItemRenderMode(leaf, 3, 3)).toBe('leaf')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('renders depth-2 pure folder when maxDepth is 0 (unlimited)', () => {
|
|
49
|
+
expect(getSidebarItemRenderMode(giscusFolderAtDepth2, 2, 0)).toBe(
|
|
50
|
+
'pure-folder',
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vitepress/components/Layout/sidebarItemRenderLogic.ts
|
|
3
|
+
*
|
|
4
|
+
* 侧边栏项渲染模式:决定 folder / parent-note / leaf / hidden
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface SidebarRenderItem {
|
|
8
|
+
text: string
|
|
9
|
+
link?: string
|
|
10
|
+
items?: SidebarRenderItem[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type SidebarItemRenderMode =
|
|
14
|
+
| 'pure-folder'
|
|
15
|
+
| 'parent-note'
|
|
16
|
+
| 'leaf'
|
|
17
|
+
| 'hidden'
|
|
18
|
+
|
|
19
|
+
export function hasSidebarChildren(item: SidebarRenderItem): boolean {
|
|
20
|
+
return !!(item.items && item.items.length > 0)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isPureSidebarFolder(item: SidebarRenderItem): boolean {
|
|
24
|
+
return hasSidebarChildren(item) && !item.link
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param maxDepth 最大可见层级(0 或负数表示不限制)
|
|
29
|
+
*/
|
|
30
|
+
export function getSidebarItemRenderMode(
|
|
31
|
+
item: SidebarRenderItem,
|
|
32
|
+
depth: number,
|
|
33
|
+
maxDepth: number,
|
|
34
|
+
): SidebarItemRenderMode {
|
|
35
|
+
const hasDepthLimit = maxDepth > 0 && Number.isFinite(maxDepth)
|
|
36
|
+
|
|
37
|
+
if (isPureSidebarFolder(item) && (!hasDepthLimit || depth < maxDepth)) {
|
|
38
|
+
return 'pure-folder'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (hasSidebarChildren(item) && (!hasDepthLimit || depth < maxDepth)) {
|
|
42
|
+
return 'parent-note'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!hasSidebarChildren(item) && item.link) {
|
|
46
|
+
return 'leaf'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return 'hidden'
|
|
50
|
+
}
|
|
@@ -8,6 +8,7 @@ import { Transformer } from 'markmap-lib'
|
|
|
8
8
|
import { Toolbar } from 'markmap-toolbar'
|
|
9
9
|
import 'markmap-toolbar/dist/style.css'
|
|
10
10
|
import { Markmap, IMarkmapOptions } from 'markmap-view'
|
|
11
|
+
import { onContentUpdated } from 'vitepress'
|
|
11
12
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
12
13
|
|
|
13
14
|
import { icon__fullscreen, icon__fullscreen_exit, icon__confirm } from '../../assets/icons'
|
|
@@ -30,6 +31,10 @@ const containerRef = ref<HTMLDivElement | null>(null)
|
|
|
30
31
|
let markmapInstance: Markmap | null = null
|
|
31
32
|
let observer: MutationObserver | null = null
|
|
32
33
|
let toolbarEl: HTMLElement | null = null
|
|
34
|
+
let toolbarReinitTimer: ReturnType<typeof setTimeout> | null = null
|
|
35
|
+
let darkClassObserver: MutationObserver | null = null
|
|
36
|
+
|
|
37
|
+
const isMarkmapDark = ref(false)
|
|
33
38
|
|
|
34
39
|
// 从 localStorage 读取配置,如果没有则使用 props 或默认值
|
|
35
40
|
const getInitialExpandLevel = () => {
|
|
@@ -42,6 +47,9 @@ const getInitialExpandLevel = () => {
|
|
|
42
47
|
|
|
43
48
|
const getThemeColorFn = () => {
|
|
44
49
|
if (typeof window !== 'undefined') {
|
|
50
|
+
if (document.documentElement.classList.contains('markmap-dark')) {
|
|
51
|
+
return scaleOrdinal(schemeSet3)
|
|
52
|
+
}
|
|
45
53
|
const theme = localStorage.getItem(MARKMAP_THEME_KEY) || 'default'
|
|
46
54
|
switch (theme) {
|
|
47
55
|
case 'colorful':
|
|
@@ -131,6 +139,7 @@ function initToolbar() {
|
|
|
131
139
|
toolbarEl.style.position = 'absolute'
|
|
132
140
|
toolbarEl.style.top = '1rem'
|
|
133
141
|
toolbarEl.style.right = '.5rem'
|
|
142
|
+
toolbarEl.style.zIndex = '10'
|
|
134
143
|
toolbarEl.style.scale = '.8'
|
|
135
144
|
const brand = toolbarEl.querySelector('.mm-toolbar-brand')
|
|
136
145
|
if (brand) toolbarEl.removeChild(brand)
|
|
@@ -367,7 +376,43 @@ function onUpdateClick() {
|
|
|
367
376
|
renderMarkmap(decodeURIComponent(props.content || ''), expandLevel.value)
|
|
368
377
|
}
|
|
369
378
|
|
|
379
|
+
function syncMarkmapDarkState(reRender = false) {
|
|
380
|
+
const dark = document.documentElement.classList.contains('markmap-dark')
|
|
381
|
+
const changed = isMarkmapDark.value !== dark
|
|
382
|
+
isMarkmapDark.value = dark
|
|
383
|
+
if (typeof window !== 'undefined') {
|
|
384
|
+
localStorage.setItem(MARKMAP_THEME_KEY, dark ? 'dark' : 'default')
|
|
385
|
+
}
|
|
386
|
+
if (reRender && changed && markmapInstance && props.content) {
|
|
387
|
+
renderMarkmap(decodeURIComponent(props.content || ''), expandLevel.value)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function ensureToolbarAfterContentUpdate() {
|
|
392
|
+
if (toolbarReinitTimer) clearTimeout(toolbarReinitTimer)
|
|
393
|
+
// ContentCollapse.onContentUpdated 会在 ~150ms 后重组 DOM,稍晚再补挂工具栏
|
|
394
|
+
toolbarReinitTimer = setTimeout(() => {
|
|
395
|
+
toolbarReinitTimer = null
|
|
396
|
+
if (!containerRef.value || !markmapInstance) return
|
|
397
|
+
if (!containerRef.value.querySelector('.mm-toolbar')) {
|
|
398
|
+
initToolbar()
|
|
399
|
+
}
|
|
400
|
+
}, 350)
|
|
401
|
+
}
|
|
402
|
+
|
|
370
403
|
onMounted(() => {
|
|
404
|
+
if (typeof window !== 'undefined') {
|
|
405
|
+
if (localStorage.getItem(MARKMAP_THEME_KEY) === 'dark') {
|
|
406
|
+
document.documentElement.classList.add('markmap-dark')
|
|
407
|
+
}
|
|
408
|
+
syncMarkmapDarkState(false)
|
|
409
|
+
darkClassObserver = new MutationObserver(() => syncMarkmapDarkState(true))
|
|
410
|
+
darkClassObserver.observe(document.documentElement, {
|
|
411
|
+
attributes: true,
|
|
412
|
+
attributeFilter: ['class'],
|
|
413
|
+
})
|
|
414
|
+
}
|
|
415
|
+
|
|
371
416
|
renderMarkmap(decodeURIComponent(props.content || ''))
|
|
372
417
|
|
|
373
418
|
// 添加全屏事件监听
|
|
@@ -376,7 +421,24 @@ onMounted(() => {
|
|
|
376
421
|
document.addEventListener('MSFullscreenChange', handleFullscreenChange)
|
|
377
422
|
})
|
|
378
423
|
|
|
424
|
+
onContentUpdated(() => {
|
|
425
|
+
ensureToolbarAfterContentUpdate()
|
|
426
|
+
})
|
|
427
|
+
|
|
379
428
|
onBeforeUnmount(() => {
|
|
429
|
+
if (darkClassObserver) {
|
|
430
|
+
darkClassObserver.disconnect()
|
|
431
|
+
darkClassObserver = null
|
|
432
|
+
}
|
|
433
|
+
if (toolbarReinitTimer) {
|
|
434
|
+
clearTimeout(toolbarReinitTimer)
|
|
435
|
+
toolbarReinitTimer = null
|
|
436
|
+
}
|
|
437
|
+
if (toolbarEl) {
|
|
438
|
+
toolbarEl.remove()
|
|
439
|
+
toolbarEl = null
|
|
440
|
+
toolbarLevelInput = null
|
|
441
|
+
}
|
|
380
442
|
if (markmapInstance) {
|
|
381
443
|
try {
|
|
382
444
|
markmapInstance.destroy()
|
|
@@ -398,6 +460,7 @@ onBeforeUnmount(() => {
|
|
|
398
460
|
<template>
|
|
399
461
|
<div
|
|
400
462
|
class="markmapContainer"
|
|
463
|
+
:class="{ 'is-markmap-dark': isMarkmapDark }"
|
|
401
464
|
ref="containerRef"
|
|
402
465
|
style="position: relative"
|
|
403
466
|
>
|
|
@@ -434,16 +497,10 @@ onBeforeUnmount(() => {
|
|
|
434
497
|
animation: pulse 1.5s ease-in-out infinite;
|
|
435
498
|
}
|
|
436
499
|
}
|
|
437
|
-
|
|
438
|
-
/* 鼠标悬停显示 toolbar */
|
|
439
|
-
&:hover :global(.mm-toolbar) {
|
|
440
|
-
opacity: 1;
|
|
441
|
-
pointer-events: auto;
|
|
442
|
-
}
|
|
443
500
|
}
|
|
444
501
|
|
|
445
502
|
/* dark background */
|
|
446
|
-
|
|
503
|
+
.markmapContainer.is-markmap-dark {
|
|
447
504
|
background-color: #1d1d1d;
|
|
448
505
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
|
|
449
506
|
|
|
@@ -534,9 +591,9 @@ onBeforeUnmount(() => {
|
|
|
534
591
|
box-shadow: none;
|
|
535
592
|
}
|
|
536
593
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
594
|
+
.markmapContainer.is-markmap-dark:fullscreen,
|
|
595
|
+
.markmapContainer.is-markmap-dark:-ms-fullscreen,
|
|
596
|
+
.markmapContainer.is-markmap-dark:-webkit-full-screen {
|
|
540
597
|
background: #1d1d1d;
|
|
541
598
|
}
|
|
542
599
|
|
|
@@ -47,7 +47,7 @@ vitepress/components/Settings/Settings.vue
|
|
|
47
47
|
<span class="infoWrap">
|
|
48
48
|
<span class="infoIcon">?</span>
|
|
49
49
|
<span class="tooltip">
|
|
50
|
-
|
|
50
|
+
控制侧边栏笔记编号显示,以及已完成/未完成笔记前缀。保存后会刷新页面以应用侧边栏配置。
|
|
51
51
|
</span>
|
|
52
52
|
</span>
|
|
53
53
|
</div>
|
|
@@ -64,28 +64,6 @@ vitepress/components/Settings/Settings.vue
|
|
|
64
64
|
<span>显示笔记编号</span>
|
|
65
65
|
</label>
|
|
66
66
|
|
|
67
|
-
<div class="controlRow">
|
|
68
|
-
<span class="controlLabel">目录风格</span>
|
|
69
|
-
<div class="segmented">
|
|
70
|
-
<label
|
|
71
|
-
v-for="option in sidebarDensityOptions"
|
|
72
|
-
:key="option.value"
|
|
73
|
-
:class="[
|
|
74
|
-
'segment',
|
|
75
|
-
{ activeSegment: sidebarDensity === option.value },
|
|
76
|
-
]"
|
|
77
|
-
>
|
|
78
|
-
<input
|
|
79
|
-
v-model="sidebarDensity"
|
|
80
|
-
type="radio"
|
|
81
|
-
name="sidebar-density"
|
|
82
|
-
:value="option.value"
|
|
83
|
-
/>
|
|
84
|
-
<span>{{ option.label }}</span>
|
|
85
|
-
</label>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
67
|
<div class="prefixGrid">
|
|
90
68
|
<label class="field">
|
|
91
69
|
<span class="controlLabel">已完成笔记的前缀</span>
|
|
@@ -113,26 +91,58 @@ vitepress/components/Settings/Settings.vue
|
|
|
113
91
|
<div class="settingItem">
|
|
114
92
|
<div class="settingMeta">
|
|
115
93
|
<div class="labelLine">
|
|
116
|
-
<span class="itemName"
|
|
94
|
+
<span class="itemName">正文区域</span>
|
|
117
95
|
<span class="infoWrap">
|
|
118
96
|
<span class="infoIcon">?</span>
|
|
119
97
|
<span class="tooltip">
|
|
120
|
-
|
|
98
|
+
控制笔记正文在中间栏的显示宽度。保存后会刷新页面以应用页宽变更。
|
|
121
99
|
</span>
|
|
122
100
|
</span>
|
|
123
101
|
</div>
|
|
102
|
+
<span class="statusText">{{
|
|
103
|
+
contentWidthMode === 'wide' ? '超宽显示' : '标准页宽'
|
|
104
|
+
}}</span>
|
|
124
105
|
</div>
|
|
125
106
|
|
|
126
|
-
<div class="
|
|
127
|
-
<
|
|
128
|
-
<span class="controlLabel"
|
|
129
|
-
<
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
107
|
+
<div class="fieldStack">
|
|
108
|
+
<div class="controlRow">
|
|
109
|
+
<span class="controlLabel">页宽模式</span>
|
|
110
|
+
<div class="segmented segmented-two">
|
|
111
|
+
<label
|
|
112
|
+
v-for="option in contentWidthModeOptions"
|
|
113
|
+
:key="option.value"
|
|
114
|
+
:class="[
|
|
115
|
+
'segment',
|
|
116
|
+
{ activeSegment: contentWidthMode === option.value },
|
|
117
|
+
]"
|
|
118
|
+
>
|
|
119
|
+
<input
|
|
120
|
+
v-model="contentWidthMode"
|
|
121
|
+
type="radio"
|
|
122
|
+
name="content-width-mode"
|
|
123
|
+
:value="option.value"
|
|
124
|
+
/>
|
|
125
|
+
<span>{{ option.label }}</span>
|
|
126
|
+
</label>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
135
131
|
|
|
132
|
+
<div class="settingItem">
|
|
133
|
+
<div class="settingMeta">
|
|
134
|
+
<div class="labelLine">
|
|
135
|
+
<span class="itemName">笔记内 MarkMap</span>
|
|
136
|
+
<span class="infoWrap">
|
|
137
|
+
<span class="infoIcon">?</span>
|
|
138
|
+
<span class="tooltip">
|
|
139
|
+
配置笔记中 markmap 代码块的初始展开层级。
|
|
140
|
+
</span>
|
|
141
|
+
</span>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<div class="inlineGrid">
|
|
136
146
|
<label class="field">
|
|
137
147
|
<span class="controlLabel">展开层级</span>
|
|
138
148
|
<div class="inputWithUnit">
|
|
@@ -175,55 +185,53 @@ import { ref, computed, onMounted } from 'vue'
|
|
|
175
185
|
|
|
176
186
|
import {
|
|
177
187
|
NOTES_DIR_KEY,
|
|
178
|
-
MARKMAP_THEME_KEY,
|
|
179
188
|
MARKMAP_EXPAND_LEVEL_KEY,
|
|
180
189
|
SIDEBAR_SHOW_NOTE_ID_KEY,
|
|
181
|
-
SIDEBAR_DENSITY_KEY,
|
|
182
190
|
SIDEBAR_DONE_PREFIX_KEY,
|
|
183
191
|
SIDEBAR_UNDONE_PREFIX_KEY,
|
|
192
|
+
CONTENT_WIDTH_MODE_KEY,
|
|
184
193
|
} from '../constants'
|
|
185
194
|
// @ts-expect-error - VitePress Data Loader
|
|
186
195
|
import { data as tnotesConfig } from '../tnotes-config.data'
|
|
187
196
|
|
|
188
|
-
type
|
|
197
|
+
type ContentWidthMode = 'wide' | 'standard'
|
|
189
198
|
|
|
190
|
-
const
|
|
199
|
+
const DEFAULT_CONTENT_WIDTH_MODE: ContentWidthMode = 'wide'
|
|
191
200
|
const DEFAULT_DONE_PREFIX = '✅'
|
|
192
201
|
const DEFAULT_UNDONE_PREFIX = '⏰'
|
|
193
|
-
|
|
202
|
+
|
|
203
|
+
const contentWidthModeOptions: Array<{
|
|
194
204
|
label: string
|
|
195
|
-
value:
|
|
205
|
+
value: ContentWidthMode
|
|
196
206
|
}> = [
|
|
197
|
-
{ label: '
|
|
198
|
-
{ label: '
|
|
199
|
-
{ label: '宽松', value: 'loose' },
|
|
207
|
+
{ label: '超宽显示', value: 'wide' },
|
|
208
|
+
{ label: '标准页宽', value: 'standard' },
|
|
200
209
|
]
|
|
201
210
|
|
|
202
211
|
const path = ref('')
|
|
203
212
|
const originalPath = ref('')
|
|
204
|
-
const markmapTheme = ref('default')
|
|
205
|
-
const originalMarkmapTheme = ref('default')
|
|
206
213
|
const markmapExpandLevel = ref(5)
|
|
207
214
|
const originalMarkmapExpandLevel = ref(5)
|
|
208
215
|
const showNoteId = ref(false)
|
|
209
216
|
const originalShowNoteId = ref(false)
|
|
210
|
-
const sidebarDensity = ref<SidebarDensity>(DEFAULT_SIDEBAR_DENSITY)
|
|
211
|
-
const originalSidebarDensity = ref<SidebarDensity>(DEFAULT_SIDEBAR_DENSITY)
|
|
212
217
|
const donePrefix = ref(DEFAULT_DONE_PREFIX)
|
|
213
218
|
const originalDonePrefix = ref(DEFAULT_DONE_PREFIX)
|
|
214
219
|
const undonePrefix = ref(DEFAULT_UNDONE_PREFIX)
|
|
215
220
|
const originalUndonePrefix = ref(DEFAULT_UNDONE_PREFIX)
|
|
221
|
+
const contentWidthMode = ref<ContentWidthMode>(DEFAULT_CONTENT_WIDTH_MODE)
|
|
222
|
+
const originalContentWidthMode = ref<ContentWidthMode>(
|
|
223
|
+
DEFAULT_CONTENT_WIDTH_MODE,
|
|
224
|
+
)
|
|
216
225
|
const showSuccessToast = ref(false)
|
|
217
226
|
|
|
218
227
|
const hasChanges = computed(
|
|
219
228
|
() =>
|
|
220
229
|
path.value !== originalPath.value ||
|
|
221
|
-
markmapTheme.value !== originalMarkmapTheme.value ||
|
|
222
230
|
markmapExpandLevel.value !== originalMarkmapExpandLevel.value ||
|
|
223
231
|
showNoteId.value !== originalShowNoteId.value ||
|
|
224
|
-
sidebarDensity.value !== originalSidebarDensity.value ||
|
|
225
232
|
donePrefix.value !== originalDonePrefix.value ||
|
|
226
|
-
undonePrefix.value !== originalUndonePrefix.value
|
|
233
|
+
undonePrefix.value !== originalUndonePrefix.value ||
|
|
234
|
+
contentWidthMode.value !== originalContentWidthMode.value,
|
|
227
235
|
)
|
|
228
236
|
|
|
229
237
|
const saveText = computed(() => {
|
|
@@ -238,10 +246,6 @@ onMounted(() => {
|
|
|
238
246
|
path.value = savedPath
|
|
239
247
|
originalPath.value = savedPath
|
|
240
248
|
|
|
241
|
-
const savedTheme = localStorage.getItem(MARKMAP_THEME_KEY) || 'default'
|
|
242
|
-
markmapTheme.value = savedTheme
|
|
243
|
-
originalMarkmapTheme.value = savedTheme
|
|
244
|
-
|
|
245
249
|
const savedLevel = localStorage.getItem(MARKMAP_EXPAND_LEVEL_KEY) || '5'
|
|
246
250
|
markmapExpandLevel.value = parseInt(savedLevel, 10)
|
|
247
251
|
originalMarkmapExpandLevel.value = markmapExpandLevel.value
|
|
@@ -253,12 +257,6 @@ onMounted(() => {
|
|
|
253
257
|
: tnotesConfig?.sidebarShowNoteId ?? false
|
|
254
258
|
originalShowNoteId.value = showNoteId.value
|
|
255
259
|
|
|
256
|
-
const savedSidebarDensity = normalizeSidebarDensity(
|
|
257
|
-
localStorage.getItem(SIDEBAR_DENSITY_KEY),
|
|
258
|
-
)
|
|
259
|
-
sidebarDensity.value = savedSidebarDensity
|
|
260
|
-
originalSidebarDensity.value = savedSidebarDensity
|
|
261
|
-
|
|
262
260
|
const savedDonePrefix = localStorage.getItem(SIDEBAR_DONE_PREFIX_KEY)
|
|
263
261
|
donePrefix.value =
|
|
264
262
|
savedDonePrefix !== null ? savedDonePrefix : DEFAULT_DONE_PREFIX
|
|
@@ -268,14 +266,16 @@ onMounted(() => {
|
|
|
268
266
|
undonePrefix.value =
|
|
269
267
|
savedUndonePrefix !== null ? savedUndonePrefix : DEFAULT_UNDONE_PREFIX
|
|
270
268
|
originalUndonePrefix.value = undonePrefix.value
|
|
271
|
-
})
|
|
272
269
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
270
|
+
const savedContentWidthMode = normalizeContentWidthMode(
|
|
271
|
+
localStorage.getItem(CONTENT_WIDTH_MODE_KEY),
|
|
272
|
+
)
|
|
273
|
+
contentWidthMode.value = savedContentWidthMode
|
|
274
|
+
originalContentWidthMode.value = savedContentWidthMode
|
|
275
|
+
})
|
|
277
276
|
|
|
278
|
-
|
|
277
|
+
function normalizeContentWidthMode(value: string | null): ContentWidthMode {
|
|
278
|
+
return value === 'standard' ? 'standard' : 'wide'
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
function clearPath() {
|
|
@@ -288,28 +288,26 @@ function save() {
|
|
|
288
288
|
try {
|
|
289
289
|
const needReload =
|
|
290
290
|
showNoteId.value !== originalShowNoteId.value ||
|
|
291
|
-
sidebarDensity.value !== originalSidebarDensity.value ||
|
|
292
291
|
donePrefix.value !== originalDonePrefix.value ||
|
|
293
|
-
undonePrefix.value !== originalUndonePrefix.value
|
|
292
|
+
undonePrefix.value !== originalUndonePrefix.value ||
|
|
293
|
+
contentWidthMode.value !== originalContentWidthMode.value
|
|
294
294
|
|
|
295
295
|
localStorage.setItem(NOTES_DIR_KEY, path.value)
|
|
296
|
-
localStorage.setItem(MARKMAP_THEME_KEY, markmapTheme.value)
|
|
297
296
|
localStorage.setItem(
|
|
298
297
|
MARKMAP_EXPAND_LEVEL_KEY,
|
|
299
298
|
markmapExpandLevel.value.toString(),
|
|
300
299
|
)
|
|
301
300
|
localStorage.setItem(SIDEBAR_SHOW_NOTE_ID_KEY, showNoteId.value.toString())
|
|
302
|
-
localStorage.setItem(SIDEBAR_DENSITY_KEY, sidebarDensity.value)
|
|
303
301
|
localStorage.setItem(SIDEBAR_DONE_PREFIX_KEY, donePrefix.value)
|
|
304
302
|
localStorage.setItem(SIDEBAR_UNDONE_PREFIX_KEY, undonePrefix.value)
|
|
303
|
+
localStorage.setItem(CONTENT_WIDTH_MODE_KEY, contentWidthMode.value)
|
|
305
304
|
|
|
306
305
|
originalPath.value = path.value
|
|
307
|
-
originalMarkmapTheme.value = markmapTheme.value
|
|
308
306
|
originalMarkmapExpandLevel.value = markmapExpandLevel.value
|
|
309
307
|
originalShowNoteId.value = showNoteId.value
|
|
310
|
-
originalSidebarDensity.value = sidebarDensity.value
|
|
311
308
|
originalDonePrefix.value = donePrefix.value
|
|
312
309
|
originalUndonePrefix.value = undonePrefix.value
|
|
310
|
+
originalContentWidthMode.value = contentWidthMode.value
|
|
313
311
|
|
|
314
312
|
showSuccessToast.value = true
|
|
315
313
|
setTimeout(() => {
|
|
@@ -329,12 +327,11 @@ function save() {
|
|
|
329
327
|
|
|
330
328
|
function reset() {
|
|
331
329
|
path.value = originalPath.value
|
|
332
|
-
markmapTheme.value = originalMarkmapTheme.value
|
|
333
330
|
markmapExpandLevel.value = originalMarkmapExpandLevel.value
|
|
334
331
|
showNoteId.value = originalShowNoteId.value
|
|
335
|
-
sidebarDensity.value = originalSidebarDensity.value
|
|
336
332
|
donePrefix.value = originalDonePrefix.value
|
|
337
333
|
undonePrefix.value = originalUndonePrefix.value
|
|
334
|
+
contentWidthMode.value = originalContentWidthMode.value
|
|
338
335
|
}
|
|
339
336
|
</script>
|
|
340
337
|
|
|
@@ -431,6 +428,8 @@ function reset() {
|
|
|
431
428
|
|
|
432
429
|
.inputGroup {
|
|
433
430
|
position: relative;
|
|
431
|
+
align-self: start;
|
|
432
|
+
width: 100%;
|
|
434
433
|
}
|
|
435
434
|
|
|
436
435
|
.input,
|
|
@@ -475,6 +474,7 @@ function reset() {
|
|
|
475
474
|
width: 20px;
|
|
476
475
|
height: 20px;
|
|
477
476
|
padding: 0;
|
|
477
|
+
line-height: 1;
|
|
478
478
|
color: var(--vp-c-text-3);
|
|
479
479
|
background: transparent;
|
|
480
480
|
border: none;
|
|
@@ -536,6 +536,10 @@ function reset() {
|
|
|
536
536
|
border-radius: 6px;
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
+
.segmented-two {
|
|
540
|
+
grid-template-columns: repeat(2, 1fr);
|
|
541
|
+
}
|
|
542
|
+
|
|
539
543
|
.segment {
|
|
540
544
|
display: inline-flex;
|
|
541
545
|
align-items: center;
|