feat: v0.11.0 VS Code-like explorer, markdown preview, search in files
- Explorer: context menus, multi-select, inline rename/new, drag to move or copy, desktop drag-and-drop uploads (folders too), cut/copy/paste, duplicate, download, delete to a 7-day trash with Undo. Server side in libexec/devdesk-fsops.sh with bats tests. Closes #54 - Markdown preview in a shadow root: headings with anchors and outline, highlighted code with copy, callouts, task lists, front matter, links that open files, live split view. Editor status bar, multi-cursor, closeBrackets, Ctrl+G, tab menus and reordering. Closes #55 - Search in files (Ctrl+Shift+F) via git grep / grep. Closes #56 - Fix: nested $(...) path checks now fail hard (set -e does not reach them; an escape created /x in testing); newest folder listing wins; sessionAction returns the reply JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WHRLCCdXYm41Qx5kNhehaP
This commit is contained in:
+76
-2
@@ -799,7 +799,7 @@ body.dd-resizing .dd-files-resizer { background: linear-gradient(90deg, transpar
|
||||
.dd-explorer-resizer { flex: 0 0 4px; margin-left: -2px; margin-right: -2px; cursor: col-resize; z-index: 2; }
|
||||
.dd-explorer-resizer:hover { background: var(--accent-cyan); }
|
||||
.dd-explorer-views { display: flex; border-bottom: 1px solid var(--border-dim); }
|
||||
.dd-explorer-views button {
|
||||
.dd-explorer-views button[role="tab"] {
|
||||
flex: 1;
|
||||
padding: 6px 4px 5px;
|
||||
border: 0;
|
||||
@@ -812,7 +812,7 @@ body.dd-resizing .dd-files-resizer { background: linear-gradient(90deg, transpar
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dd-explorer-views button:hover { color: var(--text-primary); }
|
||||
.dd-explorer-views button[role="tab"]:hover { color: var(--text-primary); }
|
||||
.dd-explorer-views button[aria-selected="true"] { color: var(--accent-orange); border-bottom-color: var(--accent-orange); }
|
||||
.dd-files-count:not(:empty) { margin-left: 3px; padding: 0 5px; border-radius: 8px; background: var(--accent-amber-dim); color: var(--accent-amber); font-size: 0.6rem; }
|
||||
.dd-explorer-body { flex: 1; min-height: 0; overflow: auto; padding: 4px 0 12px; outline: none; }
|
||||
@@ -1070,3 +1070,77 @@ body.dd-touch .dd-footer-usage { display: none; }
|
||||
.dd-repo-change-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dd-repo-change-stat { flex: none; color: var(--text-muted); }
|
||||
.dd-link-btn { padding: 0; border: 0; background: none; color: var(--accent-cyan); font: inherit; text-decoration: underline dotted; cursor: pointer; }
|
||||
|
||||
/* Toast actions (Undo) and right-click menus (devdesk#54) */
|
||||
.lt-toast-action { flex: none; padding: 2px 8px; border: 1px solid currentColor; background: none; color: inherit; font: inherit; font-size: 0.72rem; cursor: pointer; }
|
||||
.lt-toast-action:hover { background: var(--accent-cyan-dim); }
|
||||
.dd-ctx-menu { position: fixed; top: 0; left: 0; z-index: 200; min-width: 220px; max-height: 80vh; }
|
||||
.dd-ctx-menu .dd-menu-item { justify-content: space-between; padding: 5px 10px; }
|
||||
.dd-ctx-menu .dd-menu-item.is-danger { color: var(--accent-red); }
|
||||
.dd-ctx-kbd { margin-left: 24px; color: var(--text-muted); font-family: var(--font-mono); font-size: 0.66rem; }
|
||||
.dd-menu-sep { height: 1px; margin: 4px 6px; background: var(--border-dim); }
|
||||
|
||||
/* Explorer operations (devdesk#54) */
|
||||
.dd-explorer-actions { display: flex; align-items: center; gap: 1px; padding: 0 4px; border-left: 1px solid var(--border-dim); }
|
||||
.dd-explorer-actions .dd-icon-btn { width: 24px; height: 24px; padding: 0; font-size: 0.82rem; line-height: 1; }
|
||||
.dd-files:not([data-view="explorer"]) .dd-explorer-actions { display: none; }
|
||||
.dd-tree-row.is-selected { background: var(--accent-cyan-dim); }
|
||||
.dd-tree-row.is-selected.is-active { box-shadow: inset 2px 0 0 var(--accent-cyan); }
|
||||
.dd-explorer-body:focus-within .dd-tree-row.is-selected { background: rgba(0, 150, 220, 0.22); }
|
||||
.dd-tree-row.is-cut { opacity: 0.45; }
|
||||
.dd-tree-row.is-drop { background: var(--accent-orange-dim); }
|
||||
.dd-tree-row.is-drop.is-dir { box-shadow: inset 0 0 0 1px var(--accent-orange); }
|
||||
.dd-explorer-body.is-drop { background: var(--accent-orange-dim); box-shadow: inset 0 0 0 1px var(--accent-orange); }
|
||||
.dd-tree-row.is-editing { cursor: default; background: var(--bg-tertiary); }
|
||||
.dd-tree-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 20px;
|
||||
padding: 0 4px;
|
||||
border: 1px solid var(--accent-cyan);
|
||||
background: var(--bg-input, var(--bg-primary));
|
||||
color: var(--text-primary);
|
||||
font: inherit;
|
||||
outline: none;
|
||||
}
|
||||
.dd-upload-bar { display: flex; flex-direction: column; gap: 4px; padding: 6px 10px; border-top: 1px solid var(--border-dim); font-size: 0.68rem; color: var(--text-secondary); }
|
||||
.dd-upload-bar[hidden] { display: none; }
|
||||
.dd-upload-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dd-upload-meter { height: 3px; background: var(--bg-tertiary); }
|
||||
.dd-upload-fill { display: block; width: 0; height: 100%; background: var(--accent-cyan); transition: width 0.15s linear; }
|
||||
.dd-drag-ghost { position: fixed; top: -100px; left: -100px; padding: 3px 10px; background: var(--accent-cyan); color: var(--bg-primary); font-family: var(--font-mono); font-size: 0.72rem; font-weight: 700; }
|
||||
|
||||
/* Markdown preview and split, editor status bar (devdesk#55) */
|
||||
.dd-viewer-content.is-preview { overflow: hidden; }
|
||||
.dd-md-host { flex: 1; min-height: 0; outline: none; }
|
||||
.dd-viewer-content.is-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
|
||||
.dd-split-editor { min-width: 0; height: 100%; overflow: hidden; border-right: 1px solid var(--border-dim); }
|
||||
.dd-split-editor .cm-editor { height: 100%; }
|
||||
.dd-split-preview { min-width: 0; }
|
||||
.dd-editor-status { display: flex; align-items: center; gap: 14px; flex: none; height: 22px; padding: 0 10px; border-top: 1px solid var(--border-dim); background: var(--bg-secondary); color: var(--text-muted); font-family: var(--font-mono); font-size: 0.66rem; white-space: nowrap; overflow: hidden; }
|
||||
.dd-status-pos { color: var(--text-secondary); }
|
||||
.dd-status-sel { color: var(--accent-cyan); }
|
||||
.dd-status-spacer { flex: 1; }
|
||||
|
||||
/* Search in files (devdesk#56) */
|
||||
.dd-search { display: flex; flex-direction: column; min-height: 100%; }
|
||||
.dd-search-box { display: flex; gap: 2px; padding: 6px 8px; border-bottom: 1px solid var(--border-dim); }
|
||||
.dd-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 6px; font-family: var(--font-mono); font-size: 0.74rem; }
|
||||
.dd-search-flag { flex: none; width: 26px; height: 26px; padding: 0; border: 1px solid transparent; background: none; color: var(--text-muted); font-family: var(--font-mono); font-size: 0.7rem; cursor: pointer; }
|
||||
.dd-search-flag:hover { color: var(--text-primary); }
|
||||
.dd-search-flag[aria-pressed="true"] { border-color: var(--accent-cyan); background: var(--accent-cyan-dim); color: var(--accent-cyan); }
|
||||
.dd-search-summary { padding: 4px 10px; color: var(--text-muted); font-size: 0.66rem; }
|
||||
.dd-search-file { display: flex; align-items: center; gap: 6px; width: 100%; padding: 3px 8px; border: 0; background: none; color: var(--text-primary); font-family: var(--font-mono); font-size: 0.74rem; text-align: left; cursor: pointer; }
|
||||
.dd-search-file:hover { background: var(--bg-tertiary); }
|
||||
.dd-search-file::before { content: '▾'; width: 10px; color: var(--text-muted); font-size: 0.66rem; }
|
||||
.dd-search-file[aria-expanded="false"]::before { content: '▸'; }
|
||||
.dd-search-file .dd-tree-name { flex: none; }
|
||||
.dd-search-file .dd-change-dir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dd-search-count { flex: none; padding: 0 6px; border-radius: 8px; background: var(--bg-tertiary); color: var(--text-secondary); font-size: 0.62rem; }
|
||||
.dd-search-lines[hidden] { display: none; }
|
||||
.dd-search-line { display: flex; gap: 8px; padding: 2px 8px 2px 30px; color: var(--text-secondary); font-family: var(--font-mono); font-size: 0.72rem; white-space: nowrap; cursor: pointer; outline: none; }
|
||||
.dd-search-line:hover, .dd-search-line:focus { background: var(--bg-tertiary); color: var(--text-primary); }
|
||||
.dd-search-line:focus { box-shadow: inset 0 0 0 1px var(--accent-cyan); }
|
||||
.dd-search-ln { flex: none; min-width: 2.5em; color: var(--text-muted); text-align: right; }
|
||||
.dd-search-text { overflow: hidden; text-overflow: ellipsis; }
|
||||
.dd-search-text mark { background: var(--accent-amber-dim); color: var(--accent-amber); outline: 1px solid color-mix(in srgb, var(--accent-amber) 50%, transparent); }
|
||||
|
||||
Reference in New Issue
Block a user