From ee71a2aed6386cdb6fd12a46cdafe2a888178b0f Mon Sep 17 00:00:00 2001 From: xiaolai Date: Fri, 31 Jul 2026 06:22:43 +0800 Subject: [PATCH 1/3] fix(toast): use AlertCircle for error toasts XCircle rendered an X-in-a-circle next to sonner's own close button, reading as a larger duplicate dismiss control. AlertCircle keeps the severity ramp at i / ! / warning and leaves the X unique to dismissal. --- src/App.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 451d07130..583d9a81f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,7 @@ import { FeatureErrorBoundary } from "@/components/FeatureErrorBoundary"; import { useTranslation, withTranslation, type WithTranslation } from "react-i18next"; import { Routes, Route } from "react-router-dom"; import { Toaster } from "sonner"; -import { CheckCircle, XCircle, Info, AlertTriangle, Loader2 } from "lucide-react"; +import { CheckCircle, AlertCircle, Info, AlertTriangle, Loader2 } from "lucide-react"; import { DocumentSplitContainer } from "@/components/Editor"; import { Sidebar } from "@/components/Sidebar"; import { SidebarResizeHandle } from "@/components/Sidebar/SidebarResizeHandle"; @@ -284,7 +284,10 @@ function App() { closeButton icons={{ success: , - error: , + // AlertCircle, not XCircle: an X-in-a-circle reads as a second + // (bigger) close button next to sonner's own closeButton. Keeping + // the severity ramp as i / ! / ⚠ leaves the X unique to dismissal. + error: , info: , warning: , loading: , From 84025581ec54700c0a8e7cc40b1b6a64e328dc18 Mon Sep 17 00:00:00 2001 From: xiaolai Date: Thu, 6 Aug 2026 10:00:34 +0800 Subject: [PATCH 2/3] chore: bump version to 0.9.29 --- package.json | 2 +- server/mcp/package.json | 2 +- server/mcp/src/cli.ts | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 90e769549..1e84d8ab2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vmark", "private": true, - "version": "0.9.28", + "version": "0.9.29", "license": "ISC", "description": "The plain-text workspace where humans and AI collaborate", "type": "module", diff --git a/server/mcp/package.json b/server/mcp/package.json index c8fc71b33..ea7dae1da 100644 --- a/server/mcp/package.json +++ b/server/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@vmark/mcp-server", - "version": "0.9.28", + "version": "0.9.29", "description": "MCP server for VMark — the plain-text workspace where humans and AI collaborate", "type": "module", "main": "dist/index.js", diff --git a/server/mcp/src/cli.ts b/server/mcp/src/cli.ts index 8c409d518..ff2c53c17 100644 --- a/server/mcp/src/cli.ts +++ b/server/mcp/src/cli.ts @@ -23,7 +23,7 @@ * lockstep with the app is the five-file `sed` in the bump procedure * (`.claude/rules/40-version-bump.md`). Edit it only through that procedure. */ -const VERSION = '0.9.28'; +const VERSION = '0.9.29'; /** * Handle --version flag. diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 068cbd632..3a6622a56 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -6280,7 +6280,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vmark" -version = "0.9.28" +version = "0.9.29" dependencies = [ "base64 0.23.0", "block2 0.6.2", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d55784a5e..bafe3dc67 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vmark" -version = "0.9.28" +version = "0.9.29" description = "The plain-text workspace where humans and AI collaborate" authors = ["Xiaolai"] license = "ISC" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9063fd954..4473465d5 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "VMark", - "version": "0.9.28", + "version": "0.9.29", "identifier": "app.vmark", "build": { "beforeDevCommand": "pnpm dev", From cdec851635532356e9993eadb9c43f96db6a674b Mon Sep 17 00:00:00 2001 From: xiaolai Date: Thu, 6 Aug 2026 10:21:04 +0800 Subject: [PATCH 3/3] refactor(toast): move the toast icon set out of App.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cherry-picked toast fix carried a three-line comment explaining why the error icon is AlertCircle rather than XCircle, and that was enough to push src/App.tsx from 298 to 301 lines — past the 300-line limit, failing lint:file-size in fe-static. Shaving the comment to land exactly on 300 would keep a composition root at its cap and make the next one-line change someone else's problem. A severity->icon map is data, not composition, so it moves to src/components/toastIcons.tsx and takes the rationale with it. App.tsx drops to 292 lines with real headroom, and its lucide-react import goes too — the icons are now referenced in exactly one place. check:static passes end to end (file-size, knip, shell-slots, dependency-cruiser all green). --- src/App.tsx | 13 ++----------- src/components/toastIcons.tsx | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/components/toastIcons.tsx diff --git a/src/App.tsx b/src/App.tsx index 583d9a81f..f706633a0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,7 @@ import { FeatureErrorBoundary } from "@/components/FeatureErrorBoundary"; import { useTranslation, withTranslation, type WithTranslation } from "react-i18next"; import { Routes, Route } from "react-router-dom"; import { Toaster } from "sonner"; -import { CheckCircle, AlertCircle, Info, AlertTriangle, Loader2 } from "lucide-react"; +import { TOAST_ICONS } from "@/components/toastIcons"; import { DocumentSplitContainer } from "@/components/Editor"; import { Sidebar } from "@/components/Sidebar"; import { SidebarResizeHandle } from "@/components/Sidebar/SidebarResizeHandle"; @@ -282,16 +282,7 @@ function App() { , - // AlertCircle, not XCircle: an X-in-a-circle reads as a second - // (bigger) close button next to sonner's own closeButton. Keeping - // the severity ramp as i / ! / ⚠ leaves the X unique to dismissal. - error: , - info: , - warning: , - loading: , - }} + icons={TOAST_ICONS} /> diff --git a/src/components/toastIcons.tsx b/src/components/toastIcons.tsx new file mode 100644 index 000000000..ff3719b99 --- /dev/null +++ b/src/components/toastIcons.tsx @@ -0,0 +1,26 @@ +/** + * Purpose: the icon set sonner's `` renders per toast severity. + * + * Extracted from `App.tsx`, which is the document window's composition root and + * sits at the 300-line limit — an explanatory comment on one icon was enough to + * push it over. A severity→icon map is data, not composition, so it does not + * belong in the root anyway. + * + * @coordinates-with src/App.tsx — the sole consumer, passed as `` + * @module components/toastIcons + */ + +import { CheckCircle, AlertCircle, Info, AlertTriangle, Loader2 } from "lucide-react"; + +const SIZE = 16; + +export const TOAST_ICONS = { + success: , + // AlertCircle, not XCircle: an X-in-a-circle reads as a second (and larger) + // close button beside sonner's own `closeButton`. Keeping the severity ramp + // as i / ! / ⚠ leaves the X shape unique to dismissal. + error: , + info: , + warning: , + loading: , +};