2026-05-03 19:49:21 +02:00
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
use crate::window_state::MAIN_WINDOW_LABEL;
|
2026-05-02 02:57:45 +02:00
|
|
|
use serde::{Deserialize, Deserializer};
|
|
|
|
|
use std::{
|
|
|
|
|
collections::{BTreeMap, HashSet},
|
|
|
|
|
error::Error,
|
|
|
|
|
sync::OnceLock,
|
|
|
|
|
};
|
2026-05-03 19:49:21 +02:00
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
use tauri::{menu::MenuEvent, Manager};
|
feat: auto-build, GitHub Release, and in-app updater (#14)
* ci: auto-release workflow on merge to main
Rewrite .github/workflows/release.yml to trigger on every push to main
instead of manual tag pushes. The workflow now:
- Computes version as 0.YYYYMMDD.GITHUB_RUN_NUMBER
- Builds aarch64-apple-darwin and x86_64-apple-darwin in parallel
- Merges them into a universal binary using lipo
- Creates a universal .dmg and signed updater tarball
- Generates latest.json with per-arch and universal platform entries
- Publishes a GitHub Release with auto-generated release notes
- Updates a GitHub Pages release history site (gh-pages branch)
Product decisions:
- Universal binary approach: copy arm64 .app as base, lipo the main
executable, keep everything else from arm64 (shared frameworks are
architecture-independent). This is the standard Tauri pattern.
- Per-arch updater tarballs are also uploaded so the Tauri updater can
download the correct arch-specific build (smaller download).
- Release notes are auto-generated from git log since last tag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: github pages with release history
Use peaceiris/actions-gh-pages@v4 to deploy a release history site.
The page fetches releases.json (also deployed) and renders each release
with date, notes, and download links for .dmg files.
This handles the gh-pages branch creation automatically on first run.
The page is available at https://refactoringhq.github.io/laputa-app/
Product decision: used fetch() to load releases.json at runtime instead
of inlining it, which is cleaner and avoids shell escaping issues with
release note content. The releases.json is deployed alongside index.html.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: in-app update notification UI
Replace the old window.confirm updater with a proper React-based
update notification system:
- useUpdater hook now exposes state machine (idle → available →
downloading → ready) and actions (startDownload, openReleaseNotes,
dismiss)
- UpdateBanner component renders at the top of the app shell:
- "Available" state: shows version, Release Notes link, Update Now
button, dismiss X
- "Downloading" state: animated spinner, progress bar with percentage
- "Ready" state: Restart Now button to apply the update
- Silently checks on startup after 3s delay; fails silently on
network errors or 404
- Release Notes link opens the GitHub Pages release history site
Product decisions:
- Banner at top of app (not a modal) — non-intrusive, visible but
not blocking. User can dismiss and continue working.
- Progress bar shows during download so user knows it's working.
- Separate "Restart Now" state after download so user controls when
the app restarts (they may have unsaved work).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: updater component tests
Rewrite useUpdater hook tests and add UpdateBanner component tests:
Hook tests (10 cases):
- Starts in idle state
- Does nothing when not in Tauri
- Checks for updates after 3s delay
- Stays idle when no update available
- Transitions to available when update found
- Handles missing release body gracefully
- Stays idle on network error (fails silently)
- Dismiss returns to idle
- openReleaseNotes opens correct URL
- startDownload transitions through downloading to ready
Component tests (10 cases):
- Renders nothing when idle
- Renders nothing on error
- Shows version and buttons when available
- Update Now calls startDownload
- Release Notes calls openReleaseNotes
- Dismiss button works
- Shows progress bar during download
- Shows 0% at start of download
- Shows restart button when ready
- Restart button calls restartApp
All 457 tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: auto-build-release wireframes
Copy ui-design.pen as base. Frames to be added for:
1. Update notification banner (visible state) — horizontal bar at
top of app shell with version text, Release Notes link, Update
Now button, and dismiss X
2. Update download progress state — spinner icon, progress bar with
percentage, downloading text
3. "Restart to apply" state — green accent, version text, Restart
Now button
Note: Pencil editor was not available during this session. The base
design file is committed; frames will be added when the editor is
accessible. The implemented component (UpdateBanner.tsx) serves as
the source of truth for the design.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update ARCHITECTURE.md with release/update system
Add comprehensive documentation for:
- Release pipeline (4-phase workflow: version → build → release → pages)
- Versioning scheme (0.YYYYMMDD.RUN_NUMBER)
- Universal binary strategy (lipo merge)
- Updater endpoint and latest.json manifest
- In-app update UI state machine
- GitHub Pages release history site
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: rustfmt formatting
* fix: rustfmt build.rs
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:50:36 +01:00
|
|
|
use tauri::{
|
2026-05-02 02:57:45 +02:00
|
|
|
menu::{MenuBuilder, MenuItem, MenuItemBuilder, MenuItemKind, Submenu, SubmenuBuilder},
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
App, AppHandle, Emitter,
|
feat: auto-build, GitHub Release, and in-app updater (#14)
* ci: auto-release workflow on merge to main
Rewrite .github/workflows/release.yml to trigger on every push to main
instead of manual tag pushes. The workflow now:
- Computes version as 0.YYYYMMDD.GITHUB_RUN_NUMBER
- Builds aarch64-apple-darwin and x86_64-apple-darwin in parallel
- Merges them into a universal binary using lipo
- Creates a universal .dmg and signed updater tarball
- Generates latest.json with per-arch and universal platform entries
- Publishes a GitHub Release with auto-generated release notes
- Updates a GitHub Pages release history site (gh-pages branch)
Product decisions:
- Universal binary approach: copy arm64 .app as base, lipo the main
executable, keep everything else from arm64 (shared frameworks are
architecture-independent). This is the standard Tauri pattern.
- Per-arch updater tarballs are also uploaded so the Tauri updater can
download the correct arch-specific build (smaller download).
- Release notes are auto-generated from git log since last tag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: github pages with release history
Use peaceiris/actions-gh-pages@v4 to deploy a release history site.
The page fetches releases.json (also deployed) and renders each release
with date, notes, and download links for .dmg files.
This handles the gh-pages branch creation automatically on first run.
The page is available at https://refactoringhq.github.io/laputa-app/
Product decision: used fetch() to load releases.json at runtime instead
of inlining it, which is cleaner and avoids shell escaping issues with
release note content. The releases.json is deployed alongside index.html.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: in-app update notification UI
Replace the old window.confirm updater with a proper React-based
update notification system:
- useUpdater hook now exposes state machine (idle → available →
downloading → ready) and actions (startDownload, openReleaseNotes,
dismiss)
- UpdateBanner component renders at the top of the app shell:
- "Available" state: shows version, Release Notes link, Update Now
button, dismiss X
- "Downloading" state: animated spinner, progress bar with percentage
- "Ready" state: Restart Now button to apply the update
- Silently checks on startup after 3s delay; fails silently on
network errors or 404
- Release Notes link opens the GitHub Pages release history site
Product decisions:
- Banner at top of app (not a modal) — non-intrusive, visible but
not blocking. User can dismiss and continue working.
- Progress bar shows during download so user knows it's working.
- Separate "Restart Now" state after download so user controls when
the app restarts (they may have unsaved work).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: updater component tests
Rewrite useUpdater hook tests and add UpdateBanner component tests:
Hook tests (10 cases):
- Starts in idle state
- Does nothing when not in Tauri
- Checks for updates after 3s delay
- Stays idle when no update available
- Transitions to available when update found
- Handles missing release body gracefully
- Stays idle on network error (fails silently)
- Dismiss returns to idle
- openReleaseNotes opens correct URL
- startDownload transitions through downloading to ready
Component tests (10 cases):
- Renders nothing when idle
- Renders nothing on error
- Shows version and buttons when available
- Update Now calls startDownload
- Release Notes calls openReleaseNotes
- Dismiss button works
- Shows progress bar during download
- Shows 0% at start of download
- Shows restart button when ready
- Restart button calls restartApp
All 457 tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* design: auto-build-release wireframes
Copy ui-design.pen as base. Frames to be added for:
1. Update notification banner (visible state) — horizontal bar at
top of app shell with version text, Release Notes link, Update
Now button, and dismiss X
2. Update download progress state — spinner icon, progress bar with
percentage, downloading text
3. "Restart to apply" state — green accent, version text, Restart
Now button
Note: Pencil editor was not available during this session. The base
design file is committed; frames will be added when the editor is
accessible. The implemented component (UpdateBanner.tsx) serves as
the source of truth for the design.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update ARCHITECTURE.md with release/update system
Add comprehensive documentation for:
- Release pipeline (4-phase workflow: version → build → release → pages)
- Versioning scheme (0.YYYYMMDD.RUN_NUMBER)
- Universal binary strategy (lipo merge)
- Updater endpoint and latest.json manifest
- In-app update UI state machine
- GitHub Pages release history site
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: rustfmt formatting
* fix: rustfmt build.rs
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:50:36 +01:00
|
|
|
};
|
2026-02-22 18:44:54 +01:00
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
const APP_COMMAND_MANIFEST_JSON: &str = include_str!("../../src/shared/appCommandManifest.json");
|
|
|
|
|
const NOTE_DEPENDENT_GROUP: &str = "noteDependent";
|
|
|
|
|
const EDITOR_FIND_DEPENDENT_GROUP: &str = "editorFindDependent";
|
|
|
|
|
const NOTE_LIST_SEARCH_DEPENDENT_GROUP: &str = "noteListSearchDependent";
|
|
|
|
|
const RESTORE_DELETED_DEPENDENT_GROUP: &str = "restoreDeletedDependent";
|
|
|
|
|
const GIT_COMMIT_DEPENDENT_GROUP: &str = "gitCommitDependent";
|
|
|
|
|
const GIT_CONFLICT_DEPENDENT_GROUP: &str = "gitConflictDependent";
|
|
|
|
|
const GIT_NO_REMOTE_DEPENDENT_GROUP: &str = "gitNoRemoteDependent";
|
|
|
|
|
|
|
|
|
|
type MenuResult = Result<Submenu<tauri::Wry>, Box<dyn Error>>;
|
|
|
|
|
type AppSubmenuBuilder<'a> = SubmenuBuilder<'a, tauri::Wry, App>;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
struct AppCommandManifest {
|
|
|
|
|
commands: BTreeMap<String, ManifestCommand>,
|
|
|
|
|
menus: Vec<ManifestMenuSection>,
|
|
|
|
|
app_menu: Vec<ManifestMenuItem>,
|
|
|
|
|
menu_state_groups: BTreeMap<String, Vec<MenuStateGroupReference>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct ManifestCommand {
|
|
|
|
|
id: String,
|
|
|
|
|
shortcut: Option<ManifestShortcut>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct ManifestShortcut {
|
|
|
|
|
accelerator: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct ManifestMenuSection {
|
|
|
|
|
label: String,
|
|
|
|
|
items: Vec<ManifestMenuItem>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
#[serde(tag = "kind")]
|
|
|
|
|
enum ManifestMenuItem {
|
|
|
|
|
#[serde(rename = "separator")]
|
|
|
|
|
Separator,
|
|
|
|
|
#[serde(rename = "command")]
|
|
|
|
|
Command {
|
|
|
|
|
command: String,
|
|
|
|
|
id: Option<String>,
|
|
|
|
|
label: PlatformLabel,
|
|
|
|
|
#[serde(default, deserialize_with = "deserialize_accelerator")]
|
|
|
|
|
accelerator: ManifestAccelerator,
|
|
|
|
|
enabled: Option<bool>,
|
|
|
|
|
},
|
|
|
|
|
#[serde(rename = "menu-event")]
|
|
|
|
|
MenuEvent {
|
|
|
|
|
id: String,
|
|
|
|
|
label: PlatformLabel,
|
|
|
|
|
#[serde(default, deserialize_with = "deserialize_accelerator")]
|
|
|
|
|
accelerator: ManifestAccelerator,
|
|
|
|
|
enabled: Option<bool>,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
#[serde(untagged)]
|
|
|
|
|
enum PlatformLabel {
|
|
|
|
|
Plain(String),
|
|
|
|
|
Platform {
|
|
|
|
|
macos: Option<String>,
|
|
|
|
|
windows: Option<String>,
|
|
|
|
|
linux: Option<String>,
|
|
|
|
|
default: String,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default)]
|
|
|
|
|
enum ManifestAccelerator {
|
|
|
|
|
#[default]
|
|
|
|
|
Inherit,
|
|
|
|
|
Suppressed,
|
|
|
|
|
Explicit(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
#[serde(untagged)]
|
|
|
|
|
enum MenuStateGroupReference {
|
|
|
|
|
Command { command: String },
|
|
|
|
|
Id { id: String },
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn deserialize_accelerator<'de, D>(deserializer: D) -> Result<ManifestAccelerator, D::Error>
|
|
|
|
|
where
|
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
|
{
|
|
|
|
|
Option::<String>::deserialize(deserializer).map(|accelerator| match accelerator {
|
|
|
|
|
Some(accelerator) => ManifestAccelerator::Explicit(accelerator),
|
|
|
|
|
None => ManifestAccelerator::Suppressed,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PlatformLabel {
|
|
|
|
|
fn resolve(&self, target_os: &str) -> &str {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Plain(label) => label.as_str(),
|
|
|
|
|
Self::Platform {
|
|
|
|
|
macos,
|
|
|
|
|
windows,
|
|
|
|
|
linux,
|
|
|
|
|
default,
|
|
|
|
|
} => match target_os {
|
|
|
|
|
"macos" => macos.as_deref().unwrap_or(default.as_str()),
|
|
|
|
|
"windows" => windows.as_deref().unwrap_or(default.as_str()),
|
|
|
|
|
"linux" => linux.as_deref().unwrap_or(default.as_str()),
|
|
|
|
|
_ => default.as_str(),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ManifestMenuItem {
|
|
|
|
|
fn command_id<'a>(&'a self, manifest: &'a AppCommandManifest) -> Option<&'a str> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Command { command, .. } => manifest
|
|
|
|
|
.commands
|
|
|
|
|
.get(command)
|
|
|
|
|
.map(|command| command.id.as_str()),
|
|
|
|
|
Self::MenuEvent { id, .. } => Some(id.as_str()),
|
|
|
|
|
Self::Separator => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn menu_item_id<'a>(&'a self, manifest: &'a AppCommandManifest) -> Option<&'a str> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Command { command, id, .. } => id.as_deref().or_else(|| {
|
|
|
|
|
manifest
|
|
|
|
|
.commands
|
|
|
|
|
.get(command)
|
|
|
|
|
.map(|command| command.id.as_str())
|
|
|
|
|
}),
|
|
|
|
|
Self::MenuEvent { id, .. } => Some(id.as_str()),
|
|
|
|
|
Self::Separator => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn label(&self, target_os: &str) -> Option<&str> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Command { label, .. } | Self::MenuEvent { label, .. } => {
|
|
|
|
|
Some(label.resolve(target_os))
|
|
|
|
|
}
|
|
|
|
|
Self::Separator => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn accelerator<'a>(&'a self, manifest: &'a AppCommandManifest) -> Option<&'a str> {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Command {
|
|
|
|
|
command,
|
|
|
|
|
accelerator,
|
|
|
|
|
..
|
|
|
|
|
} => match accelerator {
|
|
|
|
|
ManifestAccelerator::Explicit(accelerator) => Some(accelerator.as_str()),
|
|
|
|
|
ManifestAccelerator::Suppressed => None,
|
|
|
|
|
ManifestAccelerator::Inherit => manifest
|
|
|
|
|
.commands
|
|
|
|
|
.get(command)
|
|
|
|
|
.and_then(|command| command.shortcut.as_ref())
|
|
|
|
|
.map(|shortcut| shortcut.accelerator.as_str()),
|
|
|
|
|
},
|
|
|
|
|
Self::MenuEvent { accelerator, .. } => match accelerator {
|
|
|
|
|
ManifestAccelerator::Explicit(accelerator) => Some(accelerator.as_str()),
|
|
|
|
|
ManifestAccelerator::Suppressed | ManifestAccelerator::Inherit => None,
|
|
|
|
|
},
|
|
|
|
|
Self::Separator => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn enabled(&self) -> bool {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Command { enabled, .. } | Self::MenuEvent { enabled, .. } => {
|
|
|
|
|
enabled.unwrap_or(true)
|
|
|
|
|
}
|
|
|
|
|
Self::Separator => true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static APP_COMMAND_MANIFEST: OnceLock<AppCommandManifest> = OnceLock::new();
|
|
|
|
|
static CUSTOM_MENU_IDS: OnceLock<HashSet<String>> = OnceLock::new();
|
|
|
|
|
|
|
|
|
|
fn manifest() -> &'static AppCommandManifest {
|
|
|
|
|
APP_COMMAND_MANIFEST.get_or_init(|| {
|
|
|
|
|
serde_json::from_str(APP_COMMAND_MANIFEST_JSON)
|
|
|
|
|
.expect("shared app command manifest must be valid JSON")
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn manifest_menu_items() -> impl Iterator<Item = &'static ManifestMenuItem> {
|
|
|
|
|
let manifest = manifest();
|
|
|
|
|
manifest
|
|
|
|
|
.menus
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|section| section.items.iter())
|
|
|
|
|
.chain(manifest.app_menu.iter())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn custom_menu_ids() -> &'static HashSet<String> {
|
|
|
|
|
CUSTOM_MENU_IDS.get_or_init(|| {
|
|
|
|
|
manifest_menu_items()
|
|
|
|
|
.filter_map(|item| item.menu_item_id(manifest()))
|
|
|
|
|
.map(str::to_owned)
|
|
|
|
|
.collect()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn manifest_section(label: &str) -> Result<&'static ManifestMenuSection, Box<dyn Error>> {
|
|
|
|
|
manifest()
|
|
|
|
|
.menus
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|section| section.label == label)
|
|
|
|
|
.ok_or_else(|| format!("Missing menu section in command manifest: {label}").into())
|
|
|
|
|
}
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
|
2026-04-30 06:46:45 +02:00
|
|
|
fn app_menu_includes_services(target_os: &str) -> bool {
|
|
|
|
|
target_os == "macos"
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 19:49:21 +02:00
|
|
|
fn window_menu_event_handler_required(target_os: &str) -> bool {
|
|
|
|
|
target_os != "macos"
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
fn build_manifest_menu_item(
|
|
|
|
|
app: &App,
|
|
|
|
|
item: &ManifestMenuItem,
|
|
|
|
|
) -> Result<Option<MenuItem<tauri::Wry>>, Box<dyn Error>> {
|
|
|
|
|
let Some(id) = item.menu_item_id(manifest()) else {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
};
|
|
|
|
|
let Some(label) = item.label(std::env::consts::OS) else {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut builder = MenuItemBuilder::new(label).id(id).enabled(item.enabled());
|
|
|
|
|
if let Some(accelerator) = item.accelerator(manifest()) {
|
|
|
|
|
builder = builder.accelerator(accelerator);
|
|
|
|
|
}
|
|
|
|
|
Ok(Some(builder.build(app)?))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn append_manifest_item<'a>(
|
|
|
|
|
app: &'a App,
|
|
|
|
|
builder: AppSubmenuBuilder<'a>,
|
|
|
|
|
item: &ManifestMenuItem,
|
|
|
|
|
) -> Result<AppSubmenuBuilder<'a>, Box<dyn Error>> {
|
|
|
|
|
if matches!(item, ManifestMenuItem::Separator) {
|
|
|
|
|
return Ok(builder.separator());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let Some(item) = build_manifest_menu_item(app, item)? else {
|
|
|
|
|
return Ok(builder);
|
|
|
|
|
};
|
|
|
|
|
Ok(builder.item(&item))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_manifest_menu(app: &App, label: &str) -> MenuResult {
|
|
|
|
|
let section = manifest_section(label)?;
|
|
|
|
|
let mut builder = SubmenuBuilder::new(app, section.label.as_str());
|
|
|
|
|
for item in §ion.items {
|
|
|
|
|
builder = append_manifest_item(app, builder, item)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(builder.build()?)
|
|
|
|
|
}
|
|
|
|
|
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
fn build_app_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
let mut builder = SubmenuBuilder::new(app, "Tolaria").about(None).separator();
|
|
|
|
|
|
|
|
|
|
for item in &manifest().app_menu {
|
|
|
|
|
builder = append_manifest_item(app, builder, item)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder = builder.separator();
|
2026-04-30 06:46:45 +02:00
|
|
|
|
|
|
|
|
if app_menu_includes_services(std::env::consts::OS) {
|
|
|
|
|
builder = builder
|
|
|
|
|
.services()
|
|
|
|
|
.separator()
|
|
|
|
|
.hide()
|
|
|
|
|
.hide_others()
|
|
|
|
|
.show_all()
|
|
|
|
|
.separator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(builder.quit().build()?)
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_file_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
build_manifest_menu(app, "File")
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_edit_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
let section = manifest_section("Edit")?;
|
|
|
|
|
let mut items = section.items.iter();
|
|
|
|
|
let mut builder = SubmenuBuilder::new(app, "Edit")
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
.undo()
|
|
|
|
|
.redo()
|
|
|
|
|
.separator()
|
|
|
|
|
.cut()
|
|
|
|
|
.copy()
|
2026-05-02 02:57:45 +02:00
|
|
|
.paste();
|
|
|
|
|
|
|
|
|
|
if let Some(paste_plain_text) = items.next() {
|
|
|
|
|
builder = append_manifest_item(app, builder, paste_plain_text)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder = builder.separator().select_all().separator();
|
|
|
|
|
|
|
|
|
|
if matches!(items.clone().next(), Some(ManifestMenuItem::Separator)) {
|
|
|
|
|
items.next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for item in items {
|
|
|
|
|
builder = append_manifest_item(app, builder, item)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(builder.build()?)
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_view_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
build_manifest_menu(app, "View")
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
fn build_go_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
build_manifest_menu(app, "Go")
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_note_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
build_manifest_menu(app, "Note")
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_vault_menu(app: &App) -> MenuResult {
|
2026-05-02 02:57:45 +02:00
|
|
|
build_manifest_menu(app, "Vault")
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
fn build_window_menu(app: &App) -> MenuResult {
|
|
|
|
|
Ok(SubmenuBuilder::new(app, "Window")
|
|
|
|
|
.minimize()
|
|
|
|
|
.maximize()
|
|
|
|
|
.separator()
|
|
|
|
|
.close_window()
|
|
|
|
|
.build()?)
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
pub fn setup_menu(app: &App) -> Result<(), Box<dyn Error>> {
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
let app_menu = build_app_menu(app)?;
|
|
|
|
|
let file_menu = build_file_menu(app)?;
|
|
|
|
|
let edit_menu = build_edit_menu(app)?;
|
|
|
|
|
let view_menu = build_view_menu(app)?;
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
let go_menu = build_go_menu(app)?;
|
|
|
|
|
let note_menu = build_note_menu(app)?;
|
|
|
|
|
let vault_menu = build_vault_menu(app)?;
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
let window_menu = build_window_menu(app)?;
|
2026-02-22 18:44:54 +01:00
|
|
|
|
2026-02-25 18:30:20 +01:00
|
|
|
let menu = MenuBuilder::new(app)
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
.item(&app_menu)
|
|
|
|
|
.item(&file_menu)
|
|
|
|
|
.item(&edit_menu)
|
|
|
|
|
.item(&view_menu)
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
.item(&go_menu)
|
|
|
|
|
.item(¬e_menu)
|
|
|
|
|
.item(&vault_menu)
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
.item(&window_menu)
|
2026-02-25 18:30:20 +01:00
|
|
|
.build()?;
|
2026-02-22 18:44:54 +01:00
|
|
|
|
|
|
|
|
app.set_menu(menu)?;
|
|
|
|
|
|
|
|
|
|
app.on_menu_event(|app_handle, event| {
|
|
|
|
|
let id = event.id().0.as_str();
|
2026-04-11 10:39:08 +02:00
|
|
|
let _ = emit_custom_menu_event(app_handle, id);
|
2026-02-22 18:44:54 +01:00
|
|
|
});
|
|
|
|
|
|
2026-05-03 19:49:21 +02:00
|
|
|
register_window_menu_event_handler(app)?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
fn register_window_menu_event_handler(app: &App) -> Result<(), Box<dyn Error>> {
|
|
|
|
|
debug_assert!(window_menu_event_handler_required(std::env::consts::OS));
|
|
|
|
|
let window = app.get_webview_window(MAIN_WINDOW_LABEL).ok_or_else(|| {
|
|
|
|
|
format!("setup_menu: window '{MAIN_WINDOW_LABEL}' not found; menu events will not fire")
|
|
|
|
|
})?;
|
|
|
|
|
let app_handle = app.handle().clone();
|
|
|
|
|
window.on_menu_event(move |_window, event: MenuEvent| {
|
|
|
|
|
let id = event.id().0.as_str();
|
|
|
|
|
let _ = emit_custom_menu_event(&app_handle, id);
|
|
|
|
|
});
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
fn register_window_menu_event_handler(_app: &App) -> Result<(), Box<dyn Error>> {
|
|
|
|
|
debug_assert!(!window_menu_event_handler_required(std::env::consts::OS));
|
2026-02-22 18:44:54 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
fn emitted_menu_event_id(id: &str) -> Option<&'static str> {
|
|
|
|
|
manifest_menu_items().find_map(|item| {
|
|
|
|
|
if item.menu_item_id(manifest()) == Some(id) {
|
|
|
|
|
item.command_id(manifest())
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 10:39:08 +02:00
|
|
|
pub fn emit_custom_menu_event(app_handle: &AppHandle, id: &str) -> Result<(), String> {
|
2026-05-02 02:57:45 +02:00
|
|
|
if !custom_menu_ids().contains(id) {
|
2026-04-11 10:39:08 +02:00
|
|
|
return Err(format!("Unknown custom menu event: {id}"));
|
|
|
|
|
}
|
2026-05-02 02:57:45 +02:00
|
|
|
let emitted_id = emitted_menu_event_id(id)
|
|
|
|
|
.ok_or_else(|| format!("Missing emitted command for custom menu event: {id}"))?;
|
2026-04-11 10:39:08 +02:00
|
|
|
app_handle
|
2026-04-19 13:47:02 +02:00
|
|
|
.emit("menu-event", emitted_id)
|
|
|
|
|
.map_err(|err| format!("Failed to emit menu-event {emitted_id}: {err}"))
|
2026-04-11 10:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
fn menu_state_group_ids(group_name: &str) -> Vec<&'static str> {
|
|
|
|
|
manifest()
|
|
|
|
|
.menu_state_groups
|
|
|
|
|
.get(group_name)
|
|
|
|
|
.into_iter()
|
|
|
|
|
.flatten()
|
|
|
|
|
.filter_map(|reference| match reference {
|
|
|
|
|
MenuStateGroupReference::Command { command } => manifest()
|
|
|
|
|
.commands
|
|
|
|
|
.get(command)
|
|
|
|
|
.map(|command| command.id.as_str()),
|
|
|
|
|
MenuStateGroupReference::Id { id } => Some(id.as_str()),
|
|
|
|
|
})
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_items_enabled<'a>(
|
|
|
|
|
app_handle: &AppHandle,
|
|
|
|
|
ids: impl IntoIterator<Item = &'a str>,
|
|
|
|
|
enabled: bool,
|
|
|
|
|
) {
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
let Some(menu) = app_handle.menu() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
for id in ids {
|
2026-05-02 02:57:45 +02:00
|
|
|
if let Some(MenuItemKind::MenuItem(mi)) = menu.get(id) {
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
let _ = mi.set_enabled(enabled);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
fn set_menu_state_group_enabled(app_handle: &AppHandle, group_name: &str, enabled: bool) {
|
|
|
|
|
set_items_enabled(app_handle, menu_state_group_ids(group_name), enabled);
|
|
|
|
|
}
|
|
|
|
|
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
/// Enable or disable menu items that depend on having an active note tab.
|
|
|
|
|
pub fn set_note_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, NOTE_DEPENDENT_GROUP, enabled);
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-27 10:12:13 +02:00
|
|
|
/// Enable or disable menu items that depend on the editor being the active surface.
|
|
|
|
|
pub fn set_editor_find_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, EDITOR_FIND_DEPENDENT_GROUP, enabled);
|
2026-04-27 10:12:13 +02:00
|
|
|
}
|
|
|
|
|
|
2026-04-21 00:47:45 +02:00
|
|
|
/// Enable or disable menu items that depend on the note list being the active surface.
|
|
|
|
|
pub fn set_note_list_search_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, NOTE_LIST_SEARCH_DEPENDENT_GROUP, enabled);
|
2026-04-21 00:47:45 +02:00
|
|
|
}
|
|
|
|
|
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
/// Enable or disable menu items that depend on having uncommitted changes.
|
|
|
|
|
pub fn set_git_commit_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, GIT_COMMIT_DEPENDENT_GROUP, enabled);
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Enable or disable menu items that depend on having merge conflicts.
|
|
|
|
|
pub fn set_git_conflict_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, GIT_CONFLICT_DEPENDENT_GROUP, enabled);
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-19 16:18:35 +02:00
|
|
|
/// Enable or disable menu items that depend on the active vault having no remote.
|
|
|
|
|
pub fn set_git_no_remote_items_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, GIT_NO_REMOTE_DEPENDENT_GROUP, enabled);
|
2026-04-19 16:18:35 +02:00
|
|
|
}
|
|
|
|
|
|
2026-04-07 20:09:04 +02:00
|
|
|
/// Enable or disable menu items that depend on a deleted note preview being active.
|
|
|
|
|
pub fn set_restore_deleted_item_enabled(app_handle: &AppHandle, enabled: bool) {
|
2026-05-02 02:57:45 +02:00
|
|
|
set_menu_state_group_enabled(app_handle, RESTORE_DELETED_DEPENDENT_GROUP, enabled);
|
2026-04-07 20:09:04 +02:00
|
|
|
}
|
|
|
|
|
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
2026-05-02 02:57:45 +02:00
|
|
|
fn menu_item_by_id(id: &str) -> &'static ManifestMenuItem {
|
|
|
|
|
manifest_menu_items()
|
|
|
|
|
.find(|item| item.menu_item_id(manifest()) == Some(id))
|
|
|
|
|
.unwrap_or_else(|| panic!("missing menu item {id}"))
|
|
|
|
|
}
|
|
|
|
|
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
#[test]
|
2026-05-02 02:57:45 +02:00
|
|
|
fn custom_ids_are_manifest_menu_item_ids() {
|
|
|
|
|
let expected: HashSet<_> = manifest_menu_items()
|
|
|
|
|
.filter_map(|item| item.menu_item_id(manifest()))
|
|
|
|
|
.map(str::to_owned)
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
assert_eq!(custom_menu_ids(), &expected);
|
|
|
|
|
assert!(custom_menu_ids().contains("file-quick-open-alias"));
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2026-05-02 02:57:45 +02:00
|
|
|
fn manifest_command_items_reference_known_commands() {
|
|
|
|
|
for item in manifest_menu_items() {
|
|
|
|
|
if let ManifestMenuItem::Command { command, .. } = item {
|
|
|
|
|
assert!(
|
|
|
|
|
manifest().commands.contains_key(command),
|
|
|
|
|
"menu item references missing command key {command}"
|
|
|
|
|
);
|
|
|
|
|
}
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
|
2026-04-21 00:47:45 +02:00
|
|
|
#[test]
|
2026-05-02 02:57:45 +02:00
|
|
|
fn overridden_menu_item_ids_emit_their_primary_command() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
emitted_menu_event_id("file-quick-open-alias"),
|
|
|
|
|
Some("file-quick-open")
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
emitted_menu_event_id("edit-toggle-note-list-search"),
|
|
|
|
|
Some("edit-toggle-note-list-search")
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(emitted_menu_event_id("file-save"), Some("file-save"));
|
2026-04-21 00:47:45 +02:00
|
|
|
}
|
|
|
|
|
|
2026-04-27 10:12:13 +02:00
|
|
|
#[test]
|
2026-05-02 02:57:45 +02:00
|
|
|
fn state_group_ids_are_manifest_menu_items() {
|
|
|
|
|
for (group, references) in &manifest().menu_state_groups {
|
|
|
|
|
for reference in references {
|
|
|
|
|
let id = match reference {
|
|
|
|
|
MenuStateGroupReference::Command { command } => manifest()
|
|
|
|
|
.commands
|
|
|
|
|
.get(command)
|
|
|
|
|
.map(|command| command.id.as_str())
|
|
|
|
|
.unwrap_or_else(|| panic!("state group {group} references {command}")),
|
|
|
|
|
MenuStateGroupReference::Id { id } => id.as_str(),
|
|
|
|
|
};
|
|
|
|
|
assert!(
|
|
|
|
|
custom_menu_ids().contains(id),
|
|
|
|
|
"state group {group} references non-menu item {id}"
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-04-27 10:12:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
#[test]
|
2026-05-02 02:57:45 +02:00
|
|
|
fn view_toggle_properties_keeps_renderer_owned_accelerator() {
|
|
|
|
|
let item = menu_item_by_id("view-toggle-properties");
|
|
|
|
|
|
|
|
|
|
assert_eq!(item.accelerator(manifest()), None);
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn no_duplicate_custom_ids() {
|
2026-05-02 02:57:45 +02:00
|
|
|
let mut seen = HashSet::new();
|
|
|
|
|
for id in manifest_menu_items().filter_map(|item| item.menu_item_id(manifest())) {
|
feat: reorganize menu bar with Go, Note, and Vault menus
Add missing command palette commands to menu bar and reorganize into
logical groups: File, Edit, View, Go, Note, Vault, Window. New menus
expose navigation filters, note actions, vault management, themes, and
git operations. Context-sensitive items (archive, trash, diff, raw
editor, commit, conflicts) are greyed out when not applicable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:13:54 +01:00
|
|
|
assert!(seen.insert(id), "duplicate custom ID: {id}");
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-30 06:46:45 +02:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn app_services_menu_is_macos_only() {
|
|
|
|
|
assert!(app_menu_includes_services("macos"));
|
|
|
|
|
assert!(!app_menu_includes_services("windows"));
|
|
|
|
|
assert!(!app_menu_includes_services("linux"));
|
|
|
|
|
}
|
2026-05-03 19:49:21 +02:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn window_menu_event_handler_is_required_off_macos() {
|
|
|
|
|
assert!(!window_menu_event_handler_required("macos"));
|
|
|
|
|
assert!(window_menu_event_handler_required("windows"));
|
|
|
|
|
assert!(window_menu_event_handler_required("linux"));
|
|
|
|
|
}
|
feat: populate macOS menu bar with native menus (File, Edit, View, Window) (#77)
* feat: populate macOS menu bar with File, Edit, View, Window menus
Add complete native macOS menu structure with all app actions:
- Laputa menu: About, Settings (Cmd+,), Hide/Quit
- File: New Note (Cmd+N), Quick Open (Cmd+P), Save (Cmd+S), Close Tab (Cmd+W)
- Edit: standard Undo/Redo/Cut/Copy/Paste/Select All
- View: Editor Only (Cmd+1), Editor+Notes (Cmd+2), All Panels (Cmd+3),
Toggle Inspector, Command Palette (Cmd+K)
- Window: Minimize, Maximize, Close Window
All accelerators registered via Tauri menu API. Menu events dispatched
to frontend via useMenuEvents hook. Save/Close Tab items dynamically
disabled when no note tab is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: wrap Enter selection assertion in waitFor for effect re-registration
* fix: resolve rebase conflict markers in menu.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:05:24 +01:00
|
|
|
}
|