diff --git a/apps/client/src/desktop.ts b/apps/client/src/desktop.ts index cb90e998f2..bba3b6b90b 100644 --- a/apps/client/src/desktop.ts +++ b/apps/client/src/desktop.ts @@ -99,15 +99,22 @@ function initFullScreenDetection(currentWindow: Electron.BrowserWindow) { } function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) { + const material = style.getPropertyValue("--background-material").trim(); if (window.glob.platform === "win32") { - const material = style.getPropertyValue("--background-material"); - // TriliumNextTODO: find a nicer way to make TypeScript happy – unfortunately TS did not like Array.includes here const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const; const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption); if (foundBgMaterialOption) { currentWindow.setBackgroundMaterial(foundBgMaterialOption); } } + + if (window.glob.platform === "darwin") { + const bgMaterialOptions = [ "popover", "tooltip", "titlebar", "selection", "menu", "sidebar", "header", "sheet", "window", "hud", "fullscreen-ui", "content", "under-window", "under-page" ] as const; + const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption); + if (foundBgMaterialOption) { + currentWindow.setVibrancy(foundBgMaterialOption); + } + } } /** diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index f81e8fcf72..7ff132e1af 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -40,13 +40,30 @@ body.mobile { /* #region Mica */ +/* Quirk: --background-material is read before "theme-supports-background-effects" class + * is applied. Apply the matterial even if the theme doesn't support it. */ body.background-effects.platform-win32 { - /* Quirk: --background-material is read before "theme-supports-background-effects" class - * is applied. Apply the matterial even if the theme doesn't support it. */ - --background-material: tabbed; + &.layout-vertical { + --background-material: mica; + } + + &.layout-horizontal { + --background-material: tabbed; + } } -body.background-effects.theme-supports-background-effects.platform-win32 { +body.background-effects.platform-darwin { + /** Reference: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc **/ + &.layout-vertical { + --background-material: under-window; + } + + &.layout-horizontal { + --background-material: hud; + } +} + +body.background-effects.theme-supports-background-effects { --launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx); --launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx); --launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx); @@ -56,33 +73,29 @@ body.background-effects.theme-supports-background-effects.platform-win32 { --root-background: transparent; } -body.background-effects.platform-win32.layout-vertical { - --background-material: mica; -} - -body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical { +body.background-effects.theme-supports-background-effects.layout-vertical { --left-pane-background-color: var(--window-background-color-bgfx); --center-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx); --right-pane-background-color: var(--right-pane-background-color-bgfx); } -body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal { +body.background-effects.theme-supports-background-effects.layout-horizontal { --center-pane-background-color-bgfx: var(--center-pane-horiz-layout-background-color-bgfx); --gutter-color: var(--left-pane-background-color); } -body.background-effects.theme-supports-background-effects.platform-win32, -body.background-effects.theme-supports-background-effects.platform-win32 #root-widget { +body.background-effects.theme-supports-background-effects, +body.background-effects.theme-supports-background-effects #root-widget { background: var(--window-background-color-bgfx) !important; } -body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal #horizontal-main-container, -body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical #vertical-main-container { +body.background-effects.theme-supports-background-effects.layout-horizontal #horizontal-main-container, +body.background-effects.theme-supports-background-effects.layout-vertical #vertical-main-container { background-color: var(--root-background); } /* Note split with background effects */ -body.background-effects.theme-supports-background-effects.platform-win32 #center-pane .note-split.bgfx { +body.background-effects.theme-supports-background-effects #center-pane .note-split.bgfx { --note-split-background-color: var(--center-pane-background-color-bgfx); } @@ -1054,7 +1067,7 @@ body.layout-horizontal .tab-row-widget-container { overflow: hidden; } -body.desktop:not(.background-effects.platform-win32) #root-widget.horizontal-layout { +body.desktop:not(.background-effects) #root-widget.horizontal-layout { background-color: var(--root-background) !important; } diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index f112508c1e..88ed7ac752 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -1958,8 +1958,8 @@ "desktop-application": "Desktop Application", "native-title-bar": "Native title bar", "native-title-bar-description": "For Windows and macOS, keeping the native title bar off makes the application look more compact. On Linux, keeping the native title bar on integrates better with the rest of the system.", - "background-effects": "Enable background effects (Windows 11 only)", - "background-effects-description": "The Mica effect adds a blurred, stylish background to app windows, creating depth and a modern look. \"Native title bar\" must be disabled.", + "background-effects": "Enable background effects", + "background-effects-description": "Adds a blurred, stylish background to app windows, creating depth and a modern look. \"Native title bar\" must be disabled.", "restart-app-button": "Restart the application to view the changes", "zoom-factor": "Zoom factor" }, @@ -2152,7 +2152,7 @@ "next_theme_message": "You are currently using the legacy theme, would you like to try the new theme?", "next_theme_button": "Try the new theme", "background_effects_title": "Background effects are now stable", - "background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of color to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer.", + "background_effects_message": "On Windows and macOS devices, background effects are now stable. The background effects adds a touch of color to the user interface by blurring the background behind it.", "background_effects_button": "Enable background effects", "new_layout_title": "New layout", "new_layout_message": "We’ve introduced a modernized layout for Trilium. The ribbon has been removed and seamlessly integrated into the main interface, with a new status bar and expandable sections (such as promoted attributes) taking over key functions.\n\nThe new layout is enabled by default, and can be temporarily disabled via Options → Appearance.", @@ -2267,5 +2267,8 @@ "pages_other": "{{count}} pages", "pages_alt": "Page {{pageNumber}}", "pages_loading": "Loading..." + }, + "platform_indicator": { + "available_on": "Available on {{platform}}" } } diff --git a/apps/client/src/widgets/dialogs/call_to_action_definitions.ts b/apps/client/src/widgets/dialogs/call_to_action_definitions.ts index d783b1dbba..afaecbdfa3 100644 --- a/apps/client/src/widgets/dialogs/call_to_action_definitions.ts +++ b/apps/client/src/widgets/dialogs/call_to_action_definitions.ts @@ -1,7 +1,7 @@ import appContext from "../../components/app_context"; import { t } from "../../services/i18n"; import options from "../../services/options"; -import utils from "../../services/utils"; +import utils, { isMac } from "../../services/utils"; /** * A "call-to-action" is an interactive message for the user, generally to present new features. @@ -41,10 +41,6 @@ export interface CallToAction { }[]; } -function isNextTheme() { - return [ "next", "next-light", "next-dark" ].includes(options.get("theme")); -} - const CALL_TO_ACTIONS: CallToAction[] = [ { id: "new_layout", @@ -63,7 +59,7 @@ const CALL_TO_ACTIONS: CallToAction[] = [ id: "background_effects", title: t("call_to_action.background_effects_title"), message: t("call_to_action.background_effects_message"), - enabled: () => false, + enabled: () => (isMac() && !options.is("backgroundEffects")), buttons: [ { text: t("call_to_action.background_effects_button"), @@ -78,7 +74,7 @@ const CALL_TO_ACTIONS: CallToAction[] = [ id: "next_theme", title: t("call_to_action.next_theme_title"), message: t("call_to_action.next_theme_message"), - enabled: () => !isNextTheme(), + enabled: () => ![ "next", "next-light", "next-dark" ].includes(options.get("theme")), buttons: [ { text: t("call_to_action.next_theme_button"), diff --git a/apps/client/src/widgets/react/Icon.tsx b/apps/client/src/widgets/react/Icon.tsx index 8d12548334..4bae69c460 100644 --- a/apps/client/src/widgets/react/Icon.tsx +++ b/apps/client/src/widgets/react/Icon.tsx @@ -1,7 +1,7 @@ import clsx from "clsx"; import { HTMLAttributes } from "preact"; -interface IconProps extends Pick, "className" | "onClick"> { +interface IconProps extends Pick, "className" | "onClick" | "title"> { icon?: string; className?: string; } diff --git a/apps/client/src/widgets/type_widgets/options/appearance.tsx b/apps/client/src/widgets/type_widgets/options/appearance.tsx index fd8412a69a..3cff63ed66 100644 --- a/apps/client/src/widgets/type_widgets/options/appearance.tsx +++ b/apps/client/src/widgets/type_widgets/options/appearance.tsx @@ -18,6 +18,7 @@ import FormTextBox, { FormTextBoxWithUnit } from "../../react/FormTextBox"; import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; import Icon from "../../react/Icon"; import OptionsSection from "./components/OptionsSection"; +import PlatformIndicator from "./components/PlatformIndicator"; import RadioWithIllustration from "./components/RadioWithIllustration"; import RelatedSettings from "./components/RelatedSettings"; @@ -174,13 +175,13 @@ function LayoutIllustration({ isNewLayout }: { isNewLayout?: boolean }) { ) : ( -
-
- - Title - +
+
+ + Title + +
-
)} {!isNewLayout &&
@@ -192,7 +193,7 @@ function LayoutIllustration({ isNewLayout }: { isNewLayout?: boolean }) {
-
+
} @@ -356,7 +357,11 @@ function ElectronIntegration() { + {t("electron_integration.background-effects")} + {" "} + + } currentValue={backgroundEffects} onChange={setBackgroundEffects} disabled={nativeTitleBarVisible} /> diff --git a/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.css b/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.css new file mode 100644 index 0000000000..e91e873559 --- /dev/null +++ b/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.css @@ -0,0 +1,5 @@ +.platform-indicator { + display: inline-flex; + gap: 0.25em; + color: var(--muted-text-color); +} diff --git a/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.tsx b/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.tsx new file mode 100644 index 0000000000..bb95e8d9ce --- /dev/null +++ b/apps/client/src/widgets/type_widgets/options/components/PlatformIndicator.tsx @@ -0,0 +1,34 @@ +import "./PlatformIndicator.css"; + +import { useRef } from "preact/hooks"; + +import { t } from "../../../../services/i18n"; +import { useStaticTooltip } from "../../../react/hooks"; +import Icon from "../../../react/Icon"; + +interface PlatformIndicatorProps { + windows?: boolean | "11"; + mac: boolean; +} + +export default function PlatformIndicator({ windows, mac }: PlatformIndicatorProps) { + const containerRef = useRef(null); + useStaticTooltip(containerRef, { + selector: "span", + animation: false, + title() { return this.title; }, + }); + + return ( +
+ {windows && } + {mac && } +
+ ); +} diff --git a/apps/server/src/routes/index.ts b/apps/server/src/routes/index.ts index 7bc59411a0..8f96e5124b 100644 --- a/apps/server/src/routes/index.ts +++ b/apps/server/src/routes/index.ts @@ -12,7 +12,7 @@ import log from "../services/log.js"; import optionService from "../services/options.js"; import protectedSessionService from "../services/protected_session.js"; import sql from "../services/sql.js"; -import { isDev, isElectron, isWindows11 } from "../services/utils.js"; +import { isDev, isElectron, isMac, isWindows11 } from "../services/utils.js"; import { generateToken as generateCsrfToken } from "./csrf_protection.js"; @@ -43,7 +43,10 @@ export function bootstrap(req: Request, res: Response) { platform: process.platform, isElectron, hasNativeTitleBar: isElectron && nativeTitleBarVisible, - hasBackgroundEffects: isElectron && isWindows11 && !nativeTitleBarVisible && options.backgroundEffects === "true", + hasBackgroundEffects: options.backgroundEffects === "true" + && isElectron + && (isWindows11 || isMac) + && !nativeTitleBarVisible, maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"), maxEntityChangeSyncIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"), instanceName: config.General ? config.General.instanceName : null, diff --git a/apps/server/src/services/window.ts b/apps/server/src/services/window.ts index 917d2012c7..39c6093646 100644 --- a/apps/server/src/services/window.ts +++ b/apps/server/src/services/window.ts @@ -242,7 +242,8 @@ function getWindowExtraOpts() { // Window effects (Mica) if (optionService.getOptionBool("backgroundEffects")) { if (isMac) { - // Vibrancy not yet supported. + extraOpts.transparent = true; + extraOpts.visualEffectState = "active"; } else if (isWindows) { extraOpts.backgroundMaterial = "auto"; } else {