From 812cf7477f965cd48bbb53557dfa3efd82df2458 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 22:56:20 +0900 Subject: [PATCH 1/7] chore: update Cargo.lock version reference to 1.5.16 Co-Authored-By: Claude Sonnet 4.6 --- src-tauri/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index dcdeb78..237bdb4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2031,7 +2031,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "marka" -version = "1.5.14" +version = "1.5.16" dependencies = [ "serde", "serde_json", From 62e6e7f8dfd1245c11215cad8184f09de54f6bef Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 23:23:07 +0900 Subject: [PATCH 2/7] feat(ui): tab drag-reorder, dedup tabs, keep favorites on folder close, print-only preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tab drag-to-reorder: fix dragLeave child-element issue, add dataTransfer.setData and effectAllowed/dropEffect for reliable HTML5 drag; buttons marked draggable=false - No duplicate tabs: loadFile/loadPlainTextFile return early if path already open - Favorites preserved when closing folder (removed setFavorites from handleCloseFolder) - Print (Ctrl+P): @page named margin boxes clear browser date/title/URL headers, page number centered at bottom-center; @media print hides all non-preview elements - Bumps version 1.5.16 → 1.5.17 Co-Authored-By: Claude Sonnet 4.6 --- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- src/app.tsx | 4 +-- src/components/editor/open-tabs.tsx | 46 +++++++++++++++++++++--- src/hooks/use-file-session.ts | 23 ++++++++++-- src/styles/editor/panes.css | 5 +++ src/styles/globals.css | 55 ++++++++++++++++++++++++++++- 9 files changed, 127 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 339dc72..dd7736e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "marka-md", "private": true, - "version": "1.5.16", + "version": "1.5.17", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 237bdb4..4c460a0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2031,7 +2031,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "marka" -version = "1.5.16" +version = "1.5.17" dependencies = [ "serde", "serde_json", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 036da15..a9bd4e3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "marka" -version = "1.5.9" +version = "1.5.17" description = "marka.md — a local markdown editor for the notes you share with ai" authors = ["Matt Enarle"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9eec499..d5d3121 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "https://schema.tauri.app/config/2", "productName": "marka.md", "mainBinaryName": "marka.md", - "version": "1.5.16", + "version": "1.5.17", "identifier": "com.mattenarle.markamd", "build": { "beforeDevCommand": "bun run dev", diff --git a/src/app.tsx b/src/app.tsx index 5852da7..6fab325 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -109,6 +109,7 @@ export function App() { activeTabId, switchTab, closeTab, + reorderTabs, rootPath, setRootPath, saveStatus, @@ -175,12 +176,10 @@ export function App() { if (activePath && isPathWithin(activePath, path)) { startNewBuffer(); } - setFavorites((prev) => prev.filter((favorite) => !isPathWithin(favorite, path))); }, [ activePath, folders, isPathWithin, - setFavorites, setFolders, setRootPath, startNewBuffer, @@ -891,6 +890,7 @@ export function App() { activeTabId={activeTabId} onSelect={switchTab} onClose={handleCloseTab} + onReorder={reorderTabs} onContextMenu={(e, path) => handleContextMenu(e, { path, name: basename(path), isDir: false })} /> {editorOnly ? ( diff --git a/src/components/editor/open-tabs.tsx b/src/components/editor/open-tabs.tsx index 61cd1b2..15f192b 100644 --- a/src/components/editor/open-tabs.tsx +++ b/src/components/editor/open-tabs.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, type WheelEvent, type MouseEvent as ReactMouseEvent } from "react"; +import { useEffect, useRef, useState, type WheelEvent, type MouseEvent as ReactMouseEvent } from "react"; import { X } from "lucide-react"; import { Icon } from "@/components/primitives"; import type { FileTab } from "@/hooks/use-file-session"; @@ -9,12 +9,15 @@ type OpenTabsProps = { activeTabId: string; onSelect: (id: string) => void; onClose: (id: string) => void; + onReorder?: (from: number, to: number) => void; onContextMenu?: (e: React.MouseEvent, path: string) => void; }; -export function OpenTabs({ tabs, activeTabId, onSelect, onClose, onContextMenu }: OpenTabsProps) { +export function OpenTabs({ tabs, activeTabId, onSelect, onClose, onReorder, onContextMenu }: OpenTabsProps) { const { t } = useI18n(); const listRef = useRef(null); + const dragIndexRef = useRef(null); + const [overIndex, setOverIndex] = useState(null); useEffect(() => { const active = listRef.current?.querySelector(".mdv-tab.is-active"); @@ -38,16 +41,49 @@ export function OpenTabs({ tabs, activeTabId, onSelect, onClose, onContextMenu } aria-label={t("tabs.openFiles")} onWheel={handleWheel} > - {tabs.map((tab) => { + {tabs.map((tab, tabIndex) => { const active = tab.id === activeTabId; const dirty = tab.source !== tab.savedContent; + const isDragOver = overIndex === tabIndex && dragIndexRef.current !== tabIndex; return (
{ + dragIndexRef.current = tabIndex; + e.dataTransfer.effectAllowed = "move"; + // required by some runtimes to initiate drag + e.dataTransfer.setData("text/plain", String(tabIndex)); + }} + onDragOver={(e) => { + if (dragIndexRef.current === null || dragIndexRef.current === tabIndex || !onReorder) return; + e.preventDefault(); + e.dataTransfer.dropEffect = "move"; + if (overIndex !== tabIndex) setOverIndex(tabIndex); + }} + onDragLeave={(e) => { + // only clear when actually leaving this element, not entering a child + if (!e.currentTarget.contains(e.relatedTarget as Node | null)) { + setOverIndex(null); + } + }} + onDrop={(e) => { + e.preventDefault(); + const from = dragIndexRef.current; + if (from !== null && from !== tabIndex && onReorder) { + onReorder(from, tabIndex); + } + dragIndexRef.current = null; + setOverIndex(null); + }} + onDragEnd={() => { + dragIndexRef.current = null; + setOverIndex(null); + }} onContextMenu={tab.path && onContextMenu ? (e: ReactMouseEvent) => { e.preventDefault(); onContextMenu(e, tab.path!); @@ -56,6 +92,7 @@ export function OpenTabs({ tabs, activeTabId, onSelect, onClose, onContextMenu }