write(ui): 三栏宽度可拖拽 + localStorage 持久化
deploy articulate / build-and-deploy (push) Successful in 1m15s
deploy cube / build-and-deploy (push) Successful in 1m40s
deploy karaoke / build-and-deploy (push) Successful in 1m6s
deploy llm-proxy / build-and-deploy (push) Successful in 2m3s
deploy music / build-and-deploy (push) Successful in 2m16s
deploy notes / build-and-deploy (push) Successful in 2m2s
deploy simpleasm / build-and-deploy (push) Successful in 1m30s
deploy werewolf / build-and-deploy (push) Successful in 1m12s
deploy write / build-and-deploy (push) Successful in 1m54s
deploy articulate / build-and-deploy (push) Successful in 1m15s
deploy cube / build-and-deploy (push) Successful in 1m40s
deploy karaoke / build-and-deploy (push) Successful in 1m6s
deploy llm-proxy / build-and-deploy (push) Successful in 2m3s
deploy music / build-and-deploy (push) Successful in 2m16s
deploy notes / build-and-deploy (push) Successful in 2m2s
deploy simpleasm / build-and-deploy (push) Successful in 1m30s
deploy werewolf / build-and-deploy (push) Successful in 1m12s
deploy write / build-and-deploy (push) Successful in 1m54s
- sidebar | workspace 拖拽条:调整侧栏宽(180-500px) - editor | preview 拖拽条:调整源码/预览比例(15%-85%) - CSS var --sidebar-w / --editor-fr / --preview-fr 驱动 grid-template-columns - 鼠标 down 开始 drag,move 实时算 px/dx,up 落盘 localStorage - 移动端(<768px)自动隐藏拖拽条,回到 100% 切 tab 模式
This commit is contained in:
Generated
+194
-7
@@ -56,6 +56,7 @@ checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"base64",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
@@ -75,8 +76,10 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sha1",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -116,12 +119,27 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.1"
|
||||
@@ -150,6 +168,25 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cube"
|
||||
version = "0.1.0"
|
||||
@@ -174,6 +211,22 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
@@ -319,6 +372,16 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
@@ -882,7 +945,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
@@ -897,13 +960,13 @@ dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand",
|
||||
"rand 0.9.4",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
@@ -938,14 +1001,35 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -955,7 +1039,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1188,6 +1281,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
@@ -1297,13 +1401,33 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1400,6 +1524,18 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.18"
|
||||
@@ -1550,6 +1686,30 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.6",
|
||||
"sha1",
|
||||
"thiserror 1.0.69",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
@@ -1580,6 +1740,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
@@ -1901,6 +2067,27 @@ version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "write"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"cube-core",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"reqwest",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.3"
|
||||
|
||||
@@ -10,6 +10,7 @@ members = [
|
||||
"apps/karaoke",
|
||||
"apps/notes",
|
||||
"apps/llm-proxy",
|
||||
"apps/write",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
|
||||
@@ -14,6 +14,62 @@ const statusErr = ref(false)
|
||||
const busy = ref(false)
|
||||
const recording = ref(false)
|
||||
|
||||
onMounted(() => applyLayoutVars())
|
||||
|
||||
// ====== 拖拽布局:sidebar 宽(px) + editor/preview 比例(0-1)======
|
||||
const sidebarW = ref(parseInt(localStorage.getItem('write.sidebarW') || '260'))
|
||||
const editorRatio = ref(parseFloat(localStorage.getItem('write.editorRatio') || '0.5'))
|
||||
|
||||
function applyLayoutVars(): void {
|
||||
const r = document.documentElement
|
||||
r.style.setProperty('--sidebar-w', sidebarW.value + 'px')
|
||||
r.style.setProperty('--editor-fr', editorRatio.value + 'fr')
|
||||
r.style.setProperty('--preview-fr', (1 - editorRatio.value) + 'fr')
|
||||
}
|
||||
|
||||
let dragKind: 'sidebar' | 'editor' | null = null
|
||||
let dragStartX = 0
|
||||
let dragStartVal = 0
|
||||
let dragPaneW = 0
|
||||
|
||||
function startDrag(e: MouseEvent, kind: 'sidebar' | 'editor'): void {
|
||||
dragKind = kind
|
||||
dragStartX = e.clientX
|
||||
if (kind === 'sidebar') {
|
||||
dragStartVal = sidebarW.value
|
||||
} else {
|
||||
dragStartVal = editorRatio.value
|
||||
const pane = (e.currentTarget as HTMLElement).parentElement
|
||||
dragPaneW = pane ? pane.offsetWidth : window.innerWidth
|
||||
}
|
||||
document.body.style.cursor = 'col-resize'
|
||||
document.body.style.userSelect = 'none'
|
||||
window.addEventListener('mousemove', onDrag)
|
||||
window.addEventListener('mouseup', endDrag)
|
||||
e.preventDefault()
|
||||
}
|
||||
function onDrag(e: MouseEvent): void {
|
||||
if (!dragKind) return
|
||||
const dx = e.clientX - dragStartX
|
||||
if (dragKind === 'sidebar') {
|
||||
sidebarW.value = Math.max(180, Math.min(500, dragStartVal + dx))
|
||||
} else {
|
||||
const newR = dragStartVal + dx / Math.max(1, dragPaneW)
|
||||
editorRatio.value = Math.max(0.15, Math.min(0.85, newR))
|
||||
}
|
||||
applyLayoutVars()
|
||||
}
|
||||
function endDrag(): void {
|
||||
if (!dragKind) return
|
||||
localStorage.setItem('write.sidebarW', String(sidebarW.value))
|
||||
localStorage.setItem('write.editorRatio', String(editorRatio.value))
|
||||
dragKind = null
|
||||
document.body.style.cursor = ''
|
||||
document.body.style.userSelect = ''
|
||||
window.removeEventListener('mousemove', onDrag)
|
||||
window.removeEventListener('mouseup', endDrag)
|
||||
}
|
||||
|
||||
const needToken = ref(!getToken())
|
||||
const tokenInput = ref('')
|
||||
|
||||
@@ -218,6 +274,8 @@ onMounted(() => {
|
||||
|
||||
<div class="sidebar-backdrop" @click="drawerOpen = false"></div>
|
||||
|
||||
<div class="splitter splitter-main" @mousedown="startDrag($event, 'sidebar')" title="拖动调整侧栏宽度"></div>
|
||||
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>✍ write</h1>
|
||||
@@ -256,6 +314,7 @@ onMounted(() => {
|
||||
:disabled="activeId === null"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="splitter splitter-editor" @mousedown="startDrag($event, 'editor')" title="拖动调整源码/预览比例"></div>
|
||||
<div class="preview" v-html="renderedPreview"></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ textarea, input { font: inherit; }
|
||||
|
||||
.app {
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
grid-template-columns: var(--sidebar-w, 260px) 6px 1fr;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@@ -92,11 +92,25 @@ textarea, input { font: inherit; }
|
||||
|
||||
.editor-pane {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-columns: var(--editor-fr, 1fr) 6px var(--preview-fr, 1fr);
|
||||
min-height: 0;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
/* 拖拽分隔条 */
|
||||
.splitter {
|
||||
background: #e5e5e5;
|
||||
cursor: col-resize;
|
||||
transition: background 0.12s;
|
||||
user-select: none;
|
||||
}
|
||||
.splitter:hover { background: #b0c5ff; }
|
||||
.splitter-main { /* sidebar | workspace */ }
|
||||
.splitter-editor { /* editor | preview */ }
|
||||
@media (max-width: 768px) {
|
||||
.splitter { display: none; }
|
||||
}
|
||||
|
||||
.title-row {
|
||||
grid-column: 1 / -1;
|
||||
padding: 10px 16px;
|
||||
|
||||
Reference in New Issue
Block a user