Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
26807e6
fix: show dot-prefixed tool folders in sidebar
gzg1023 May 30, 2026
e665302
feat(ui): add copy path, toolbar toggle, and breadcrumb view controls
hoiyada7-maker May 30, 2026
db7ccc4
chore(release): bump version to 1.5.5
hoiyada7-maker May 30, 2026
c787e65
ci(release): allow unsigned builds, add workflow_dispatch trigger
hoiyada7-maker May 30, 2026
95512b6
fix(ci): remove machine-specific .cargo/config.toml from git
hoiyada7-maker May 30, 2026
cd88a25
feat(ui): add Reveal in File Explorer to right-click context menu
hoiyada7-maker May 30, 2026
e46a966
chore(release): bump version to 1.5.6
hoiyada7-maker May 30, 2026
b315c52
fix(ts): remove unused dirname import
hoiyada7-maker May 31, 2026
2ecaaf8
Merge pull request #51 from gzg1023/main
mattenarle10 May 31, 2026
b3c38be
feat(ui): add copy path, toolbar toggle, and breadcrumb view controls…
hoiyada7-maker May 31, 2026
cd0c92f
docs: add contributor guidance to readme (#53)
mattenarle10 May 31, 2026
4889850
chore(deps): bump tar from 0.4.45 to 0.4.46 in /src-tauri (#50)
dependabot[bot] May 31, 2026
e640c5a
chore(release): prepare v1.5.5 (#54)
mattenarle10 May 31, 2026
d869a67
docs: refresh v1.5.5 workflow copy
mattenarle10 May 31, 2026
b518eaa
docs: tighten readme structure
mattenarle10 May 31, 2026
2ac18f3
docs: simplify readme contributor strip
mattenarle10 May 31, 2026
7bc3194
docs: polish readme presentation
mattenarle10 May 31, 2026
3b83bee
docs: remove readme preview image
mattenarle10 May 31, 2026
52e2f7a
feat(ui): multi-folder explorer with favorites and star
hoiyada7-maker May 31, 2026
ad63cd3
feat(ui): open non-md files as plain text in editor
hoiyada7-maker May 31, 2026
a46200f
fix(rust): restore macos-private-api feature dropped during version bump
hoiyada7-maker May 31, 2026
6049ac4
feat(ui): remember per-extension open preference and sync editor-only…
hoiyada7-maker May 31, 2026
5642abb
chore(release): bump version to 1.5.7
hoiyada7-maker May 31, 2026
78afe74
fix(ui): resolve local image paths in markdown preview
hoiyada7-maker Jun 1, 2026
c7fce8a
chore(release): bump version to 1.5.8
hoiyada7-maker Jun 1, 2026
1dc62f3
fix(rust): restore macos-private-api feature dropped during version bump
hoiyada7-maker Jun 1, 2026
df17e10
Merge remote-tracking branch 'origin/main' into pr-55-review
mattenarle10 Jun 1, 2026
04e9acb
ci(release): make updater signing conditional
mattenarle10 Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 52 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
tag_name:
description: "Release tag to publish, e.g. v1.5.5"
required: true

permissions:
contents: write
Expand Down Expand Up @@ -38,6 +43,11 @@ jobs:
# which sees the var as "set" and tries to `security import` empty
# data, hard-failing the bundle step.
HAS_APPLE_CERT: ${{ secrets.APPLE_CERTIFICATE != '' }}
# Tauri updater artifacts require a private signing key. Keep signed
# auto-update releases when configured, but let unsigned/manual builds
# complete without injecting empty signing env vars.
HAS_TAURI_SIGNING_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY != '' }}
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.ref_name }}
steps:
- name: checkout
uses: actions/checkout@v6
Expand All @@ -54,16 +64,16 @@ jobs:
set -e
# find the most recent tag BEFORE the one we're building. `git tag --sort`
# gives semver-ordered tags; we filter out the current ref and pick the next.
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^${{ github.ref_name }}$" | head -1 || true)
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^${{ env.RELEASE_TAG }}$" | head -1 || true)
if [ -z "$PREV_TAG" ]; then
COMMITS="- first public release 🐙"
DIFF_URL=""
else
COMMITS=$(git log "$PREV_TAG..${{ github.ref_name }}" --pretty=format:'- %s' --no-merges --reverse)
COMMITS=$(git log "$PREV_TAG..${{ env.RELEASE_TAG }}" --pretty=format:'- %s' --no-merges --reverse)
if [ -z "$COMMITS" ]; then
COMMITS="- (no commit changes since $PREV_TAG — version bump only)"
fi
DIFF_URL="full diff: https://github.com/mattenarle10/markamd/compare/$PREV_TAG...${{ github.ref_name }}"
DIFF_URL="full diff: https://github.com/${{ github.repository }}/compare/$PREV_TAG...${{ env.RELEASE_TAG }}"
fi
echo "PREV_TAG=$PREV_TAG" >> "$GITHUB_OUTPUT"
{
Expand All @@ -79,7 +89,7 @@ jobs:
env:
COMMITS: ${{ steps.changelog.outputs.COMMITS }}
DIFF_URL: ${{ steps.changelog.outputs.DIFF_URL }}
TAG_NAME: ${{ github.ref_name }}
TAG_NAME: ${{ env.RELEASE_TAG }}
run: |
set -e
NOTES_FILE="docs/release-notes/${TAG_NAME}.md"
Expand Down Expand Up @@ -136,6 +146,18 @@ jobs:
- name: install dependencies
run: bun install

- name: disable updater artifacts for unsigned build
if: env.HAS_TAURI_SIGNING_KEY != 'true'
shell: bash
run: |
node -e "
const fs = require('fs');
const path = 'src-tauri/tauri.conf.json';
const cfg = JSON.parse(fs.readFileSync(path, 'utf8'));
cfg.bundle.createUpdaterArtifacts = false;
fs.writeFileSync(path, JSON.stringify(cfg, null, 2));
"

- name: import apple cert + propagate signing env (macOS only)
if: matrix.os == 'macos-latest' && env.HAS_APPLE_CERT == 'true'
env:
Expand Down Expand Up @@ -166,7 +188,8 @@ jobs:
echo "APPLE_TEAM_ID=$APPLE_TEAM_ID"
} >> "$GITHUB_ENV"

- name: build + release
- name: build + release (signed updater)
if: env.HAS_TAURI_SIGNING_KEY == 'true'
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -178,8 +201,8 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: ${{ github.ref_name }}
releaseName: "marka.md ${{ github.ref_name }}"
tagName: ${{ env.RELEASE_TAG }}
releaseName: "marka.md ${{ env.RELEASE_TAG }}"
releaseBody: ${{ steps.release_body.outputs.BODY }}
# publish as a DRAFT so the matrix runners can both upload artifacts
# (including their per-platform latest.json entries) without racing
Expand All @@ -192,6 +215,19 @@ jobs:
prerelease: false
args: ${{ matrix.args }}

- name: build + release (unsigned, no updater artifacts)
if: env.HAS_TAURI_SIGNING_KEY != 'true'
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: ${{ env.RELEASE_TAG }}
releaseName: "marka.md ${{ env.RELEASE_TAG }}"
releaseBody: ${{ steps.release_body.outputs.BODY }}
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}

# tauri-action emits `marka.md_<version>_<arch>.dmg` by default. Rename
# per arch so users get clean filenames + the landing dropdown can keep
# linking to `marka.md.dmg` (apple-silicon default). Intel gets a clear
Expand All @@ -204,9 +240,9 @@ jobs:
shell: bash
run: |
set -e
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases --jq '.[] | select(.tag_name == "${{ github.ref_name }}") | .id' | head -1)
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases --jq '.[] | select(.tag_name == "${{ env.RELEASE_TAG }}") | .id' | head -1)
if [ -z "$RELEASE_ID" ]; then
echo "no release found for tag ${{ github.ref_name }} — skipping rename"
echo "no release found for tag ${{ env.RELEASE_TAG }} — skipping rename"
exit 0
fi
ASSET_ID=$(gh api "repos/${{ github.repository }}/releases/$RELEASE_ID/assets" --jq '.[] | select(.name | test("aarch64.*\\.dmg$")) | .id' | head -1)
Expand All @@ -224,9 +260,9 @@ jobs:
shell: bash
run: |
set -e
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases --jq '.[] | select(.tag_name == "${{ github.ref_name }}") | .id' | head -1)
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases --jq '.[] | select(.tag_name == "${{ env.RELEASE_TAG }}") | .id' | head -1)
if [ -z "$RELEASE_ID" ]; then
echo "no release found for tag ${{ github.ref_name }} — skipping rename"
echo "no release found for tag ${{ env.RELEASE_TAG }} — skipping rename"
exit 0
fi
ASSET_ID=$(gh api "repos/${{ github.repository }}/releases/$RELEASE_ID/assets" --jq '.[] | select(.name | test("x64.*\\.dmg$")) | .id' | head -1)
Expand All @@ -246,13 +282,15 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.ref_name }}
steps:
- name: publish draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "publishing draft release for ${{ github.ref_name }}"
gh release edit "${{ github.ref_name }}" \
echo "publishing draft release for ${{ env.RELEASE_TAG }}"
gh release edit "${{ env.RELEASE_TAG }}" \
--repo "${{ github.repository }}" \
--draft=false \
--latest
Expand All @@ -273,7 +311,7 @@ jobs:
env:
DEPLOY_HOOK: ${{ secrets.VERCEL_DEPLOY_HOOK }}
run: |
echo "triggering markamd-site rebuild for ${{ github.ref_name }}"
echo "triggering markamd-site rebuild for ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.ref_name }}"
curl -fsS -X POST "$DEPLOY_HOOK"
- name: no hook configured
if: env.HAS_HOOK != 'true'
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ dist-ssr
# personal scratchpad — never committed
notes/

# local MSVC build environment override (machine-specific paths, breaks Linux CI)
src-tauri/.cargo/config.toml

# secrets — defensive ignores. real secrets live in 1Password + GH secrets,
# but if someone accidentally drops a .p12 / .key / .pem into the repo, git
# will refuse to track it instead of leaking it to a PR.
Expand Down
120 changes: 42 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,49 +18,34 @@
<img src="https://img.shields.io/badge/notarized-Apple%20Developer-orange?style=flat-square" alt="notarized" />
</p>

a cross-platform (**macOS · Windows · Linux**) markdown editor specialized for **ai context management**. live editor on the left (codemirror 6), rendered preview on the right (markdown-it + shiki + mermaid), and a context tray for staging multiple notes into one AI-ready bundle. minimal chrome, grouped themes (neutral + catppuccin + ai-inspired + crafted), orange octopus mascot. ~10 mb bundle, ~240 mb resident — lean for a tauri app.
a cross-platform (**macOS · Windows · Linux**) markdown editor specialized for **ai context management**. live editor, rendered preview, file tabs, csv preview, grouped themes, and a context tray for staging multiple notes into one AI-ready bundle.

> built around one loop: **collect notes → write → share with ai**. nothing leaves your machine until you copy.

works with claude, chatgpt, gemini, your local agent — anywhere that reads plain markdown.

## features

- **live preview** — ~50 ms render, shiki code highlighting (36 langs, lazy-loaded), mermaid diagrams
- **csv preview** — open `.csv` files as a capped, read-only table for quick data checks beside your notes
- **grouped themes** — mono, mono dark, catppuccin family, crafted palettes, plus AI-inspired Claude / Codex / Gemini / Cursor themes · animated sections + hover-to-preview
- **reading mode** — ⌘. distraction-free preview with iA-style typography
- **editor-only mode** — ⌘⇧. hide the preview when you want to focus on writing
- **vim mode** — opt-in via theme menu · NORMAL/INSERT/VISUAL/REPLACE pill in the status bar
- **find** — ⌘f works in BOTH editor (codemirror) and reading mode (text-node walker w/ live highlights)
- **command palette** — ⌘k, fuzzy + grouped
- **ide-style sidebar** — drag-to-move, right-click rename / new / delete, ⌘⌥Z undo
- **session restore** — last open file + folder come back on launch
- **save as** — ⌘⇧s opens save-as dialog (also auto-fallback for untitled buffers)
- **markdown extras** — `==highlight==` (mark), `~~strike~~`, `[ ] / [x]` task lists with theme-aware checkboxes
- **share to ai** — ⌘⇧c copies clean markdown to clipboard
- **context tray** — stage multiple sidebar files, see file/token counts, copy them as one prompt bundle
- **export to pdf** — visible file-action button + ⌘p
- **external file watch** — auto-reloads when the file changes outside the app · conflict toast on dirty buffer
- **cross-platform auto-update** — minisign-signed releases on macOS / Windows / Linux
- **window transparency slider** — continuous opacity, macOS vibrancy
- **platform-aware shortcuts** — ⌘ on mac, Ctrl on Windows/Linux, surfaced correctly everywhere
- **no autosave** — ⌘s commits. trust your fingers, not background daemons.
works with claude, chatgpt, gemini, local agents, and anything that reads plain markdown.

## what you get

| area | details |
|---|---|
| writing | live preview, shiki highlighting, mermaid diagrams, task lists, mark/strike syntax, reading mode, editor-only mode, opt-in vim |
| ai context | stage sidebar files, see file/token counts, copy one AI-ready bundle with relative paths |
| files | tabs, folder sidebar, search, drag-to-move, undo file ops, copy paths, reveal in file manager, useful dot-tool folders |
| data + export | capped CSV preview, rendered code copy buttons, mermaid-aware PDF export, stable print margins |
| desktop polish | grouped themes, transparency controls, platform-aware shortcuts, session restore, external file watching, signed updates |

## install

[download the latest release →](https://github.com/mattenarle10/markamd/releases/latest)

### macOS (notarized + auto-updating, universal arch coverage)
### macOS

- **apple silicon** (M1/M2/M3/M4): grab `marka.md.dmg` → drag **marka.md.app** into `/Applications` → open.
- **intel mac**: grab `marka.md_intel.dmg` → same install steps.

### Windows (10+, x64)

grab `marka.md_*-setup.exe` → run.

Windows SmartScreen may show "Windows protected your PC". Click **More info** → **Run anyway**. marka.md is free + MIT — we don't sign Windows builds (paid certs aren't worth it for a free OSS project). Full source is right here if you'd rather build it yourself.
grab `marka.md_*-setup.exe` → run. Windows SmartScreen may ask for confirmation because the Windows build is unsigned.

### Linux (x86_64)

Expand All @@ -70,11 +55,9 @@ three flavors, pick what fits your distro:
- **.deb** (Debian / Ubuntu / Mint / Pop!_OS): `sudo dpkg -i marka.md_*_amd64.deb`
- **.rpm** (Fedora / RHEL / Rocky / openSUSE): `sudo dnf install marka.md-*.x86_64.rpm`

no signing required on Linux — it's the freedom platform 🐧

### from source

requires bun (or npm), rust toolchain. on macOS: xcode command line tools. on Windows: MSVC build tools (Visual Studio installer → "Desktop development with C++"). on Linux: `libwebkit2gtk-4.1-dev libsoup-3.0-dev` + friends.
requires bun, rust, and platform build tools. on Linux, install `libwebkit2gtk-4.1-dev libsoup-3.0-dev` and related Tauri deps.

```sh
bun install
Expand All @@ -92,8 +75,8 @@ shortcuts shown with **macOS** modifiers below. on **Windows / Linux**, substitu
| ⌘O | open a `.md` file |
| ⌘⇧O | open a folder of notes |
| ⌘N | new untitled buffer |
| ⌘S | save (manual — no autosave) |
| ⌘⇧S | save as (also auto-fallback for untitled buffers) |
| ⌘S | save |
| ⌘⇧S | save as (also handles untitled buffers) |
| ⌘B | toggle sidebar |
| ⌘. | toggle reading mode (preview only) |
| ⌘⇧. | toggle editor-only mode (preview hidden) |
Expand All @@ -118,52 +101,40 @@ shortcuts shown with **macOS** modifiers below. on **Windows / Linux**, substitu
| icons | lucide-react |
| styling | css variables, no framework |

## project structure
## roadmap

```
src/
├── app.tsx # shell — composes hooks + renders layout
├── components/
│ ├── primitives/ # button, icon, popover, kbd, shortcut, tooltip
│ ├── chrome/ # title-bar, breadcrumb, status-bar, logo
│ ├── editor/ # editor, preview, splitter, reading-find
│ ├── files/ # sidebar, file-tree, folder-node, editable-row, sidebar-search, context-menu
│ └── overlays/ # palette, help, about, welcome, drop, toast
├── hooks/ # use-file-session, use-file-ops, use-update-flow, use-context-menu,
│ # use-overlays, use-notifications, use-shortcuts, use-file-watcher,
│ # use-sync-scroll, use-debounced, use-persisted-state
├── lib/ # markdown, theme, platform, files, commands, pdf-export, updater,
│ # window-drag, storage, bundle, demo
├── styles/ # tokens, globals, per-domain css (chrome/, editor/, files/, overlays/, shared/)
└── assets/mascot/ # in-app sprites
src-tauri/ # rust shell, tauri config, capabilities
.github/workflows/ # release.yml (matrix build) + ci.yml + dependabot
```
Per-release detail lives on the [changelog](https://markamd.vercel.app/changelog).

every folder exports its public api via `index.ts`. path alias `@/*` resolves to `src/*`. state lives in cohesive custom hooks under `src/hooks/`; `app.tsx` is mostly composition + jsx.
- recently shipped: context tray, file tabs, CSV preview, grouped themes, interface languages, PDF/export polish, and file workflow improvements
- next: native/silent PDF generation and optional context bundle presets for stricter agent formats

## roadmap
## contributors

Thanks to everyone helping shape marka.md through PRs, issues, testing, and feedback.

<p>
<a href="https://github.com/mattenarle10"><img src="https://avatars.githubusercontent.com/u/89822774?v=4" width="44" height="44" alt="@mattenarle10" /></a>
<a href="https://github.com/gzg1023"><img src="https://avatars.githubusercontent.com/u/25383924?v=4" width="44" height="44" alt="@gzg1023" /></a>
<a href="https://github.com/hoiyada7-maker"><img src="https://avatars.githubusercontent.com/u/256971142?v=4" width="44" height="44" alt="@hoiyada7-maker" /></a>
</p>

per-release detail lives on the [changelog](https://markamd.vercel.app/changelog) (auto-fresh from GitHub releases). high-level:
Small, focused PRs are easiest to review and ship. Good places to help:

**v1.5**:
- **context tray** — multi-file bundling, ⌘-click to stage, token estimates, copy as one prompt blob
- **what's new toast** — first launch after update now points users straight to the changelog
- **pdf export polish** — cleaner document margins, no browser-added date/time/path headers, and rendered mermaid diagrams
- **theme polish** — mono / mono dark, animated grouped theme menu, and AI-inspired Claude / Codex / Gemini / Cursor palettes
- **file tabs + languages** — open multiple notes, switch between them quickly, and use the app in more interface languages
- **code block wrapping** — long rendered code lines wrap in preview and PDF export
- **macOS app naming + file handling** — packaged builds use `marka.md` consistently and default-handler launches open the selected markdown file reliably
- bug fixes from the [issue tracker](https://github.com/mattenarle10/markamd/issues)
- platform polish for Windows, Linux, and Intel macOS
- markdown, mermaid, PDF, and translation edge cases
- small UX improvements with screenshots or short screen recordings

**next**:
- native/silent PDF generation, so export does not depend on the browser print dialog
- optional richer context bundle presets for agents with stricter prompt formats
Before opening a PR:

contributions welcome — see [feedback](#feedback) below to suggest priorities.
- keep one behavior change per PR when possible
- include screenshots for UI changes
- update help/about/readme copy when the user-facing surface changes
- run `bun test`, `bun run build`, and `cargo check --release` from `src-tauri`

## privacy

local-first. nothing ever leaves your machine. no telemetry, no analytics, no accounts, no cloud sync. your `.md` files stay on disk. clipboard transfers happen only when you press ⌘⇧C — and then they're yours, going wherever you paste them.
local-first. no telemetry, no accounts, no cloud sync. your `.md` files stay on disk, and clipboard transfers happen only when you copy.

see [the full privacy notice](https://markamd.vercel.app/privacy) for the website analytics caveat (vercel speed insights, cookieless).

Expand All @@ -176,16 +147,9 @@ ideas, bugs, or just want to say hi?
- **landing page hub** → [markamd.vercel.app/feedback](https://markamd.vercel.app/feedback)
- **security issues** → [SECURITY.md](./SECURITY.md)

i read everything. PRs welcome.

## support

marka.md is free + MIT, and intends to stay that way. if it saves you time wrangling AI context:

- ⭐ [star the repo](https://github.com/mattenarle10/markamd) — biggest single signal
- 🗣️ tell another dev / share it

both appreciated, neither required. 🐙
marka.md is free + MIT. if it saves you time, [star the repo](https://github.com/mattenarle10/markamd) or share it with another dev.

## license

Expand Down
19 changes: 19 additions & 0 deletions docs/release-notes/v1.5.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# v1.5.5

v1.5.5 is a small workflow and navigation polish release.

## added

- **Copy Path / Copy Relative Path**: sidebar context menus can copy absolute or root-relative paths.
- **Reveal in File Manager**: open a selected file or folder in Finder, Explorer, or the Linux file manager.
- **Breadcrumb view controls**: reading mode, titlebar visibility, and the theme menu now live beside the file actions.

## improved

- Hidden-but-useful tool folders like `.github`, `.vscode`, `.cursor`, `.claude`, and `.codex` now show in the sidebar.
- Reading mode keeps its exit controls reachable even when the titlebar is hidden.
- README contributor guidance is shorter and clearer for first-time PRs.

## security

- Updated the indirect Rust `tar` dependency from `0.4.45` to `0.4.46`.
Loading