Skip to content

Commit 15f6ac8

Browse files
authored
macOS Vibrancy Support (#8519)
2 parents 13de997 + f9803a4 commit 15f6ac8

File tree

10 files changed

+107
-40
lines changed

10 files changed

+107
-40
lines changed

apps/client/src/desktop.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,22 @@ function initFullScreenDetection(currentWindow: Electron.BrowserWindow) {
9999
}
100100

101101
function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
102+
const material = style.getPropertyValue("--background-material").trim();
102103
if (window.glob.platform === "win32") {
103-
const material = style.getPropertyValue("--background-material");
104-
// TriliumNextTODO: find a nicer way to make TypeScript happy – unfortunately TS did not like Array.includes here
105104
const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const;
106105
const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
107106
if (foundBgMaterialOption) {
108107
currentWindow.setBackgroundMaterial(foundBgMaterialOption);
109108
}
110109
}
110+
111+
if (window.glob.platform === "darwin") {
112+
const bgMaterialOptions = [ "popover", "tooltip", "titlebar", "selection", "menu", "sidebar", "header", "sheet", "window", "hud", "fullscreen-ui", "content", "under-window", "under-page" ] as const;
113+
const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
114+
if (foundBgMaterialOption) {
115+
currentWindow.setVibrancy(foundBgMaterialOption);
116+
}
117+
}
111118
}
112119

113120
/**

apps/client/src/stylesheets/theme-next/shell.css

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,30 @@ body.mobile {
4040

4141
/* #region Mica */
4242

43+
/* Quirk: --background-material is read before "theme-supports-background-effects" class
44+
* is applied. Apply the matterial even if the theme doesn't support it. */
4345
body.background-effects.platform-win32 {
44-
/* Quirk: --background-material is read before "theme-supports-background-effects" class
45-
* is applied. Apply the matterial even if the theme doesn't support it. */
46-
--background-material: tabbed;
46+
&.layout-vertical {
47+
--background-material: mica;
48+
}
49+
50+
&.layout-horizontal {
51+
--background-material: tabbed;
52+
}
53+
}
54+
55+
body.background-effects.platform-darwin {
56+
/** Reference: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc **/
57+
&.layout-vertical {
58+
--background-material: under-window;
59+
}
60+
61+
&.layout-horizontal {
62+
--background-material: hud;
63+
}
4764
}
4865

49-
body.background-effects.theme-supports-background-effects.platform-win32 {
66+
body.background-effects.theme-supports-background-effects {
5067
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
5168
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
5269
--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 {
5673
--root-background: transparent;
5774
}
5875

59-
body.background-effects.platform-win32.layout-vertical {
60-
--background-material: mica;
61-
}
62-
63-
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical {
76+
body.background-effects.theme-supports-background-effects.layout-vertical {
6477
--left-pane-background-color: var(--window-background-color-bgfx);
6578
--center-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx);
6679
--right-pane-background-color: var(--right-pane-background-color-bgfx);
6780
}
6881

69-
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal {
82+
body.background-effects.theme-supports-background-effects.layout-horizontal {
7083
--center-pane-background-color-bgfx: var(--center-pane-horiz-layout-background-color-bgfx);
7184
--gutter-color: var(--left-pane-background-color);
7285
}
7386

74-
body.background-effects.theme-supports-background-effects.platform-win32,
75-
body.background-effects.theme-supports-background-effects.platform-win32 #root-widget {
87+
body.background-effects.theme-supports-background-effects,
88+
body.background-effects.theme-supports-background-effects #root-widget {
7689
background: var(--window-background-color-bgfx) !important;
7790
}
7891

79-
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal #horizontal-main-container,
80-
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical #vertical-main-container {
92+
body.background-effects.theme-supports-background-effects.layout-horizontal #horizontal-main-container,
93+
body.background-effects.theme-supports-background-effects.layout-vertical #vertical-main-container {
8194
background-color: var(--root-background);
8295
}
8396

8497
/* Note split with background effects */
85-
body.background-effects.theme-supports-background-effects.platform-win32 #center-pane .note-split.bgfx {
98+
body.background-effects.theme-supports-background-effects #center-pane .note-split.bgfx {
8699
--note-split-background-color: var(--center-pane-background-color-bgfx);
87100
}
88101

@@ -1054,7 +1067,7 @@ body.layout-horizontal .tab-row-widget-container {
10541067
overflow: hidden;
10551068
}
10561069

1057-
body.desktop:not(.background-effects.platform-win32) #root-widget.horizontal-layout {
1070+
body.desktop:not(.background-effects) #root-widget.horizontal-layout {
10581071
background-color: var(--root-background) !important;
10591072
}
10601073

apps/client/src/translations/en/translation.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,8 +1958,8 @@
19581958
"desktop-application": "Desktop Application",
19591959
"native-title-bar": "Native title bar",
19601960
"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.",
1961-
"background-effects": "Enable background effects (Windows 11 only)",
1962-
"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.",
1961+
"background-effects": "Enable background effects",
1962+
"background-effects-description": "Adds a blurred, stylish background to app windows, creating depth and a modern look. \"Native title bar\" must be disabled.",
19631963
"restart-app-button": "Restart the application to view the changes",
19641964
"zoom-factor": "Zoom factor"
19651965
},
@@ -2152,7 +2152,7 @@
21522152
"next_theme_message": "You are currently using the legacy theme, would you like to try the new theme?",
21532153
"next_theme_button": "Try the new theme",
21542154
"background_effects_title": "Background effects are now stable",
2155-
"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.",
2155+
"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.",
21562156
"background_effects_button": "Enable background effects",
21572157
"new_layout_title": "New layout",
21582158
"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 @@
22672267
"pages_other": "{{count}} pages",
22682268
"pages_alt": "Page {{pageNumber}}",
22692269
"pages_loading": "Loading..."
2270+
},
2271+
"platform_indicator": {
2272+
"available_on": "Available on {{platform}}"
22702273
}
22712274
}

apps/client/src/widgets/dialogs/call_to_action_definitions.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import appContext from "../../components/app_context";
22
import { t } from "../../services/i18n";
33
import options from "../../services/options";
4-
import utils from "../../services/utils";
4+
import utils, { isMac } from "../../services/utils";
55

66
/**
77
* A "call-to-action" is an interactive message for the user, generally to present new features.
@@ -41,10 +41,6 @@ export interface CallToAction {
4141
}[];
4242
}
4343

44-
function isNextTheme() {
45-
return [ "next", "next-light", "next-dark" ].includes(options.get("theme"));
46-
}
47-
4844
const CALL_TO_ACTIONS: CallToAction[] = [
4945
{
5046
id: "new_layout",
@@ -63,7 +59,7 @@ const CALL_TO_ACTIONS: CallToAction[] = [
6359
id: "background_effects",
6460
title: t("call_to_action.background_effects_title"),
6561
message: t("call_to_action.background_effects_message"),
66-
enabled: () => false,
62+
enabled: () => (isMac() && !options.is("backgroundEffects")),
6763
buttons: [
6864
{
6965
text: t("call_to_action.background_effects_button"),
@@ -78,7 +74,7 @@ const CALL_TO_ACTIONS: CallToAction[] = [
7874
id: "next_theme",
7975
title: t("call_to_action.next_theme_title"),
8076
message: t("call_to_action.next_theme_message"),
81-
enabled: () => !isNextTheme(),
77+
enabled: () => ![ "next", "next-light", "next-dark" ].includes(options.get("theme")),
8278
buttons: [
8379
{
8480
text: t("call_to_action.next_theme_button"),

apps/client/src/widgets/react/Icon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import clsx from "clsx";
22
import { HTMLAttributes } from "preact";
33

4-
interface IconProps extends Pick<HTMLAttributes<HTMLSpanElement>, "className" | "onClick"> {
4+
interface IconProps extends Pick<HTMLAttributes<HTMLSpanElement>, "className" | "onClick" | "title"> {
55
icon?: string;
66
className?: string;
77
}

apps/client/src/widgets/type_widgets/options/appearance.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import FormTextBox, { FormTextBoxWithUnit } from "../../react/FormTextBox";
1818
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
1919
import Icon from "../../react/Icon";
2020
import OptionsSection from "./components/OptionsSection";
21+
import PlatformIndicator from "./components/PlatformIndicator";
2122
import RadioWithIllustration from "./components/RadioWithIllustration";
2223
import RelatedSettings from "./components/RelatedSettings";
2324

@@ -174,13 +175,13 @@ function LayoutIllustration({ isNewLayout }: { isNewLayout?: boolean }) {
174175
</div>
175176
</div>
176177
) : (
177-
<div>
178-
<div className="title-bar">
179-
<Icon icon="bx bx-leaf" />
180-
<span className="title">Title</span>
181-
<Icon icon="bx bx-dock-right" />
178+
<div>
179+
<div className="title-bar">
180+
<Icon icon="bx bx-leaf" />
181+
<span className="title">Title</span>
182+
<Icon icon="bx bx-dock-right" />
183+
</div>
182184
</div>
183-
</div>
184185
)}
185186

186187
{!isNewLayout && <div className="ribbon">
@@ -192,7 +193,7 @@ function LayoutIllustration({ isNewLayout }: { isNewLayout?: boolean }) {
192193
</div>
193194

194195
<div className="ribbon-body">
195-
<div className="ribbon-body-content"></div>
196+
<div className="ribbon-body-content" />
196197
</div>
197198
</div>}
198199

@@ -356,7 +357,11 @@ function ElectronIntegration() {
356357

357358
<FormGroup name="background-effects" description={t("electron_integration.background-effects-description")}>
358359
<FormCheckbox
359-
label={t("electron_integration.background-effects")}
360+
label={<>
361+
{t("electron_integration.background-effects")}
362+
{" "}
363+
<PlatformIndicator windows="11" mac />
364+
</>}
360365
currentValue={backgroundEffects} onChange={setBackgroundEffects}
361366
disabled={nativeTitleBarVisible}
362367
/>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.platform-indicator {
2+
display: inline-flex;
3+
gap: 0.25em;
4+
color: var(--muted-text-color);
5+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import "./PlatformIndicator.css";
2+
3+
import { useRef } from "preact/hooks";
4+
5+
import { t } from "../../../../services/i18n";
6+
import { useStaticTooltip } from "../../../react/hooks";
7+
import Icon from "../../../react/Icon";
8+
9+
interface PlatformIndicatorProps {
10+
windows?: boolean | "11";
11+
mac: boolean;
12+
}
13+
14+
export default function PlatformIndicator({ windows, mac }: PlatformIndicatorProps) {
15+
const containerRef = useRef<HTMLDivElement>(null);
16+
useStaticTooltip(containerRef, {
17+
selector: "span",
18+
animation: false,
19+
title() { return this.title; },
20+
});
21+
22+
return (
23+
<div ref={containerRef} className="platform-indicator">
24+
{windows && <Icon
25+
icon="bx bxl-windows"
26+
title={t("platform_indicator.available_on", { platform: windows === "11" ? "Windows 11" : "Windows" })}
27+
/>}
28+
{mac && <Icon
29+
icon="bx bxl-apple"
30+
title={t("platform_indicator.available_on", { platform: "macOS" })}
31+
/>}
32+
</div>
33+
);
34+
}

apps/server/src/routes/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import log from "../services/log.js";
1212
import optionService from "../services/options.js";
1313
import protectedSessionService from "../services/protected_session.js";
1414
import sql from "../services/sql.js";
15-
import { isDev, isElectron, isWindows11 } from "../services/utils.js";
15+
import { isDev, isElectron, isMac, isWindows11 } from "../services/utils.js";
1616
import { generateToken as generateCsrfToken } from "./csrf_protection.js";
1717

1818

@@ -43,7 +43,10 @@ export function bootstrap(req: Request, res: Response) {
4343
platform: process.platform,
4444
isElectron,
4545
hasNativeTitleBar: isElectron && nativeTitleBarVisible,
46-
hasBackgroundEffects: isElectron && isWindows11 && !nativeTitleBarVisible && options.backgroundEffects === "true",
46+
hasBackgroundEffects: options.backgroundEffects === "true"
47+
&& isElectron
48+
&& (isWindows11 || isMac)
49+
&& !nativeTitleBarVisible,
4750
maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"),
4851
maxEntityChangeSyncIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"),
4952
instanceName: config.General ? config.General.instanceName : null,

apps/server/src/services/window.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ function getWindowExtraOpts() {
242242
// Window effects (Mica)
243243
if (optionService.getOptionBool("backgroundEffects")) {
244244
if (isMac) {
245-
// Vibrancy not yet supported.
245+
extraOpts.transparent = true;
246+
extraOpts.visualEffectState = "active";
246247
} else if (isWindows) {
247248
extraOpts.backgroundMaterial = "auto";
248249
} else {

0 commit comments

Comments
 (0)