From 61fe27abbe748f0dd610901245be093c4984e8ca Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 11 Dec 2025 22:29:22 +0200 Subject: [PATCH] feat(layout): extract floating titlebar into its own experimental feature --- apps/client/src/layouts/desktop_layout.tsx | 5 +- .../src/services/experimental_features.ts | 5 ++ .../src/translations/en/translation.json | 4 +- apps/client/src/widgets/note_title.css | 46 +++++++++++++------ 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/client/src/layouts/desktop_layout.tsx b/apps/client/src/layouts/desktop_layout.tsx index d50486750..9c0e02001 100644 --- a/apps/client/src/layouts/desktop_layout.tsx +++ b/apps/client/src/layouts/desktop_layout.tsx @@ -79,6 +79,7 @@ export default class DesktopLayout { const fullWidthTabBar = launcherPaneIsHorizontal || (isElectron && !hasNativeTitleBar && isMac); const customTitleBarButtons = !hasNativeTitleBar && !isMac && !isWindows; const isNewLayout = isExperimentalFeatureEnabled("new-layout"); + const isFloatingTitlebar = isExperimentalFeatureEnabled("floating-titlebar"); const titleRow = new FlexContainer("row") .class("title-row") @@ -149,7 +150,7 @@ export default class DesktopLayout { .child() .optChild(isNewLayout, ) ) - .optChild(!isNewLayout, titleRow) + .optChild(!isFloatingTitlebar, titleRow) .optChild(!isNewLayout, ) .optChild(isNewLayout, ) .child(new WatchedFileUpdateStatusWidget()) @@ -157,7 +158,7 @@ export default class DesktopLayout { .child( new ScrollingContainer() .filling() - .optChild(isNewLayout, titleRow) + .optChild(isFloatingTitlebar, titleRow) .optChild(isNewLayout, ) .optChild(!isNewLayout, new ContentHeader() .child() diff --git a/apps/client/src/services/experimental_features.ts b/apps/client/src/services/experimental_features.ts index 5f7e5d010..980bd74d5 100644 --- a/apps/client/src/services/experimental_features.ts +++ b/apps/client/src/services/experimental_features.ts @@ -12,6 +12,11 @@ export const experimentalFeatures = [ id: "new-layout", name: t("experimental_features.new_layout_name"), description: t("experimental_features.new_layout_description"), + }, + { + id: "floating-titlebar", + name: t("experimental_features.floating_titlebar"), + description: t("experimental_features.floating_titlebar_description"), } ] as const satisfies ExperimentalFeature[]; diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 7f49dea52..136513ef8 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -1102,7 +1102,9 @@ "title": "Experimental Options", "disclaimer": "These options are experimental and may cause instability. Use with caution.", "new_layout_name": "New Layout", - "new_layout_description": "Try out the new layout for a more modern look and improved usability. Subject to heavy change in the upcoming releases." + "new_layout_description": "Try out the new layout for a more modern look and improved usability. Subject to heavy change in the upcoming releases.", + "floating_titlebar": "Floating Titlebar", + "floating_titlebar_description": "The title bar is part of the content and is scrolled along with the note content." }, "fonts": { "theme_defined": "Theme defined", diff --git a/apps/client/src/widgets/note_title.css b/apps/client/src/widgets/note_title.css index 6a6ae9808..2395c9d23 100644 --- a/apps/client/src/widgets/note_title.css +++ b/apps/client/src/widgets/note_title.css @@ -30,7 +30,6 @@ body.desktop .note-title-widget input.note-title { } body.experimental-feature-new-layout { - .title-row, .title-details { max-width: var(--max-content-width); padding: 0; @@ -52,14 +51,6 @@ body.experimental-feature-new-layout { } } - .title-row { - .note-icon-widget { - padding: 0; - width: 41px; - } - } - - .note-split.type-code:not(.mime-text-x-sqlite) .title-row, .note-split.type-code:not(.mime-text-x-sqlite) .title-details { background-color: var(--main-background-color); } @@ -79,21 +70,48 @@ body.experimental-feature-new-layout { .scrolling-container:has(> :is(.note-detail.full-height, .note-list-widget.full-height)), .note-split.type-book { - .title-row, .title-details { width: 100%; max-width: unset; padding-inline-start: 15px; - } - - .title-details { padding-bottom: 0.2em; font-size: 0.8em; } } - &.prefers-centered-content .title-row, &.prefers-centered-content .title-details { margin-inline: auto; } } + +body.experimental-feature-floating-titlebar { + .title-row { + max-width: var(--max-content-width); + padding: 0; + padding-inline-start: 24px; + } + + .note-icon-widget { + padding: 0; + width: 41px; + } + + .note-split.type-code:not(.mime-text-x-sqlite) .title-row { + background-color: var(--main-background-color); + } + + .scrolling-container:has(> :is(.note-detail.full-height, .note-list-widget.full-height)), + .note-split.type-book { + .title-row { + width: 100%; + max-width: unset; + padding-inline-start: 15px; + padding-bottom: 0.2em; + font-size: 0.8em; + } + } + + &.prefers-centered-content .title-row { + margin-inline: auto; + } +}