+
-
+
+
+ {!forceRawMode && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- {!forceRawMode && }
-
-
-
-
-
)
}
+function BreadcrumbOverflowMenu({
+ entry,
+ showDiffToggle,
+ diffMode,
+ diffLoading,
+ onToggleDiff,
+ noteWidth,
+ onToggleNoteWidth,
+ onRevealFile,
+ onCopyFilePath,
+ onArchive,
+ onUnarchive,
+ onDelete,
+ locale = 'en',
+}: Pick<
+ BreadcrumbBarProps,
+ | 'entry'
+ | 'showDiffToggle'
+ | 'diffMode'
+ | 'diffLoading'
+ | 'onToggleDiff'
+ | 'noteWidth'
+ | 'onToggleNoteWidth'
+ | 'onRevealFile'
+ | 'onCopyFilePath'
+ | 'onArchive'
+ | 'onUnarchive'
+ | 'onDelete'
+ | 'locale'
+>) {
+ const runDiffAction = availableDiffAction(showDiffToggle, onToggleDiff)
+ const runRevealAction = pathAction(onRevealFile, entry.path)
+ const runCopyPathAction = pathAction(onCopyFilePath, entry.path)
+ const runArchiveAction = archiveAction(entry.archived, onArchive, onUnarchive)
+ const diffLabel = translate(locale, diffMenuLabelKey({ showDiffToggle, diffMode, diffLoading }))
+ const noteWidthLabel = translate(locale, noteWidthLabelKey(noteWidth))
+ const archiveLabel = translate(locale, archiveLabelKey(entry.archived))
+
+ return (
+
+
+
+
+
+
+
+
+
+ {diffLabel}
+
+
+
+ {noteWidthLabel}
+
+
+
+ {translate(locale, 'editor.toolbar.revealFile')}
+
+
+
+ {translate(locale, 'editor.toolbar.copyFilePath')}
+
+
+
+ {archiveLabel}
+
+
+
+ {translate(locale, 'editor.toolbar.delete')}
+
+
+
+ )
+}
+
function BreadcrumbTitle({
entry,
locale,
@@ -680,7 +960,7 @@ function BreadcrumbTitle({
}: Pick
) {
const typeLabel = entry.isA ?? 'Note'
return (
-
+
{typeLabel}
›
@@ -701,6 +981,9 @@ export const BreadcrumbBar = memo(function BreadcrumbBar({
...actionProps
}: BreadcrumbBarProps) {
const { onMouseDown } = useDragRegion()
+ const actionsRef = useRef
(null)
+ const titleRef = useRef(null)
+ const overflowCollapsed = useBreadcrumbOverflow(titleRef, actionsRef)
return (
@@ -713,11 +996,11 @@ export const BreadcrumbBar = memo(function BreadcrumbBar({
style={{
height: 52,
background: 'var(--background)',
- padding: '6px 16px',
+ padding: '6px 16px 6px var(--breadcrumb-bar-left-padding, 16px)',
boxSizing: 'border-box',
}}
>
-
+
+
-
)
diff --git a/src/components/BreadcrumbBar.visibility.test.tsx b/src/components/BreadcrumbBar.visibility.test.tsx
index b74776a4..d435ccec 100644
--- a/src/components/BreadcrumbBar.visibility.test.tsx
+++ b/src/components/BreadcrumbBar.visibility.test.tsx
@@ -67,4 +67,22 @@ describe('BreadcrumbBar filename visibility', () => {
expect(editorCss).toContain('padding: 0;')
expect(editorCss).toContain('border-radius: 0;')
})
+
+ it('offsets the editor-only breadcrumb title past the macOS traffic lights', () => {
+ const editorCss = readFileSync(`${process.cwd()}/src/components/Editor.css`, 'utf8')
+
+ expect(editorCss).toContain('.app:not(:has(.app__sidebar)):not(:has(.app__note-list)) .breadcrumb-bar')
+ expect(editorCss).toContain('--breadcrumb-bar-left-padding: 90px;')
+ })
+
+ it('moves lower-priority breadcrumb actions into the overflow menu from measured overflow state', () => {
+ const editorCss = readFileSync(`${process.cwd()}/src/components/Editor.css`, 'utf8')
+
+ expect(editorCss).not.toContain('@container (max-width:')
+ expect(editorCss).toContain(".breadcrumb-bar__actions[data-overflow-collapsed='true']")
+ expect(editorCss).toContain('.breadcrumb-bar__overflowable-action')
+ expect(editorCss).toContain('display: none;')
+ expect(editorCss).toContain('.breadcrumb-bar__overflow-menu')
+ expect(editorCss).toContain('display: flex;')
+ })
})
diff --git a/src/components/Editor.css b/src/components/Editor.css
index 40e71a42..0bb0ad48 100644
--- a/src/components/Editor.css
+++ b/src/components/Editor.css
@@ -25,9 +25,15 @@
/* Breadcrumb bar: border can still react to the data attribute, but the
breadcrumb filename/title stays visible at all times. */
.breadcrumb-bar {
+ container-type: inline-size;
+ --breadcrumb-bar-left-padding: 16px;
transition: border-color 0.2s ease;
}
+.app:not(:has(.app__sidebar)):not(:has(.app__note-list)) .breadcrumb-bar {
+ --breadcrumb-bar-left-padding: 90px;
+}
+
.breadcrumb-bar[data-title-hidden] {
border-bottom-color: var(--border);
}
@@ -48,6 +54,18 @@
background: transparent;
}
+.breadcrumb-bar__overflow-menu {
+ display: none;
+}
+
+.breadcrumb-bar__actions[data-overflow-collapsed='true'] .breadcrumb-bar__overflowable-action {
+ display: none;
+}
+
+.breadcrumb-bar__actions[data-overflow-collapsed='true'] .breadcrumb-bar__overflow-menu {
+ display: flex;
+}
+
/* Scroll area wrapping title + editor — single scroll context for alignment */
.editor-scroll-area {
flex: 1;
diff --git a/src/components/sidebar/FavoritesSection.tsx b/src/components/sidebar/FavoritesSection.tsx
index 098f7abe..bcde6600 100644
--- a/src/components/sidebar/FavoritesSection.tsx
+++ b/src/components/sidebar/FavoritesSection.tsx
@@ -11,7 +11,7 @@ import { buildTypeEntryMap, getTypeColor, getTypeLightColor } from '../../utils/
import { NoteTitleIcon } from '../NoteTitleIcon'
import { isSelectionActive } from '../SidebarParts'
import { SidebarGroupHeader } from './SidebarGroupHeader'
-import { SIDEBAR_ITEM_PADDING } from './sidebarStyles'
+import { SIDEBAR_ITEM_PADDING, SIDEBAR_SECTION_CONTENT_PADDING_BOTTOM } from './sidebarStyles'
import { translate, type AppLocale } from '../../lib/i18n'
const FAVORITE_TYPE_ICON_MAP: Record
= {
@@ -141,7 +141,7 @@ export function FavoritesSection({
{!collapsed && (
-
+
{favorites.map((entry) => (
{!collapsed && (
-
+
{onReorderViews ? (
@@ -303,13 +304,15 @@ export function TypesSection({
)}
{!collapsed && (
-
-
- {visibleSections.map((group) => (
-
- ))}
-
-
+
+
+
+ {visibleSections.map((group) => (
+
+ ))}
+
+
+
)}
)
diff --git a/src/components/sidebar/sidebarStyles.ts b/src/components/sidebar/sidebarStyles.ts
index af469a6d..ec79e2b7 100644
--- a/src/components/sidebar/sidebarStyles.ts
+++ b/src/components/sidebar/sidebarStyles.ts
@@ -9,3 +9,5 @@ export const SIDEBAR_GROUP_HEADER_PADDING = {
regular: '8px 14px 8px 16px',
withCount: '8px 8px 8px 16px',
} as const
+
+export const SIDEBAR_SECTION_CONTENT_PADDING_BOTTOM = 8
diff --git a/src/lib/locales/de-DE.json b/src/lib/locales/de-DE.json
index 4edf6428..843a6393 100644
--- a/src/lib/locales/de-DE.json
+++ b/src/lib/locales/de-DE.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Diese Notiz löschen",
"editor.toolbar.revealFile": "Im Finder anzeigen",
"editor.toolbar.copyFilePath": "Dateipfad kopieren",
+ "editor.toolbar.moreActions": "Weitere Notizaktionen",
"editor.toolbar.openProperties": "Eigenschaften-Panel öffnen",
"editor.imageLightbox.title": "Bildvorschau",
"editor.filename.rename": "Dateinamen umbenennen",
diff --git a/src/lib/locales/en.json b/src/lib/locales/en.json
index 37ed6656..259bb5d5 100644
--- a/src/lib/locales/en.json
+++ b/src/lib/locales/en.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Delete this note",
"editor.toolbar.revealFile": "Reveal in Finder",
"editor.toolbar.copyFilePath": "Copy file path",
+ "editor.toolbar.moreActions": "More note actions",
"editor.toolbar.openProperties": "Open the properties panel",
"editor.imageLightbox.title": "Image preview",
"editor.filename.rename": "Rename filename",
diff --git a/src/lib/locales/es-419.json b/src/lib/locales/es-419.json
index 79c09e79..72069e33 100644
--- a/src/lib/locales/es-419.json
+++ b/src/lib/locales/es-419.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Eliminar esta nota",
"editor.toolbar.revealFile": "Mostrar en el Finder",
"editor.toolbar.copyFilePath": "Copiar la ruta del archivo",
+ "editor.toolbar.moreActions": "Más acciones de nota",
"editor.toolbar.openProperties": "Abrir el panel de propiedades",
"editor.imageLightbox.title": "Vista previa de la imagen",
"editor.filename.rename": "Cambiar el nombre del archivo",
diff --git a/src/lib/locales/es-ES.json b/src/lib/locales/es-ES.json
index 0a920095..a23e4939 100644
--- a/src/lib/locales/es-ES.json
+++ b/src/lib/locales/es-ES.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Eliminar esta nota",
"editor.toolbar.revealFile": "Mostrar en el Finder",
"editor.toolbar.copyFilePath": "Copiar la ruta del archivo",
+ "editor.toolbar.moreActions": "Más acciones de nota",
"editor.toolbar.openProperties": "Abrir el panel de propiedades",
"editor.imageLightbox.title": "Vista previa de la imagen",
"editor.filename.rename": "Cambiar el nombre del archivo",
diff --git a/src/lib/locales/fr-FR.json b/src/lib/locales/fr-FR.json
index 7fbbc6b2..0787ddf0 100644
--- a/src/lib/locales/fr-FR.json
+++ b/src/lib/locales/fr-FR.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Supprimer cette note",
"editor.toolbar.revealFile": "Afficher dans le Finder",
"editor.toolbar.copyFilePath": "Copier le chemin du fichier",
+ "editor.toolbar.moreActions": "Autres actions de note",
"editor.toolbar.openProperties": "Ouvrir le panneau des propriétés",
"editor.imageLightbox.title": "Aperçu de l'image",
"editor.filename.rename": "Renommer le fichier",
diff --git a/src/lib/locales/it-IT.json b/src/lib/locales/it-IT.json
index ae07ef1b..df4b50e9 100644
--- a/src/lib/locales/it-IT.json
+++ b/src/lib/locales/it-IT.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Elimina questa nota",
"editor.toolbar.revealFile": "Mostra nel Finder",
"editor.toolbar.copyFilePath": "Copia il percorso del file",
+ "editor.toolbar.moreActions": "Altre azioni della nota",
"editor.toolbar.openProperties": "Apri il pannello delle proprietà",
"editor.imageLightbox.title": "Anteprima immagine",
"editor.filename.rename": "Rinomina nome file",
diff --git a/src/lib/locales/ja-JP.json b/src/lib/locales/ja-JP.json
index 7aa0172c..9eeb521f 100644
--- a/src/lib/locales/ja-JP.json
+++ b/src/lib/locales/ja-JP.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "このノートを削除",
"editor.toolbar.revealFile": "Finderで表示",
"editor.toolbar.copyFilePath": "ファイルパスをコピー",
+ "editor.toolbar.moreActions": "その他のノート操作",
"editor.toolbar.openProperties": "プロパティパネルを開く",
"editor.imageLightbox.title": "画像プレビュー",
"editor.filename.rename": "ファイル名を変更",
diff --git a/src/lib/locales/ko-KR.json b/src/lib/locales/ko-KR.json
index 7c102608..75968ed7 100644
--- a/src/lib/locales/ko-KR.json
+++ b/src/lib/locales/ko-KR.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "이 노트 삭제",
"editor.toolbar.revealFile": "Finder에서 표시",
"editor.toolbar.copyFilePath": "파일 경로 복사",
+ "editor.toolbar.moreActions": "추가 노트 작업",
"editor.toolbar.openProperties": "속성 패널 열기",
"editor.imageLightbox.title": "이미지 미리 보기",
"editor.filename.rename": "파일 이름 변경",
diff --git a/src/lib/locales/pl-PL.json b/src/lib/locales/pl-PL.json
index 48f0fc6b..d6c3dd35 100644
--- a/src/lib/locales/pl-PL.json
+++ b/src/lib/locales/pl-PL.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Usuń tę notatkę",
"editor.toolbar.revealFile": "Pokaż w Finderze",
"editor.toolbar.copyFilePath": "Kopiuj ścieżkę pliku",
+ "editor.toolbar.moreActions": "Więcej działań notatki",
"editor.toolbar.openProperties": "Otwórz panel właściwości",
"editor.imageLightbox.title": "Podgląd obrazu",
"editor.filename.rename": "Zmień nazwę pliku",
diff --git a/src/lib/locales/pt-BR.json b/src/lib/locales/pt-BR.json
index 0b99a1cb..28542068 100644
--- a/src/lib/locales/pt-BR.json
+++ b/src/lib/locales/pt-BR.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Excluir esta nota",
"editor.toolbar.revealFile": "Exibir no Finder",
"editor.toolbar.copyFilePath": "Copiar caminho do arquivo",
+ "editor.toolbar.moreActions": "Mais ações da nota",
"editor.toolbar.openProperties": "Abrir o painel de propriedades",
"editor.imageLightbox.title": "Pré-visualização da imagem",
"editor.filename.rename": "Renomear nome do arquivo",
diff --git a/src/lib/locales/pt-PT.json b/src/lib/locales/pt-PT.json
index f2bdfd7d..4c16dda8 100644
--- a/src/lib/locales/pt-PT.json
+++ b/src/lib/locales/pt-PT.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Eliminar esta nota",
"editor.toolbar.revealFile": "Mostrar no Finder",
"editor.toolbar.copyFilePath": "Copiar caminho do ficheiro",
+ "editor.toolbar.moreActions": "Mais ações da nota",
"editor.toolbar.openProperties": "Abrir o painel de propriedades",
"editor.imageLightbox.title": "Pré-visualização da imagem",
"editor.filename.rename": "Mudar o nome do ficheiro",
diff --git a/src/lib/locales/ru-RU.json b/src/lib/locales/ru-RU.json
index c6e7a10f..d32dc5eb 100644
--- a/src/lib/locales/ru-RU.json
+++ b/src/lib/locales/ru-RU.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "Удалить эту заметку",
"editor.toolbar.revealFile": "Показать в Finder",
"editor.toolbar.copyFilePath": "Копировать путь к файлу",
+ "editor.toolbar.moreActions": "Другие действия с заметкой",
"editor.toolbar.openProperties": "Открыть панель свойств",
"editor.imageLightbox.title": "Предварительный просмотр изображения",
"editor.filename.rename": "Переименовать файл",
diff --git a/src/lib/locales/vi.json b/src/lib/locales/vi.json
index 77715f1e..ead90c3f 100644
--- a/src/lib/locales/vi.json
+++ b/src/lib/locales/vi.json
@@ -264,6 +264,7 @@
"editor.toolbar.delete": "Xóa ghi chú này",
"editor.toolbar.revealFile": "Hiển thị trong Finder",
"editor.toolbar.copyFilePath": "Sao chép đường dẫn tệp",
+ "editor.toolbar.moreActions": "Thêm hành động ghi chú",
"editor.toolbar.openProperties": "Mở bảng thuộc tính",
"editor.filename.rename": "Đổi tên tệp",
"editor.filename.renameToTitle": "Đổi tên tệp cho khớp với tiêu đề",
diff --git a/src/lib/locales/zh-CN.json b/src/lib/locales/zh-CN.json
index fdab96f8..b1c5d16d 100644
--- a/src/lib/locales/zh-CN.json
+++ b/src/lib/locales/zh-CN.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "删除这条笔记",
"editor.toolbar.revealFile": "在访达中显示",
"editor.toolbar.copyFilePath": "复制文件路径",
+ "editor.toolbar.moreActions": "更多笔记操作",
"editor.toolbar.openProperties": "打开属性面板",
"editor.imageLightbox.title": "图像预览",
"editor.filename.rename": "重命名文件名",
diff --git a/src/lib/locales/zh-TW.json b/src/lib/locales/zh-TW.json
index dad615bf..8fdb70fc 100644
--- a/src/lib/locales/zh-TW.json
+++ b/src/lib/locales/zh-TW.json
@@ -368,6 +368,7 @@
"editor.toolbar.delete": "刪除這條筆記",
"editor.toolbar.revealFile": "在訪達中顯示",
"editor.toolbar.copyFilePath": "複製檔案路徑",
+ "editor.toolbar.moreActions": "更多筆記操作",
"editor.toolbar.openProperties": "開啟屬性面板",
"editor.imageLightbox.title": "圖片預覽",
"editor.filename.rename": "重新命名檔名",
diff --git a/src/utils/openNoteWindow.test.ts b/src/utils/openNoteWindow.test.ts
index b7c516c7..7977ae0f 100644
--- a/src/utils/openNoteWindow.test.ts
+++ b/src/utils/openNoteWindow.test.ts
@@ -32,6 +32,12 @@ vi.mock('@tauri-apps/api/webviewWindow', () => ({
},
}))
+vi.mock('@tauri-apps/api/dpi', () => ({
+ LogicalPosition: class MockLogicalPosition {
+ constructor(public x: number, public y: number) {}
+ },
+}))
+
describe('openNoteWindow', () => {
beforeEach(() => {
vi.clearAllMocks()
@@ -73,6 +79,7 @@ describe('openNoteWindow', () => {
height: 700,
resizable: true,
titleBarStyle: 'overlay',
+ trafficLightPosition: expect.objectContaining({ x: 18, y: 24 }),
hiddenTitle: true,
decorations: true,
}),
diff --git a/src/utils/openNoteWindow.ts b/src/utils/openNoteWindow.ts
index 2b56c3f7..12710182 100644
--- a/src/utils/openNoteWindow.ts
+++ b/src/utils/openNoteWindow.ts
@@ -2,6 +2,8 @@ import { isTauri } from '../mock-tauri'
import { shouldUseLinuxWindowChrome } from './platform'
import { rememberNoteWindowParams } from './windowMode'
+const MACOS_TRAFFIC_LIGHT_POSITION = { x: 18, y: 24 } as const
+
export function buildNoteWindowUrl(notePath: string, vaultPath: string, noteTitle: string, windowLabel?: string): string {
const params = new URLSearchParams({
window: 'note',
@@ -24,6 +26,7 @@ export function buildNoteWindowUrl(notePath: string, vaultPath: string, noteTitl
export async function openNoteInNewWindow(notePath: string, vaultPath: string, noteTitle: string): Promise {
if (!isTauri()) return
+ const { LogicalPosition } = await import('@tauri-apps/api/dpi')
const { WebviewWindow } = await import('@tauri-apps/api/webviewWindow')
const label = `note-${Date.now()}`
rememberNoteWindowParams(label, { notePath, vaultPath, noteTitle })
@@ -35,6 +38,7 @@ export async function openNoteInNewWindow(notePath: string, vaultPath: string, n
height: 700,
resizable: true,
titleBarStyle: 'overlay',
+ trafficLightPosition: new LogicalPosition(MACOS_TRAFFIC_LIGHT_POSITION.x, MACOS_TRAFFIC_LIGHT_POSITION.y),
hiddenTitle: true,
decorations: !shouldUseLinuxWindowChrome(),
})