From 3fd7afbb57d30b0ba878e49c7ec08c8a638ee3bc Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Fri, 29 Aug 2025 19:09:40 +0300 Subject: [PATCH] feat(react/widgets): port title bar buttons --- apps/client/src/layouts/desktop_layout.tsx | 6 +- apps/client/src/widgets/title_bar_buttons.css | 30 +++++++ apps/client/src/widgets/title_bar_buttons.ts | 82 ------------------- apps/client/src/widgets/title_bar_buttons.tsx | 63 ++++++++++++++ 4 files changed, 96 insertions(+), 85 deletions(-) create mode 100644 apps/client/src/widgets/title_bar_buttons.css delete mode 100644 apps/client/src/widgets/title_bar_buttons.ts create mode 100644 apps/client/src/widgets/title_bar_buttons.tsx diff --git a/apps/client/src/layouts/desktop_layout.tsx b/apps/client/src/layouts/desktop_layout.tsx index f689f1082..8ff8fc6d5 100644 --- a/apps/client/src/layouts/desktop_layout.tsx +++ b/apps/client/src/layouts/desktop_layout.tsx @@ -1,6 +1,5 @@ import FlexContainer from "../widgets/containers/flex_container.js"; import TabRowWidget from "../widgets/tab_row.js"; -import TitleBarButtonsWidget from "../widgets/title_bar_buttons.js"; import LeftPaneContainer from "../widgets/containers/left_pane_container.js"; import NoteTreeWidget from "../widgets/note_tree.js"; import NoteTitleWidget from "../widgets/note_title.jsx"; @@ -42,6 +41,7 @@ import SearchResult from "../widgets/search_result.jsx"; import GlobalMenu from "../widgets/buttons/global_menu.jsx"; import SqlResults from "../widgets/sql_result.js"; import SqlTableSchemas from "../widgets/sql_table_schemas.js"; +import TitleBarButtons from "../widgets/title_bar_buttons.jsx"; export default class DesktopLayout { @@ -78,7 +78,7 @@ export default class DesktopLayout { .child(new FlexContainer("row").id("tab-row-left-spacer")) .optChild(launcherPaneIsHorizontal, new LeftPaneToggleWidget(true)) .child(new TabRowWidget().class("full-width")) - .optChild(customTitleBarButtons, new TitleBarButtonsWidget()) + .optChild(customTitleBarButtons, ) .css("height", "40px") .css("background-color", "var(--launcher-pane-background-color)") .setParent(appContext) @@ -99,7 +99,7 @@ export default class DesktopLayout { new FlexContainer("column") .id("rest-pane") .css("flex-grow", "1") - .optChild(!fullWidthTabBar, new FlexContainer("row").child(new TabRowWidget()).optChild(customTitleBarButtons, new TitleBarButtonsWidget()).css("height", "40px")) + .optChild(!fullWidthTabBar, new FlexContainer("row").child(new TabRowWidget()).optChild(customTitleBarButtons, ).css("height", "40px")) .child( new FlexContainer("row") .filling() diff --git a/apps/client/src/widgets/title_bar_buttons.css b/apps/client/src/widgets/title_bar_buttons.css new file mode 100644 index 000000000..aff57d421 --- /dev/null +++ b/apps/client/src/widgets/title_bar_buttons.css @@ -0,0 +1,30 @@ +.component.title-bar-buttons { + flex-shrink: 0; + contain: none; +} + +.title-bar-buttons div button { + border: none !important; + border-radius: 0; + background: none !important; + font-size: 150%; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; +} + +.title-bar-buttons div:hover button { + background-color: var(--accented-background-color) !important; +} + +.title-bar-buttons div { + display: inline-block; + height: 40px; + width: 40px; +} + +.title-bar-buttons .btn.focus, .title-bar-buttons .btn:focus { + box-shadow: none; +} \ No newline at end of file diff --git a/apps/client/src/widgets/title_bar_buttons.ts b/apps/client/src/widgets/title_bar_buttons.ts deleted file mode 100644 index 9807262c1..000000000 --- a/apps/client/src/widgets/title_bar_buttons.ts +++ /dev/null @@ -1,82 +0,0 @@ -import BasicWidget from "./basic_widget.js"; -import options from "../services/options.js"; -import utils from "../services/utils.js"; - -const TPL = /*html*/` -
- - - -
-
-
-
`; - -export default class TitleBarButtonsWidget extends BasicWidget { - doRender() { - if (!utils.isElectron() || options.is("nativeTitleBarVisible")) { - return (this.$widget = $("
")); - } - - this.$widget = $(TPL); - this.contentSized(); - - const $minimizeBtn = this.$widget.find(".minimize-btn"); - const $maximizeBtn = this.$widget.find(".maximize-btn"); - const $closeBtn = this.$widget.find(".close-btn"); - - $minimizeBtn.on("click", () => { - $minimizeBtn.trigger("blur"); - const remote = utils.dynamicRequire("@electron/remote"); - remote.BrowserWindow.getFocusedWindow().minimize(); - }); - - $maximizeBtn.on("click", () => { - $maximizeBtn.trigger("blur"); - const remote = utils.dynamicRequire("@electron/remote"); - const focusedWindow = remote.BrowserWindow.getFocusedWindow(); - - if (focusedWindow.isMaximized()) { - focusedWindow.unmaximize(); - } else { - focusedWindow.maximize(); - } - }); - - $closeBtn.on("click", () => { - $closeBtn.trigger("blur"); - const remote = utils.dynamicRequire("@electron/remote"); - remote.BrowserWindow.getFocusedWindow().close(); - }); - } -} diff --git a/apps/client/src/widgets/title_bar_buttons.tsx b/apps/client/src/widgets/title_bar_buttons.tsx new file mode 100644 index 000000000..62e053185 --- /dev/null +++ b/apps/client/src/widgets/title_bar_buttons.tsx @@ -0,0 +1,63 @@ +import { dynamicRequire, isElectron } from "../services/utils"; +import { useTriliumOption } from "./react/hooks"; +import "./title_bar_buttons.css"; +import type { BrowserWindow } from "electron"; + +interface TitleBarButtonProps { + className: string; + icon: string; + onClick: (context: { + window: BrowserWindow + }) => void; +} + +export default function TitleBarButtons() { + const [ nativeTitleBarVisible ] = useTriliumOption("nativeTitleBarVisible"); + const isEnabled = (isElectron() && nativeTitleBarVisible); + + return ( +
+ {isEnabled && ( + <> + window.minimize()} + /> + + { + if (window.isMaximized()) { + window.unmaximize(); + } else { + window.maximize(); + } + }} + /> + + window.close()} + /> + + )} +
+ ) +} + +function TitleBarButton({ className, icon, onClick }: TitleBarButtonProps) { + // divs act as a hitbox for the buttons, making them clickable on corners + return ( +
+
+ ); +}