From 61b21678fe3c334297f58109cb01e5b39b70c86a Mon Sep 17 00:00:00 2001 From: Cx330 <1487537121@qq.com> Date: Thu, 13 Aug 2026 15:56:33 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8D=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content.md | 96 ++++++++--------- css/styles.css | 200 ++++++++++++++++++++++++++++++++++- index.html | 41 +++---- javascript/markmap_editor.js | 99 ++++++++++++++--- 4 files changed, 355 insertions(+), 81 deletions(-) diff --git a/content.md b/content.md index c125546..c112790 100644 --- a/content.md +++ b/content.md @@ -1,59 +1,59 @@ --- -title: Markmap Features +title: Markmap 功能示例 markmap: colorFreezeLevel: 2 direction: balanced theme: soft --- -## Themes +## 主题 -- classic -- soft -- dark -- forest -- monochrome -- minimal +- 经典 +- 柔和 +- 深色 +- 森林 +- 单色 +- 极简 -## Directions +## 方向 -- right -- left -- down -- balanced +- 向右 +- 向左 +- 向下 +- 平衡布局 -## Link Styles +## 连线样式 -- `classic` - stroke lines -- `0.3` - slight taper -- `0.5` - moderate taper -- `0.85` - brush style -- `1` - full taper +- `classic` - 直线描边 +- `0.3` - 轻微锥形 +- `0.5` - 中等锥形 +- `0.85` - 画笔风格 +- `1` - 完全锥形 -## Node Styling +## 节点样式 -### Backgrounds +### 背景 -- Capsule root node -- Rounded rect L1/L2 -- Underline L3+ -- Auto border colors +- 根节点胶囊形 +- 一级/二级圆角矩形 +- 三级及以下下划线 +- 自动边框配色 -### Typography +### 字体 -- Font size by depth -- Font weight by depth -- Auto text color (dark/light) +- 按层级缩放字号 +- 按层级调整字重 +- 自动文本配色(深/浅色) -### Effects +### 特效 -- Drop shadow (L1) -- Hover dimming -- Canvas background color +- 阴影效果(一级节点) +- 悬停变暗 +- 画布背景色 -## Directives +## 指令 -### Icons +### 图标 - `done` - `wip` @@ -64,21 +64,21 @@ markmap: - `flag` - `question` -### Relations +### 关系连线 -- `rel: target | label` -- Auto arc direction -- Collision avoidance +- `rel: 目标 | 标签` +- 自动弧线方向 +- 避免碰撞 -### Boundaries +### 边界分组 -- `boundary: name` - with title -- `boundary: name | #color` - custom color -- `boundary: | #color` - color only, no title -- `boundary` - default style +- `boundary: 名称` - 带标题 +- `boundary: 名称 | #颜色` - 自定义颜色 +- `boundary: | #颜色` - 仅颜色,无标题 +- `boundary` - 默认样式 -### Folding +### 折叠 -- `fold` - fold node -- `foldAll` - fold recursively -- Balanced: left/right independent +- `fold` - 折叠节点 +- `foldAll` - 递归折叠 +- 平衡模式:左右独立折叠 diff --git a/css/styles.css b/css/styles.css index 866a3bf..ca1fa92 100644 --- a/css/styles.css +++ b/css/styles.css @@ -58,6 +58,7 @@ header { flex-shrink: 0; box-shadow: 0 1px 8px rgba(0, 0, 0, 0.06); z-index: 100; + position: relative; -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%); border-bottom: 1px solid var(--header-border); @@ -96,6 +97,17 @@ header .toolbar { gap: 10px; } +.header-right { + display: flex; + align-items: center; + gap: 6px; +} + +/* 移动端菜单按钮:仅移动端显示 */ +#mobile-menu-btn { + display: none; +} + .icon-btn { background-color: var(--btn-bg); color: var(--text-secondary); @@ -123,7 +135,8 @@ header .toolbar { fill: currentColor; } -header .toolbar button { +header .toolbar button, +#mode-toggle { background-color: var(--btn-bg); color: var(--text-secondary); border: 1px solid var(--header-border); @@ -138,7 +151,8 @@ header .toolbar button { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); } -header .toolbar button:hover { +header .toolbar button:hover, +#mode-toggle:hover { background-color: var(--accent-soft); border-color: var(--accent-color); color: var(--accent-color); @@ -146,7 +160,8 @@ header .toolbar button:hover { box-shadow: 0 2px 8px rgba(74, 158, 255, 0.15); } -header .toolbar button:active { +header .toolbar button:active, +#mode-toggle:active { background-color: var(--accent-medium); transform: translateY(0); } @@ -367,6 +382,7 @@ main { position: relative; z-index: 10; transition: background 0.2s; + touch-action: none; } #splitter::after { @@ -714,3 +730,181 @@ body.fullscreen .markmap-toolbar { bottom: 24px; right: 24px; } + +/* ── 移动端响应式布局 ── */ +/* 窄屏设备:编辑区在上,渲染区在下,纵向排列 */ + +@media (max-width: 768px) { + /* Header:紧凑高度 */ + header { + height: 48px; + padding: 0 10px; + } + + header h1 { + font-size: 15px; + } + + .header-left { + gap: 6px; + } + + /* 日间/夜间按钮:常驻显示,缩小尺寸 */ + #mode-toggle { + padding: 5px 10px; + font-size: 12px; + } + + /* 工具栏:改为下拉浮层(用 header 前缀提升特异性,覆盖桌面端 header .toolbar) */ + header .toolbar { + display: none; + position: absolute; + top: 48px; + right: 8px; + flex-direction: column; + background: var(--header-bg); + border: 1px solid var(--header-border); + border-radius: 10px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); + -webkit-backdrop-filter: blur(20px) saturate(180%); + backdrop-filter: blur(20px) saturate(180%); + padding: 6px; + gap: 2px; + z-index: 200; + min-width: 140px; + } + + header .toolbar.show { + display: flex; + } + + header .toolbar button { + width: 100%; + text-align: left; + padding: 10px 14px; + font-size: 13px; + border: none; + background: transparent; + border-radius: 8px; + justify-content: flex-start; + } + + header .toolbar button:hover { + transform: none; + box-shadow: none; + } + + /* 主题选择器:下拉内联展开 */ + .theme-selector .theme-dropdown { + position: static; + box-shadow: none; + border: none; + background: transparent; + -webkit-backdrop-filter: none; + backdrop-filter: none; + padding: 0 0 0 12px; + min-width: 0; + } + + .theme-selector .theme-dropdown.show { + display: flex; + flex-direction: column; + } + + .theme-dropdown button { + padding: 8px 12px; + font-size: 12px; + } + + /* 显示移动端菜单按钮 */ + #mobile-menu-btn { + display: flex; + padding: 6px; + } + + /* 菜单打开时按钮激活态 */ + #mobile-menu-btn.menu-active { + background-color: var(--accent-soft); + border-color: var(--accent-color); + color: var(--accent-color); + } + + .icon-btn { + padding: 6px; + } + + /* 移动端禁用 :hover 粘连,改用 JS 控制 active 状态 */ + .icon-btn:hover, + header .toolbar button:hover, + #mode-toggle:hover { + background-color: var(--btn-bg); + border-color: var(--header-border); + color: var(--text-secondary); + transform: none; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); + } + + /* main 改为纵向排列 */ + main { + flex-direction: column; + } + + /* 编辑区:上方,固定比例高度 */ + #editor-container { + width: 100% !important; + height: 40%; + flex-shrink: 0; + } + + /* iOS 防止聚焦缩放:font-size 需 >= 16px */ + #editor { + font-size: 16px; + padding: 12px 14px; + } + + /* 分割线:改为水平方向 */ + #splitter { + width: 100%; + height: 5px; + cursor: row-resize; + } + + #splitter::after { + width: 32px; + height: 3px; + } + + /* 渲染区:下方,自动填充剩余空间 */ + #markmap-container { + flex: 1; + min-height: 0; + } + + /* 侧边栏:改为浮层覆盖 */ + #sidebar { + position: fixed; + top: 48px; + left: 0; + bottom: 0; + width: 240px; + z-index: 500; + box-shadow: 4px 0 16px rgba(0, 0, 0, 0.15); + } + + #sidebar.collapsed { + width: 0; + border-right: none; + box-shadow: none; + } + + /* 底部浮动工具栏调整 */ + .markmap-toolbar { + bottom: 12px; + right: 12px; + } + + /* footer 隐藏,节省空间 */ + footer { + display: none; + } +} diff --git a/index.html b/index.html index 05e7c52..c203af9 100644 --- a/index.html +++ b/index.html @@ -16,25 +16,30 @@

Markmap 编辑器

-
- - - - - -
- -
- - - - - - - +
+ +
+ + + + + +
+ +
+ + + + + + + +
- +
@@ -54,7 +59,7 @@
diff --git a/javascript/markmap_editor.js b/javascript/markmap_editor.js index b6c2c71..aa3a090 100644 --- a/javascript/markmap_editor.js +++ b/javascript/markmap_editor.js @@ -1099,7 +1099,48 @@ function initModeToggle() { applyMode(); } +// ── 移动端菜单 ── +// 点击 ⋮ 按钮展开/收起工具栏下拉浮层 +// 选择操作后自动收起(主题按钮除外,它有自己的子菜单) + +function initMobileMenu() { + const menuBtn = document.getElementById('mobile-menu-btn'); + const toolbar = document.querySelector('.toolbar'); + if (!menuBtn || !toolbar) return; + + function closeMenu() { + toolbar.classList.remove('show'); + menuBtn.classList.remove('menu-active'); + } + + // 点击 ⋮ 按钮切换工具栏显隐 + menuBtn.addEventListener('click', () => { + const willShow = !toolbar.classList.contains('show'); + toolbar.classList.toggle('show', willShow); + menuBtn.classList.toggle('menu-active', willShow); + }); + + // 点击工具栏内按钮后自动收起(主题按钮除外,它有自己的子菜单) + toolbar.querySelectorAll('button').forEach(btn => { + if (btn.id === 'theme-btn') return; + btn.addEventListener('click', closeMenu); + }); + + // 点击外部关闭菜单 + document.addEventListener('click', (e) => { + if (!e.target.closest('#mobile-menu-btn') && !e.target.closest('.toolbar')) { + closeMenu(); + } + }); +} + // ── 可拖动分割线 ── +// 桌面端:左右拖动调整编辑区宽度 +// 移动端:上下拖动调整编辑区高度,支持触屏 + +function isMobileLayout() { + return window.matchMedia('(max-width: 768px)').matches; +} function initSplitter() { const splitter = document.getElementById('splitter'); @@ -1109,35 +1150,68 @@ function initSplitter() { let isDragging = false; - splitter.addEventListener('mousedown', (e) => { + function onStart(e) { isDragging = true; splitter.classList.add('dragging'); - document.body.style.cursor = 'col-resize'; + document.body.style.cursor = isMobileLayout() ? 'row-resize' : 'col-resize'; document.body.style.userSelect = 'none'; e.preventDefault(); - }); + } - document.addEventListener('mousemove', (e) => { + function onMove(e) { if (!isDragging) return; const rect = main.getBoundingClientRect(); - const x = e.clientX - rect.left; - const percentage = (x / rect.width) * 100; - // 限制在 10% ~ 90% 之间 - const clamped = Math.max(10, Math.min(90, percentage)); - editorContainer.style.width = `${clamped}%`; - }); + if (isMobileLayout()) { + // 移动端:纵向拖动,调整编辑区高度 + const clientY = e.touches ? e.touches[0].clientY : e.clientY; + const y = clientY - rect.top; + const percentage = (y / rect.height) * 100; + const clamped = Math.max(15, Math.min(85, percentage)); + editorContainer.style.height = `${clamped}%`; + editorContainer.style.width = '100%'; + } else { + // 桌面端:横向拖动,调整编辑区宽度 + const clientX = e.touches ? e.touches[0].clientX : e.clientX; + const x = clientX - rect.left; + const percentage = (x / rect.width) * 100; + const clamped = Math.max(10, Math.min(90, percentage)); + editorContainer.style.width = `${clamped}%`; + editorContainer.style.height = ''; + } + } - document.addEventListener('mouseup', () => { + function onEnd() { if (isDragging) { isDragging = false; splitter.classList.remove('dragging'); document.body.style.cursor = ''; document.body.style.userSelect = ''; - // 重新适配思维导图到新容器尺寸 if (mm) mm.fit(); } + } + + // 鼠标事件 + splitter.addEventListener('mousedown', onStart); + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onEnd); + + // 触屏事件 + splitter.addEventListener('touchstart', onStart, { passive: false }); + document.addEventListener('touchmove', onMove, { passive: false }); + document.addEventListener('touchend', onEnd); + + // 窗口尺寸变化时重置布局模式 + window.addEventListener('resize', () => { + if (!isMobileLayout()) { + // 切回桌面端时清除移动端设置的 height + editorContainer.style.height = ''; + } else { + // 切到移动端时清除桌面端设置的 width + editorContainer.style.width = '100%'; + } + if (mm) mm.fit(); }); } @@ -1266,6 +1340,7 @@ async function init() { // 初始化主题选择器、模式切换和分割线 initThemeSelector(); initModeToggle(); + initMobileMenu(); initSplitter(); // 插入图片按钮