@tnotesjs/core 0.1.27 → 0.2.0

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.
Files changed (71) hide show
  1. package/README.md +2 -1
  2. package/package.json +3 -1
  3. package/templates/sub-repo/.gitattributes +30 -0
  4. package/templates/sub-repo/.github/workflows/deploy.yml +87 -0
  5. package/templates/sub-repo/.vitepress/config.mts +12 -0
  6. package/templates/sub-repo/.vitepress/env.d.ts +10 -0
  7. package/templates/sub-repo/.vitepress/theme/index.ts +12 -0
  8. package/templates/sub-repo/.vscode/settings.json +330 -0
  9. package/templates/sub-repo/.vscode/tnotes.code-snippets +110 -0
  10. package/templates/sub-repo/public/favicon.ico +0 -0
  11. package/templates/sub-repo/public/logo.png +0 -0
  12. package/templates/sub-repo/tsconfig.json +45 -0
  13. package/vitepress/assets/icons/icon__setting_dark.svg +4 -0
  14. package/vitepress/assets/icons/icon__setting_light.svg +4 -0
  15. package/vitepress/assets/icons/index.ts +2 -2
  16. package/vitepress/client/localSearchIndexBridge.ts +24 -0
  17. package/vitepress/components/Discussions/Discussions.vue +1 -1
  18. package/vitepress/components/Footprints/Footprints.vue +90 -25
  19. package/vitepress/components/Layout/CustomSidebar.vue +489 -117
  20. package/vitepress/components/Layout/Layout.vue +5 -0
  21. package/vitepress/components/Layout/NavBarSettingsTrigger.vue +10 -2
  22. package/vitepress/components/Layout/SidebarItems.vue +517 -342
  23. package/vitepress/components/Layout/SidebarNavBefore.vue +1 -50
  24. package/vitepress/components/Layout/SidebarResizeHandle.vue +6 -23
  25. package/vitepress/components/Layout/composables/docLayoutLogic.ts +59 -0
  26. package/vitepress/components/Layout/composables/useDocLayout.test.ts +69 -0
  27. package/vitepress/components/Layout/composables/useDocLayout.ts +128 -0
  28. package/vitepress/components/Layout/composables/useSidebarDrag.ts +514 -0
  29. package/vitepress/components/Layout/composables/useSidebarLayout.ts +25 -8
  30. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +8 -3
  31. package/vitepress/components/Layout/sidebarCollapsedState.test.ts +183 -0
  32. package/vitepress/components/Layout/sidebarCollapsedState.ts +241 -0
  33. package/vitepress/components/Layout/sidebarDragLogic.test.ts +1146 -0
  34. package/vitepress/components/Layout/sidebarDragLogic.ts +1307 -0
  35. package/vitepress/components/Layout/sidebarHitTest.test.ts +572 -0
  36. package/vitepress/components/Layout/sidebarHitTest.ts +801 -0
  37. package/vitepress/components/Layout/sidebarItemRenderLogic.test.ts +53 -0
  38. package/vitepress/components/Layout/sidebarItemRenderLogic.ts +50 -0
  39. package/vitepress/components/MarkMap/MarkMap.vue +67 -10
  40. package/vitepress/components/Settings/Settings.vue +78 -74
  41. package/vitepress/components/SidebarCard/FolderTreeItems.vue +268 -0
  42. package/vitepress/components/SidebarCard/SidebarCard.vue +125 -274
  43. package/vitepress/components/constants.ts +18 -6
  44. package/vitepress/components/sidebar.data.ts +13 -11
  45. package/vitepress/components/sidebarTreeHelpers.test.ts +142 -0
  46. package/vitepress/components/sidebarTreeHelpers.ts +168 -0
  47. package/vitepress/components/utils/vscodePaths.test.ts +41 -0
  48. package/vitepress/components/utils/vscodePaths.ts +52 -0
  49. package/vitepress/config/index.ts +2 -0
  50. package/vitepress/plugins/localSearchIndexBuilder.ts +209 -0
  51. package/vitepress/plugins/localSearchReindex.test.ts +46 -0
  52. package/vitepress/plugins/localSearchReindexLogic.ts +50 -0
  53. package/vitepress/plugins/localSearchReindexPatch.test.ts +30 -0
  54. package/vitepress/plugins/localSearchReindexPatch.ts +37 -0
  55. package/vitepress/plugins/localSearchReindexPlugin.ts +318 -0
  56. package/vitepress/plugins/sidebarStructurePlugin.ts +209 -63
  57. package/vitepress/theme/index.ts +8 -0
  58. package/vitepress/theme/styles/base.scss +0 -8
  59. package/vitepress/theme/styles/components/markmap.scss +23 -2
  60. package/vitepress/theme/styles/components/swiper.scss +1 -1
  61. package/vitepress/theme/styles/doc-layout.scss +212 -0
  62. package/vitepress/theme/styles/index.scss +3 -0
  63. package/vitepress/theme/styles/layout.scss +60 -10
  64. package/dist/chunk-4KG6RXFS.js +0 -4637
  65. package/dist/chunk-AGSL3VZE.js +0 -193
  66. package/dist/cli/index.js +0 -683
  67. package/dist/index.js +0 -8
  68. package/dist/vitepress/config/index.js +0 -1178
  69. package/vitepress/assets/icons/icon__mindmap.svg +0 -1
  70. package/vitepress/assets/icons/icon__setting.svg +0 -1
  71. package/vitepress/components/SidebarCard/MindMapView.vue +0 -488
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 48 48"><path fill="none" stroke="#646cff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M26 24h16M26 38h16M26 10h16M18 24H6h4m8 14c-6-2-2-14-8-14m8-14c-6 2-2 14-8 14"/></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#67676c" d="M19.9 12.66a1 1 0 0 1 0-1.32l1.28-1.44a1 1 0 0 0 .12-1.17l-2-3.46a1 1 0 0 0-1.07-.48l-1.88.38a1 1 0 0 1-1.15-.66l-.61-1.83a1 1 0 0 0-.95-.68h-4a1 1 0 0 0-1 .68l-.56 1.83a1 1 0 0 1-1.15.66L5 4.79a1 1 0 0 0-1 .48L2 8.73a1 1 0 0 0 .1 1.17l1.27 1.44a1 1 0 0 1 0 1.32L2.1 14.1a1 1 0 0 0-.1 1.17l2 3.46a1 1 0 0 0 1.07.48l1.88-.38a1 1 0 0 1 1.15.66l.61 1.83a1 1 0 0 0 1 .68h4a1 1 0 0 0 .95-.68l.61-1.83a1 1 0 0 1 1.15-.66l1.88.38a1 1 0 0 0 1.07-.48l2-3.46a1 1 0 0 0-.12-1.17ZM18.41 14l.8.9l-1.28 2.22l-1.18-.24a3 3 0 0 0-3.45 2L12.92 20h-2.56L10 18.86a3 3 0 0 0-3.45-2l-1.18.24l-1.3-2.21l.8-.9a3 3 0 0 0 0-4l-.8-.9l1.28-2.2l1.18.24a3 3 0 0 0 3.45-2L10.36 4h2.56l.38 1.14a3 3 0 0 0 3.45 2l1.18-.24l1.28 2.22l-.8.9a3 3 0 0 0 0 3.98m-6.77-6a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2"/></svg>
@@ -1,488 +0,0 @@
1
- <!--
2
- vitepress/components/SidebarCard/MindMapView.vue
3
- -->
4
-
5
- <script setup>
6
- import { scaleOrdinal, schemePastel2, schemeSet3, schemeTableau10 } from 'd3'
7
- import { Transformer } from 'markmap-lib'
8
- import { Toolbar } from 'markmap-toolbar'
9
- import 'markmap-toolbar/dist/style.css'
10
- import { Markmap } from 'markmap-view'
11
- import { withBase, useData } from 'vitepress'
12
- import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
13
-
14
- import {
15
- icon__fullscreen,
16
- icon__fullscreen_exit,
17
- icon__confirm,
18
- } from '../../assets/icons'
19
- import {
20
- MARKMAP_THEME_KEY,
21
- MARKMAP_EXPAND_LEVEL_KEY,
22
- REPO_NAME,
23
- } from '../constants'
24
-
25
- const props = defineProps({
26
- sidebarData: {
27
- type: Array,
28
- required: true,
29
- },
30
- })
31
-
32
- const svgRef = ref(null)
33
- const containerRef = ref(null)
34
- const expandLevel = ref(2)
35
- const isFullscreen = ref(false)
36
- const markmapTheme = ref('default')
37
-
38
- const containerBg = computed(() =>
39
- markmapTheme.value === 'dark' ? '#1d1d1d' : '#ffffff',
40
- )
41
-
42
- let markmapInstance = null
43
- let toolbarEl = null
44
- let toolbarLevelInput = null
45
- let darkClassObserver = null
46
- const transformer = new Transformer()
47
- const { isDark } = useData()
48
-
49
- // 同步暗色状态到 markmap-dark 类(markmap 内部样式依赖此类)
50
- function syncMarkmapDark(dark) {
51
- if (dark) {
52
- document.documentElement.classList.add('markmap-dark')
53
- } else {
54
- document.documentElement.classList.remove('markmap-dark')
55
- }
56
- }
57
-
58
- watch(isDark, (val) => syncMarkmapDark(val))
59
- watch(markmapTheme, (val) => syncMarkmapDark(val === 'dark'))
60
-
61
- // 读取 localStorage 配置
62
- function loadSettings() {
63
- if (typeof window === 'undefined') return
64
- const savedTheme = localStorage.getItem(MARKMAP_THEME_KEY)
65
- if (savedTheme && ['default', 'colorful', 'dark'].includes(savedTheme)) {
66
- markmapTheme.value = savedTheme
67
- }
68
- const savedLevel = localStorage.getItem(MARKMAP_EXPAND_LEVEL_KEY)
69
- if (savedLevel) {
70
- const level = parseInt(savedLevel)
71
- if (!isNaN(level) && level >= 1 && level <= 100) {
72
- expandLevel.value = level
73
- }
74
- }
75
- }
76
-
77
- const getThemeColorFn = () => {
78
- const theme = markmapTheme.value
79
- switch (theme) {
80
- case 'colorful':
81
- return scaleOrdinal(schemeTableau10)
82
- case 'dark':
83
- return scaleOrdinal(schemeSet3)
84
- default:
85
- return scaleOrdinal(schemePastel2)
86
- }
87
- }
88
-
89
- // 将 sidebar 数据转换为 markdown
90
- function sidebarToMarkdown(items, level = 1, isRoot = true) {
91
- if (level === 1 && isRoot) {
92
- const rootName = REPO_NAME.replace(/^TNotes\./, '')
93
- const rootMarkdown = `# ${rootName}\n\n`
94
- const childrenMarkdown = sidebarToMarkdown(items, 1, false)
95
- return rootMarkdown + childrenMarkdown
96
- }
97
-
98
- return items
99
- .map((item) => {
100
- const indent = ' '.repeat(level - 1)
101
- let text
102
- if (item.link) {
103
- const encodedLink = withBase(item.link).replace(/ /g, '%20')
104
- text = `[${item.text}](${encodedLink})`
105
- } else if (level === 1) {
106
- text = `**${item.text}**`
107
- } else {
108
- text = item.text
109
- }
110
-
111
- let markdown = `${indent}- ${text}\n`
112
- if (item.items && item.items.length > 0) {
113
- markdown += sidebarToMarkdown(item.items, level + 1, false)
114
- }
115
- return markdown
116
- })
117
- .join('')
118
- }
119
-
120
- function renderMindmap() {
121
- if (!props.sidebarData || !svgRef.value) return
122
-
123
- nextTick().then(() => {
124
- if (markmapInstance) {
125
- try {
126
- markmapInstance.destroy()
127
- } catch {}
128
- markmapInstance = null
129
- }
130
-
131
- if (!svgRef.value) return
132
-
133
- const markdown = sidebarToMarkdown(props.sidebarData)
134
- if (!markdown.trim()) {
135
- svgRef.value.innerHTML = '<text x="20" y="30" fill="#999">空内容</text>'
136
- return
137
- }
138
-
139
- try {
140
- const { root } = transformer.transform(markdown)
141
- const colorFn = getThemeColorFn()
142
- const options = {
143
- initialExpandLevel: expandLevel.value,
144
- duration: 100,
145
- nodeMinHeight: 24,
146
- spacingVertical: 10,
147
- spacingHorizontal: 20,
148
- maxWidth: 400,
149
- maxInitialScale: 2,
150
- color: (node) => colorFn(`${node.state?.path || ''}`),
151
- }
152
-
153
- markmapInstance = Markmap.create(svgRef.value, options, root)
154
-
155
- // 为链接添加 target="_blank"
156
- setTimeout(() => {
157
- if (svgRef.value) {
158
- svgRef.value.querySelectorAll('a').forEach((link) => {
159
- link.setAttribute('target', '_blank')
160
- })
161
- }
162
- }, 100)
163
-
164
- setTimeout(() => {
165
- try {
166
- markmapInstance?.fit()
167
- } catch {}
168
- }, 0)
169
-
170
- initToolbar()
171
- } catch (error) {
172
- console.error('Markmap render error:', error)
173
- if (svgRef.value) {
174
- svgRef.value.innerHTML =
175
- '<text x="20" y="30" fill="red">思维导图渲染错误</text>'
176
- }
177
- }
178
- })
179
- }
180
-
181
- function initToolbar() {
182
- if (!markmapInstance || !containerRef.value) return
183
-
184
- if (toolbarEl) {
185
- toolbarEl.remove()
186
- toolbarEl = null
187
- toolbarLevelInput = null
188
- }
189
-
190
- const { el } = Toolbar.create(markmapInstance)
191
- toolbarEl = el
192
- toolbarEl.style.position = 'absolute'
193
- toolbarEl.style.top = '1rem'
194
- toolbarEl.style.right = '0.5rem'
195
- toolbarEl.style.scale = '0.8'
196
- toolbarEl.style.zIndex = '10'
197
-
198
- const brand = toolbarEl.querySelector('.mm-toolbar-brand')
199
- if (brand) toolbarEl.removeChild(brand)
200
-
201
- addLevelControl(toolbarEl)
202
- addFullscreenButton(toolbarEl)
203
-
204
- containerRef.value.appendChild(toolbarEl)
205
- }
206
-
207
- function addLevelControl(toolbar) {
208
- const container = document.createElement('div')
209
- container.style.display = 'flex'
210
- container.style.alignItems = 'center'
211
- container.style.gap = '8px'
212
- container.style.marginRight = '5px'
213
-
214
- const levelInput = document.createElement('input')
215
- levelInput.type = 'number'
216
- levelInput.min = '1'
217
- levelInput.max = '100'
218
- levelInput.value = expandLevel.value.toString()
219
- levelInput.style.width = '2.4rem'
220
- levelInput.style.height = '1.6rem'
221
- levelInput.style.padding = '2px 6px'
222
- levelInput.style.fontSize = '12px'
223
- levelInput.style.lineHeight = '1.2'
224
- levelInput.style.textAlign = 'center'
225
- levelInput.style.boxSizing = 'border-box'
226
- levelInput.style.borderBottom = '.5px solid var(--vp-c-tip-1)'
227
- levelInput.style.color = 'var(--vp-c-tip-1)'
228
- levelInput.title = '展开层级'
229
-
230
- toolbarLevelInput = levelInput
231
-
232
- levelInput.addEventListener('input', (e) => {
233
- const input = e.target
234
- let value = parseInt(input.value)
235
- if (input.value === '' || isNaN(value)) return
236
- if (value < 1) input.value = '1'
237
- else if (value > 100) input.value = '100'
238
- })
239
-
240
- levelInput.addEventListener('change', (e) => {
241
- const value = parseInt(e.target.value)
242
- if (!isNaN(value) && value >= 1 && value <= 100) {
243
- expandLevel.value = value
244
- } else {
245
- levelInput.value = expandLevel.value.toString()
246
- }
247
- })
248
-
249
- levelInput.addEventListener('keydown', (e) => {
250
- if (e.key === 'Enter') {
251
- const val = parseInt(e.target.value)
252
- if (!isNaN(val) && val >= 1 && val <= 100) {
253
- expandLevel.value = val
254
- } else {
255
- levelInput.value = expandLevel.value.toString()
256
- }
257
- onUpdateClick()
258
- }
259
- })
260
-
261
- const updateBtn = document.createElement('button')
262
- updateBtn.type = 'button'
263
- updateBtn.className = 'mm-toolbar-item'
264
- updateBtn.title = '确定层级并更新'
265
- updateBtn.innerHTML = `<img src="${icon__confirm}" alt="确定" style="width:16px;height:16px;display:block" />`
266
- updateBtn.addEventListener('click', onUpdateClick)
267
-
268
- container.appendChild(levelInput)
269
- container.appendChild(updateBtn)
270
- toolbar.insertBefore(container, toolbar.firstChild)
271
- }
272
-
273
- function addFullscreenButton(toolbar) {
274
- const fullscreenBtn = document.createElement('div')
275
- fullscreenBtn.className = 'mm-toolbar-item'
276
- fullscreenBtn.title = isFullscreen.value ? '退出全屏' : '全屏'
277
- fullscreenBtn.innerHTML = isFullscreen.value
278
- ? `<img src="${icon__fullscreen_exit}" alt="退出全屏" style="width:18px;height:18px;display:block" />`
279
- : `<img src="${icon__fullscreen}" alt="全屏" style="width:18px;height:18px;display:block" />`
280
- fullscreenBtn.addEventListener('click', toggleFullscreen)
281
- toolbar.appendChild(fullscreenBtn)
282
- }
283
-
284
- function onUpdateClick() {
285
- localStorage.setItem(MARKMAP_EXPAND_LEVEL_KEY, expandLevel.value.toString())
286
- renderMindmap()
287
- }
288
-
289
- function toggleFullscreen() {
290
- if (!containerRef.value) return
291
-
292
- if (!isFullscreen.value) {
293
- if (containerRef.value.requestFullscreen) {
294
- containerRef.value.requestFullscreen().catch((err) => {
295
- console.error('全屏请求失败:', err)
296
- })
297
- } else if (containerRef.value.webkitRequestFullscreen) {
298
- containerRef.value.webkitRequestFullscreen()
299
- }
300
- } else {
301
- if (document.exitFullscreen) {
302
- document.exitFullscreen()
303
- } else if (document.webkitExitFullscreen) {
304
- document.webkitExitFullscreen()
305
- }
306
- }
307
- }
308
-
309
- function handleFullscreenChange() {
310
- isFullscreen.value = !!(
311
- document.fullscreenElement || document.webkitFullscreenElement
312
- )
313
-
314
- if (toolbarEl) {
315
- const fullscreenBtn = Array.from(toolbarEl.children).find((child) =>
316
- child.querySelector('img[alt="全屏"], img[alt="退出全屏"]'),
317
- )
318
- if (fullscreenBtn) {
319
- fullscreenBtn.title = isFullscreen.value ? '退出全屏' : '全屏'
320
- fullscreenBtn.innerHTML = isFullscreen.value
321
- ? `<img src="${icon__fullscreen_exit}" alt="退出全屏" style="width:18px;height:18px;display:block" />`
322
- : `<img src="${icon__fullscreen}" alt="全屏" style="width:18px;height:18px;display:block" />`
323
- }
324
- }
325
-
326
- if (svgRef.value) {
327
- if (isFullscreen.value) {
328
- svgRef.value.style.height = 'calc(100vh - 100px)'
329
- } else {
330
- svgRef.value.style.height = ''
331
- }
332
-
333
- setTimeout(() => {
334
- try {
335
- markmapInstance?.fit()
336
- } catch {}
337
- }, 300)
338
- }
339
- }
340
-
341
- watch(expandLevel, (v) => {
342
- if (toolbarLevelInput) {
343
- const asStr = (v || 0).toString()
344
- if (toolbarLevelInput.value !== asStr) {
345
- toolbarLevelInput.value = asStr
346
- }
347
- }
348
- })
349
-
350
- watch(
351
- () => props.sidebarData,
352
- () => renderMindmap(),
353
- { deep: true },
354
- )
355
-
356
- onMounted(() => {
357
- loadSettings()
358
- syncMarkmapDark(markmapTheme.value === 'dark' || isDark.value)
359
- document.addEventListener('fullscreenchange', handleFullscreenChange)
360
- document.addEventListener('webkitfullscreenchange', handleFullscreenChange)
361
-
362
- // 监听 markmap 工具栏切换暗色主题(它直接 toggle markmap-dark 类,不通知 Vue)
363
- darkClassObserver = new MutationObserver(() => {
364
- const hasDark = document.documentElement.classList.contains('markmap-dark')
365
- markmapTheme.value = hasDark ? 'dark' : 'default'
366
- })
367
- darkClassObserver.observe(document.documentElement, {
368
- attributes: true,
369
- attributeFilter: ['class'],
370
- })
371
-
372
- renderMindmap()
373
- })
374
-
375
- onBeforeUnmount(() => {
376
- if (markmapInstance) {
377
- try {
378
- markmapInstance.destroy()
379
- } catch {}
380
- markmapInstance = null
381
- }
382
- if (toolbarEl) {
383
- toolbarEl.remove()
384
- toolbarEl = null
385
- toolbarLevelInput = null
386
- }
387
- document.removeEventListener('fullscreenchange', handleFullscreenChange)
388
- document.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
389
- if (darkClassObserver) {
390
- darkClassObserver.disconnect()
391
- darkClassObserver = null
392
- }
393
- })
394
- </script>
395
-
396
- <template>
397
- <div class="mindmap-view">
398
- <div
399
- ref="containerRef"
400
- class="mindmap-container"
401
- :style="{ backgroundColor: containerBg }"
402
- >
403
- <svg ref="svgRef"></svg>
404
- </div>
405
- </div>
406
- </template>
407
-
408
- <style scoped lang="scss">
409
- .mindmap-view {
410
- width: 100%;
411
- padding: 1rem 0;
412
- display: flex;
413
- flex-direction: column;
414
-
415
- .mindmap-container {
416
- width: 100%;
417
- height: 500px;
418
- position: relative;
419
- overflow: hidden;
420
- border-radius: 8px;
421
- padding: 1rem;
422
- transition: all 0.3s ease;
423
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
424
- box-sizing: border-box;
425
-
426
- &:hover {
427
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
428
- }
429
-
430
- svg {
431
- width: 100%;
432
- height: 100%;
433
- display: block;
434
- transition: height 0.3s ease;
435
- }
436
-
437
- /* 鼠标悬停显示 toolbar */
438
- &:hover :deep(.mm-toolbar) {
439
- opacity: 1;
440
- pointer-events: auto;
441
- }
442
- }
443
- }
444
-
445
-
446
- /* 暗色主题 */
447
- :global(.dark) .mindmap-container,
448
- :global(.markmap-dark) .mindmap-container {
449
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
450
-
451
- &:hover {
452
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
453
- }
454
- }
455
-
456
- /* 全屏样式 */
457
- .mindmap-container:fullscreen,
458
- .mindmap-container:-webkit-full-screen {
459
- width: 100%;
460
- height: 100%;
461
- padding: 20px;
462
- background: white;
463
- display: flex;
464
- flex-direction: column;
465
- justify-content: center;
466
- box-shadow: none;
467
- }
468
-
469
- :global(.dark) .mindmap-container:fullscreen,
470
- :global(.dark) .mindmap-container:-webkit-full-screen,
471
- :global(.markmap-dark) .mindmap-container:fullscreen,
472
- :global(.markmap-dark) .mindmap-container:-webkit-full-screen {
473
- background: #1d1d1d;
474
- }
475
-
476
- @media (max-width: 768px) {
477
- .mindmap-container {
478
- height: 400px;
479
- padding: 0.75rem;
480
- }
481
- }
482
-
483
- @media (max-width: 480px) {
484
- .mindmap-container {
485
- padding: 0.5rem;
486
- }
487
- }
488
- </style>