From 254771c2e0c2b342f028e63da98b1567870ae57a Mon Sep 17 00:00:00 2001 From: barry Date: Wed, 29 Apr 2026 10:08:54 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=A8=A1=E5=9D=97=E5=90=8D=E7=A7=B0=E4=B8=BA=20kookse?= =?UTF-8?q?e/markview=EF=BC=8C=E4=BF=AE=E6=AD=A3=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/copilot-instructions.md | 75 +++++++++++------- .goreleaser.yml | 32 ++++---- CLAUDE.md | 135 -------------------------------- Makefile | 2 +- README.md | 6 +- cmd/build.go | 2 +- cmd/root.go | 8 +- cmd/root_test.go | 2 +- go.mod | 2 +- internal/backup/backup.go | 2 +- internal/build/build.go | 6 +- internal/logfile/logfile.go | 2 +- internal/server/server.go | 4 +- main.go | 2 +- 14 files changed, 81 insertions(+), 199 deletions(-) delete mode 100644 CLAUDE.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c50931e..f813614 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,11 +2,11 @@ ## What is mo -`mo` is a CLI tool that opens Markdown files in a browser with live-reload. It runs a Go HTTP server that embeds a React SPA as a single binary. The Go module is `github.com/k1LoW/mo`. +`mo` is a CLI tool that opens Markdown files in a browser with live-reload. It runs a Go HTTP server that embeds a React SPA as a single binary. The Go module is `github.com/kooksee/markview`. ## Build & Run -Requires Go and [pnpm](https://pnpm.io/). Node.js version is managed via `pnpm.executionEnv.nodeVersion` in `internal/frontend/package.json`. +Requires Go 1.26+ and [pnpm](https://pnpm.io/). Node.js version is managed via `pnpm.executionEnv.nodeVersion` in `internal/frontend/package.json`. ```bash # Full build (frontend + Go binary, with ldflags) @@ -36,10 +36,27 @@ go test ./internal/server/ -run TestHandleFiles # Run linters (golangci-lint + gostyle) make lint +# Format code (frontend) +make fmt + +# Check formatting without modifying +make fmt-check + +# Take screenshots for README (requires Chrome) +make screenshot + # CI target (install dev deps + generate + test) make ci + +# Install to $GOPATH/bin (run after modifications to verify build and install) +make install + +# Frontend dev server with backend proxy (proxies /_/ to localhost:6275) +cd internal/frontend && pnpm run dev ``` +**Workflow**: After making code changes, run `make install` to build and install the binary. + ### CLI Flags - `--port` / `-p` — Server port (default: 6275) @@ -52,6 +69,7 @@ make ci - `--shutdown` — Shut down the running mo server - `--restart` — Restart the running mo server - `--foreground` — Run mo server in foreground (do not background) +- `--dangerously-allow-remote-access` — Allow remote access without authentication (trusted networks only) ## Architecture @@ -61,11 +79,38 @@ make ci - `internal/server/server.go` — HTTP server, state management (mutex-guarded), SSE for live-reload, file watcher (fsnotify). All API routes use `/_/` prefix to avoid collision with SPA route paths (group names). - `internal/static/static.go` — `go:generate` runs the frontend build, then `go:embed` embeds the output from `internal/static/dist/`. - `internal/frontend/` — Vite + React 19 + TypeScript + Tailwind CSS v4 SPA. Build output goes to `internal/static/dist/` (configured in `vite.config.ts`). +- `internal/backup/` — State persistence for open files/groups using atomic JSON writes to `$XDG_STATE_HOME/mo/backup/`. Enables session restoration across server restarts. +- `internal/logfile/` — Rotating JSON logging to `$XDG_STATE_HOME/mo/log/` (max 10MB, 3 backups, 7-day retention). +- `internal/xdg/` — XDG Base Directory helper. `StateHome()` returns `$XDG_STATE_HOME` or default `~/.local/state`. - `version/version.go` — Version info, updated by tagpr on release. Build embeds revision via ldflags. +## Frontend + +- Package manager: **pnpm** (version specified in `internal/frontend/package.json` `packageManager` field) +- Markdown rendering: `react-markdown` + `remark-gfm` + `rehype-raw` + `rehype-slug` (heading IDs) + `@shikijs/rehype` (syntax highlighting) + `mermaid` (diagram rendering) +- SPA routing via `window.location.pathname` (no router library) +- Key components: `App.tsx` (routing/state), `Sidebar.tsx` (file list with flat/tree view, resizable, drag-and-drop reorder), `TreeView.tsx` (tree view with collapsible directories), `MarkdownViewer.tsx` (rendering + raw view toggle), `TocPanel.tsx` (table of contents, resizable), `GroupDropdown.tsx` (group switcher), `FileContextMenu.tsx` (shared kebab menu for file operations), `WidthToggle.tsx` (wide/narrow content width toggle) +- Custom hooks: `useSSE.ts` (SSE subscription with auto-reconnect), `useApi.ts` (typed API fetch wrappers), `useActiveHeading.ts` (scroll-based active heading tracking via IntersectionObserver) +- Utilities: `buildTree.ts` (converts flat file list to hierarchical tree with common prefix removal and single-child directory collapsing) +- Theme: GitHub-style light/dark via CSS custom properties (`--color-gh-*`) in `styles/app.css`, toggled by `data-theme` attribute on ``. UI components use Tailwind classes like `bg-gh-bg-sidebar`, `text-gh-text-secondary`, etc. +- Toggle button pattern: `RawToggle.tsx` and `TocToggle.tsx` follow the same style (`bg-transparent border border-gh-border rounded-md p-1.5 text-gh-text-secondary`). Header buttons (`ViewModeToggle`, `ThemeToggle`, `WidthToggle`, sidebar toggle) use `text-gh-header-text` instead. New buttons should match the appropriate variant. + +## Key Design Patterns + +- **Single instance**: CLI probes `/_/api/status` on the target port via `probeServer()`. If already running, pushes files via `POST /_/api/files` and exits. +- **File IDs**: Files get deterministic string IDs derived from the SHA-256 hash of the absolute path (first 8 hex characters). IDs are stable across server restarts, enabling deep linking. The frontend primarily references files by ID. Absolute paths are available via `FileEntry.path` for display (e.g., tooltip, tree view). +- **Tab groups**: Files are organized into named groups. Group name maps to the URL path (e.g., `/design`). Default group name is `"default"`. +- **Live-reload via SSE**: fsnotify watches files; `file-changed` events trigger frontend to re-fetch content by file ID. +- **Sidebar view modes**: Flat (default, with drag-and-drop reorder via dnd-kit) and tree (hierarchical directory view). View mode is persisted per-group in localStorage. Collapsed directory state is managed inside `TreeView` and also persisted per-group. +- **Resizable panels**: Both `Sidebar.tsx` (left) and `TocPanel.tsx` (right) use the same drag-to-resize pattern with localStorage persistence. Left sidebar uses `e.clientX`, right panel uses `window.innerWidth - e.clientX`. +- **Toolbar buttons in content area**: The toolbar column (ToC + Raw toggles) lives inside `MarkdownViewer.tsx`, positioned with `shrink-0 flex flex-col gap-2 -mr-4 -mt-4` to align with the header. +- **State persistence**: Server state (files, groups, patterns) is backed up to `$XDG_STATE_HOME/mo/backup/mo-.json` via `internal/backup`. On `--restart`, the server reloads this state to preserve the session. When starting a new server, backup is always restored and merged with CLI-specified files/patterns (restored entries first, CLI entries appended, duplicates skipped). The backup file is preserved across clean `--shutdown` and is only removed via the `--clear` path in the CLI. +- **Glob pattern watching**: `--watch` registers glob patterns that are expanded to matching files and monitored for new files via fsnotify directory watches. Patterns are stored with reference-counted directory watches (`watchedDirs map[string]int`). `--unwatch` removes patterns and decrements watch ref counts. Groups persist as long as they have files or patterns. +- **localStorage conventions**: All keys use `mo-` prefix (e.g., `mo-sidebar-width`, `mo-sidebar-viewmode`, `mo-sidebar-tree-collapsed`, `mo-theme`). Read patterns use `try/catch` around `JSON.parse` with fallback defaults. + ## API Conventions -All internal API endpoints are under `/_/api/` and SSE under `/_/events`. The `/_/` prefix is intentional to avoid collisions with user-facing group name routes (e.g., `/mygroup`). +All internal endpoints use `/_/api/` prefix and SSE uses `/_/events`. The `/_/` prefix avoids collisions with user-facing group name routes. Key endpoints: - `GET /_/api/groups` — List all groups with files @@ -80,30 +125,6 @@ Key endpoints: - `GET /_/api/status` — Server status (version, pid, groups with patterns) - `GET /_/events` — SSE (event types: `update`, `file-changed`, `restart`) -## Frontend - -- Located in `internal/frontend/`, uses **pnpm** as the package manager. -- React 19, TypeScript, Tailwind CSS v4. -- Markdown rendering: `react-markdown` + `remark-gfm` + `rehype-raw` + `rehype-slug` (heading IDs) + `@shikijs/rehype` (syntax highlighting) + `mermaid` (diagram rendering). -- SPA routing via `window.location.pathname` (no router library). -- Key components: `App.tsx` (routing/state), `Sidebar.tsx` (file list with flat/tree view, resizable, drag-and-drop reorder), `TreeView.tsx` (tree view with collapsible directories), `MarkdownViewer.tsx` (rendering + raw view toggle), `TocPanel.tsx` (table of contents, resizable), `GroupDropdown.tsx` (group switcher), `FileContextMenu.tsx` (shared kebab menu for file operations), `WidthToggle.tsx` (wide/narrow content width toggle). -- Custom hooks: `useSSE.ts` (SSE subscription with auto-reconnect), `useApi.ts` (typed API fetch wrappers), `useActiveHeading.ts` (scroll-based active heading tracking via IntersectionObserver). -- Theme: GitHub-style light/dark via CSS custom properties (`--color-gh-*`) in `styles/app.css`, toggled by `data-theme` attribute on ``. UI components use Tailwind classes like `bg-gh-bg-sidebar`, `text-gh-text-secondary`, etc. -- Toggle button pattern: `RawToggle.tsx` and `TocToggle.tsx` follow the same style (`bg-transparent border border-gh-border rounded-md p-1.5 text-gh-text-secondary`). Header buttons (`ViewModeToggle`, `ThemeToggle`, `WidthToggle`, sidebar toggle) use `text-gh-header-text` instead. New buttons should match the appropriate variant. - -## Key Patterns - -- **Single instance design**: CLI probes `/_/api/status` on the target port via `probeServer()`. If already running, pushes files via `POST /_/api/files` and exits. -- **File IDs**: Files get deterministic string IDs derived from the SHA-256 hash of the absolute path (first 8 hex characters). IDs are stable across server restarts, enabling deep linking. The frontend primarily references files by ID. Absolute paths are available via `FileEntry.path` for display. -- **Tab groups**: Files are organized into named groups (default: "default"). Group name maps to the URL path. -- **Live-reload via SSE**: fsnotify watches files; `file-changed` events trigger frontend to re-fetch content by file ID. -- **State persistence**: Server state (files, groups, patterns) is backed up to `$XDG_STATE_HOME/mo/backup/mo-.json` via `internal/backup`. When starting a new server, backup is always restored and merged with CLI-specified files/patterns (restored entries first, CLI entries appended, duplicates skipped). The backup file is only deleted when the CLI is invoked with `--clear`. -- **Glob pattern watching**: `--watch` registers glob patterns that are expanded to matching files and monitored for new files via fsnotify directory watches. Patterns are stored with reference-counted directory watches (`watchedDirs map[string]int`). `--unwatch` removes patterns and decrements watch ref counts. Groups persist as long as they have files or patterns. -- **Resizable panels**: Both `Sidebar.tsx` (left) and `TocPanel.tsx` (right) use the same drag-to-resize pattern with localStorage persistence. Left sidebar uses `e.clientX`, right panel uses `window.innerWidth - e.clientX`. -- **Toolbar buttons in content area**: The toolbar column (ToC + Raw toggles) lives inside `MarkdownViewer.tsx`, positioned with `shrink-0 flex flex-col gap-2 -mr-4 -mt-4` to align with the header. -- **Sidebar view modes**: Flat (default, with drag-and-drop reorder via dnd-kit) and tree (hierarchical directory view). View mode is persisted per-group in localStorage. Collapsed directory state is managed inside `TreeView` and also persisted per-group. -- **localStorage conventions**: All keys use `mo-` prefix (e.g., `mo-sidebar-width`, `mo-sidebar-viewmode`, `mo-sidebar-tree-collapsed`, `mo-theme`). Read patterns use `try/catch` around `JSON.parse` with fallback defaults. - ## CI/CD - **CI**: golangci-lint (via reviewdog), gostyle, `make ci` (test + coverage), octocov diff --git a/.goreleaser.yml b/.goreleaser.yml index 4465d88..788ffcd 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,12 +5,11 @@ before: - go mod tidy - go generate ./internal/static/ builds: - - - id: mo-darwin + - id: mo-darwin flags: - -trimpath ldflags: - - -s -w -X github.com/k1LoW/mo/version.Revision={{.ShortCommit}} + - -s -w -X github.com/kooksee/markview/version.Revision={{.ShortCommit}} env: - CGO_ENABLED=0 goos: @@ -18,24 +17,22 @@ builds: goarch: - amd64 - arm64 - - - id: mo-windows + - id: mo-windows flags: - -trimpath ldflags: - - -s -w -X github.com/k1LoW/mo/version.Revision={{.ShortCommit}} + - -s -w -X github.com/kooksee/markview/version.Revision={{.ShortCommit}} env: - CGO_ENABLED=0 goos: - windows goarch: - amd64 - - - id: mo-linux + - id: mo-linux flags: - -trimpath ldflags: - - -s -w -X github.com/k1LoW/mo/version.Revision={{.ShortCommit}} + - -s -w -X github.com/kooksee/markview/version.Revision={{.ShortCommit}} env: - CGO_ENABLED=0 goos: @@ -44,9 +41,9 @@ builds: - amd64 - arm64 archives: - - - id: mo-archive - name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + - id: mo-archive + name_template: "{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if + .Arm }}v{{ .Arm }}{{ end }}" format_overrides: - goos: darwin formats: @@ -57,20 +54,19 @@ archives: - README.md - CHANGELOG.md checksum: - name_template: 'checksums.txt' + name_template: "checksums.txt" changelog: sort: asc filters: exclude: - - '^docs:' - - '^test:' + - "^docs:" + - "^test:" nfpms: - - - id: mo-nfpms + - id: mo-nfpms file_name_template: "{{ .ProjectName }}_{{ .Version }}-1_{{ .Arch }}" ids: - mo-linux - homepage: https://github.com/k1LoW/mo + homepage: https://github.com/kooksee/markview maintainer: Ken'ichiro Oyama description: "mo is a Markdown viewer that opens .md files in a browser" license: MIT diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 2e69530..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,135 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## What is mo - -`mo` is a CLI tool that opens Markdown files in a browser with live-reload. It runs a Go HTTP server that embeds a React SPA as a single binary. The Go module is `github.com/k1LoW/mo`. - -## Build & Run - -Requires Go 1.26+ and [pnpm](https://pnpm.io/). Node.js version is managed via `pnpm.executionEnv.nodeVersion` in `internal/frontend/package.json`. - -```bash -# Full build (frontend + Go binary, with ldflags) -make build - -# Dev: build frontend then run with args (uses port 16275, foreground mode) -make dev ARGS="testdata/basic.md" - -# Dev with tab groups (-t can only specify one group per invocation) -make dev ARGS="-t design testdata/basic.md" - -# Frontend code generation only (called by make build/dev via go generate) -make generate - -# Run all tests (frontend + Go) -make test - -# Run a single frontend test (vitest) -cd internal/frontend && pnpm test src/utils/buildTree.test.ts - -# Run Go tests only -go test ./... - -# Run a single Go test -go test ./internal/server/ -run TestHandleFiles - -# Run linters (golangci-lint + gostyle) -make lint - -# Format code (frontend) -make fmt - -# Check formatting without modifying -make fmt-check - -# Take screenshots for README (requires Chrome) -make screenshot - -# CI target (install dev deps + generate + test) -make ci - -# Install to $GOPATH/bin (run after modifications to verify build and install) -make install - -# Frontend dev server with backend proxy (proxies /_/ to localhost:6275) -cd internal/frontend && pnpm run dev -``` - -**Workflow**: After making code changes, run `make install` to build and install the binary. - -### CLI Flags - -- `--port` / `-p` — Server port (default: 6275) -- `--target` / `-t` — Tab group name (default: `"default"`) -- `--open` — Always open browser -- `--no-open` — Never open browser -- `--watch` / `-w` — Glob pattern to watch for matching files (repeatable) -- `--unwatch` — Remove a watched glob pattern (repeatable) -- `--status` — Show status of all running mo servers -- `--shutdown` — Shut down the running mo server -- `--restart` — Restart the running mo server -- `--foreground` — Run mo server in foreground (do not background) -- `--dangerously-allow-remote-access` — Allow remote access without authentication (trusted networks only) - -## Architecture - -**Go backend + embedded React SPA**, single binary. - -- `cmd/root.go` — CLI entry point (Cobra). Handles single-instance detection: if a server is already running on the port, adds files via HTTP API instead of starting a new server. -- `internal/server/server.go` — HTTP server, state management (mutex-guarded), SSE for live-reload, file watcher (fsnotify). All API routes use `/_/` prefix to avoid collision with SPA route paths (group names). -- `internal/static/static.go` — `go:generate` runs the frontend build, then `go:embed` embeds the output from `internal/static/dist/`. -- `internal/frontend/` — Vite + React 19 + TypeScript + Tailwind CSS v4 SPA. Build output goes to `internal/static/dist/` (configured in `vite.config.ts`). -- `internal/backup/` — State persistence for open files/groups using atomic JSON writes to `$XDG_STATE_HOME/mo/backup/`. Enables session restoration across server restarts. -- `internal/logfile/` — Rotating JSON logging to `$XDG_STATE_HOME/mo/log/` (max 10MB, 3 backups, 7-day retention). -- `internal/xdg/` — XDG Base Directory helper. `StateHome()` returns `$XDG_STATE_HOME` or default `~/.local/state`. -- `version/version.go` — Version info, updated by tagpr on release. Build embeds revision via ldflags. - -## Frontend - -- Package manager: **pnpm** (version specified in `internal/frontend/package.json` `packageManager` field) -- Markdown rendering: `react-markdown` + `remark-gfm` + `rehype-raw` + `rehype-slug` (heading IDs) + `@shikijs/rehype` (syntax highlighting) + `mermaid` (diagram rendering) -- SPA routing via `window.location.pathname` (no router library) -- Key components: `App.tsx` (routing/state), `Sidebar.tsx` (file list with flat/tree view, resizable, drag-and-drop reorder), `TreeView.tsx` (tree view with collapsible directories), `MarkdownViewer.tsx` (rendering + raw view toggle), `TocPanel.tsx` (table of contents, resizable), `GroupDropdown.tsx` (group switcher), `FileContextMenu.tsx` (shared kebab menu for file operations), `WidthToggle.tsx` (wide/narrow content width toggle) -- Custom hooks: `useSSE.ts` (SSE subscription with auto-reconnect), `useApi.ts` (typed API fetch wrappers), `useActiveHeading.ts` (scroll-based active heading tracking via IntersectionObserver) -- Utilities: `buildTree.ts` (converts flat file list to hierarchical tree with common prefix removal and single-child directory collapsing) -- Theme: GitHub-style light/dark via CSS custom properties (`--color-gh-*`) in `styles/app.css`, toggled by `data-theme` attribute on ``. UI components use Tailwind classes like `bg-gh-bg-sidebar`, `text-gh-text-secondary`, etc. -- Toggle button pattern: `RawToggle.tsx` and `TocToggle.tsx` follow the same style (`bg-transparent border border-gh-border rounded-md p-1.5 text-gh-text-secondary`). Header buttons (`ViewModeToggle`, `ThemeToggle`, `WidthToggle`, sidebar toggle) use `text-gh-header-text` instead. New buttons should match the appropriate variant. - -## Key Design Patterns - -- **Single instance**: CLI probes `/_/api/status` on the target port via `probeServer()`. If already running, pushes files via `POST /_/api/files` and exits. -- **File IDs**: Files get deterministic string IDs derived from the SHA-256 hash of the absolute path (first 8 hex characters). IDs are stable across server restarts, enabling deep linking. The frontend primarily references files by ID. Absolute paths are available via `FileEntry.path` for display (e.g., tooltip, tree view). -- **Tab groups**: Files are organized into named groups. Group name maps to the URL path (e.g., `/design`). Default group name is `"default"`. -- **Live-reload via SSE**: fsnotify watches files; `file-changed` events trigger frontend to re-fetch content by file ID. -- **Sidebar view modes**: Flat (default, with drag-and-drop reorder via dnd-kit) and tree (hierarchical directory view). View mode is persisted per-group in localStorage. Collapsed directory state is managed inside `TreeView` and also persisted per-group. -- **Resizable panels**: Both `Sidebar.tsx` (left) and `TocPanel.tsx` (right) use the same drag-to-resize pattern with localStorage persistence. Left sidebar uses `e.clientX`, right panel uses `window.innerWidth - e.clientX`. -- **Toolbar buttons in content area**: The toolbar column (ToC + Raw toggles) lives inside `MarkdownViewer.tsx`, positioned with `shrink-0 flex flex-col gap-2 -mr-4 -mt-4` to align with the header. -- **State persistence**: Server state (files, groups, patterns) is backed up to `$XDG_STATE_HOME/mo/backup/mo-.json` via `internal/backup`. On `--restart`, the server reloads this state to preserve the session. When starting a new server, backup is always restored and merged with CLI-specified files/patterns (restored entries first, CLI entries appended, duplicates skipped). The backup file is preserved across clean `--shutdown` and is only removed via the `--clear` path in the CLI. -- **Glob pattern watching**: `--watch` registers glob patterns that are expanded to matching files and monitored for new files via fsnotify directory watches. Patterns are stored with reference-counted directory watches (`watchedDirs map[string]int`). `--unwatch` removes patterns and decrements watch ref counts. Groups persist as long as they have files or patterns. -- **localStorage conventions**: All keys use `mo-` prefix (e.g., `mo-sidebar-width`, `mo-sidebar-viewmode`, `mo-sidebar-tree-collapsed`, `mo-theme`). Read patterns use `try/catch` around `JSON.parse` with fallback defaults. - -## API Conventions - -All internal endpoints use `/_/api/` prefix and SSE uses `/_/events`. The `/_/` prefix avoids collisions with user-facing group name routes. - -Key endpoints: -- `GET /_/api/groups` — List all groups with files -- `POST /_/api/files` — Add file -- `DELETE /_/api/files/{id}` — Remove file -- `GET /_/api/files/{id}/content` — File content (markdown) -- `PUT /_/api/files/{id}/group` — Move file to another group -- `PUT /_/api/reorder` — Reorder files in a group (group name in body) -- `POST /_/api/files/open` — Open relative file link -- `POST /_/api/patterns` — Add glob watch pattern -- `DELETE /_/api/patterns` — Remove glob watch pattern -- `GET /_/api/status` — Server status (version, pid, groups with patterns) -- `GET /_/events` — SSE (event types: `update`, `file-changed`, `restart`) - -## CI/CD - -- **CI**: golangci-lint (via reviewdog), gostyle, `make ci` (test + coverage), octocov -- **Release**: tagpr for automated tagging, goreleaser for cross-platform builds. The `go generate` step (frontend build) runs in goreleaser's `before.hooks`. -- **License check**: Trivy scans for license issues -- CI requires pnpm setup (`pnpm/action-setup`) before any Go build step because `go generate` triggers the frontend build. diff --git a/Makefile b/Makefile index 81d1bdb..10b3a78 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PKG = github.com/k1LoW/mo +PKG = github.com/kooksee/markview COMMIT = $(shell git rev-parse --short HEAD) BUILD_LDFLAGS = "-s -w -X $(PKG)/version.Revision=$(COMMIT)" diff --git a/README.md b/README.md index 9bac4fb..20c4c66 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@




-mo +mo


# mo -[![build](https://github.com/k1LoW/mo/actions/workflows/ci.yml/badge.svg)](https://github.com/k1LoW/mo/actions/workflows/ci.yml) ![Coverage](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/coverage.svg) ![Code to Test Ratio](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/ratio.svg) ![Test Execution Time](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/time.svg) +[![build](https://github.com/kooksee/markview/actions/workflows/ci.yml/badge.svg)](https://github.com/kooksee/markview/actions/workflows/ci.yml) ![Coverage](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/coverage.svg) ![Code to Test Ratio](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/ratio.svg) ![Test Execution Time](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/time.svg) `mo` is a **M**arkdown viewer that **o**pens `.md` files in a browser. @@ -40,7 +40,7 @@ $ brew install k1LoW/tap/mo **manually:** -Download binary from [releases page](https://github.com/k1LoW/mo/releases) +Download binary from [releases page](https://github.com/kooksee/markview/releases) ## Usage diff --git a/cmd/build.go b/cmd/build.go index b79571c..d43a347 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "github.com/k1LoW/mo/internal/build" + "github.com/kooksee/markview/internal/build" "github.com/spf13/cobra" ) diff --git a/cmd/root.go b/cmd/root.go index 7d9bfc6..f88e7bb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -20,10 +20,10 @@ import ( "time" "github.com/k1LoW/donegroup" - "github.com/k1LoW/mo/internal/backup" - "github.com/k1LoW/mo/internal/logfile" - "github.com/k1LoW/mo/internal/server" - "github.com/k1LoW/mo/version" + "github.com/kooksee/markview/internal/backup" + "github.com/kooksee/markview/internal/logfile" + "github.com/kooksee/markview/internal/server" + "github.com/kooksee/markview/version" "github.com/muesli/termenv" "github.com/pkg/browser" "github.com/spf13/cobra" diff --git a/cmd/root_test.go b/cmd/root_test.go index acb1b8f..c1938a9 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/k1LoW/mo/internal/server" + "github.com/kooksee/markview/internal/server" ) func TestResolvePatterns_NoGlobChars(t *testing.T) { diff --git a/go.mod b/go.mod index 5cfa0cb..7b974e6 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/k1LoW/mo +module github.com/kooksee/markview go 1.26.0 diff --git a/internal/backup/backup.go b/internal/backup/backup.go index a6c248a..0234786 100644 --- a/internal/backup/backup.go +++ b/internal/backup/backup.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "github.com/k1LoW/mo/internal/xdg" + "github.com/kooksee/markview/internal/xdg" ) // Dir returns the path to the backup directory. diff --git a/internal/build/build.go b/internal/build/build.go index 2123043..7e67c21 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -12,9 +12,9 @@ import ( "path/filepath" "strings" - "github.com/k1LoW/mo/internal/server" - "github.com/k1LoW/mo/internal/static" - "github.com/k1LoW/mo/version" + "github.com/kooksee/markview/internal/server" + "github.com/kooksee/markview/internal/static" + "github.com/kooksee/markview/version" ) // staticFileContent holds a file's content for static export. diff --git a/internal/logfile/logfile.go b/internal/logfile/logfile.go index 33d345c..e7d20b7 100644 --- a/internal/logfile/logfile.go +++ b/internal/logfile/logfile.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/k1LoW/mo/internal/xdg" + "github.com/kooksee/markview/internal/xdg" ) const logFilePrefix = "mo-" diff --git a/internal/server/server.go b/internal/server/server.go index ea00a34..51a671f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -19,8 +19,8 @@ import ( "github.com/bmatcuk/doublestar/v4" "github.com/fsnotify/fsnotify" "github.com/k1LoW/donegroup" - "github.com/k1LoW/mo/internal/static" - "github.com/k1LoW/mo/version" + "github.com/kooksee/markview/internal/static" + "github.com/kooksee/markview/version" ) type FileEntry struct { diff --git a/main.go b/main.go index 56a5672..e24c2fe 100644 --- a/main.go +++ b/main.go @@ -25,7 +25,7 @@ import ( "log/slog" "os" - "github.com/k1LoW/mo/cmd" + "github.com/kooksee/markview/cmd" ) func main() { From 85e9d283eef6d0dfb5eac873eae72a9eee0676c1 Mon Sep 17 00:00:00 2001 From: barry Date: Wed, 29 Apr 2026 10:30:47 +0800 Subject: [PATCH 2/6] refactor: rename project from "mo" to "markview" across the codebase - Updated backup paths and filenames to reflect the new project name. - Changed static data injection variable from `__MO_STATIC_DATA__` to `__MARKVIEW_STATIC_DATA__`. - Modified frontend components and hooks to use "markview" in local storage keys and titles. - Adjusted test data and documentation to reference "markview" instead of "mo". - Updated logging and server configurations to align with the new naming convention. --- .github/copilot-instructions.md | 22 +- .gitignore | 2 +- .goreleaser.yml | 14 +- CHANGELOG.md | 198 +++++++++--------- Makefile | 4 +- README.md | 96 ++++----- cmd/build.go | 18 +- cmd/root.go | 118 +++++------ internal/backup/backup.go | 6 +- internal/backup/backup_test.go | 4 +- internal/build/build.go | 4 +- internal/frontend/index.html | 25 ++- internal/frontend/scripts/screenshots.mjs | 20 +- internal/frontend/src/App.tsx | 10 +- .../src/components/OutlineGraphView.tsx | 4 +- .../src/components/OutlineTreeView.tsx | 22 +- .../frontend/src/components/RestartButton.tsx | 4 +- .../frontend/src/components/SettingsModal.tsx | 10 +- internal/frontend/src/components/Sidebar.tsx | 6 +- .../src/components/ThemeToggle.test.tsx | 14 +- .../frontend/src/components/ThemeToggle.tsx | 4 +- internal/frontend/src/components/TocPanel.tsx | 8 +- internal/frontend/src/components/TreeView.tsx | 6 +- internal/frontend/src/hooks/useAppSettings.ts | 6 +- .../frontend/src/hooks/useMermaidSettings.ts | 2 +- .../src/hooks/useScrollRestoration.ts | 2 +- internal/frontend/src/utils/staticData.ts | 12 +- internal/logfile/logfile.go | 8 +- internal/server/server.go | 2 +- testdata/basic.md | 2 +- testdata/code-blocks.md | 8 +- testdata/long-document.md | 16 +- testdata/mermaid-mixed.md | 4 +- testdata/plantuml-complete.md | 18 +- testdata/plantuml.md | 10 +- testdata/sample.mdx | 2 +- testdata/svgbob-complex.md | 2 +- version/version.go | 2 +- 38 files changed, 360 insertions(+), 355 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f813614..c936a36 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,8 +1,8 @@ -# Copilot Instructions for mo (Markdown Opener) +# Copilot Instructions for markview -## What is mo +## What is markview -`mo` is a CLI tool that opens Markdown files in a browser with live-reload. It runs a Go HTTP server that embeds a React SPA as a single binary. The Go module is `github.com/kooksee/markview`. +`markview` is a CLI tool that opens Markdown files in a browser with live-reload. It runs a Go HTTP server that embeds a React SPA as a single binary. The Go module is `github.com/kooksee/markview`. ## Build & Run @@ -65,10 +65,10 @@ cd internal/frontend && pnpm run dev - `--no-open` — Never open browser - `--watch` / `-w` — Glob pattern to watch for matching files (repeatable) - `--unwatch` — Remove a watched glob pattern (repeatable) -- `--status` — Show status of all running mo servers -- `--shutdown` — Shut down the running mo server -- `--restart` — Restart the running mo server -- `--foreground` — Run mo server in foreground (do not background) +- `--status` — Show status of all running markview servers +- `--shutdown` — Shut down the running markview server +- `--restart` — Restart the running markview server +- `--foreground` — Run markview server in foreground (do not background) - `--dangerously-allow-remote-access` — Allow remote access without authentication (trusted networks only) ## Architecture @@ -79,8 +79,8 @@ cd internal/frontend && pnpm run dev - `internal/server/server.go` — HTTP server, state management (mutex-guarded), SSE for live-reload, file watcher (fsnotify). All API routes use `/_/` prefix to avoid collision with SPA route paths (group names). - `internal/static/static.go` — `go:generate` runs the frontend build, then `go:embed` embeds the output from `internal/static/dist/`. - `internal/frontend/` — Vite + React 19 + TypeScript + Tailwind CSS v4 SPA. Build output goes to `internal/static/dist/` (configured in `vite.config.ts`). -- `internal/backup/` — State persistence for open files/groups using atomic JSON writes to `$XDG_STATE_HOME/mo/backup/`. Enables session restoration across server restarts. -- `internal/logfile/` — Rotating JSON logging to `$XDG_STATE_HOME/mo/log/` (max 10MB, 3 backups, 7-day retention). +- `internal/backup/` — State persistence for open files/groups using atomic JSON writes to `$XDG_STATE_HOME/markview/backup/`. Enables session restoration across server restarts. +- `internal/logfile/` — Rotating JSON logging to `$XDG_STATE_HOME/markview/log/` (max 10MB, 3 backups, 7-day retention). - `internal/xdg/` — XDG Base Directory helper. `StateHome()` returns `$XDG_STATE_HOME` or default `~/.local/state`. - `version/version.go` — Version info, updated by tagpr on release. Build embeds revision via ldflags. @@ -104,9 +104,9 @@ cd internal/frontend && pnpm run dev - **Sidebar view modes**: Flat (default, with drag-and-drop reorder via dnd-kit) and tree (hierarchical directory view). View mode is persisted per-group in localStorage. Collapsed directory state is managed inside `TreeView` and also persisted per-group. - **Resizable panels**: Both `Sidebar.tsx` (left) and `TocPanel.tsx` (right) use the same drag-to-resize pattern with localStorage persistence. Left sidebar uses `e.clientX`, right panel uses `window.innerWidth - e.clientX`. - **Toolbar buttons in content area**: The toolbar column (ToC + Raw toggles) lives inside `MarkdownViewer.tsx`, positioned with `shrink-0 flex flex-col gap-2 -mr-4 -mt-4` to align with the header. -- **State persistence**: Server state (files, groups, patterns) is backed up to `$XDG_STATE_HOME/mo/backup/mo-.json` via `internal/backup`. On `--restart`, the server reloads this state to preserve the session. When starting a new server, backup is always restored and merged with CLI-specified files/patterns (restored entries first, CLI entries appended, duplicates skipped). The backup file is preserved across clean `--shutdown` and is only removed via the `--clear` path in the CLI. +- **State persistence**: Server state (files, groups, patterns) is backed up to `$XDG_STATE_HOME/markview/backup/markview-.json` via `internal/backup`. On `--restart`, the server reloads this state to preserve the session. When starting a new server, backup is always restored and merged with CLI-specified files/patterns (restored entries first, CLI entries appended, duplicates skipped). The backup file is preserved across clean `--shutdown` and is only removed via the `--clear` path in the CLI. - **Glob pattern watching**: `--watch` registers glob patterns that are expanded to matching files and monitored for new files via fsnotify directory watches. Patterns are stored with reference-counted directory watches (`watchedDirs map[string]int`). `--unwatch` removes patterns and decrements watch ref counts. Groups persist as long as they have files or patterns. -- **localStorage conventions**: All keys use `mo-` prefix (e.g., `mo-sidebar-width`, `mo-sidebar-viewmode`, `mo-sidebar-tree-collapsed`, `mo-theme`). Read patterns use `try/catch` around `JSON.parse` with fallback defaults. +- **localStorage conventions**: All keys use `markview-` prefix (e.g., `markview-sidebar-width`, `markview-sidebar-viewmode`, `markview-sidebar-tree-collapsed`, `markview-theme`). Read patterns use `try/catch` around `JSON.parse` with fallback defaults. ## API Conventions diff --git a/.gitignore b/.gitignore index 67b10ec..fc0bd0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ internal/static/dist/**/* internal/frontend/CREDITS_FRONTEND coverage.out -mo +markview .pnpm-store/ diff --git a/.goreleaser.yml b/.goreleaser.yml index 788ffcd..50ff352 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,7 +5,7 @@ before: - go mod tidy - go generate ./internal/static/ builds: - - id: mo-darwin + - id: markview-darwin flags: - -trimpath ldflags: @@ -17,7 +17,7 @@ builds: goarch: - amd64 - arm64 - - id: mo-windows + - id: markview-windows flags: - -trimpath ldflags: @@ -28,7 +28,7 @@ builds: - windows goarch: - amd64 - - id: mo-linux + - id: markview-linux flags: - -trimpath ldflags: @@ -41,7 +41,7 @@ builds: - amd64 - arm64 archives: - - id: mo-archive + - id: markview-archive name_template: "{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" format_overrides: @@ -62,13 +62,13 @@ changelog: - "^docs:" - "^test:" nfpms: - - id: mo-nfpms + - id: markview-nfpms file_name_template: "{{ .ProjectName }}_{{ .Version }}-1_{{ .Arch }}" ids: - - mo-linux + - markview-linux homepage: https://github.com/kooksee/markview maintainer: Ken'ichiro Oyama - description: "mo is a Markdown viewer that opens .md files in a browser" + description: "markview is a Markdown viewer that opens .md files in a browser" license: MIT formats: - deb diff --git a/CHANGELOG.md b/CHANGELOG.md index 60b250c..8d62c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,182 +1,182 @@ # Changelog -## [v0.18.1](https://github.com/k1LoW/mo/compare/v0.18.0...v0.18.1) - 2026-03-10 +## [v0.18.1](https://github.com/kooksee/markview/compare/v0.18.0...v0.18.1) - 2026-03-10 ### Other Changes -- feat: add --skip-bind-address-confirmation flag to bypass non-loopback bind prompt by @110y in https://github.com/k1LoW/mo/pull/103 -- fix: rename --skip-bind-address-confirmation to --dangerously-allow-remote-access by @k1LoW in https://github.com/k1LoW/mo/pull/105 +- feat: add --skip-bind-address-confirmation flag to bypass non-loopback bind prompt by @110y in https://github.com/kooksee/markview/pull/103 +- fix: rename --skip-bind-address-confirmation to --dangerously-allow-remote-access by @k1LoW in https://github.com/kooksee/markview/pull/105 -## [v0.18.0](https://github.com/k1LoW/mo/compare/v0.17.0...v0.18.0) - 2026-03-10 +## [v0.18.0](https://github.com/kooksee/markview/compare/v0.17.0...v0.18.0) - 2026-03-10 ### New Features 🎉 -- feat: add wide/narrow layout toggle by @k1LoW in https://github.com/k1LoW/mo/pull/101 +- feat: add wide/narrow layout toggle by @k1LoW in https://github.com/kooksee/markview/pull/101 ### Other Changes -- fix: add accessibility attributes to all toggle buttons by @k1LoW in https://github.com/k1LoW/mo/pull/102 +- fix: add accessibility attributes to all toggle buttons by @k1LoW in https://github.com/kooksee/markview/pull/102 -## [v0.17.0](https://github.com/k1LoW/mo/compare/v0.16.3...v0.17.0) - 2026-03-10 +## [v0.17.0](https://github.com/kooksee/markview/compare/v0.16.3...v0.17.0) - 2026-03-10 ### New Features 🎉 -- Proposal: add --bind flag to specify listen address by @110y in https://github.com/k1LoW/mo/pull/96 -- feat: add security warning with confirmation prompt for non-localhost --bind by @k1LoW in https://github.com/k1LoW/mo/pull/98 +- Proposal: add --bind flag to specify listen address by @110y in https://github.com/kooksee/markview/pull/96 +- feat: add security warning with confirmation prompt for non-localhost --bind by @k1LoW in https://github.com/kooksee/markview/pull/98 -## [v0.16.3](https://github.com/k1LoW/mo/compare/v0.16.2...v0.16.3) - 2026-03-10 +## [v0.16.3](https://github.com/kooksee/markview/compare/v0.16.2...v0.16.3) - 2026-03-10 ### Fix bug 🐛 -- fix: render Mermaid charts using actual container width by @k1LoW in https://github.com/k1LoW/mo/pull/95 +- fix: render Mermaid charts using actual container width by @k1LoW in https://github.com/kooksee/markview/pull/95 ### Other Changes -- refactor: replace eslint with oxlint/oxfmt by @k1LoW in https://github.com/k1LoW/mo/pull/93 +- refactor: replace eslint with oxlint/oxfmt by @k1LoW in https://github.com/kooksee/markview/pull/93 -## [v0.16.2](https://github.com/k1LoW/mo/compare/v0.16.1...v0.16.2) - 2026-03-09 +## [v0.16.2](https://github.com/kooksee/markview/compare/v0.16.1...v0.16.2) - 2026-03-09 ### Fix bug 🐛 -- Remove stale files when a watched directory is moved by @110y in https://github.com/k1LoW/mo/pull/91 +- Remove stale files when a watched directory is moved by @110y in https://github.com/kooksee/markview/pull/91 -## [v0.16.1](https://github.com/k1LoW/mo/compare/v0.16.0...v0.16.1) - 2026-03-09 +## [v0.16.1](https://github.com/kooksee/markview/compare/v0.16.0...v0.16.1) - 2026-03-09 ### New Features 🎉 -- feat: preserve scroll position across live-reload and server restart by @k1LoW in https://github.com/k1LoW/mo/pull/90 +- feat: preserve scroll position across live-reload and server restart by @k1LoW in https://github.com/kooksee/markview/pull/90 ### Other Changes -- feat: add ESLint to frontend and fix all lint errors by @k1LoW in https://github.com/k1LoW/mo/pull/88 +- feat: add ESLint to frontend and fix all lint errors by @k1LoW in https://github.com/kooksee/markview/pull/88 -## [v0.16.0](https://github.com/k1LoW/mo/compare/v0.15.2...v0.16.0) - 2026-03-08 +## [v0.16.0](https://github.com/kooksee/markview/compare/v0.15.2...v0.16.0) - 2026-03-08 ### Breaking Changes 🛠 -- feat: display deeplinks when adding files via CLI by @k1LoW in https://github.com/k1LoW/mo/pull/86 -- feat: route processable output to stdout and add --json flag by @k1LoW in https://github.com/k1LoW/mo/pull/87 +- feat: display deeplinks when adding files via CLI by @k1LoW in https://github.com/kooksee/markview/pull/86 +- feat: route processable output to stdout and add --json flag by @k1LoW in https://github.com/kooksee/markview/pull/87 ### New Features 🎉 -- feat: add LaTeX/math rendering support with KaTeX by @ysaito8015 in https://github.com/k1LoW/mo/pull/84 -- feat: add drag-and-drop file addition from OS file manager by @k1LoW in https://github.com/k1LoW/mo/pull/85 +- feat: add LaTeX/math rendering support with KaTeX by @ysaito8015 in https://github.com/kooksee/markview/pull/84 +- feat: add drag-and-drop file addition from OS file manager by @k1LoW in https://github.com/kooksee/markview/pull/85 ### Other Changes -- feat: use deterministic hash-based file IDs for deep linking by @k1LoW in https://github.com/k1LoW/mo/pull/81 +- feat: use deterministic hash-based file IDs for deep linking by @k1LoW in https://github.com/kooksee/markview/pull/81 -## [v0.15.2](https://github.com/k1LoW/mo/compare/v0.15.1...v0.15.2) - 2026-03-07 +## [v0.15.2](https://github.com/kooksee/markview/compare/v0.15.1...v0.15.2) - 2026-03-07 ### Other Changes -- fix: always restore backup when starting a new server by @k1LoW in https://github.com/k1LoW/mo/pull/80 +- fix: always restore backup when starting a new server by @k1LoW in https://github.com/kooksee/markview/pull/80 -## [v0.15.1](https://github.com/k1LoW/mo/compare/v0.15.0...v0.15.1) - 2026-03-06 +## [v0.15.1](https://github.com/kooksee/markview/compare/v0.15.0...v0.15.1) - 2026-03-06 -## [v0.15.0](https://github.com/k1LoW/mo/compare/v0.14.1...v0.15.0) - 2026-03-06 +## [v0.15.0](https://github.com/kooksee/markview/compare/v0.14.1...v0.15.0) - 2026-03-06 ### New Features 🎉 -- feat: add auto-backup and restore for sessions by @k1LoW in https://github.com/k1LoW/mo/pull/76 +- feat: add auto-backup and restore for sessions by @k1LoW in https://github.com/kooksee/markview/pull/76 -## [v0.14.1](https://github.com/k1LoW/mo/compare/v0.14.0...v0.14.1) - 2026-03-06 +## [v0.14.1](https://github.com/kooksee/markview/compare/v0.14.0...v0.14.1) - 2026-03-06 ### Fix bug 🐛 -- fix: fix group dropdown not showing when no default group exists by @k1LoW in https://github.com/k1LoW/mo/pull/75 +- fix: fix group dropdown not showing when no default group exists by @k1LoW in https://github.com/kooksee/markview/pull/75 -## [v0.14.0](https://github.com/k1LoW/mo/compare/v0.13.1...v0.14.0) - 2026-03-06 +## [v0.14.0](https://github.com/kooksee/markview/compare/v0.13.1...v0.14.0) - 2026-03-06 ### New Features 🎉 -- feat: add --restart flag by @k1LoW in https://github.com/k1LoW/mo/pull/71 -- Add file search filtering to sidebar by @harakeishi in https://github.com/k1LoW/mo/pull/72 -- feat: reload all browser tabs on server restart by @k1LoW in https://github.com/k1LoW/mo/pull/70 +- feat: add --restart flag by @k1LoW in https://github.com/kooksee/markview/pull/71 +- Add file search filtering to sidebar by @harakeishi in https://github.com/kooksee/markview/pull/72 +- feat: reload all browser tabs on server restart by @k1LoW in https://github.com/kooksee/markview/pull/70 ### Fix bug 🐛 -- fix: render code blocks without language using Shiki and copy button by @babarot in https://github.com/k1LoW/mo/pull/73 +- fix: render code blocks without language using Shiki and copy button by @babarot in https://github.com/kooksee/markview/pull/73 -## [v0.13.1](https://github.com/k1LoW/mo/compare/v0.13.0...v0.13.1) - 2026-03-06 +## [v0.13.1](https://github.com/kooksee/markview/compare/v0.13.0...v0.13.1) - 2026-03-06 ### New Features 🎉 -- feat: add `--unwatch` flag to remove watched glob patterns by @k1LoW in https://github.com/k1LoW/mo/pull/65 +- feat: add `--unwatch` flag to remove watched glob patterns by @k1LoW in https://github.com/kooksee/markview/pull/65 ### Dependency Updates ⬆️ -- chore(deps): bump aquasecurity/trivy-action from 0.34.1 to 0.34.2 in the dependencies group by @dependabot[bot] in https://github.com/k1LoW/mo/pull/66 -- chore(deps): bump the dependencies group in /internal/frontend with 4 updates by @dependabot[bot] in https://github.com/k1LoW/mo/pull/67 +- chore(deps): bump aquasecurity/trivy-action from 0.34.1 to 0.34.2 in the dependencies group by @dependabot[bot] in https://github.com/kooksee/markview/pull/66 +- chore(deps): bump the dependencies group in /internal/frontend with 4 updates by @dependabot[bot] in https://github.com/kooksee/markview/pull/67 -## [v0.13.0](https://github.com/k1LoW/mo/compare/v0.12.0...v0.13.0) - 2026-03-05 +## [v0.13.0](https://github.com/kooksee/markview/compare/v0.12.0...v0.13.0) - 2026-03-05 ### New Features 🎉 -- feat: add `--watch` (`-w`) flag for glob pattern directory watching by @k1LoW in https://github.com/k1LoW/mo/pull/64 +- feat: add `--watch` (`-w`) flag for glob pattern directory watching by @k1LoW in https://github.com/kooksee/markview/pull/64 -## [v0.12.0](https://github.com/k1LoW/mo/compare/v0.11.4...v0.12.0) - 2026-03-04 +## [v0.12.0](https://github.com/kooksee/markview/compare/v0.11.4...v0.12.0) - 2026-03-04 ### New Features 🎉 -- feat: support YAML frontmatter in Markdown files by @k1LoW in https://github.com/k1LoW/mo/pull/60 -- feat: support MDX files by @k1LoW in https://github.com/k1LoW/mo/pull/62 +- feat: support YAML frontmatter in Markdown files by @k1LoW in https://github.com/kooksee/markview/pull/60 +- feat: support MDX files by @k1LoW in https://github.com/kooksee/markview/pull/62 -## [v0.11.4](https://github.com/k1LoW/mo/compare/v0.11.3...v0.11.4) - 2026-03-04 +## [v0.11.4](https://github.com/kooksee/markview/compare/v0.11.3...v0.11.4) - 2026-03-04 ### Other Changes -- Include frontend dependency licenses in CREDITS by @k1LoW in https://github.com/k1LoW/mo/pull/59 +- Include frontend dependency licenses in CREDITS by @k1LoW in https://github.com/kooksee/markview/pull/59 -## [v0.11.3](https://github.com/k1LoW/mo/compare/v0.11.2...v0.11.3) - 2026-03-03 +## [v0.11.3](https://github.com/kooksee/markview/compare/v0.11.2...v0.11.3) - 2026-03-03 ### Other Changes -- fix: avoid appending /default to URL when adding files to existing server by @k1LoW in https://github.com/k1LoW/mo/pull/56 +- fix: avoid appending /default to URL when adding files to existing server by @k1LoW in https://github.com/kooksee/markview/pull/56 -## [v0.11.2](https://github.com/k1LoW/mo/compare/v0.11.1...v0.11.2) - 2026-03-03 +## [v0.11.2](https://github.com/kooksee/markview/compare/v0.11.1...v0.11.2) - 2026-03-03 ### New Features 🎉 -- fix: handle atomic saves and improve live-reload reliability by @k1LoW in https://github.com/k1LoW/mo/pull/54 +- fix: handle atomic saves and improve live-reload reliability by @k1LoW in https://github.com/kooksee/markview/pull/54 -## [v0.11.1](https://github.com/k1LoW/mo/compare/v0.11.0...v0.11.1) - 2026-03-03 +## [v0.11.1](https://github.com/kooksee/markview/compare/v0.11.0...v0.11.1) - 2026-03-03 ### New Features 🎉 -- Allow slashes in --target group names and validate invalid characters by @k1LoW in https://github.com/k1LoW/mo/pull/53 +- Allow slashes in --target group names and validate invalid characters by @k1LoW in https://github.com/kooksee/markview/pull/53 -## [v0.11.0](https://github.com/k1LoW/mo/compare/v0.10.1...v0.11.0) - 2026-03-02 +## [v0.11.0](https://github.com/kooksee/markview/compare/v0.10.1...v0.11.0) - 2026-03-02 ### Breaking Changes 🛠 -- feat: write logs to rotating files under XDG_STATE_HOME by @k1LoW in https://github.com/k1LoW/mo/pull/46 -- feat: run mo in background by default by @k1LoW in https://github.com/k1LoW/mo/pull/50 +- feat: write logs to rotating files under XDG_STATE_HOME by @k1LoW in https://github.com/kooksee/markview/pull/46 +- feat: run markview in background by default by @k1LoW in https://github.com/kooksee/markview/pull/50 ### New Features 🎉 -- feat: add --close flag to gracefully shut down a running mo server by @k1LoW in https://github.com/k1LoW/mo/pull/47 -- feat: add --status flag to show all running mo servers by @k1LoW in https://github.com/k1LoW/mo/pull/51 +- feat: add --close flag to gracefully shut down a running markview server by @k1LoW in https://github.com/kooksee/markview/pull/47 +- feat: add --status flag to show all running markview servers by @k1LoW in https://github.com/kooksee/markview/pull/51 ### Other Changes -- Rename --close flag to --shutdown by @k1LoW in https://github.com/k1LoW/mo/pull/49 +- Rename --close flag to --shutdown by @k1LoW in https://github.com/kooksee/markview/pull/49 -## [v0.10.1](https://github.com/k1LoW/mo/compare/v0.10.0...v0.10.1) - 2026-03-02 +## [v0.10.1](https://github.com/kooksee/markview/compare/v0.10.0...v0.10.1) - 2026-03-02 ### Other Changes -- feat: update tree view toggle icon to file-tree style by @k1LoW in https://github.com/k1LoW/mo/pull/45 +- feat: update tree view toggle icon to file-tree style by @k1LoW in https://github.com/kooksee/markview/pull/45 -## [v0.10.0](https://github.com/k1LoW/mo/compare/v0.9.0...v0.10.0) - 2026-03-02 +## [v0.10.0](https://github.com/kooksee/markview/compare/v0.9.0...v0.10.0) - 2026-03-02 ### New Features 🎉 -- feat: add drag-and-drop file reordering in sidebar by @k1LoW in https://github.com/k1LoW/mo/pull/41 -- feat: add move file to another group via kebab menu by @k1LoW in https://github.com/k1LoW/mo/pull/42 -- feat: add flat/tree view toggle for sidebar by @k1LoW in https://github.com/k1LoW/mo/pull/43 +- feat: add drag-and-drop file reordering in sidebar by @k1LoW in https://github.com/kooksee/markview/pull/41 +- feat: add move file to another group via kebab menu by @k1LoW in https://github.com/kooksee/markview/pull/42 +- feat: add flat/tree view toggle for sidebar by @k1LoW in https://github.com/kooksee/markview/pull/43 -## [v0.9.0](https://github.com/k1LoW/mo/compare/v0.8.0...v0.9.0) - 2026-03-02 +## [v0.9.0](https://github.com/kooksee/markview/compare/v0.8.0...v0.9.0) - 2026-03-02 ### New Features 🎉 -- feat: add file remove feature by @k1LoW in https://github.com/k1LoW/mo/pull/36 -- feat: add Open in new tab to sidebar kebab menu by @k1LoW in https://github.com/k1LoW/mo/pull/38 -- feat: add restart server from Web UI by @k1LoW in https://github.com/k1LoW/mo/pull/39 +- feat: add file remove feature by @k1LoW in https://github.com/kooksee/markview/pull/36 +- feat: add Open in new tab to sidebar kebab menu by @k1LoW in https://github.com/kooksee/markview/pull/38 +- feat: add restart server from Web UI by @k1LoW in https://github.com/kooksee/markview/pull/39 -## [v0.8.0](https://github.com/k1LoW/mo/compare/v0.7.0...v0.8.0) - 2026-03-01 +## [v0.8.0](https://github.com/kooksee/markview/compare/v0.7.0...v0.8.0) - 2026-03-01 ### New Features 🎉 -- feat: add copy buttons to Mermaid blocks by @k1LoW in https://github.com/k1LoW/mo/pull/34 +- feat: add copy buttons to Mermaid blocks by @k1LoW in https://github.com/kooksee/markview/pull/34 -## [v0.7.0](https://github.com/k1LoW/mo/compare/v0.6.0...v0.7.0) - 2026-03-01 +## [v0.7.0](https://github.com/kooksee/markview/compare/v0.6.0...v0.7.0) - 2026-03-01 ### New Features 🎉 -- feat: add copy button to code blocks by @k1LoW in https://github.com/k1LoW/mo/pull/32 +- feat: add copy button to code blocks by @k1LoW in https://github.com/kooksee/markview/pull/32 ### Other Changes -- test: improve frontend testing with colocation and component tests by @k1LoW in https://github.com/k1LoW/mo/pull/33 +- test: improve frontend testing with colocation and component tests by @k1LoW in https://github.com/kooksee/markview/pull/33 -## [v0.6.0](https://github.com/k1LoW/mo/compare/v0.5.2...v0.6.0) - 2026-03-01 +## [v0.6.0](https://github.com/kooksee/markview/compare/v0.5.2...v0.6.0) - 2026-03-01 ### New Features 🎉 -- feat: add copy-to-clipboard button with format selection by @k1LoW in https://github.com/k1LoW/mo/pull/29 +- feat: add copy-to-clipboard button with format selection by @k1LoW in https://github.com/kooksee/markview/pull/29 ### Other Changes -- fix: differentiate ToC indentation for each heading level by @k1LoW in https://github.com/k1LoW/mo/pull/30 +- fix: differentiate ToC indentation for each heading level by @k1LoW in https://github.com/kooksee/markview/pull/30 -## [v0.5.2](https://github.com/k1LoW/mo/compare/v0.5.1...v0.5.2) - 2026-03-01 +## [v0.5.2](https://github.com/kooksee/markview/compare/v0.5.1...v0.5.2) - 2026-03-01 -## [v0.5.1](https://github.com/k1LoW/mo/compare/v0.5.0...v0.5.1) - 2026-03-01 +## [v0.5.1](https://github.com/kooksee/markview/compare/v0.5.0...v0.5.1) - 2026-03-01 ### Fix bug 🐛 -- fix: resolve render loop caused by unstable references in ToC integration by @k1LoW in https://github.com/k1LoW/mo/pull/26 +- fix: resolve render loop caused by unstable references in ToC integration by @k1LoW in https://github.com/kooksee/markview/pull/26 -## [v0.5.0](https://github.com/k1LoW/mo/compare/v0.4.1...v0.5.0) - 2026-02-28 +## [v0.5.0](https://github.com/kooksee/markview/compare/v0.4.1...v0.5.0) - 2026-02-28 ### New Features 🎉 -- feat: add raw markdown view toggle by @k1LoW in https://github.com/k1LoW/mo/pull/22 -- feat: add table of contents right panel by @k1LoW in https://github.com/k1LoW/mo/pull/24 +- feat: add raw markdown view toggle by @k1LoW in https://github.com/kooksee/markview/pull/22 +- feat: add table of contents right panel by @k1LoW in https://github.com/kooksee/markview/pull/24 -## [v0.4.1](https://github.com/k1LoW/mo/compare/v0.4.0...v0.4.1) - 2026-02-28 +## [v0.4.1](https://github.com/kooksee/markview/compare/v0.4.0...v0.4.1) - 2026-02-28 ### Fix bug 🐛 -- fix: reject directory paths passed as file arguments by @matsuyoshi30 in https://github.com/k1LoW/mo/pull/20 +- fix: reject directory paths passed as file arguments by @matsuyoshi30 in https://github.com/kooksee/markview/pull/20 -## [v0.4.0](https://github.com/k1LoW/mo/compare/v0.3.2...v0.4.0) - 2026-02-28 +## [v0.4.0](https://github.com/kooksee/markview/compare/v0.3.2...v0.4.0) - 2026-02-28 ### New Features 🎉 -- feat: add --open and --no-open flags to control browser opening by @k1LoW in https://github.com/k1LoW/mo/pull/19 +- feat: add --open and --no-open flags to control browser opening by @k1LoW in https://github.com/kooksee/markview/pull/19 -## [v0.3.2](https://github.com/k1LoW/mo/compare/v0.3.1...v0.3.2) - 2026-02-28 +## [v0.3.2](https://github.com/kooksee/markview/compare/v0.3.1...v0.3.2) - 2026-02-28 ### Fix bug 🐛 -- fix: serialize mermaid rendering to fix multiple diagrams by @k1LoW in https://github.com/k1LoW/mo/pull/15 +- fix: serialize mermaid rendering to fix multiple diagrams by @k1LoW in https://github.com/kooksee/markview/pull/15 -## [v0.3.1](https://github.com/k1LoW/mo/compare/v0.3.0...v0.3.1) - 2026-02-27 +## [v0.3.1](https://github.com/kooksee/markview/compare/v0.3.0...v0.3.1) - 2026-02-27 ### Other Changes -- refactor: improve donegroup usage for graceful shutdown by @k1LoW in https://github.com/k1LoW/mo/pull/13 -- refactor: replace log and fmt.Fprintf(os.Stderr) with slog by @k1LoW in https://github.com/k1LoW/mo/pull/14 +- refactor: improve donegroup usage for graceful shutdown by @k1LoW in https://github.com/kooksee/markview/pull/13 +- refactor: replace log and fmt.Fprintf(os.Stderr) with slog by @k1LoW in https://github.com/kooksee/markview/pull/14 -## [v0.3.0](https://github.com/k1LoW/mo/compare/v0.2.0...v0.3.0) - 2026-02-27 +## [v0.3.0](https://github.com/kooksee/markview/compare/v0.2.0...v0.3.0) - 2026-02-27 ### New Features 🎉 -- feat: support GitHub Alerts (admonitions) by @k1LoW in https://github.com/k1LoW/mo/pull/11 +- feat: support GitHub Alerts (admonitions) by @k1LoW in https://github.com/kooksee/markview/pull/11 -## [v0.2.0](https://github.com/k1LoW/mo/compare/v0.1.1...v0.2.0) - 2026-02-27 +## [v0.2.0](https://github.com/kooksee/markview/compare/v0.1.1...v0.2.0) - 2026-02-27 ### New Features 🎉 -- feat: show file path tooltip on sidebar hover by @k1LoW in https://github.com/k1LoW/mo/pull/8 +- feat: show file path tooltip on sidebar hover by @k1LoW in https://github.com/kooksee/markview/pull/8 -## [v0.1.1](https://github.com/k1LoW/mo/compare/v0.1.0...v0.1.1) - 2026-02-27 +## [v0.1.1](https://github.com/kooksee/markview/compare/v0.1.0...v0.1.1) - 2026-02-27 -## [v0.1.0](https://github.com/k1LoW/mo/commits/v0.1.0) - 2026-02-27 +## [v0.1.0](https://github.com/kooksee/markview/commits/v0.1.0) - 2026-02-27 ### Dependency Updates ⬆️ -- chore(deps): bump pnpm/action-setup from 4.1.0 to 4.2.0 in the dependencies group by @dependabot[bot] in https://github.com/k1LoW/mo/pull/4 -- chore(deps): bump the dependencies group in /internal/frontend with 3 updates by @dependabot[bot] in https://github.com/k1LoW/mo/pull/6 +- chore(deps): bump pnpm/action-setup from 4.1.0 to 4.2.0 in the dependencies group by @dependabot[bot] in https://github.com/kooksee/markview/pull/4 +- chore(deps): bump the dependencies group in /internal/frontend with 3 updates by @dependabot[bot] in https://github.com/kooksee/markview/pull/6 diff --git a/Makefile b/Makefile index 10b3a78..c9296ff 100644 --- a/Makefile +++ b/Makefile @@ -15,13 +15,13 @@ test: go test ./... -coverprofile=coverage.out -covermode=count -count=1 build: generate - go build -ldflags=$(BUILD_LDFLAGS) -trimpath -o mo . + go build -ldflags=$(BUILD_LDFLAGS) -trimpath -o markview . install: generate go install -ldflags=$(BUILD_LDFLAGS) -trimpath . dev: build - ./mo -p 16275 --foreground $(ARGS) + ./markview -p 16275 --foreground $(ARGS) screenshot: build cd internal/frontend && pnpm run screenshots diff --git a/README.md b/README.md index 20c4c66..a4a0af5 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@




-mo +markview


-# mo +# markview [![build](https://github.com/kooksee/markview/actions/workflows/ci.yml/badge.svg)](https://github.com/kooksee/markview/actions/workflows/ci.yml) ![Coverage](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/coverage.svg) ![Code to Test Ratio](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/ratio.svg) ![Test Execution Time](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/kooksee/markview/time.svg) -`mo` is a **M**arkdown viewer that **o**pens `.md` files in a browser. +`markview` is a Markdown viewer that opens `.md` files in a browser. + +> For AI coding assistant/project guidance, use `.github/copilot-instructions.md` as the single source of truth. ## Features @@ -35,7 +37,7 @@ **homebrew tap:** ```console -$ brew install k1LoW/tap/mo +$ brew install kooksee/tap/markview ``` **manually:** @@ -45,26 +47,26 @@ Download binary from [releases page](https://github.com/kooksee/markview/release ## Usage ``` console -$ mo README.md # Open a single file -$ mo README.md CHANGELOG.md docs/*.md # Open multiple files -$ mo spec.md --target design # Open in a named group +$ markview README.md # Open a single file +$ markview README.md CHANGELOG.md docs/*.md # Open multiple files +$ markview spec.md --target design # Open in a named group ``` -`mo` opens Markdown files in a browser with live-reload. When you save a file, the browser automatically reflects the changes. +`markview` opens Markdown files in a browser with live-reload. When you save a file, the browser automatically reflects the changes. ### Single server, multiple files -By default, `mo` runs a single server on port `6275`. If a server is already running on the same port, subsequent `mo` invocations add files to the existing session instead of starting a new one. +By default, `markview` runs a single server on port `6275`. If a server is already running on the same port, subsequent `markview` invocations add files to the existing session instead of starting a new one. ``` console -$ mo README.md # Starts a mo server in the background -$ mo CHANGELOG.md # Adds the file to the running mo server +$ markview README.md # Starts a markview server in the background +$ markview CHANGELOG.md # Adds the file to the running markview server ``` To run a completely separate session, use a different port: ``` console -$ mo draft.md -p 6276 +$ markview draft.md -p 6276 ``` ![Multiple files with sidebar](images/multiple-files.png) @@ -74,9 +76,9 @@ $ mo draft.md -p 6276 Files can be organized into named groups using the `--target` (`-t`) flag. Each group gets its own URL path and sidebar. ``` console -$ mo spec.md --target design # Opens at http://localhost:6275/design -$ mo api.md --target design # Adds to the "design" group -$ mo notes.md --target notes # Opens at http://localhost:6275/notes +$ markview spec.md --target design # Opens at http://localhost:6275/design +$ markview api.md --target design # Adds to the "design" group +$ markview notes.md --target notes # Opens at http://localhost:6275/notes ``` ![Group view](images/groups.png) @@ -86,9 +88,9 @@ $ mo notes.md --target notes # Opens at http://localhost:6275/notes Use `--watch` (`-w`) to specify glob patterns. Matching files are opened automatically, and watched directories are monitored for new files. ``` console -$ mo --watch '**/*.md' # Watch and open all .md files recursively -$ mo --watch 'docs/**/*.md' --target docs # Watch docs/ tree in "docs" group -$ mo --watch '*.md' --watch 'docs/**/*.md' # Multiple patterns +$ markview --watch '**/*.md' # Watch and open all .md files recursively +$ markview --watch 'docs/**/*.md' --target docs # Watch docs/ tree in "docs" group +$ markview --watch '*.md' --watch 'docs/**/*.md' # Multiple patterns ``` `--watch` cannot be combined with file arguments. The `**` pattern matches directories recursively. @@ -98,9 +100,9 @@ $ mo --watch '*.md' --watch 'docs/**/*.md' # Multiple patterns Use `--unwatch` to stop watching a previously registered pattern. Files already added remain in the sidebar. ``` console -$ mo --unwatch '**/*.md' # Stop watching a pattern (default group) -$ mo --unwatch 'docs/**/*.md' --target docs # Stop watching in a specific group -$ mo --unwatch '/Users/you/project/**/*.md' # Stop watching by absolute path +$ markview --unwatch '**/*.md' # Stop watching a pattern (default group) +$ markview --unwatch 'docs/**/*.md' --target docs # Stop watching in a specific group +$ markview --unwatch '/Users/you/project/**/*.md' # Stop watching by absolute path ``` Patterns are resolved to absolute paths before matching, so you can specify either a relative glob or the full path shown by `--status`. @@ -115,55 +117,55 @@ The sidebar supports flat and tree view modes. Flat view shows file names only, ### Starting and stopping -`mo` runs in the background by default — the command returns immediately, leaving the shell free for other work. This makes it easy to incorporate into scripts, tool chains, or LLM-driven workflows. +`markview` runs in the background by default — the command returns immediately, leaving the shell free for other work. This makes it easy to incorporate into scripts, tool chains, or LLM-driven workflows. ``` console -$ mo README.md -mo: serving at http://localhost:6275 (pid 12345) +$ markview README.md +markview: serving at http://localhost:6275 (pid 12345) $ # shell is available immediately ``` -Use `--status` to check all running mo servers, and `--shutdown` to stop one: +Use `--status` to check all running markview servers, and `--shutdown` to stop one: ``` console -$ mo --status # Show all running mo servers +$ markview --status # Show all running markview servers http://localhost:6275 (pid 12345, v0.12.0) default: 5 file(s) watching: /Users/you/project/src/**/*.md, /Users/you/project/*.md docs: 2 file(s) watching: /Users/you/project/docs/**/*.md -$ mo --shutdown # Shut down the mo server on the default port -$ mo --shutdown -p 6276 # Shut down the mo server on a specific port -$ mo --restart # Restart the mo server on the default port +$ markview --shutdown # Shut down the markview server on the default port +$ markview --shutdown -p 6276 # Shut down the markview server on a specific port +$ markview --restart # Restart the markview server on the default port ``` -If you need the mo server to run in the foreground (e.g. for debugging), use `--foreground`: +If you need the markview server to run in the foreground (e.g. for debugging), use `--foreground`: ``` console -$ mo --foreground README.md +$ markview --foreground README.md ``` ### Server restart -Click the restart restart button (bottom-right corner) or run `mo --restart` to restart the `mo` server process. The current session — all open files and groups — is preserved across the restart. This is useful when you have updated the `mo` binary and want to pick up the new version without re-opening your files. +Click the restart restart button (bottom-right corner) or run `markview --restart` to restart the `markview` server process. The current session — all open files and groups — is preserved across the restart. This is useful when you have updated the `markview` binary and want to pick up the new version without re-opening your files. ### Session backup and restore -`mo` automatically saves session state (open files and watch patterns per group) when files are added or removed. When starting a new server, the previous session is automatically restored and merged with any files specified on the command line. Restored session entries appear first, followed by newly specified files. +`markview` automatically saves session state (open files and watch patterns per group) when files are added or removed. When starting a new server, the previous session is automatically restored and merged with any files specified on the command line. Restored session entries appear first, followed by newly specified files. ``` console -$ mo README.md CHANGELOG.md # Start with two files -$ mo --shutdown # Shut down the server -$ mo # Restores README.md and CHANGELOG.md -$ mo TODO.md # Restores previous session + adds TODO.md +$ markview README.md CHANGELOG.md # Start with two files +$ markview --shutdown # Shut down the server +$ markview # Restores README.md and CHANGELOG.md +$ markview TODO.md # Restores previous session + adds TODO.md ``` Use `--clear` to remove a saved session: ``` console -$ mo --clear # Clear saved session for the default port -$ mo --clear -p 6276 # Clear saved session for a specific port +$ markview --clear # Clear saved session for the default port +$ markview --clear -p 6276 # Clear saved session for a specific port ``` ### JSON output @@ -171,7 +173,7 @@ $ mo --clear -p 6276 # Clear saved session for a specific port Use `--json` to get structured JSON output on stdout, useful for scripting and integration with other tools. ``` console -$ mo --json README.md +$ markview --json README.md { "url": "http://localhost:6275", "files": [ @@ -187,7 +189,7 @@ $ mo --json README.md `--status` also supports `--json`: ``` console -$ mo --status --json +$ markview --status --json [ { "url": "http://localhost:6275", @@ -215,17 +217,17 @@ $ mo --status --json | `--bind` | `-b` | `0.0.0.0` | Bind address (e.g. `localhost`) | | `--open` | | | Always open browser | | `--no-open` | | | Never open browser | -| `--status` | | | Show all running mo servers | +| `--status` | | | Show all running markview servers | | `--watch` | `-w` | | Glob pattern to watch for matching files (repeatable) | | `--unwatch` | | | Remove a watched glob pattern (repeatable) | -| `--shutdown` | | | Shut down the running mo server | -| `--restart` | | | Restart the running mo server | +| `--shutdown` | | | Shut down the running markview server | +| `--restart` | | | Restart the running markview server | | `--clear` | | | Clear saved session for the specified port | -| `--foreground` | | | Run mo server in foreground | +| `--foreground` | | | Run markview server in foreground | | `--json` | | | Output structured data as JSON to stdout | > [!WARNING] -> Binding to a non-loopback address exposes mo to the network **without any authentication**. Remote clients can read any file accessible by the user, browse the filesystem via glob patterns, and shut down the server. A confirmation prompt is shown when `--bind` is set to a non-loopback address. +> Binding to a non-loopback address exposes markview to the network **without any authentication**. Remote clients can read any file accessible by the user, browse the filesystem via glob patterns, and shut down the server. A confirmation prompt is shown when `--bind` is set to a non-loopback address. ## Build @@ -244,4 +246,4 @@ $ make build - [MIT License](LICENSE) - Include logo as well as source code. - Only logo license can be selected [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). - - Also, if there is no alteration to the logo and it is used for technical information about mo, I would not say anything if the copyright notice is omitted. + - Also, if there is no alteration to the logo and it is used for technical information about markview, I would not say anything if the copyright notice is omitted. diff --git a/cmd/build.go b/cmd/build.go index d43a347..8f25e42 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -23,10 +23,10 @@ The output is a directory containing index.html and all necessary assets, with all file contents embedded. No server is needed to view the result. Examples: - mo build docs/ Build from docs/ to docs-static/ - mo build docs/ -o dist/ Build from docs/ to dist/ - mo build . Build from current directory - mo build README.md CHANGELOG.md Build from specific files`, + markview build docs/ Build from docs/ to docs-static/ + markview build docs/ -o dist/ Build from docs/ to dist/ + markview build . Build from current directory + markview build README.md CHANGELOG.md Build from specific files`, Args: cobra.MinimumNArgs(1), RunE: runBuild, } @@ -62,11 +62,11 @@ func runBuild(_ *cobra.Command, args []string) error { return fmt.Errorf("cannot resolve output directory: %w", err) } - fmt.Fprintf(os.Stderr, "mo: scanning %s for markdown files...\n", firstAbs) + fmt.Fprintf(os.Stderr, "markview: scanning %s for markdown files...\n", firstAbs) if err := build.BuildStaticSite(firstAbs, absOutput); err != nil { return err } - fmt.Fprintf(os.Stderr, "mo: static site built to %s\n", absOutput) + fmt.Fprintf(os.Stderr, "markview: static site built to %s\n", absOutput) return nil } @@ -89,17 +89,17 @@ func runBuild(_ *cobra.Command, args []string) error { outputDir := buildOutput if outputDir == "" { - outputDir = "mo-static" + outputDir = "markview-static" } absOutput, err := filepath.Abs(outputDir) if err != nil { return fmt.Errorf("cannot resolve output directory: %w", err) } - fmt.Fprintf(os.Stderr, "mo: building from %d file(s)...\n", len(files)) + fmt.Fprintf(os.Stderr, "markview: building from %d file(s)...\n", len(files)) if err := build.BuildStaticSiteFromFiles(files, absOutput); err != nil { return err } - fmt.Fprintf(os.Stderr, "mo: static site built to %s\n", absOutput) + fmt.Fprintf(os.Stderr, "markview: static site built to %s\n", absOutput) return nil } diff --git a/cmd/root.go b/cmd/root.go index f88e7bb..fc8ab4c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -55,66 +55,66 @@ var ( ) var rootCmd = &cobra.Command{ - Use: "mo [flags] [FILE ...]", - Short: "mo is a Markdown viewer that opens .md files in a browser.", - Long: `mo is a Markdown viewer that opens .md files in a browser with live-reload. + Use: "markview [flags] [FILE ...]", + Short: "markview is a Markdown viewer that opens .md files in a browser.", + Long: `markview is a Markdown viewer that opens .md files in a browser with live-reload. It runs in the background, serving Markdown files using a built-in React SPA, and automatically refreshes the browser when files are saved. Examples: - mo README.md Open a single file - mo README.md CHANGELOG.md docs/*.md Open multiple files - mo spec.md --target design Open in a named group - mo draft.md --port 6276 Use a different port + markview README.md Open a single file + markview README.md CHANGELOG.md docs/*.md Open multiple files + markview spec.md --target design Open in a named group + markview draft.md --port 6276 Use a different port Single Server, Multiple Files: - By default, mo runs a single server on port 6275. - If a mo server is already running on the same port, subsequent mo + By default, markview runs a single server on port 6275. + If a markview server is already running on the same port, subsequent markview invocations add files to the existing session instead of starting a new one. - $ mo README.md # Starts a mo server in the background - $ mo CHANGELOG.md # Adds the file to the running mo server + $ markview README.md # Starts a markview server in the background + $ markview CHANGELOG.md # Adds the file to the running markview server To run a completely separate session, use a different port: - $ mo draft.md -p 6276 + $ markview draft.md -p 6276 Groups: Files can be organized into named groups using the --target (-t) flag. Each group gets its own URL path (e.g., http://localhost:6275/design) and its own sidebar in the browser. - $ mo spec.md --target design # Opens at /design - $ mo api.md --target design # Adds to the "design" group - $ mo notes.md --target notes # Opens at /notes + $ markview spec.md --target design # Opens at /design + $ markview api.md --target design # Adds to the "design" group + $ markview notes.md --target notes # Opens at /notes If no --target is specified, files are added to the "default" group. Starting and Stopping: - mo runs in the background by default. The command returns + markview runs in the background by default. The command returns immediately, leaving the shell free for other work. - $ mo README.md # Starts mo in the background - $ mo --status # Shows all running mo servers - $ mo --shutdown # Shuts it down - $ mo --restart # Restarts it (preserving session) + $ markview README.md # Starts markview in the background + $ markview --status # Shows all running markview servers + $ markview --shutdown # Shuts it down + $ markview --restart # Restarts it (preserving session) - Use --foreground to keep the mo server in the foreground. + Use --foreground to keep the markview server in the foreground. Session Restore: - mo automatically saves session state. When starting a new server, + markview automatically saves session state. When starting a new server, the previous session is restored and merged with any specified files. - $ mo README.md CHANGELOG.md # Start with two files - $ mo --shutdown # Shut down the server - $ mo # Restores README.md and CHANGELOG.md - $ mo TODO.md # Restores previous session + adds TODO.md + $ markview README.md CHANGELOG.md # Start with two files + $ markview --shutdown # Shut down the server + $ markview # Restores README.md and CHANGELOG.md + $ markview TODO.md # Restores previous session + adds TODO.md Use --clear to remove a saved session. Live-Reload: - mo watches all opened files for changes using filesystem notifications. + markview watches all opened files for changes using filesystem notifications. When a file is saved, the browser automatically re-renders the content. Supported Markdown Features: @@ -130,13 +130,13 @@ Glob Patterns: watched and new files are automatically added. Cannot be combined with file arguments. - $ mo -w '**/*.md' Watch all .md files recursively - $ mo -w 'docs/**/*.md' -t docs Watch docs/ tree in "docs" group - $ mo -w '*.md' -w 'docs/**/*.md' Watch multiple patterns - $ mo --unwatch '**/*.md' Stop watching a pattern + $ markview -w '**/*.md' Watch all .md files recursively + $ markview -w 'docs/**/*.md' -t docs Watch docs/ tree in "docs" group + $ markview -w '*.md' -w 'docs/**/*.md' Watch multiple patterns + $ markview --unwatch '**/*.md' Stop watching a pattern WARNING: --bind with a non-loopback address: - Binding to a non-loopback address (e.g. 0.0.0.0) exposes mo to the + Binding to a non-loopback address (e.g. 0.0.0.0) exposes markview to the network without any authentication. Remote clients can read any file accessible by this user, browse the filesystem via glob patterns, and shut down the server. A confirmation prompt is shown before starting.`, @@ -158,13 +158,13 @@ func init() { rootCmd.Flags().BoolVar(&open, "open", false, "Always open browser (even when adding to existing group)") rootCmd.Flags().BoolVar(&noOpen, "no-open", false, "Do not open browser automatically") rootCmd.MarkFlagsMutuallyExclusive("open", "no-open") - rootCmd.Flags().BoolVar(&shutdownServer, "shutdown", false, "Shut down the running mo server on the specified port") - rootCmd.Flags().BoolVar(&restartServer, "restart", false, "Restart the running mo server on the specified port") + rootCmd.Flags().BoolVar(&shutdownServer, "shutdown", false, "Shut down the running markview server on the specified port") + rootCmd.Flags().BoolVar(&restartServer, "restart", false, "Restart the running markview server on the specified port") rootCmd.MarkFlagsMutuallyExclusive("shutdown", "restart") rootCmd.Flags().StringVar(&restore, "restore", "", "Restore state from file (internal use)") rootCmd.Flags().MarkHidden("restore") //nolint:errcheck - rootCmd.Flags().BoolVar(&foreground, "foreground", false, "Run mo server in foreground (do not background)") - rootCmd.Flags().BoolVar(&statusServer, "status", false, "Show status of all running mo servers") + rootCmd.Flags().BoolVar(&foreground, "foreground", false, "Run markview server in foreground (do not background)") + rootCmd.Flags().BoolVar(&statusServer, "status", false, "Show status of all running markview servers") rootCmd.Flags().StringArrayVarP(&watchPatterns, "watch", "w", nil, "Glob pattern to watch for matching files (repeatable)") rootCmd.Flags().StringArrayVar(&unwatchPatterns, "unwatch", nil, "Remove a watched glob pattern (repeatable)") rootCmd.Flags().BoolVar(&clearBackup, "clear", false, "Clear saved session for the specified port") @@ -187,24 +187,24 @@ func run(cmd *cobra.Command, args []string) error { if clearBackup { if !backup.Exists(port) { - fmt.Fprintf(os.Stderr, "mo: no saved session for port %d\n", port) + fmt.Fprintf(os.Stderr, "markview: no saved session for port %d\n", port) return nil } - fmt.Fprintf(os.Stderr, "mo: clear saved session for port %d? [Y/n] ", port) + fmt.Fprintf(os.Stderr, "markview: clear saved session for port %d? [Y/n] ", port) scanner := bufio.NewScanner(os.Stdin) if !scanner.Scan() { - fmt.Fprintln(os.Stderr, "mo: canceled") + fmt.Fprintln(os.Stderr, "markview: canceled") return nil } ans := strings.TrimSpace(scanner.Text()) if ans != "" && strings.ToLower(ans) != "y" && strings.ToLower(ans) != "yes" { - fmt.Fprintln(os.Stderr, "mo: canceled") + fmt.Fprintln(os.Stderr, "markview: canceled") return nil } if err := backup.Remove(port); err != nil { return err } - fmt.Fprintf(os.Stderr, "mo: cleared saved session for port %d\n", port) + fmt.Fprintf(os.Stderr, "markview: cleared saved session for port %d\n", port) return nil } @@ -307,7 +307,7 @@ func run(cmd *cobra.Command, args []string) error { var uploadedFiles []server.UploadedFileData if len(restoredFiles) > 0 || len(restoredPatterns) > 0 || len(restoredUploads) > 0 { slog.Info("restoring session from backup", "port", port) - fmt.Fprintf(os.Stderr, "mo: restoring previous session for port %d\n", port) + fmt.Fprintf(os.Stderr, "markview: restoring previous session for port %d\n", port) filesByGroup = mergeGroups(restoredFiles, filesByGroup) patternsByGroup = mergeGroups(restoredPatterns, patternsByGroup) uploadedFiles = restoredUploads @@ -321,7 +321,7 @@ func run(cmd *cobra.Command, args []string) error { o := termenv.NewOutput(os.Stderr) c := func(s string) termenv.Style { return o.String(s).Foreground(o.Color("208")) } fmt.Fprintln(os.Stderr, c("SECURITY WARNING:").Bold(), - c(fmt.Sprintf("Binding to non-loopback address %s. mo has no authentication -- remote clients can:", bind))) + c(fmt.Sprintf("Binding to non-loopback address %s. markview has no authentication -- remote clients can:", bind))) fmt.Fprintln(os.Stderr, c(" - Read any file accessible by this user")) fmt.Fprintln(os.Stderr, c(" - Browse the filesystem via glob patterns")) fmt.Fprintln(os.Stderr, c(" - Shut down or restart the server")) @@ -331,12 +331,12 @@ func run(cmd *cobra.Command, args []string) error { if err := scanner.Err(); err != nil { return err } - fmt.Fprintln(os.Stderr, "mo: canceled") + fmt.Fprintln(os.Stderr, "markview: canceled") return nil } ans := strings.ToLower(strings.TrimSpace(scanner.Text())) if ans != "y" && ans != "yes" { - fmt.Fprintln(os.Stderr, "mo: canceled") + fmt.Fprintln(os.Stderr, "markview: canceled") return nil } } @@ -472,7 +472,7 @@ func tryAddToExisting(addr string, files []string, patterns []string) bool { added := len(files) + len(patterns) slog.Info("added to existing server", "files", len(files), "patterns", len(patterns), "addr", addr) emitServeOutput(addr, deeplinks, false) - fmt.Fprintf(os.Stderr, "mo: added %d item(s) to http://%s\n", added, addr) + fmt.Fprintf(os.Stderr, "markview: added %d item(s) to http://%s\n", added, addr) if isNewGroup || open { openBrowser(addr) @@ -708,7 +708,7 @@ type probeResult struct { groups []string } -// probeServer checks that a mo server is running on addr by calling +// probeServer checks that a markview server is running on addr by calling // GET /_/api/status and validating the response contains a version field. func probeServer(addr string, timeout ...time.Duration) (*probeResult, error) { t := probeTimeoutDefault @@ -718,7 +718,7 @@ func probeServer(addr string, timeout ...time.Duration) (*probeResult, error) { client := &http.Client{Timeout: t} resp, err := client.Get(fmt.Sprintf("http://%s/_/api/status", addr)) if err != nil { - return nil, fmt.Errorf("no mo server found on %s", addr) + return nil, fmt.Errorf("no markview server found on %s", addr) } defer resp.Body.Close() @@ -734,7 +734,7 @@ func probeServer(addr string, timeout ...time.Duration) (*probeResult, error) { } `json:"groups"` } if err := json.NewDecoder(resp.Body).Decode(&status); err != nil || status.Version == "" { - return nil, fmt.Errorf("server on %s is not a mo instance", addr) + return nil, fmt.Errorf("server on %s is not a markview instance", addr) } groups := make([]string, len(status.Groups)) @@ -761,7 +761,7 @@ func doShutdown(addr string) error { } slog.Info("shutdown request sent", "addr", addr) - fmt.Fprintf(os.Stderr, "mo: shutdown request sent to %s\n", addr) + fmt.Fprintf(os.Stderr, "markview: shutdown request sent to %s\n", addr) return nil } @@ -782,7 +782,7 @@ func doRestart(addr string) error { } slog.Info("restart request sent", "addr", addr) - fmt.Fprintf(os.Stderr, "mo: restart request sent to %s\n", addr) + fmt.Fprintf(os.Stderr, "markview: restart request sent to %s\n", addr) return nil } @@ -821,7 +821,7 @@ func doUnwatch(addr string, patterns []string, groupName string) error { } slog.Info("pattern removed", "pattern", pat, "group", groupName) - fmt.Fprintf(os.Stderr, "mo: unwatched %s\n", pat) + fmt.Fprintf(os.Stderr, "markview: unwatched %s\n", pat) } return nil @@ -848,7 +848,7 @@ func doStatus() error { if jsonOutput { writeJSON([]jsonStatusEntry{}) } else { - fmt.Fprintln(os.Stderr, "mo: no mo server found") + fmt.Fprintln(os.Stderr, "markview: no markview server found") } return nil } @@ -924,7 +924,7 @@ func doStatus() error { } writeJSON(jsonEntries) } else if !found { - fmt.Fprintln(os.Stderr, "mo: no mo server found") + fmt.Fprintln(os.Stderr, "markview: no markview server found") } return nil @@ -943,12 +943,12 @@ func discoverPorts() []int { var ports []int for _, e := range entries { name := e.Name() - // Match "mo-{port}.log" - if !strings.HasPrefix(name, "mo-") || !strings.HasSuffix(name, ".log") { + // Match "markview-{port}.log" + if !strings.HasPrefix(name, "markview-") || !strings.HasSuffix(name, ".log") { continue } - // Exclude rotated backups like "mo-6275.log.1" - raw := strings.TrimSuffix(strings.TrimPrefix(name, "mo-"), ".log") + // Exclude rotated backups like "markview-6275.log.1" + raw := strings.TrimSuffix(strings.TrimPrefix(name, "markview-"), ".log") p, err := strconv.Atoi(raw) if err != nil { continue @@ -1122,7 +1122,7 @@ func startBackground(addr string, filesByGroup map[string][]string, patternsByGr } } emitServeOutput(addr, deeplinks, true) - fmt.Fprintf(os.Stderr, "mo: serving at http://%s (pid %d)\n", addr, pid) + fmt.Fprintf(os.Stderr, "markview: serving at http://%s (pid %d)\n", addr, pid) openBrowser(addr) diff --git a/internal/backup/backup.go b/internal/backup/backup.go index 0234786..319e8fd 100644 --- a/internal/backup/backup.go +++ b/internal/backup/backup.go @@ -15,7 +15,7 @@ func Dir() (string, error) { if err != nil { return "", err } - return filepath.Join(stateHome, "mo", "backup"), nil + return filepath.Join(stateHome, "markview", "backup"), nil } // Path returns the backup file path for the given port. @@ -24,7 +24,7 @@ func Path(port int) (string, error) { if err != nil { return "", err } - return filepath.Join(dir, fmt.Sprintf("mo-%d.json", port)), nil + return filepath.Join(dir, fmt.Sprintf("markview-%d.json", port)), nil } // Save atomically writes data to the backup file for the given port. @@ -43,7 +43,7 @@ func Save(port int, data any) (retErr error) { return fmt.Errorf("failed to marshal backup data: %w", err) } - tmp, err := os.CreateTemp(dir, "mo-backup-*.tmp") + tmp, err := os.CreateTemp(dir, "markview-backup-*.tmp") if err != nil { return fmt.Errorf("failed to create temp file: %w", err) } diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go index 6da24ce..4125172 100644 --- a/internal/backup/backup_test.go +++ b/internal/backup/backup_test.go @@ -130,7 +130,7 @@ func TestPath(t *testing.T) { t.Fatalf("Path returned error: %v", err) } - want := dir + "/mo/backup/mo-6275.json" + want := dir + "/markview/backup/markview-6275.json" if p != want { t.Fatalf("got %s, want %s", p, want) } @@ -141,7 +141,7 @@ func TestSaveCreatesDirectory(t *testing.T) { t.Setenv("XDG_STATE_HOME", dir) // Directory does not exist yet - backupDir := dir + "/mo/backup" + backupDir := dir + "/markview/backup" if _, err := os.Stat(backupDir); !os.IsNotExist(err) { t.Fatal("backup directory should not exist before Save") } diff --git a/internal/build/build.go b/internal/build/build.go index 7e67c21..6f31138 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -230,7 +230,7 @@ func buildAndWrite(entries []*server.FileEntry, outputDir string) error { if path == "index.html" { injection := fmt.Sprintf( - ``, + ``, string(dataJSON), ) fileData = bytes.Replace( @@ -251,7 +251,7 @@ func buildAndWrite(entries []*server.FileEntry, outputDir string) error { return fmt.Errorf("writing output: %w", err) } - fmt.Fprintf(os.Stderr, "mo: %d file(s) processed\n", len(entries)) + fmt.Fprintf(os.Stderr, "markview: %d file(s) processed\n", len(entries)) return nil } diff --git a/internal/frontend/index.html b/internal/frontend/index.html index 1b75ad5..2ba0b56 100644 --- a/internal/frontend/index.html +++ b/internal/frontend/index.html @@ -1,13 +1,16 @@ - - - - - mo - - -
- - - + + + + + + markview + + + +
+ + + + \ No newline at end of file diff --git a/internal/frontend/scripts/screenshots.mjs b/internal/frontend/scripts/screenshots.mjs index 46a596a..c2bf5cd 100644 --- a/internal/frontend/scripts/screenshots.mjs +++ b/internal/frontend/scripts/screenshots.mjs @@ -15,7 +15,7 @@ async function waitForServer(maxRetries = 30) { try { const res = await fetch(`${BASE}/_/api/groups`); if (res.ok) return; - } catch {} + } catch { } await new Promise((r) => setTimeout(r, 500)); } throw new Error("Server did not start"); @@ -37,13 +37,13 @@ async function waitForRendering(page) { .locator(".shiki") .first() .waitFor({ timeout: 15000 }) - .catch(() => {}); + .catch(() => { }); // Wait for Mermaid SVGs await page .locator("svg[id^='mermaid']") .first() .waitFor({ timeout: 15000 }) - .catch(() => {}); + .catch(() => { }); // Extra settle time await page.waitForTimeout(1000); } @@ -52,7 +52,7 @@ async function main() { // Start server with an initial file console.log("Starting server on port", PORT); const firstFile = resolve(TESTDATA, "basic.md"); - const server = spawn(resolve(ROOT, "mo"), [firstFile, "-p", String(PORT)], { + const server = spawn(resolve(ROOT, "markview"), [firstFile, "-p", String(PORT)], { cwd: ROOT, stdio: "ignore", }); @@ -78,7 +78,7 @@ async function main() { const page1 = await context.newPage(); await page1.addInitScript(() => { - localStorage.setItem("mo-theme", "dark"); + localStorage.setItem("markview-theme", "dark"); }); await page1.goto(BASE); await page1.waitForLoadState("load"); @@ -108,7 +108,7 @@ async function main() { const page2 = await context.newPage(); // Set dark theme before navigating so Mermaid initializes with dark theme await page2.addInitScript(() => { - localStorage.setItem("mo-theme", "dark"); + localStorage.setItem("markview-theme", "dark"); }); await page2.goto(`${BASE}/design`); await page2.waitForLoadState("load"); @@ -146,7 +146,7 @@ async function main() { const page3 = await context.newPage(); await page3.addInitScript(() => { - localStorage.setItem("mo-theme", "dark"); + localStorage.setItem("markview-theme", "dark"); }); await page3.goto(`${BASE}/project`); await page3.waitForLoadState("load"); @@ -180,12 +180,12 @@ async function main() { } } finally { server.kill(); - // Kill any remaining mo process on the port + // Kill any remaining markview process on the port try { execSync(`lsof -i :${PORT} -t | xargs kill 2>/dev/null`, { stdio: "ignore", }); - } catch {} + } catch { } console.log("Done"); } } @@ -196,6 +196,6 @@ main().catch((err) => { execSync(`lsof -i :${PORT} -t | xargs kill 2>/dev/null`, { stdio: "ignore", }); - } catch {} + } catch { } process.exit(1); }); diff --git a/internal/frontend/src/App.tsx b/internal/frontend/src/App.tsx index 1b29f25..6e908ed 100644 --- a/internal/frontend/src/App.tsx +++ b/internal/frontend/src/App.tsx @@ -28,10 +28,10 @@ import { OutlineGravityView } from "./components/OutlineGravityView"; import { OutlineTreeView } from "./components/OutlineTreeView"; import { isStaticMode } from "./utils/staticData"; -const WIDTH_STORAGE_KEY = "mo-layout-width"; -const VIEWMODE_STORAGE_KEY = "mo-sidebar-viewmode"; -const PDF_OPEN_FILE_PARAM = "mo_open"; -const PDF_OPEN_FROM_PARAM = "mo_from"; +const WIDTH_STORAGE_KEY = "markview-layout-width"; +const VIEWMODE_STORAGE_KEY = "markview-sidebar-viewmode"; +const PDF_OPEN_FILE_PARAM = "markview_open"; +const PDF_OPEN_FROM_PARAM = "markview_from"; interface PendingPdfOpenRequest { fromFileId: string; @@ -261,7 +261,7 @@ export function App() { ); useEffect(() => { - document.title = activeFileName || "mo"; + document.title = activeFileName || "markview"; }, [activeFileName]); useSSE({ diff --git a/internal/frontend/src/components/OutlineGraphView.tsx b/internal/frontend/src/components/OutlineGraphView.tsx index 1ae3900..f377a67 100644 --- a/internal/frontend/src/components/OutlineGraphView.tsx +++ b/internal/frontend/src/components/OutlineGraphView.tsx @@ -117,7 +117,7 @@ interface OutlineGraphViewProps { onClose: () => void; } -const FLOW_DIRECTION_KEY = "mo-outline-graph-direction"; +const FLOW_DIRECTION_KEY = "markview-outline-graph-direction"; export function OutlineGraphView({ onClose }: OutlineGraphViewProps) { const [outline, setOutline] = useState(null); @@ -259,7 +259,7 @@ export function OutlineGraphView({ onClose }: OutlineGraphViewProps) { mermaid .render(id, code, container) .then(({ svg: s }) => setSvg(s)) - .catch(() => {}) + .catch(() => { }) .finally(() => container.remove()); }); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] }); diff --git a/internal/frontend/src/components/OutlineTreeView.tsx b/internal/frontend/src/components/OutlineTreeView.tsx index 7445d47..d5d551c 100644 --- a/internal/frontend/src/components/OutlineTreeView.tsx +++ b/internal/frontend/src/components/OutlineTreeView.tsx @@ -81,16 +81,16 @@ function buildFileOutline( const targetOutline = hasTargetContent && !collapsedIds.has(linkId) ? buildFileOutline( - targetFile, - outline, - fileIds, - fileById, - targetColorIdx, - new Set(visited), - depth + 1, - linkId, - collapsedIds, - ) + targetFile, + outline, + fileIds, + fileById, + targetColorIdx, + new Set(visited), + depth + 1, + linkId, + collapsedIds, + ) : []; linkChildren.push({ @@ -288,7 +288,7 @@ interface OutlineTreeViewProps { onClose: () => void; } -const LAYOUT_DIRECTION_KEY = "mo-outline-layout-direction"; +const LAYOUT_DIRECTION_KEY = "markview-outline-layout-direction"; export function OutlineTreeView({ onClose }: OutlineTreeViewProps) { const [outline, setOutline] = useState(null); diff --git a/internal/frontend/src/components/RestartButton.tsx b/internal/frontend/src/components/RestartButton.tsx index 7efaf0b..74d3111 100644 --- a/internal/frontend/src/components/RestartButton.tsx +++ b/internal/frontend/src/components/RestartButton.tsx @@ -10,7 +10,7 @@ export function RestartButton() { useEffect(() => { fetchVersion() .then(setVersion) - .catch(() => {}); + .catch(() => { }); }, []); const handleClick = useCallback(async () => { @@ -38,7 +38,7 @@ export function RestartButton() { }, [status]); const title = version - ? `mo ${version.version} (${version.revision})\nClick to restart` + ? `markview ${version.version} (${version.revision})\nClick to restart` : "Restart server"; return ( diff --git a/internal/frontend/src/components/SettingsModal.tsx b/internal/frontend/src/components/SettingsModal.tsx index b021594..82ee466 100644 --- a/internal/frontend/src/components/SettingsModal.tsx +++ b/internal/frontend/src/components/SettingsModal.tsx @@ -15,7 +15,7 @@ interface SettingsModalProps { const THEME_OPTIONS: Array<{ value: MermaidSettings["theme"]; label: string }> = [ { value: "auto", label: "Auto (跟随亮/暗主题)" }, { value: "high-contrast", label: "高对比 (推荐)" }, - { value: "custom", label: "自定义 Mo 调色" }, + { value: "custom", label: "自定义 markview 调色" }, { value: "github-light", label: "GitHub Light" }, { value: "github-dark", label: "GitHub Dark" }, { value: "tokyo-night", label: "Tokyo Night" }, @@ -133,8 +133,8 @@ export function SettingsModal({ isOpen, onClose }: SettingsModalProps) { key={preset.key} type="button" className={`text-left px-3 py-2 rounded-lg border cursor-pointer transition-colors ${settings.preset === preset.key - ? "border-gh-accent bg-gh-accent/10 text-gh-text" - : "border-gh-border bg-gh-bg hover:bg-gh-bg-hover text-gh-text-secondary hover:text-gh-text" + ? "border-gh-accent bg-gh-accent/10 text-gh-text" + : "border-gh-border bg-gh-bg hover:bg-gh-bg-hover text-gh-text-secondary hover:text-gh-text" }`} onClick={() => handleUpdate({ ...preset.settings, preset: preset.key })} > @@ -220,8 +220,8 @@ export function SettingsModal({ isOpen, onClose }: SettingsModalProps) { - - - - - - - - - diff --git a/outline-layout-comparison.html b/outline-layout-comparison.html deleted file mode 100644 index ddfea01..0000000 --- a/outline-layout-comparison.html +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - OutlineGraphView 布局对比 - - - - -

OutlineGraphView 布局对比

-

方案 A:链式(h2 纵向)| 方案 B:subgraph 按文件分组| 含文件引用关系

- -
-
-

当前:并联布局(h1 → h2a, h2b, h2c)

-
-flowchart TB - fl1["▼ 文件A.md"] - n0["一级标题"] - n1["二级标题 A"] - n2["二级标题 B"] - n3["二级标题 C"] - fl1 --> n0 - n0 --> n1 - n0 --> n2 - n0 --> n3 -
-
-
-

方案 A:链式布局(h1 → h2a → h2b → h2c)

-
-flowchart TB - fl1["▼ 文件A.md"] - n0["一级标题"] - n1["二级标题 A"] - n2["二级标题 B"] - n3["二级标题 C"] - fl1 --> n0 - n0 --> n1 - n1 --> n2 - n2 --> n3 -
-
-
- -
-

方案 B:subgraph 按文件分组

-

用 subgraph 将每个文件的标题包成子图,h2 仍为并联

-
-
-

方案 B:单文件 subgraph

-
-flowchart TB - subgraph sg1 ["▼ 文件A.md"] - n0["一级标题"] - n1["二级标题 A"] - n2["二级标题 B"] - n3["二级标题 C"] - end - n0 --> n1 - n0 --> n2 - n0 --> n3 -
-
-
-

方案 B:多文件 subgraph

-
-flowchart TB - subgraph sg1 ["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - end - subgraph sg2 ["▼ 开发.md"] - n2_0["前端实现"] - n2_1["后端实现"] - end - n1_0 --> n1_1 - n1_0 --> n1_2 - n2_0 --> n2_1 -
-
-
-
- -
-

方案 B + 文件引用

-

跨 subgraph 的链接:标题节点 → 目标文件的节点

-
-
-flowchart TB - subgraph sg1 ["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - end - subgraph sg2 ["▼ 开发.md"] - n2_0["前端实现"] - end - n1_0 --> n1_1 - n1_0 --> n1_2 - n1_1 --> n2_0 -
-

「架构设计」链接了 开发.md,连到其首个标题

-
-
- -
-

方案 B + 一个标题引用多个文件

-
-
-flowchart TB - subgraph sg1 ["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - end - subgraph sg2 ["▼ 开发.md"] - n2_0["前端"] - end - subgraph sg3 ["▼ 测试.md"] - n3_0["用例"] - end - n1_0 --> n1_1 - n1_0 --> n1_2 - n1_1 --> n2_0 - n1_1 --> n3_0 -
-

「架构设计」同时链接 开发.md 和 测试.md

-
-
- -
-

多文件示意(方案 A 链式)

-
-
-flowchart TB - fl1["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - fl2["▼ 开发.md"] - n2_0["前端实现"] - n2_1["后端实现"] - n2_2["部署流程"] - fl1 --> n1_0 - n1_0 --> n1_1 - n1_1 --> n1_2 - fl2 --> n2_0 - n2_0 --> n2_1 - n2_1 --> n2_2 -
-
-
- -
-

文件引用关系(标题 → 被引用文件)

-

当标题内含有指向其他文件的链接时,会从该标题节点连到目标文件的文件名节点

-
-
-

并联布局 + 引用

-
-flowchart TB - fl1["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - fl2["▼ 开发.md"] - n2_0["前端实现"] - fl1 --> n1_0 - n1_0 --> n1_1 - n1_0 --> n1_2 - n1_1 --> fl2 - fl2 --> n2_0 -
-

「架构设计」链接了 开发.md

-
-
-

链式布局 + 引用

-
-flowchart TB - fl1["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - fl2["▼ 开发.md"] - n2_0["前端实现"] - fl1 --> n1_0 - n1_0 --> n1_1 - n1_1 --> n1_2 - n1_1 --> fl2 - fl2 --> n2_0 -
-

「架构设计」链接了 开发.md

-
-
-
- -
-

一个标题引用多个文件(方案 A)

-

「架构设计」同时链接了 开发.md 和 测试.md,被引用的多个文件会从同一标题节点分出,仍可能横向并排

-
-
-flowchart TB - fl1["▼ 设计.md"] - n1_0["需求分析"] - n1_1["架构设计"] - n1_2["接口定义"] - fl2["▼ 开发.md"] - n2_0["前端"] - fl3["▼ 测试.md"] - n3_0["用例"] - fl1 --> n1_0 - n1_0 --> n1_1 - n1_1 --> n1_2 - n1_1 --> fl2 - n1_1 --> fl3 - fl2 --> n2_0 - fl3 --> n3_0 -
-
-
- -
-

多文件互相引用

-
-
-flowchart TB - fl1["▼ 设计.md"] - n1_0["需求"] - n1_1["架构"] - fl2["▼ 开发.md"] - n2_0["实现"] - fl3["▼ 测试.md"] - n3_0["用例"] - fl1 --> n1_0 - n1_0 --> n1_1 - n1_1 --> fl2 - fl2 --> n2_0 - n2_0 --> fl3 - fl3 --> n3_0 - n3_0 --> fl1 -
-

设计→开发→测试→设计,形成引用闭环

-
-
- -
-

方案 C:圆形容器(你的想法)

-

每个文件 = 一个圆,一级标题在圆心,二级标题围绕圆心;文件间关系 = 圆与圆的连线(通过 h2 关联)

- -

概念示意(手绘风格)

-
- - - - - - - 设计.md - - 需求 - - 架构 - - 接口 - - 评审 - - - 开发.md - - 实现 - - 前端 - - 后端 - - - 链接 - -

圆心=一级标题,周围=二级标题;「架构」链接了 开发.md

-
- -

Mermaid 近似(subgraph 模拟圆组,h1 为枢纽)

-

Mermaid 无原生径向布局,用 subgraph 包住「h1 + h2」,文件间通过 h2→h1 连线

-
-
-flowchart TB - subgraph sg1 ["设计.md"] - h1_1(("需求")) - h2_1a["架构"] - h2_1b["接口"] - h2_1c["评审"] - h1_1 --- h2_1a - h1_1 --- h2_1b - h1_1 --- h2_1c - end - subgraph sg2 ["开发.md"] - h1_2(("实现")) - h2_2a["前端"] - h2_2b["后端"] - h1_2 --- h2_2a - h1_2 --- h2_2b - end - h2_1a -.-> h1_2 -
-

虚线:架构 → 开发.md 的引用

-
- -

多文件 + 多引用

-
-
-flowchart TB - subgraph sg1 ["设计.md"] - h1_1(("需求")) - h2_1a["架构"] - h2_1b["接口"] - h1_1 --- h2_1a - h1_1 --- h2_1b - end - subgraph sg2 ["开发.md"] - h1_2(("实现")) - h2_2a["前端"] - h1_2 --- h2_2a - end - subgraph sg3 ["测试.md"] - h1_3(("用例")) - h2_3a["单元"] - h1_3 --- h2_3a - end - h2_1a -.-> h1_2 - h2_1a -.-> h1_3 -
-

「架构」同时链接 开发.md 和 测试.md

-
- -
- 实现建议:Mermaid 的 flowchart 不支持真正的径向布局。若要实现「圆 + 圆心 + 周围节点」,需用 D3.js、Cytoscape.js 等自绘,或等 Mermaid 的 radial 布局合并。当前用 subgraph + 圆形节点 (()) 可做近似,但布局仍是 dagre 的 TB/LR。 -
-
- - - - From 97821c822c7f92951d0455d970ffdfd0d975ec67 Mon Sep 17 00:00:00 2001 From: barry Date: Wed, 29 Apr 2026 10:35:21 +0800 Subject: [PATCH 5/6] Refactor code structure for improved readability and maintainability --- CREDITS => docs/CREDITS | 74 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 37 deletions(-) rename CREDITS => docs/CREDITS (99%) diff --git a/CREDITS b/docs/CREDITS similarity index 99% rename from CREDITS rename to docs/CREDITS index 4024a11..00adf95 100644 --- a/CREDITS +++ b/docs/CREDITS @@ -2302,22 +2302,22 @@ git://github.com/Chevrotain/chevrotain.git chevrotain-allstar https://github.com/langium/chevrotain-allstar ---------------------------------------------------------------- -Copyright 2022 TypeFox GmbH - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright 2022 TypeFox GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================ @@ -5371,27 +5371,27 @@ THE SOFTWARE. rehype-github-alerts https://github.com/chrisweb/rehype-github-alerts.git ---------------------------------------------------------------- -MIT License - -Copyright (c) 2023 Chris Weber - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2023 Chris Weber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ================================================================ From 58c1792a3db72d774a103795cb7f67451260076a Mon Sep 17 00:00:00 2001 From: barry Date: Wed, 29 Apr 2026 10:40:41 +0800 Subject: [PATCH 6/6] feat: add utility functions for link resolution, image source handling, and language extraction - Implement `resolveLink`, `resolveImageSrc`, and `extractLanguage` functions in `resolve.ts`. - Create corresponding tests for link resolution and image source handling in `resolve.test.ts`. - Add `findBestSearchTarget` function for improved search functionality in `searchJump.ts` with tests in `searchJump.test.ts`. - Introduce static data handling in `staticData.ts` for SPA static mode. - Configure TypeScript settings in `tsconfig.json` for better type checking and module resolution. - Set up Vite configuration in `vite.config.ts` for optimized builds and development server proxying. --- .github/copilot-instructions.md | 10 ++++----- .github/dependabot.yml | 2 +- .github/workflows/ci.yml | 8 +++---- .github/workflows/tagpr.yml | 4 ++-- .gitignore | 2 +- .octocov.yml | 22 +++++++++---------- Makefile | 12 +++++----- {internal/frontend => frontend}/.gitignore | 0 {internal/frontend => frontend}/index.html | 0 {internal/frontend => frontend}/package.json | 0 .../frontend => frontend}/pnpm-lock.yaml | 0 .../frontend => frontend}/public/favicon.svg | 0 .../scripts/screenshots.mjs | 2 +- {internal/frontend => frontend}/src/App.tsx | 0 .../src/components/BacklinksPanel.tsx | 0 .../src/components/CopyButton.test.tsx | 0 .../src/components/CopyButton.tsx | 0 .../src/components/DropOverlay.tsx | 0 .../src/components/FileContextMenu.tsx | 0 .../src/components/FileIcon.tsx | 0 .../src/components/GlobalSearchModal.test.tsx | 0 .../src/components/GlobalSearchModal.tsx | 0 .../src/components/GraphView.tsx | 0 .../src/components/GroupDropdown.test.tsx | 0 .../src/components/GroupDropdown.tsx | 0 .../src/components/MarkdownViewer.tsx | 0 .../src/components/MermaidBlock.test.tsx | 0 .../src/components/OutlineGraphView.tsx | 0 .../src/components/OutlineGravityView.tsx | 0 .../src/components/OutlineTreeView.tsx | 0 .../src/components/PdfExportButton.tsx | 0 .../src/components/PlantUmlBlock.test.tsx | 0 .../src/components/RawToggle.test.tsx | 0 .../src/components/RawToggle.tsx | 0 .../src/components/RemoveButton.tsx | 0 .../src/components/RestartButton.tsx | 0 .../src/components/SearchToggle.tsx | 0 .../src/components/SettingsModal.tsx | 0 .../src/components/Sidebar.test.tsx | 0 .../src/components/Sidebar.tsx | 0 .../src/components/SvgBobBlock.test.tsx | 0 .../src/components/ThemeToggle.test.tsx | 0 .../src/components/ThemeToggle.tsx | 0 .../src/components/TocPanel.test.tsx | 0 .../src/components/TocPanel.tsx | 0 .../src/components/TocToggle.test.tsx | 0 .../src/components/TocToggle.tsx | 0 .../src/components/TreeView.tsx | 0 .../src/components/ViewModeToggle.tsx | 0 .../src/components/WidthToggle.test.tsx | 0 .../src/components/WidthToggle.tsx | 0 .../src/components/ZoomPanView.tsx | 0 .../src/hooks/useActiveHeading.ts | 0 .../src/hooks/useApi.test.ts | 0 .../frontend => frontend}/src/hooks/useApi.ts | 0 .../src/hooks/useAppSettings.ts | 0 .../src/hooks/useFileDrop.test.ts | 0 .../src/hooks/useFileDrop.ts | 0 .../src/hooks/useMermaidSettings.ts | 0 .../src/hooks/useSSE.test.ts | 0 .../frontend => frontend}/src/hooks/useSSE.ts | 0 .../src/hooks/useScrollRestoration.test.ts | 0 .../src/hooks/useScrollRestoration.ts | 0 {internal/frontend => frontend}/src/main.tsx | 0 .../frontend => frontend}/src/styles/app.css | 0 .../frontend => frontend}/src/test-setup.ts | 0 .../src/utils/buildTree.test.ts | 0 .../src/utils/buildTree.ts | 0 .../src/utils/extractText.test.ts | 0 .../src/utils/extractText.ts | 0 .../src/utils/frontmatter.test.ts | 0 .../src/utils/frontmatter.ts | 0 .../src/utils/fullTextSearch.test.ts | 0 .../src/utils/fullTextSearch.ts | 0 .../src/utils/groups.test.ts | 0 .../frontend => frontend}/src/utils/groups.ts | 0 .../src/utils/markdownEnhance.test.ts | 0 .../src/utils/markdownEnhance.ts | 0 .../src/utils/mdx.test.ts | 0 .../frontend => frontend}/src/utils/mdx.ts | 0 .../src/utils/pdfExport.test.ts | 0 .../src/utils/pdfExport.ts | 0 .../src/utils/resolve.test.ts | 0 .../src/utils/resolve.ts | 0 .../src/utils/searchJump.test.ts | 0 .../src/utils/searchJump.ts | 0 .../src/utils/staticData.ts | 0 {internal/frontend => frontend}/tsconfig.json | 0 .../frontend => frontend}/vite.config.ts | 2 +- internal/static/static.go | 2 +- testdata/code-blocks.md | 4 ++-- 91 files changed, 35 insertions(+), 35 deletions(-) rename {internal/frontend => frontend}/.gitignore (100%) rename {internal/frontend => frontend}/index.html (100%) rename {internal/frontend => frontend}/package.json (100%) rename {internal/frontend => frontend}/pnpm-lock.yaml (100%) rename {internal/frontend => frontend}/public/favicon.svg (100%) rename {internal/frontend => frontend}/scripts/screenshots.mjs (99%) rename {internal/frontend => frontend}/src/App.tsx (100%) rename {internal/frontend => frontend}/src/components/BacklinksPanel.tsx (100%) rename {internal/frontend => frontend}/src/components/CopyButton.test.tsx (100%) rename {internal/frontend => frontend}/src/components/CopyButton.tsx (100%) rename {internal/frontend => frontend}/src/components/DropOverlay.tsx (100%) rename {internal/frontend => frontend}/src/components/FileContextMenu.tsx (100%) rename {internal/frontend => frontend}/src/components/FileIcon.tsx (100%) rename {internal/frontend => frontend}/src/components/GlobalSearchModal.test.tsx (100%) rename {internal/frontend => frontend}/src/components/GlobalSearchModal.tsx (100%) rename {internal/frontend => frontend}/src/components/GraphView.tsx (100%) rename {internal/frontend => frontend}/src/components/GroupDropdown.test.tsx (100%) rename {internal/frontend => frontend}/src/components/GroupDropdown.tsx (100%) rename {internal/frontend => frontend}/src/components/MarkdownViewer.tsx (100%) rename {internal/frontend => frontend}/src/components/MermaidBlock.test.tsx (100%) rename {internal/frontend => frontend}/src/components/OutlineGraphView.tsx (100%) rename {internal/frontend => frontend}/src/components/OutlineGravityView.tsx (100%) rename {internal/frontend => frontend}/src/components/OutlineTreeView.tsx (100%) rename {internal/frontend => frontend}/src/components/PdfExportButton.tsx (100%) rename {internal/frontend => frontend}/src/components/PlantUmlBlock.test.tsx (100%) rename {internal/frontend => frontend}/src/components/RawToggle.test.tsx (100%) rename {internal/frontend => frontend}/src/components/RawToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/RemoveButton.tsx (100%) rename {internal/frontend => frontend}/src/components/RestartButton.tsx (100%) rename {internal/frontend => frontend}/src/components/SearchToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/SettingsModal.tsx (100%) rename {internal/frontend => frontend}/src/components/Sidebar.test.tsx (100%) rename {internal/frontend => frontend}/src/components/Sidebar.tsx (100%) rename {internal/frontend => frontend}/src/components/SvgBobBlock.test.tsx (100%) rename {internal/frontend => frontend}/src/components/ThemeToggle.test.tsx (100%) rename {internal/frontend => frontend}/src/components/ThemeToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/TocPanel.test.tsx (100%) rename {internal/frontend => frontend}/src/components/TocPanel.tsx (100%) rename {internal/frontend => frontend}/src/components/TocToggle.test.tsx (100%) rename {internal/frontend => frontend}/src/components/TocToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/TreeView.tsx (100%) rename {internal/frontend => frontend}/src/components/ViewModeToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/WidthToggle.test.tsx (100%) rename {internal/frontend => frontend}/src/components/WidthToggle.tsx (100%) rename {internal/frontend => frontend}/src/components/ZoomPanView.tsx (100%) rename {internal/frontend => frontend}/src/hooks/useActiveHeading.ts (100%) rename {internal/frontend => frontend}/src/hooks/useApi.test.ts (100%) rename {internal/frontend => frontend}/src/hooks/useApi.ts (100%) rename {internal/frontend => frontend}/src/hooks/useAppSettings.ts (100%) rename {internal/frontend => frontend}/src/hooks/useFileDrop.test.ts (100%) rename {internal/frontend => frontend}/src/hooks/useFileDrop.ts (100%) rename {internal/frontend => frontend}/src/hooks/useMermaidSettings.ts (100%) rename {internal/frontend => frontend}/src/hooks/useSSE.test.ts (100%) rename {internal/frontend => frontend}/src/hooks/useSSE.ts (100%) rename {internal/frontend => frontend}/src/hooks/useScrollRestoration.test.ts (100%) rename {internal/frontend => frontend}/src/hooks/useScrollRestoration.ts (100%) rename {internal/frontend => frontend}/src/main.tsx (100%) rename {internal/frontend => frontend}/src/styles/app.css (100%) rename {internal/frontend => frontend}/src/test-setup.ts (100%) rename {internal/frontend => frontend}/src/utils/buildTree.test.ts (100%) rename {internal/frontend => frontend}/src/utils/buildTree.ts (100%) rename {internal/frontend => frontend}/src/utils/extractText.test.ts (100%) rename {internal/frontend => frontend}/src/utils/extractText.ts (100%) rename {internal/frontend => frontend}/src/utils/frontmatter.test.ts (100%) rename {internal/frontend => frontend}/src/utils/frontmatter.ts (100%) rename {internal/frontend => frontend}/src/utils/fullTextSearch.test.ts (100%) rename {internal/frontend => frontend}/src/utils/fullTextSearch.ts (100%) rename {internal/frontend => frontend}/src/utils/groups.test.ts (100%) rename {internal/frontend => frontend}/src/utils/groups.ts (100%) rename {internal/frontend => frontend}/src/utils/markdownEnhance.test.ts (100%) rename {internal/frontend => frontend}/src/utils/markdownEnhance.ts (100%) rename {internal/frontend => frontend}/src/utils/mdx.test.ts (100%) rename {internal/frontend => frontend}/src/utils/mdx.ts (100%) rename {internal/frontend => frontend}/src/utils/pdfExport.test.ts (100%) rename {internal/frontend => frontend}/src/utils/pdfExport.ts (100%) rename {internal/frontend => frontend}/src/utils/resolve.test.ts (100%) rename {internal/frontend => frontend}/src/utils/resolve.ts (100%) rename {internal/frontend => frontend}/src/utils/searchJump.test.ts (100%) rename {internal/frontend => frontend}/src/utils/searchJump.ts (100%) rename {internal/frontend => frontend}/src/utils/staticData.ts (100%) rename {internal/frontend => frontend}/tsconfig.json (100%) rename {internal/frontend => frontend}/vite.config.ts (98%) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c936a36..08796ee 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -6,7 +6,7 @@ ## Build & Run -Requires Go 1.26+ and [pnpm](https://pnpm.io/). Node.js version is managed via `pnpm.executionEnv.nodeVersion` in `internal/frontend/package.json`. +Requires Go 1.26+ and [pnpm](https://pnpm.io/). Node.js version is managed via `pnpm.executionEnv.nodeVersion` in `frontend/package.json`. ```bash # Full build (frontend + Go binary, with ldflags) @@ -25,7 +25,7 @@ make generate make test # Run a single frontend test (vitest) -cd internal/frontend && pnpm test src/utils/buildTree.test.ts +cd frontend && pnpm test src/utils/buildTree.test.ts # Run Go tests only go test ./... @@ -52,7 +52,7 @@ make ci make install # Frontend dev server with backend proxy (proxies /_/ to localhost:6275) -cd internal/frontend && pnpm run dev +cd frontend && pnpm run dev ``` **Workflow**: After making code changes, run `make install` to build and install the binary. @@ -78,7 +78,7 @@ cd internal/frontend && pnpm run dev - `cmd/root.go` — CLI entry point (Cobra). Handles single-instance detection: if a server is already running on the port, adds files via HTTP API instead of starting a new one. - `internal/server/server.go` — HTTP server, state management (mutex-guarded), SSE for live-reload, file watcher (fsnotify). All API routes use `/_/` prefix to avoid collision with SPA route paths (group names). - `internal/static/static.go` — `go:generate` runs the frontend build, then `go:embed` embeds the output from `internal/static/dist/`. -- `internal/frontend/` — Vite + React 19 + TypeScript + Tailwind CSS v4 SPA. Build output goes to `internal/static/dist/` (configured in `vite.config.ts`). +- `frontend/` — Vite + React 19 + TypeScript + Tailwind CSS v4 SPA. Build output goes to `internal/static/dist/` (configured in `vite.config.ts`). - `internal/backup/` — State persistence for open files/groups using atomic JSON writes to `$XDG_STATE_HOME/markview/backup/`. Enables session restoration across server restarts. - `internal/logfile/` — Rotating JSON logging to `$XDG_STATE_HOME/markview/log/` (max 10MB, 3 backups, 7-day retention). - `internal/xdg/` — XDG Base Directory helper. `StateHome()` returns `$XDG_STATE_HOME` or default `~/.local/state`. @@ -86,7 +86,7 @@ cd internal/frontend && pnpm run dev ## Frontend -- Package manager: **pnpm** (version specified in `internal/frontend/package.json` `packageManager` field) +- Package manager: **pnpm** (version specified in `frontend/package.json` `packageManager` field) - Markdown rendering: `react-markdown` + `remark-gfm` + `rehype-raw` + `rehype-slug` (heading IDs) + `@shikijs/rehype` (syntax highlighting) + `mermaid` (diagram rendering) - SPA routing via `window.location.pathname` (no router library) - Key components: `App.tsx` (routing/state), `Sidebar.tsx` (file list with flat/tree view, resizable, drag-and-drop reorder), `TreeView.tsx` (tree view with collapsible directories), `MarkdownViewer.tsx` (rendering + raw view toggle), `TocPanel.tsx` (table of contents, resizable), `GroupDropdown.tsx` (group switcher), `FileContextMenu.tsx` (shared kebab menu for file operations), `WidthToggle.tsx` (wide/narrow content width toggle) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d6153b8..8a47622 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -36,7 +36,7 @@ updates: - "k1LoW" - package-ecosystem: "npm" - directory: "/internal/frontend" + directory: "/frontend" groups: dependencies: patterns: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 895f065..37078bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ ubuntu-latest, macos-latest ] env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} permissions: @@ -31,18 +31,18 @@ jobs: - name: Set up pnpm uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: - package_json_file: internal/frontend/package.json + package_json_file: frontend/package.json - name: Generate frontend assets run: go generate ./internal/static/ - name: Run oxlint if: runner.os == 'Linux' - run: cd internal/frontend && pnpm install && pnpm run lint + run: cd frontend && pnpm install && pnpm run lint - name: Run oxfmt check if: runner.os == 'Linux' - run: cd internal/frontend && pnpm run fmt:check + run: cd frontend && pnpm run fmt:check - name: Run lint if: runner.os == 'Linux' diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml index 5c00b7f..fe12271 100644 --- a/.github/workflows/tagpr.yml +++ b/.github/workflows/tagpr.yml @@ -30,7 +30,7 @@ jobs: - name: Set up pnpm uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: - package_json_file: internal/frontend/package.json + package_json_file: frontend/package.json - id: run-tagpr name: Run tagpr @@ -60,7 +60,7 @@ jobs: - name: Set up pnpm uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: - package_json_file: internal/frontend/package.json + package_json_file: frontend/package.json - name: Run GoReleaser uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 diff --git a/.gitignore b/.gitignore index fc0bd0b..7a9ebd3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ internal/static/dist/**/* -internal/frontend/CREDITS_FRONTEND +frontend/CREDITS_FRONTEND coverage.out markview .pnpm-store/ diff --git a/.octocov.yml b/.octocov.yml index 4619a91..50c36ce 100644 --- a/.octocov.yml +++ b/.octocov.yml @@ -1,20 +1,20 @@ coverage: paths: - coverage.out - - internal/frontend/coverage/lcov.info + - frontend/coverage/lcov.info codeToTestRatio: code: - - '**/*.go' - - '!**/*_test.go' - - 'internal/frontend/src/**/*.ts' - - 'internal/frontend/src/**/*.tsx' - - '!internal/frontend/src/**/*.test.ts' - - '!internal/frontend/src/**/*.test.tsx' - - '!internal/frontend/node_modules/**' + - "**/*.go" + - "!**/*_test.go" + - "frontend/src/**/*.ts" + - "frontend/src/**/*.tsx" + - "!frontend/src/**/*.test.ts" + - "!frontend/src/**/*.test.tsx" + - "!frontend/node_modules/**" test: - - '**/*_test.go' - - 'internal/frontend/src/**/*.test.ts' - - 'internal/frontend/src/**/*.test.tsx' + - "**/*_test.go" + - "frontend/src/**/*.test.ts" + - "frontend/src/**/*.test.tsx" testExecutionTime: if: true diff: diff --git a/Makefile b/Makefile index c9296ff..4b94c28 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ generate: go generate ./internal/static/ test: - cd internal/frontend && pnpm install && pnpm run test:coverage + cd frontend && pnpm install && pnpm run test:coverage go test ./... -coverprofile=coverage.out -covermode=count -count=1 build: generate @@ -24,18 +24,18 @@ dev: build ./markview -p 16275 --foreground $(ARGS) screenshot: build - cd internal/frontend && pnpm run screenshots + cd frontend && pnpm run screenshots lint: - cd internal/frontend && pnpm install && pnpm run lint + cd frontend && pnpm install && pnpm run lint golangci-lint run ./... go vet -vettool=`which gostyle` -gostyle.config=$(PWD)/.gostyle.yml ./... fmt: - cd internal/frontend && pnpm install && pnpm run fmt + cd frontend && pnpm install && pnpm run fmt fmt-check: - cd internal/frontend && pnpm install && pnpm run fmt:check + cd frontend && pnpm install && pnpm run fmt:check depsdev: go install github.com/Songmu/gocredits/cmd/gocredits@latest @@ -45,7 +45,7 @@ credits: depsdev generate go mod download gocredits -w . printf "\n================================================================\n\n" >> CREDITS - cat internal/frontend/CREDITS_FRONTEND >> CREDITS + cat frontend/CREDITS_FRONTEND >> CREDITS prerelease_for_tagpr: credits git add CHANGELOG.md CREDITS go.mod go.sum diff --git a/internal/frontend/.gitignore b/frontend/.gitignore similarity index 100% rename from internal/frontend/.gitignore rename to frontend/.gitignore diff --git a/internal/frontend/index.html b/frontend/index.html similarity index 100% rename from internal/frontend/index.html rename to frontend/index.html diff --git a/internal/frontend/package.json b/frontend/package.json similarity index 100% rename from internal/frontend/package.json rename to frontend/package.json diff --git a/internal/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml similarity index 100% rename from internal/frontend/pnpm-lock.yaml rename to frontend/pnpm-lock.yaml diff --git a/internal/frontend/public/favicon.svg b/frontend/public/favicon.svg similarity index 100% rename from internal/frontend/public/favicon.svg rename to frontend/public/favicon.svg diff --git a/internal/frontend/scripts/screenshots.mjs b/frontend/scripts/screenshots.mjs similarity index 99% rename from internal/frontend/scripts/screenshots.mjs rename to frontend/scripts/screenshots.mjs index c2bf5cd..50ff327 100644 --- a/internal/frontend/scripts/screenshots.mjs +++ b/frontend/scripts/screenshots.mjs @@ -4,7 +4,7 @@ import { resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const ROOT = resolve(__dirname, "../../.."); +const ROOT = resolve(__dirname, "../.."); const PORT = 16275; const BASE = `http://localhost:${PORT}`; const IMAGES_DIR = resolve(ROOT, "images"); diff --git a/internal/frontend/src/App.tsx b/frontend/src/App.tsx similarity index 100% rename from internal/frontend/src/App.tsx rename to frontend/src/App.tsx diff --git a/internal/frontend/src/components/BacklinksPanel.tsx b/frontend/src/components/BacklinksPanel.tsx similarity index 100% rename from internal/frontend/src/components/BacklinksPanel.tsx rename to frontend/src/components/BacklinksPanel.tsx diff --git a/internal/frontend/src/components/CopyButton.test.tsx b/frontend/src/components/CopyButton.test.tsx similarity index 100% rename from internal/frontend/src/components/CopyButton.test.tsx rename to frontend/src/components/CopyButton.test.tsx diff --git a/internal/frontend/src/components/CopyButton.tsx b/frontend/src/components/CopyButton.tsx similarity index 100% rename from internal/frontend/src/components/CopyButton.tsx rename to frontend/src/components/CopyButton.tsx diff --git a/internal/frontend/src/components/DropOverlay.tsx b/frontend/src/components/DropOverlay.tsx similarity index 100% rename from internal/frontend/src/components/DropOverlay.tsx rename to frontend/src/components/DropOverlay.tsx diff --git a/internal/frontend/src/components/FileContextMenu.tsx b/frontend/src/components/FileContextMenu.tsx similarity index 100% rename from internal/frontend/src/components/FileContextMenu.tsx rename to frontend/src/components/FileContextMenu.tsx diff --git a/internal/frontend/src/components/FileIcon.tsx b/frontend/src/components/FileIcon.tsx similarity index 100% rename from internal/frontend/src/components/FileIcon.tsx rename to frontend/src/components/FileIcon.tsx diff --git a/internal/frontend/src/components/GlobalSearchModal.test.tsx b/frontend/src/components/GlobalSearchModal.test.tsx similarity index 100% rename from internal/frontend/src/components/GlobalSearchModal.test.tsx rename to frontend/src/components/GlobalSearchModal.test.tsx diff --git a/internal/frontend/src/components/GlobalSearchModal.tsx b/frontend/src/components/GlobalSearchModal.tsx similarity index 100% rename from internal/frontend/src/components/GlobalSearchModal.tsx rename to frontend/src/components/GlobalSearchModal.tsx diff --git a/internal/frontend/src/components/GraphView.tsx b/frontend/src/components/GraphView.tsx similarity index 100% rename from internal/frontend/src/components/GraphView.tsx rename to frontend/src/components/GraphView.tsx diff --git a/internal/frontend/src/components/GroupDropdown.test.tsx b/frontend/src/components/GroupDropdown.test.tsx similarity index 100% rename from internal/frontend/src/components/GroupDropdown.test.tsx rename to frontend/src/components/GroupDropdown.test.tsx diff --git a/internal/frontend/src/components/GroupDropdown.tsx b/frontend/src/components/GroupDropdown.tsx similarity index 100% rename from internal/frontend/src/components/GroupDropdown.tsx rename to frontend/src/components/GroupDropdown.tsx diff --git a/internal/frontend/src/components/MarkdownViewer.tsx b/frontend/src/components/MarkdownViewer.tsx similarity index 100% rename from internal/frontend/src/components/MarkdownViewer.tsx rename to frontend/src/components/MarkdownViewer.tsx diff --git a/internal/frontend/src/components/MermaidBlock.test.tsx b/frontend/src/components/MermaidBlock.test.tsx similarity index 100% rename from internal/frontend/src/components/MermaidBlock.test.tsx rename to frontend/src/components/MermaidBlock.test.tsx diff --git a/internal/frontend/src/components/OutlineGraphView.tsx b/frontend/src/components/OutlineGraphView.tsx similarity index 100% rename from internal/frontend/src/components/OutlineGraphView.tsx rename to frontend/src/components/OutlineGraphView.tsx diff --git a/internal/frontend/src/components/OutlineGravityView.tsx b/frontend/src/components/OutlineGravityView.tsx similarity index 100% rename from internal/frontend/src/components/OutlineGravityView.tsx rename to frontend/src/components/OutlineGravityView.tsx diff --git a/internal/frontend/src/components/OutlineTreeView.tsx b/frontend/src/components/OutlineTreeView.tsx similarity index 100% rename from internal/frontend/src/components/OutlineTreeView.tsx rename to frontend/src/components/OutlineTreeView.tsx diff --git a/internal/frontend/src/components/PdfExportButton.tsx b/frontend/src/components/PdfExportButton.tsx similarity index 100% rename from internal/frontend/src/components/PdfExportButton.tsx rename to frontend/src/components/PdfExportButton.tsx diff --git a/internal/frontend/src/components/PlantUmlBlock.test.tsx b/frontend/src/components/PlantUmlBlock.test.tsx similarity index 100% rename from internal/frontend/src/components/PlantUmlBlock.test.tsx rename to frontend/src/components/PlantUmlBlock.test.tsx diff --git a/internal/frontend/src/components/RawToggle.test.tsx b/frontend/src/components/RawToggle.test.tsx similarity index 100% rename from internal/frontend/src/components/RawToggle.test.tsx rename to frontend/src/components/RawToggle.test.tsx diff --git a/internal/frontend/src/components/RawToggle.tsx b/frontend/src/components/RawToggle.tsx similarity index 100% rename from internal/frontend/src/components/RawToggle.tsx rename to frontend/src/components/RawToggle.tsx diff --git a/internal/frontend/src/components/RemoveButton.tsx b/frontend/src/components/RemoveButton.tsx similarity index 100% rename from internal/frontend/src/components/RemoveButton.tsx rename to frontend/src/components/RemoveButton.tsx diff --git a/internal/frontend/src/components/RestartButton.tsx b/frontend/src/components/RestartButton.tsx similarity index 100% rename from internal/frontend/src/components/RestartButton.tsx rename to frontend/src/components/RestartButton.tsx diff --git a/internal/frontend/src/components/SearchToggle.tsx b/frontend/src/components/SearchToggle.tsx similarity index 100% rename from internal/frontend/src/components/SearchToggle.tsx rename to frontend/src/components/SearchToggle.tsx diff --git a/internal/frontend/src/components/SettingsModal.tsx b/frontend/src/components/SettingsModal.tsx similarity index 100% rename from internal/frontend/src/components/SettingsModal.tsx rename to frontend/src/components/SettingsModal.tsx diff --git a/internal/frontend/src/components/Sidebar.test.tsx b/frontend/src/components/Sidebar.test.tsx similarity index 100% rename from internal/frontend/src/components/Sidebar.test.tsx rename to frontend/src/components/Sidebar.test.tsx diff --git a/internal/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx similarity index 100% rename from internal/frontend/src/components/Sidebar.tsx rename to frontend/src/components/Sidebar.tsx diff --git a/internal/frontend/src/components/SvgBobBlock.test.tsx b/frontend/src/components/SvgBobBlock.test.tsx similarity index 100% rename from internal/frontend/src/components/SvgBobBlock.test.tsx rename to frontend/src/components/SvgBobBlock.test.tsx diff --git a/internal/frontend/src/components/ThemeToggle.test.tsx b/frontend/src/components/ThemeToggle.test.tsx similarity index 100% rename from internal/frontend/src/components/ThemeToggle.test.tsx rename to frontend/src/components/ThemeToggle.test.tsx diff --git a/internal/frontend/src/components/ThemeToggle.tsx b/frontend/src/components/ThemeToggle.tsx similarity index 100% rename from internal/frontend/src/components/ThemeToggle.tsx rename to frontend/src/components/ThemeToggle.tsx diff --git a/internal/frontend/src/components/TocPanel.test.tsx b/frontend/src/components/TocPanel.test.tsx similarity index 100% rename from internal/frontend/src/components/TocPanel.test.tsx rename to frontend/src/components/TocPanel.test.tsx diff --git a/internal/frontend/src/components/TocPanel.tsx b/frontend/src/components/TocPanel.tsx similarity index 100% rename from internal/frontend/src/components/TocPanel.tsx rename to frontend/src/components/TocPanel.tsx diff --git a/internal/frontend/src/components/TocToggle.test.tsx b/frontend/src/components/TocToggle.test.tsx similarity index 100% rename from internal/frontend/src/components/TocToggle.test.tsx rename to frontend/src/components/TocToggle.test.tsx diff --git a/internal/frontend/src/components/TocToggle.tsx b/frontend/src/components/TocToggle.tsx similarity index 100% rename from internal/frontend/src/components/TocToggle.tsx rename to frontend/src/components/TocToggle.tsx diff --git a/internal/frontend/src/components/TreeView.tsx b/frontend/src/components/TreeView.tsx similarity index 100% rename from internal/frontend/src/components/TreeView.tsx rename to frontend/src/components/TreeView.tsx diff --git a/internal/frontend/src/components/ViewModeToggle.tsx b/frontend/src/components/ViewModeToggle.tsx similarity index 100% rename from internal/frontend/src/components/ViewModeToggle.tsx rename to frontend/src/components/ViewModeToggle.tsx diff --git a/internal/frontend/src/components/WidthToggle.test.tsx b/frontend/src/components/WidthToggle.test.tsx similarity index 100% rename from internal/frontend/src/components/WidthToggle.test.tsx rename to frontend/src/components/WidthToggle.test.tsx diff --git a/internal/frontend/src/components/WidthToggle.tsx b/frontend/src/components/WidthToggle.tsx similarity index 100% rename from internal/frontend/src/components/WidthToggle.tsx rename to frontend/src/components/WidthToggle.tsx diff --git a/internal/frontend/src/components/ZoomPanView.tsx b/frontend/src/components/ZoomPanView.tsx similarity index 100% rename from internal/frontend/src/components/ZoomPanView.tsx rename to frontend/src/components/ZoomPanView.tsx diff --git a/internal/frontend/src/hooks/useActiveHeading.ts b/frontend/src/hooks/useActiveHeading.ts similarity index 100% rename from internal/frontend/src/hooks/useActiveHeading.ts rename to frontend/src/hooks/useActiveHeading.ts diff --git a/internal/frontend/src/hooks/useApi.test.ts b/frontend/src/hooks/useApi.test.ts similarity index 100% rename from internal/frontend/src/hooks/useApi.test.ts rename to frontend/src/hooks/useApi.test.ts diff --git a/internal/frontend/src/hooks/useApi.ts b/frontend/src/hooks/useApi.ts similarity index 100% rename from internal/frontend/src/hooks/useApi.ts rename to frontend/src/hooks/useApi.ts diff --git a/internal/frontend/src/hooks/useAppSettings.ts b/frontend/src/hooks/useAppSettings.ts similarity index 100% rename from internal/frontend/src/hooks/useAppSettings.ts rename to frontend/src/hooks/useAppSettings.ts diff --git a/internal/frontend/src/hooks/useFileDrop.test.ts b/frontend/src/hooks/useFileDrop.test.ts similarity index 100% rename from internal/frontend/src/hooks/useFileDrop.test.ts rename to frontend/src/hooks/useFileDrop.test.ts diff --git a/internal/frontend/src/hooks/useFileDrop.ts b/frontend/src/hooks/useFileDrop.ts similarity index 100% rename from internal/frontend/src/hooks/useFileDrop.ts rename to frontend/src/hooks/useFileDrop.ts diff --git a/internal/frontend/src/hooks/useMermaidSettings.ts b/frontend/src/hooks/useMermaidSettings.ts similarity index 100% rename from internal/frontend/src/hooks/useMermaidSettings.ts rename to frontend/src/hooks/useMermaidSettings.ts diff --git a/internal/frontend/src/hooks/useSSE.test.ts b/frontend/src/hooks/useSSE.test.ts similarity index 100% rename from internal/frontend/src/hooks/useSSE.test.ts rename to frontend/src/hooks/useSSE.test.ts diff --git a/internal/frontend/src/hooks/useSSE.ts b/frontend/src/hooks/useSSE.ts similarity index 100% rename from internal/frontend/src/hooks/useSSE.ts rename to frontend/src/hooks/useSSE.ts diff --git a/internal/frontend/src/hooks/useScrollRestoration.test.ts b/frontend/src/hooks/useScrollRestoration.test.ts similarity index 100% rename from internal/frontend/src/hooks/useScrollRestoration.test.ts rename to frontend/src/hooks/useScrollRestoration.test.ts diff --git a/internal/frontend/src/hooks/useScrollRestoration.ts b/frontend/src/hooks/useScrollRestoration.ts similarity index 100% rename from internal/frontend/src/hooks/useScrollRestoration.ts rename to frontend/src/hooks/useScrollRestoration.ts diff --git a/internal/frontend/src/main.tsx b/frontend/src/main.tsx similarity index 100% rename from internal/frontend/src/main.tsx rename to frontend/src/main.tsx diff --git a/internal/frontend/src/styles/app.css b/frontend/src/styles/app.css similarity index 100% rename from internal/frontend/src/styles/app.css rename to frontend/src/styles/app.css diff --git a/internal/frontend/src/test-setup.ts b/frontend/src/test-setup.ts similarity index 100% rename from internal/frontend/src/test-setup.ts rename to frontend/src/test-setup.ts diff --git a/internal/frontend/src/utils/buildTree.test.ts b/frontend/src/utils/buildTree.test.ts similarity index 100% rename from internal/frontend/src/utils/buildTree.test.ts rename to frontend/src/utils/buildTree.test.ts diff --git a/internal/frontend/src/utils/buildTree.ts b/frontend/src/utils/buildTree.ts similarity index 100% rename from internal/frontend/src/utils/buildTree.ts rename to frontend/src/utils/buildTree.ts diff --git a/internal/frontend/src/utils/extractText.test.ts b/frontend/src/utils/extractText.test.ts similarity index 100% rename from internal/frontend/src/utils/extractText.test.ts rename to frontend/src/utils/extractText.test.ts diff --git a/internal/frontend/src/utils/extractText.ts b/frontend/src/utils/extractText.ts similarity index 100% rename from internal/frontend/src/utils/extractText.ts rename to frontend/src/utils/extractText.ts diff --git a/internal/frontend/src/utils/frontmatter.test.ts b/frontend/src/utils/frontmatter.test.ts similarity index 100% rename from internal/frontend/src/utils/frontmatter.test.ts rename to frontend/src/utils/frontmatter.test.ts diff --git a/internal/frontend/src/utils/frontmatter.ts b/frontend/src/utils/frontmatter.ts similarity index 100% rename from internal/frontend/src/utils/frontmatter.ts rename to frontend/src/utils/frontmatter.ts diff --git a/internal/frontend/src/utils/fullTextSearch.test.ts b/frontend/src/utils/fullTextSearch.test.ts similarity index 100% rename from internal/frontend/src/utils/fullTextSearch.test.ts rename to frontend/src/utils/fullTextSearch.test.ts diff --git a/internal/frontend/src/utils/fullTextSearch.ts b/frontend/src/utils/fullTextSearch.ts similarity index 100% rename from internal/frontend/src/utils/fullTextSearch.ts rename to frontend/src/utils/fullTextSearch.ts diff --git a/internal/frontend/src/utils/groups.test.ts b/frontend/src/utils/groups.test.ts similarity index 100% rename from internal/frontend/src/utils/groups.test.ts rename to frontend/src/utils/groups.test.ts diff --git a/internal/frontend/src/utils/groups.ts b/frontend/src/utils/groups.ts similarity index 100% rename from internal/frontend/src/utils/groups.ts rename to frontend/src/utils/groups.ts diff --git a/internal/frontend/src/utils/markdownEnhance.test.ts b/frontend/src/utils/markdownEnhance.test.ts similarity index 100% rename from internal/frontend/src/utils/markdownEnhance.test.ts rename to frontend/src/utils/markdownEnhance.test.ts diff --git a/internal/frontend/src/utils/markdownEnhance.ts b/frontend/src/utils/markdownEnhance.ts similarity index 100% rename from internal/frontend/src/utils/markdownEnhance.ts rename to frontend/src/utils/markdownEnhance.ts diff --git a/internal/frontend/src/utils/mdx.test.ts b/frontend/src/utils/mdx.test.ts similarity index 100% rename from internal/frontend/src/utils/mdx.test.ts rename to frontend/src/utils/mdx.test.ts diff --git a/internal/frontend/src/utils/mdx.ts b/frontend/src/utils/mdx.ts similarity index 100% rename from internal/frontend/src/utils/mdx.ts rename to frontend/src/utils/mdx.ts diff --git a/internal/frontend/src/utils/pdfExport.test.ts b/frontend/src/utils/pdfExport.test.ts similarity index 100% rename from internal/frontend/src/utils/pdfExport.test.ts rename to frontend/src/utils/pdfExport.test.ts diff --git a/internal/frontend/src/utils/pdfExport.ts b/frontend/src/utils/pdfExport.ts similarity index 100% rename from internal/frontend/src/utils/pdfExport.ts rename to frontend/src/utils/pdfExport.ts diff --git a/internal/frontend/src/utils/resolve.test.ts b/frontend/src/utils/resolve.test.ts similarity index 100% rename from internal/frontend/src/utils/resolve.test.ts rename to frontend/src/utils/resolve.test.ts diff --git a/internal/frontend/src/utils/resolve.ts b/frontend/src/utils/resolve.ts similarity index 100% rename from internal/frontend/src/utils/resolve.ts rename to frontend/src/utils/resolve.ts diff --git a/internal/frontend/src/utils/searchJump.test.ts b/frontend/src/utils/searchJump.test.ts similarity index 100% rename from internal/frontend/src/utils/searchJump.test.ts rename to frontend/src/utils/searchJump.test.ts diff --git a/internal/frontend/src/utils/searchJump.ts b/frontend/src/utils/searchJump.ts similarity index 100% rename from internal/frontend/src/utils/searchJump.ts rename to frontend/src/utils/searchJump.ts diff --git a/internal/frontend/src/utils/staticData.ts b/frontend/src/utils/staticData.ts similarity index 100% rename from internal/frontend/src/utils/staticData.ts rename to frontend/src/utils/staticData.ts diff --git a/internal/frontend/tsconfig.json b/frontend/tsconfig.json similarity index 100% rename from internal/frontend/tsconfig.json rename to frontend/tsconfig.json diff --git a/internal/frontend/vite.config.ts b/frontend/vite.config.ts similarity index 98% rename from internal/frontend/vite.config.ts rename to frontend/vite.config.ts index 2547836..c172d2b 100644 --- a/internal/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -7,7 +7,7 @@ import path from "node:path"; export default defineConfig({ plugins: [react(), tailwindcss()], build: { - outDir: "../static/dist", + outDir: "../internal/static/dist", emptyOutDir: true, chunkSizeWarningLimit: 600, rollupOptions: { diff --git a/internal/static/static.go b/internal/static/static.go index 8d0a312..5b5cc8d 100644 --- a/internal/static/static.go +++ b/internal/static/static.go @@ -2,7 +2,7 @@ package static import "embed" -//go:generate sh -c "cd ../frontend && pnpm install && pnpm run build" +//go:generate sh -c "cd ../../frontend && pnpm install && pnpm run build" //go:embed all:dist var Frontend embed.FS diff --git a/testdata/code-blocks.md b/testdata/code-blocks.md index bd2b567..f9afb1f 100644 --- a/testdata/code-blocks.md +++ b/testdata/code-blocks.md @@ -57,8 +57,8 @@ async function fetchFiles(): Promise { set -euo pipefail echo "Building markview..." -cd internal/frontend && pnpm run build -cd ../.. +cd frontend && pnpm run build +cd .. go build -o markview . echo "Done!" ```