diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index c5b24f88e..46ad3559d 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -28,6 +28,28 @@ --ck-mention-list-max-height: 500px; } +body#trilium-app.motion-disabled *, +body#trilium-app.motion-disabled *::before, +body#trilium-app.motion-disabled *::after { + /* Disable transitions and animations */ + transition: none !important; + animation: none !important; +} + +body#trilium-app.shadows-disabled *, +body#trilium-app.shadows-disabled *::before, +body#trilium-app.shadows-disabled *::after { + /* Disable shadows */ + box-shadow: none !important; +} + +body#trilium-app.backdrop-effects-disabled *, +body#trilium-app.backdrop-effects-disabled *::before, +body#trilium-app.backdrop-effects-disabled *::after { + /* Disable backdrop effects */ + backdrop-filter: none !important; +} + .table { --bs-table-bg: transparent !important; } @@ -355,7 +377,7 @@ body.desktop .tabulator-popup-container { @supports (animation-fill-mode: forwards) { /* Delay the opening of submenus */ - body.desktop .dropdown-submenu .dropdown-menu { + body.desktop:not(.motion-disabled) .dropdown-submenu .dropdown-menu { opacity: 0; animation-fill-mode: forwards; animation-delay: var(--submenu-opening-delay); diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index b27627bd1..b32e29f2b 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -89,6 +89,7 @@ --menu-text-color: #e3e3e3; --menu-background-color: #222222d9; + --menu-background-color-no-backdrop: #1b1b1b; --menu-item-icon-color: #8c8c8c; --menu-item-disabled-opacity: 0.5; --menu-item-keyboard-shortcut-color: #ffffff8f; diff --git a/apps/client/src/stylesheets/theme-next-light.css b/apps/client/src/stylesheets/theme-next-light.css index ff82e99ba..deb9fb2ec 100644 --- a/apps/client/src/stylesheets/theme-next-light.css +++ b/apps/client/src/stylesheets/theme-next-light.css @@ -83,6 +83,7 @@ --menu-text-color: #272727; --menu-background-color: #ffffffd9; + --menu-background-color-no-backdrop: #fdfdfd; --menu-item-icon-color: #727272; --menu-item-disabled-opacity: 0.6; --menu-item-keyboard-shortcut-color: #666666a8; diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index c992f7ecb..27fbf3557 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -83,6 +83,12 @@ --tab-note-icons: true; } +body.backdrop-effects-disabled { + /* Backdrop effects are disabled, replace the menu background color with the + * no-backdrop fallback color */ + --menu-background-color: var(--menu-background-color-no-backdrop); +} + /* * MENUS * diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index b80e8745e..6a7a966c9 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -1113,6 +1113,12 @@ "layout-vertical-description": "launcher bar is on the left (default)", "layout-horizontal-description": "launcher bar is underneath the tab bar, the tab bar is now full width." }, + "ui-performance": { + "title": "Performance", + "enable-motion": "Enable transitions and animations", + "enable-shadows": "Enable shadows", + "enable-backdrop-effects": "Enable background effects for menus, popups and panels" + }, "ai_llm": { "not_started": "Not started", "title": "AI Settings", diff --git a/apps/client/src/widgets/containers/root_container.ts b/apps/client/src/widgets/containers/root_container.ts index c941cdd88..6c2d87521 100644 --- a/apps/client/src/widgets/containers/root_container.ts +++ b/apps/client/src/widgets/containers/root_container.ts @@ -1,6 +1,8 @@ -import utils from "../../services/utils.js"; -import type BasicWidget from "../basic_widget.js"; +import { EventData } from "../../components/app_context.js"; import FlexContainer from "./flex_container.js"; +import options from "../../services/options.js"; +import type BasicWidget from "../basic_widget.js"; +import utils from "../../services/utils.js"; /** * The root container is the top-most widget/container, from which the entire layout derives. @@ -27,15 +29,45 @@ export default class RootContainer extends FlexContainer { window.visualViewport?.addEventListener("resize", () => this.#onMobileResize()); } + this.#setMotion(options.is("motionEnabled")); + this.#setShadows(options.is("shadowsEnabled")); + this.#setBackdropEffects(options.is("backdropEffectsEnabled")); + return super.render(); } + entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { + if (loadResults.isOptionReloaded("motionEnabled")) { + this.#setMotion(options.is("motionEnabled")); + } + + if (loadResults.isOptionReloaded("shadowsEnabled")) { + this.#setShadows(options.is("shadowsEnabled")); + } + + if (loadResults.isOptionReloaded("backdropEffectsEnabled")) { + this.#setBackdropEffects(options.is("backdropEffectsEnabled")); + } + } + #onMobileResize() { const currentViewportHeight = getViewportHeight(); const isKeyboardOpened = (currentViewportHeight < this.originalViewportHeight); this.$widget.toggleClass("virtual-keyboard-opened", isKeyboardOpened); } + #setMotion(enabled: boolean) { + document.body.classList.toggle("motion-disabled", !enabled); + jQuery.fx.off = !enabled; + } + + #setShadows(enabled: boolean) { + document.body.classList.toggle("shadows-disabled", !enabled); + } + + #setBackdropEffects(enabled: boolean) { + document.body.classList.toggle("backdrop-effects-disabled", !enabled); + } } function getViewportHeight() { diff --git a/apps/client/src/widgets/type_widgets/options/appearance.tsx b/apps/client/src/widgets/type_widgets/options/appearance.tsx index 2b43d9e82..a6f5a77c6 100644 --- a/apps/client/src/widgets/type_widgets/options/appearance.tsx +++ b/apps/client/src/widgets/type_widgets/options/appearance.tsx @@ -88,6 +88,7 @@ export default function AppearanceSettings() { {overrideThemeFonts === "true" && } {isElectron() && } + + + + + + + +} + + function MaxContentWidth() { const [ maxContentWidth, setMaxContentWidth ] = useTriliumOption("maxContentWidth"); diff --git a/apps/server/src/assets/views/desktop.ejs b/apps/server/src/assets/views/desktop.ejs index 9934eacee..374ed0b8c 100644 --- a/apps/server/src/assets/views/desktop.ejs +++ b/apps/server/src/assets/views/desktop.ejs @@ -9,7 +9,7 @@ Trilium Notes - +