From 37d9016b8384807baf401b8bdf07895cac811d5b Mon Sep 17 00:00:00 2001 From: marlon-erler Date: Thu, 17 Sep 2026 20:03:55 +0200 Subject: [PATCH] add dynamic theme --- dist/index.css | 28 ++- dist/index.js | 88 ++++++++- src/Model/Global/.settingsModel.ts.swp | Bin 0 -> 12288 bytes src/Model/Global/settingsModel.ts | 1 + src/View/Modals/.settingsModal.tsx.swp | Bin 0 -> 16384 bytes src/View/Modals/settingsModal.tsx | 4 + src/View/translations.ts | 85 ++++----- src/ViewModel/Global/.coreViewModel.ts.swo | Bin 0 -> 16384 bytes src/ViewModel/Global/.coreViewModel.ts.swp | Bin 16384 -> 16384 bytes .../Global/.settingsViewModel.ts.swp | Bin 0 -> 36864 bytes src/ViewModel/Global/coreViewModel.ts | 2 +- src/ViewModel/Global/settingsViewModel.ts | 174 ++++++++++++++---- src/base.css | 32 ++-- 13 files changed, 296 insertions(+), 118 deletions(-) create mode 100644 src/Model/Global/.settingsModel.ts.swp create mode 100644 src/View/Modals/.settingsModal.tsx.swp create mode 100644 src/ViewModel/Global/.coreViewModel.ts.swo create mode 100644 src/ViewModel/Global/.settingsViewModel.ts.swp diff --git a/dist/index.css b/dist/index.css index 9b0eebc0..4984431e 100644 --- a/dist/index.css +++ b/dist/index.css @@ -172,14 +172,12 @@ body[theme=dark] [color]:not([color=standard]).subtle-background { } #background-wrapper { position: fixed; - top: 0px; - left: var(--safe-area-left); - right: var(--safe-area-right); - bottom: 0px; + inset: -80px; z-index: 1; pointer-events: none; overflow: hidden; opacity: 0.4; + filter: blur(40px); } main { z-index: 2; @@ -187,24 +185,20 @@ main { #background-wrapper div { content: ""; position: absolute; - top: -80px; - left: -80px; - right: -80px; - bottom: -80px; + inset: 0px; z-index: -1; pointer-events: none; - filter: blur(40px); } #background-wrapper #sky { left: -100%; bottom: -50%; - --color-1: hsl(188, 100%, 83%); - --color-2: hsl(194, 72%, 56%); - background-image: radial-gradient(var(--color-1), var(--color-2)); + background-image: radial-gradient(var(--sky-1), var(--sky-2)); } #background-wrapper #grass-1 { - --color-1: hsl(150, 100%, 30%); - --color-2: hsl(150, 100%, 25%); + --color-1: hsl(150, 60%, 30%); + --color-2: hsl(150, 60%, 25%); + filter: var(--backdrop-grass-filter); + opacity: .7; background-image: linear-gradient( 350deg, @@ -213,8 +207,10 @@ main { transparent 40%); } #background-wrapper #grass-2 { - --color-1: hsl(110, 100%, 40%); - --color-2: hsl(110, 100%, 35%); + --color-1: hsl(110, 60%, 40%); + --color-2: hsl(110, 60%, 35%); + filter: var(--backdrop-grass-filter); + opacity: .7; background-image: linear-gradient( 9deg, diff --git a/dist/index.js b/dist/index.js index 450bf304..904ac39f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -353,6 +353,7 @@ info: "About Comms" }, themes: { + dynamic: "Dynamic", dark: "Dark", light: "Light", system: "Device theme" @@ -586,6 +587,7 @@ info: "\xDCber Comms" }, themes: { + dynamic: "Dynamisch", dark: "Dunkel", light: "Hell", system: "Ger\xE4teeinstellung" @@ -801,6 +803,7 @@ info: "Sobre Comms" }, themes: { + dynamic: "Din\xE1mico", dark: "Oscuro", light: "Claro", system: "Seg\xFAn dispositivo" @@ -1257,7 +1260,7 @@ this.connectionModel = connectionModel2; this.chatListModel = chatListModel2; this.fileTransferModel = fileTransferModel2; - this.BUILD = "Build 26.09.09.A"; + this.BUILD = "Build 26.09.17.A"; // CONTEXT this.contextStack = /* @__PURE__ */ new Map(); this.closeContext = (contextId, fromHistoryEvent = false) => { @@ -1800,10 +1803,42 @@ // view this.applyTheme = () => { let theme = this.theme.value; + if (theme == "dynamic" /* Dynamic */) { + const scene = this.selectDynamicScene(); + this.setScene(scene); + return; + } if (theme == "system" /* System */) { theme = _SettingsViewModel.getSystemTheme(); } - document.body.setAttribute("theme", theme); + if (theme == "dark" /* Dark */) { + this.setScene(DynamicSceneNight); + } else { + this.setScene(DynamicSceneDay); + } + }; + this.selectDynamicScene = () => { + let hour = (/* @__PURE__ */ new Date()).getHours(); + if (hour >= 21 || hour <= 6) { + return DynamicSceneNight; + } else if (hour > 6 && hour < 10) { + return DynamicSceneSunrise; + } else if (hour < 14) { + return DynamicSceneDay; + } else if (hour < 17) { + return DynamicSceneAfternoon; + } else if (hour < 21) { + return DynamicSceneSunset; + } + }; + this.setScene = (scene) => { + document.body.style.setProperty("--backdrop-grass-filter", `brightness(${scene.brightness})`); + function setSkyColor(tone, hue, saturation, luma) { + document.body.style.setProperty(`--sky-${tone}`, `hsl(${hue}, ${saturation}%, ${luma}%)`); + } + setSkyColor(1, scene.hue1, scene.saturation, scene.luma); + setSkyColor(2, scene.hue2, scene.saturation - 10, scene.luma - 10); + document.body.setAttribute("theme", scene.baseTheme); }; // exit this.close = () => { @@ -1835,6 +1870,11 @@ "change", () => this.applyTheme() ); + const seconds = (/* @__PURE__ */ new Date()).getSeconds(); + const secondsUntilNewMinute = 60 - seconds; + setTimeout(() => { + setInterval(this.applyTheme, 1e3 * 60); + }, secondsUntilNewMinute); this.registerKeyStroke("backspace" /* CloseOrCancel */, this.close); } static generateThemeMedia() { @@ -1845,6 +1885,46 @@ return media.matches == true ? "dark" /* Dark */ : "light" /* Light */; } }; + var DynamicSceneNight = { + hue1: 215, + hue2: 220, + saturation: 50, + luma: 25, + brightness: 0.4, + baseTheme: "dark" /* Dark */ + }; + var DynamicSceneSunrise = { + hue1: 45, + hue2: 190, + saturation: 100, + luma: 50, + brightness: 1.2, + baseTheme: "light" /* Light */ + }; + var DynamicSceneDay = { + hue1: 190, + hue2: 180, + saturation: 100, + luma: 70, + brightness: 1.4, + baseTheme: "light" /* Light */ + }; + var DynamicSceneAfternoon = { + hue1: 195, + hue2: 220, + saturation: 100, + luma: 50, + brightness: 0.8, + baseTheme: "light" /* Light */ + }; + var DynamicSceneSunset = { + hue1: 20, + hue2: 260, + saturation: 100, + luma: 50, + brightness: 0.4, + baseTheme: "dark" /* Dark */ + }; // src/ViewModel/Global/fileTransferViewModel.ts var FileTransferViewModel = class extends Context { @@ -6867,6 +6947,10 @@ function SettingsAppearancePane(coreViewModel2, settingsViewModel2) { return /* @__PURE__ */ createElement("div", { class: "slide-up" }, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.settings.pages.appearance), /* @__PURE__ */ createElement("hr", null), OptionButtonList( new ListState([ + [ + coreViewModel2.translations.settings.themes.dynamic, + "dynamic" /* Dynamic */ + ], [ coreViewModel2.translations.settings.themes.dark, "dark" /* Dark */ diff --git a/src/Model/Global/.settingsModel.ts.swp b/src/Model/Global/.settingsModel.ts.swp new file mode 100644 index 0000000000000000000000000000000000000000..ec897c9911b565492d07ecf0066a16494c63f36e GIT binary patch literal 12288 zcmeI2&2Jk;7{;fCl=9KE6af{eXfQ=`Bx8s4LL8MS5U8Ri5Xo(Fh&W8_vAtxyYwgVD zLv4U^$i(rF-hA}2$H}EBLRyYgr8{1(UuSOH7dy3n3kEAf`T=Y4 z%G~74byfkZfK|XMU=^?mSOu&CRspNP|4aed-ACTWoc71_^5Xlx zzI*)9-mC&v0jq#jz$#!BunJfOtO8a6tAJI&Dqt133l(4uLLB_~AH5gOS6~Ayf-|5B4ue~V2)PEXfECaMKB$6Y;FpI8 zxeacC55X#!097yw2>9tiLOupp!4=?xSx^8^f+xTr`0W8gJ_Q@V2jk!f7yvi#C*%ik z16&0RRKZCw0``N?4-)boco$p*^WZ4Bejg#^z%eig4uS(<0Q`w{`4M~vJ_FalC*Trz2P}cJU<~Lr zybEK{y8NG3V4YB0lWQL9ICXl878>d?ztpK0O1gP%O-SBRt%ZJyi>IAdTdGo5J;a5R zELhTZaYqqf?fQYF+zUJOY@2s@Ej|rI&l3_2TkA5<5pC6pi`dF(9(0(e?eMth6|d!* zW?rA=Y38*;97Ga{)yTG*Z1SW&sVm?z3_RNFRgP_s5nUbsY49csU0KZ(s=7_x;~8YT z*O}mYM!PT&O*gN9gBOziV#Sg5HZ6K=*=aGHy(+u$#LFUF6f(dutKx8pjtmV!2<57f zOk$l|Tt;hXrd%AVCev4$8Slvf@zUS+6FslvDYt69_rU*8Ju?=S#W$ z&j}tN^0=zhqbm=z_4rVkJ}!m`NPmoms{0=18rC5|FeHn^wMLS=2bYSG^ZD+7rHL&=m`XzHR3QY7W4>(SV2|e zd+r+TX^TE;EtY+!K~KHdTZv@ANbq=>v!0q%iVoK0tZ`!HZ@X;*E7x#SH<;;1^1=Z^{E1gNTa53tc3Am(v6kN&>W{~b!Mog-nMWRe1 z%%gOI5rI`*SZ|HEqsnf?gq{>lN`HooKvZ^Q%VwL7|E|vEkF6y z-eJCvOrn;k$5-Z<8}gKXT5z*fnEEJgd!s{Dy;-WEO%pR=%zTFg&$`k}zOB76O)#7p zZL>q^JT0m-gDkOp@~dNW!LrUWrZAfXG-?4hf^A)oEuOK&wK$ z4VwhWsmexRP6HDHIaL_G!6b{uPLezIUXgvv7&C9U@!KM;yG#h0*(uexy3^6`!L^j3 t5UEzLGtN@9Vo(`MjzXrXM5+UvN21O$%OUCz9)TcxvY^{zQV{sIue^E3be literal 0 HcmV?d00001 diff --git a/src/Model/Global/settingsModel.ts b/src/Model/Global/settingsModel.ts index a2b9128f..a2935ceb 100644 --- a/src/Model/Global/settingsModel.ts +++ b/src/Model/Global/settingsModel.ts @@ -106,4 +106,5 @@ export enum ThemeSettings { Dark = "dark", Light = "light", System = "system", + Dynamic = "dynamic", } diff --git a/src/View/Modals/.settingsModal.tsx.swp b/src/View/Modals/.settingsModal.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000..191c651b1e59964f7ad80bfdf308d92bcd399a96 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/src/View/Modals/settingsModal.tsx b/src/View/Modals/settingsModal.tsx index a5cd8613..5156f143 100644 --- a/src/View/Modals/settingsModal.tsx +++ b/src/View/Modals/settingsModal.tsx @@ -170,6 +170,10 @@ function SettingsAppearancePane(
{OptionButtonList( new React.ListState<[string, string]>([ + [ + coreViewModel.translations.settings.themes.dynamic, + ThemeSettings.Dynamic, + ], [ coreViewModel.translations.settings.themes.dark, ThemeSettings.Dark, diff --git a/src/View/translations.ts b/src/View/translations.ts index ffae625e..289973f7 100644 --- a/src/View/translations.ts +++ b/src/View/translations.ts @@ -83,6 +83,7 @@ const englishTranslations = { info: "About Comms", }, themes: { + dynamic: "Dynamic", dark: "Dark", light: "Light", system: "Device theme", @@ -410,58 +411,59 @@ export const allTranslations: { info: "Über Comms", }, themes: { - dark: "Dunkel", - light: "Hell", - system: "Geräteeinstellung", - }, + dynamic: "Dynamisch", + dark: "Dunkel", + light: "Hell", + system: "Geräteeinstellung", + }, - version: "Version", - language: "Sprache", + version: "Version", + language: "Sprache", - firstDayOfWeekLabel: "Erster Wochentag", - }, + firstDayOfWeekLabel: "Erster Wochentag", + }, - connectionModal: { - connectionModalHeadline: "Verbindungen verwalten", + connectionModal: { + connectionModalHeadline: "Verbindungen verwalten", - connectButtonAudioLabel: "verbinden", - }, + connectButtonAudioLabel: "verbinden", + }, - dataTransferModal: { - transferDataHeadline: "Datenübertragung", - sendHeadline: "An anderes Gerät senden", - receiveHeadline: "An dieses Gerät senden", - exportHeadline: "Daten exportieren", - importHeadline: "Daten importieren", - selectionDescription: - "Wähle die Daten aus, die du übertragen möchtest.", - exportSelectionDescription: - "Wähle die Daten aus, die du exportieren möchtest.", - dataEntryDescription: - "Gib diese Informationen auf dem anderen Gerät ein.", - dataEntryInputDescription: - "Gib die auf dem anderen Gerät angezeigten Informationen ein.", + dataTransferModal: { + transferDataHeadline: "Datenübertragung", + sendHeadline: "An anderes Gerät senden", + receiveHeadline: "An dieses Gerät senden", + exportHeadline: "Daten exportieren", + importHeadline: "Daten importieren", + selectionDescription: + "Wähle die Daten aus, die du übertragen möchtest.", + exportSelectionDescription: + "Wähle die Daten aus, die du exportieren möchtest.", + dataEntryDescription: + "Gib diese Informationen auf dem anderen Gerät ein.", + dataEntryInputDescription: + "Gib die auf dem anderen Gerät angezeigten Informationen ein.", - fromThisDeviceButton: "An anderes Gerät senden", - toThisDeviceButton: "An dieses Gerät senden", - exportButton: "Als Datei exportieren", - importButton: "Aus Datei importieren", + fromThisDeviceButton: "An anderes Gerät senden", + toThisDeviceButton: "An dieses Gerät senden", + exportButton: "Als Datei exportieren", + importButton: "Aus Datei importieren", - generalHeadline: "Allgemein", + generalHeadline: "Allgemein", - connectionData: "Verbindungsdaten", - settingsData: "Einstellungen", + connectionData: "Verbindungsdaten", + settingsData: "Einstellungen", - chatsHeadline: "Chats", + chatsHeadline: "Chats", - transferChannelHeadline: "Übertragungskanal", - transferKeyHeadline: "Schlüssel", + transferChannelHeadline: "Übertragungskanal", + transferKeyHeadline: "Schlüssel", - sendButton: "Senden", - sendAgainButton: "Erneut senden", + sendButton: "Senden", + sendAgainButton: "Erneut senden", - filesSentCount: (count) => `Dateien gesendet: ${count}.`, - allFilesSent: "Fertig.", + filesSentCount: (count) => `Dateien gesendet: ${count}.`, + allFilesSent: "Fertig.", filesReceivedCount: (count) => `Dateien empfangen: ${count}.`, @@ -705,6 +707,7 @@ export const allTranslations: { info: "Sobre Comms", }, themes: { + dynamic: "Dinámico", dark: "Oscuro", light: "Claro", system: "Según dispositivo", @@ -758,7 +761,7 @@ export const allTranslations: { allFilesSent: "Hecho.", filesReceivedCount: (count) => `Archivos recibidos: ${count}.`, - + exportKey: "Clave de encriptación", exportKeyConfirmation: "Confirmar clave", downloadFileButton: "Descargar", diff --git a/src/ViewModel/Global/.coreViewModel.ts.swo b/src/ViewModel/Global/.coreViewModel.ts.swo new file mode 100644 index 0000000000000000000000000000000000000000..691f7bd64d8730140449bda270dc14c748a71e26 GIT binary patch literal 16384 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 delta 36 kcmZo@U~Fh$-0;OlRGyWAfr$YEq=A$G5X)`mwEfNm0E$-zSpWb4 diff --git a/src/ViewModel/Global/.settingsViewModel.ts.swp b/src/ViewModel/Global/.settingsViewModel.ts.swp new file mode 100644 index 0000000000000000000000000000000000000000..26c65a60214ec6ad35eaf88f1bf015a0a1c487be GIT binary patch literal 36864 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 AzW@LL literal 0 HcmV?d00001 diff --git a/src/ViewModel/Global/coreViewModel.ts b/src/ViewModel/Global/coreViewModel.ts index 46e94a4c..e4ec314a 100644 --- a/src/ViewModel/Global/coreViewModel.ts +++ b/src/ViewModel/Global/coreViewModel.ts @@ -9,7 +9,7 @@ import ConnectionModel from "../../Model/Global/connectionModel"; import ChatListModel from "../../Model/Chat/chatListModel"; export default class CoreViewModel { - readonly BUILD = "Build 26.09.09.A"; + readonly BUILD = "Build 26.09.17.A"; translations: Translations; diff --git a/src/ViewModel/Global/settingsViewModel.ts b/src/ViewModel/Global/settingsViewModel.ts index f603d20a..aa8b1b41 100644 --- a/src/ViewModel/Global/settingsViewModel.ts +++ b/src/ViewModel/Global/settingsViewModel.ts @@ -48,74 +48,168 @@ export default class SettingsViewModel extends Context { }; showModalPage = (page: SettingsModalPages): void => { - this.selectedModalPage.value = page; + this.selectedModalPage.value = page; }; // view applyTheme = (): void => { - let theme: string = this.theme.value; - if (theme == ThemeSettings.System) { - theme = SettingsViewModel.getSystemTheme(); - } - document.body.setAttribute("theme", theme); + let theme: string = this.theme.value; + + if (theme == ThemeSettings.Dynamic) { + const scene = this.selectDynamicScene(); + this.setScene(scene); + return; + } + + if (theme == ThemeSettings.System) { + theme = SettingsViewModel.getSystemTheme(); + } + + if (theme == ThemeSettings.Dark) { + this.setScene(DynamicSceneNight); + } else { + this.setScene(DynamicSceneDay); + } }; + selectDynamicScene = (): DynamicScene => { + let hour = new Date().getHours(); + + if (hour >= 21 || hour <= 6) { + return DynamicSceneNight; + } else if (hour > 6 && hour < 10) { + return DynamicSceneSunrise; + } else if (hour < 14) { + return DynamicSceneDay; + } else if (hour < 17) { + return DynamicSceneAfternoon + } else if (hour < 21) { + return DynamicSceneSunset + } + } + + setScene = (scene: DynamicScene): void => { + document.body.style.setProperty("--backdrop-grass-filter", `brightness(${scene.brightness})`); + + function setSkyColor(tone: 1|2, hue: number, saturation: number, luma: number) { + document.body.style.setProperty(`--sky-${tone}`, `hsl(${hue}, ${saturation}%, ${luma}%)`); + } + setSkyColor(1, scene.hue1, scene.saturation, scene.luma); + setSkyColor(2, scene.hue2, scene.saturation - 10, scene.luma-10); + + document.body.setAttribute("theme", scene.baseTheme); + } + // exit close = (): void => { - this.coreViewModel.closeContext(this.contextId); + this.coreViewModel.closeContext(this.contextId); }; handleContextClose = (): void => { - this.isShowingSettingsModal.value = false; - if (this.requiresReload.value == true) { - window.location.reload(); - } + this.isShowingSettingsModal.value = false; + if (this.requiresReload.value == true) { + window.location.reload(); + } }; // init constructor(public readonly coreViewModel: CoreViewModel) { - super("settings"); + super("settings"); - this.username.value = coreViewModel.settingsModel.username; - this.usernameInput.value = coreViewModel.settingsModel.username; - this.firstDayOfWeek.value = coreViewModel.settingsModel.firstDayOfWeek; - this.language.value = coreViewModel.settingsModel.language; - this.theme.value = coreViewModel.settingsModel.theme; + this.username.value = coreViewModel.settingsModel.username; + this.usernameInput.value = coreViewModel.settingsModel.username; + this.firstDayOfWeek.value = coreViewModel.settingsModel.firstDayOfWeek; + this.language.value = coreViewModel.settingsModel.language; + this.theme.value = coreViewModel.settingsModel.theme; - // subscriptions - this.firstDayOfWeek.subscribe(this.setFirstDayofWeek); - this.language.subscribeSilent((newValue) => { - this.coreViewModel.settingsModel.setLanguage(newValue); - this.requiresReload.value = true; - }); - this.theme.subscribeSilent((newValue) => { - this.coreViewModel.settingsModel.setTheme(newValue); - }); + // subscriptions + this.firstDayOfWeek.subscribe(this.setFirstDayofWeek); + this.language.subscribeSilent((newValue) => { + this.coreViewModel.settingsModel.setLanguage(newValue); + this.requiresReload.value = true; + }); + this.theme.subscribeSilent((newValue) => { + this.coreViewModel.settingsModel.setTheme(newValue); + }); - // set theme - this.theme.subscribe(() => { - this.applyTheme(); - }); - SettingsViewModel.generateThemeMedia().addEventListener("change", () => - this.applyTheme(), - ); + // set theme + this.theme.subscribe(() => { + this.applyTheme(); + }); + SettingsViewModel.generateThemeMedia().addEventListener("change", () => + this.applyTheme(), + ); + const seconds = new Date().getSeconds(); + const secondsUntilNewMinute = 60-seconds; + setTimeout(() => { + setInterval(this.applyTheme, 1000*60); + }, secondsUntilNewMinute); - // keystrokes - this.registerKeyStroke(CommonKeys.CloseOrCancel, this.close); + // keystrokes + this.registerKeyStroke(CommonKeys.CloseOrCancel, this.close); } static generateThemeMedia(): MediaQueryList { - return window.matchMedia("(prefers-color-scheme: dark)"); + return window.matchMedia("(prefers-color-scheme: dark)"); } static getSystemTheme(): string { - const media = SettingsViewModel.generateThemeMedia(); - return media.matches == true ? ThemeSettings.Dark : ThemeSettings.Light; + const media = SettingsViewModel.generateThemeMedia(); + return media.matches == true ? ThemeSettings.Dark : ThemeSettings.Light; } } export enum SettingsModalPages { Appearance, - Regional, - Info, + Regional, + Info, +} + +export interface DynamicScene { + hue1: number; + hue2: number; + saturation: number; + luma: number; + brightness: number; + baseTheme: ThemeSettings; +} +export const DynamicSceneNight: DynamicScene = { + hue1: 215, + hue2: 220, + saturation : 50, + luma: 25, + brightness: 0.4, + baseTheme: ThemeSettings.Dark, +} +export const DynamicSceneSunrise: DynamicScene = { + hue1: 45, + hue2: 190, + saturation : 100, + luma: 50, + brightness: 1.2, + baseTheme: ThemeSettings.Light, +} +export const DynamicSceneDay: DynamicScene = { + hue1: 190, + hue2: 180, + saturation : 100, + luma: 70, + brightness: 1.4, + baseTheme: ThemeSettings.Light, +} +export const DynamicSceneAfternoon: DynamicScene = { + hue1: 195, + hue2: 220, + saturation : 100, + luma: 50, + brightness: 0.8, + baseTheme: ThemeSettings.Light, +} +export const DynamicSceneSunset: DynamicScene = { + hue1: 20, + hue2: 260, + saturation : 100, + luma: 50, + brightness: 0.4, + baseTheme: ThemeSettings.Dark, } diff --git a/src/base.css b/src/base.css index d6089b0f..5daa50bb 100644 --- a/src/base.css +++ b/src/base.css @@ -7,14 +7,10 @@ } /* Gradient */ - #background-wrapper { position: fixed; - top: 0px; - left: var(--safe-area-left); - right: var(--safe-area-right); - bottom: 0px; + inset: -80px; z-index: 1; pointer-events: none; @@ -22,6 +18,7 @@ overflow: hidden; opacity: 0.4; + filter: blur(40px); } main { @@ -32,29 +29,25 @@ main { content: ""; position: absolute; - top: -80px; - left: -80px; - right: -80px; - bottom: -80px; + inset: 0px; z-index: -1; pointer-events: none; - - filter: blur(40px); } #background-wrapper #sky { left: -100%; bottom: -50%; - --color-1: hsl(188, 100%, 83%); - --color-2: hsl(194, 72%, 56%); - background-image: radial-gradient(var(--color-1), var(--color-2)); + background-image: radial-gradient(var(--sky-1), var(--sky-2)); } #background-wrapper #grass-1 { - --color-1: hsl(150, 100%, 30%); - --color-2: hsl(150, 100%, 25%); + --color-1: hsl(150, 60%, 30%); + --color-2: hsl(150, 60%, 25%); + + filter: var(--backdrop-grass-filter); + opacity: .7; background-image: linear-gradient( 350deg, @@ -65,8 +58,11 @@ main { } #background-wrapper #grass-2 { - --color-1: hsl(110, 100%, 40%); - --color-2: hsl(110, 100%, 35%); + --color-1: hsl(110, 60%, 40%); + --color-2: hsl(110, 60%, 35%); + + filter: var(--backdrop-grass-filter); + opacity: .7; background-image: linear-gradient( 9deg,