Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Grayjay.ClientServer/Settings/GrayjaySettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ public class LanguageSettings
public int AppLanguage { get; set; } = 0;
}

[SettingsField("Appearance", "group", "Configure the application appearance", 1)]
public AppearanceSettings Appearance { get; set; } = new AppearanceSettings();
public class AppearanceSettings
{
[SettingsField("Theme", SettingsField.DROPDOWN, "Choose whether Grayjay follows the system theme or uses a fixed theme", 0)]
[SettingsDropdownOptions("System", "Dark", "Light")]
public int Theme { get; set; } = 0;
}

//Home
public HomeSettings Home { get; set; } = new HomeSettings();
public class HomeSettings
Expand Down
3 changes: 2 additions & 1 deletion Grayjay.Desktop.CEF/CEFWindowProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Grayjay.ClientServer;
using Grayjay.ClientServer.Browser;
using Grayjay.ClientServer.Dialogs;
using Grayjay.ClientServer.Settings;
using Grayjay.Desktop.POC;
using Microsoft.AspNetCore.Mvc.Formatters;
using System;
Expand Down Expand Up @@ -44,7 +45,7 @@ public async Task<IWindow> CreateWindowAsync(string url, string title, int prefe
if(beforeLoad != null)
await beforeLoad(windowResult);
await window.SetDevelopmentToolsEnabledAsync(true);
await window.LoadUrlAsync($"{GrayjayServer.Instance.BaseUrl}{GrayjayServer.Instance.GetIndexUrl()}");
await window.LoadUrlAsync(StartupSplash.CreateThemedWebUrl(GrayjayServer.Instance.BaseUrl, GrayjayServer.Instance.GetIndexUrl(), GrayjaySettings.Instance.Appearance.Theme));
return windowResult;
}

Expand Down
8 changes: 4 additions & 4 deletions Grayjay.Desktop.CEF/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using JustCef;
using JustCef;
using Grayjay.ClientServer;
using Grayjay.ClientServer.Constants;
using Grayjay.ClientServer.Controllers;
Expand Down Expand Up @@ -409,7 +409,7 @@ static async Task EntryPoint(string[] args)
Stopwatch startWindowWatch = Stopwatch.StartNew();
Logger.i(nameof(Program), "Main: Starting window.");
window = await cef.CreateWindowAsync(
url: """data:text/html;base64,PHN0eWxlPkBpbXBvcnQgdXJsKGh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9Um9ib3RvOndnaHRANDAwOzcwMCZkaXNwbGF5PXN3YXApO2JvZHl7YmFja2dyb3VuZC1jb2xvcjojMWIxYjFiO21hcmdpbjowO2ZvbnQtZmFtaWx5OlJvYm90byxzYW5zLXNlcmlmfS5sb2FkZXItY29udGFpbmVye2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjthbGlnbi1pdGVtczpjZW50ZXI7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwdmh9LmxvYWRlci1zdmd7d2lkdGg6MjAwcHg7aGVpZ2h0OjIwMHB4O2FuaW1hdGlvbjpnZW50bGUtcHVsc2UgM3MgZWFzZS1pbi1vdXQgaW5maW5pdGV9LmxvYWRpbmctdGV4dHtjb2xvcjojZmZmO2ZvbnQtc2l6ZToyNHB4O21hcmdpbi10b3A6MjBweDtmb250LXdlaWdodDo3MDA7bGV0dGVyLXNwYWNpbmc6MXB4fS5sb2FkaW5nLXRleHQgc3BhbntvcGFjaXR5OjA7YW5pbWF0aW9uOmRvdCAxLjVzIGluZmluaXRlfS5sb2FkaW5nLXRleHQgc3BhbjpudGgtY2hpbGQoMSl7YW5pbWF0aW9uLWRlbGF5OjBzfS5sb2FkaW5nLXRleHQgc3BhbjpudGgtY2hpbGQoMil7YW5pbWF0aW9uLWRlbGF5Oi41c30ubG9hZGluZy10ZXh0IHNwYW46bnRoLWNoaWxkKDMpe2FuaW1hdGlvbi1kZWxheToxc31Aa2V5ZnJhbWVzIGdlbnRsZS1wdWxzZXswJSwxMDAle3RyYW5zZm9ybTpzY2FsZSgxKTtvcGFjaXR5Oi44fTUwJXt0cmFuc2Zvcm06c2NhbGUoMS4xKTtvcGFjaXR5OjF9fUBrZXlmcmFtZXMgZG90ezAle29wYWNpdHk6MH01MCV7b3BhY2l0eToxfTEwMCV7b3BhY2l0eTowfX08L3N0eWxlPjxkaXYgY2xhc3M9bG9hZGVyLWNvbnRhaW5lcj48c3ZnIGNsYXNzPWxvYWRlci1zdmcgZmlsbD1ub25lIGhlaWdodD0yMDAgdmlld0JveD0iMCAwIDQ4IDQ4IndpZHRoPTIwMCB4bWxucz1odHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zz48cGF0aCBkPSJNMjMuODYxMiA0MS4yNTE2TDQ2LjIyMjUgNy4wMDIySDEuNUwyMy44NjEyIDQxLjI1MTZaImZpbGw9dXJsKCNwYWludDBfbGluZWFyXzgyOF85NTA2KSAvPjxwYXRoIGQ9Ik02LjgxMjUgMzAuODcxNUM3LjcyMzgxIDI5Ljg5OTQgOS45ODM4OSAyNy42NzU4IDExLjczMzYgMjYuNTU3OUMxMy40ODMzIDI1LjQ0MDEgMTUuNTgxNCAyMi4yNDQ0IDE2LjQxMTcgMjAuNzg2M0MxOC45NDMxIDE3LjA2IDI0LjYxMzUgOS4yNzk0NSAyNy4wNDM3IDcuOTY3MTNDMjcuNDgxMSA3LjYyNjg5IDI4LjExNyA3LjA5NjMyIDI4LjM4MDMgNi44NzM1OEMyOS4yOTE2IDQuODQ4NCAzMi4zOTAxIDEuNDA1NjYgMzcuNDkzNCAzLjgzNTg2QzM3LjkzMDkgMy42OTAwMyAzOS4wMTIzIDMuNjUzNTggMzkuNDk4MyAzLjY1MzU4QzM5LjExMzUgMy45MTY4NiAzOC4zMDc1IDQuNjg2NCAzOC4xNjE3IDUuNjU4NDhDMzcuNzcyOSA4LjMzMTY0IDM2LjI5ODYgOS44OTEwMyAzNS42MSAxMC4zMzY1QzM1LjEyNCAxMy40MzUgMzQuNDU1NyAxNi4xNjkgMzIuOTk3NiAxNy4xNDFMMzQuMzM0MiAxOS41MTA0QzM2LjMzOTEgMjEuNjM2OSA0MC40OTQ3IDI2LjIyOTkgNDEuMDc3NyAyNy41OTA4QzM5LjEzMzggMjYuOTU4OSAzNy44NzgyIDI2LjM1NTQgMzcuNDkzNCAyNi4xMzI3TDQxLjA3NzcgMzEuMDUzOEMzOC45NzE4IDMwLjg5MTggMzQuMjM3IDI5LjUyMjggMzIuMTQ3MSAyNS4zNDI5QzMyLjk3MzMgMjcuNTc4NiAzMy43ODc0IDMwLjM2NTIgMzQuMDkxMiAzMS40NzlDMzIuOTU3MSAzMC41NDc1IDMwLjUxODggMjcuODQ1OSAyOS44Mzg0IDI0LjQ5MjNDMzAuMDMyOCAyNy43NDg3IDMwLjAwMDQgMzAuMDYxNCAyOS45NTk5IDMwLjgxMDdDMjkuNDEzMSAzMC4zMDQ1IDI4LjE0OTQgMjguNzMyOSAyNy40Njg5IDI2LjQ5NzJWMzAuMjY0QzI2LjY1MjkgMjkuMTI5NCAyNS4wMTEyIDI2LjM3NSAyNC44NjI5IDI0LjI5NjZDMjQuOTk5OCAyNi42NTI0IDI0LjkxNjQgMjcuNzU2NyAyNC44NTY1IDI4LjAxNkwyMS43NTgxIDI1LjA5OTlDMjAuOTI3NyAyNS41NDU0IDE4LjY5NjEgMjYuNTU3OSAxNi40MTE3IDI3LjA0NEMxNC44NTY0IDI4LjM1NjMgMTIuOTY4OSAzMS42NDExIDEyLjIxOTYgMzMuMTE5NFYzMS4yMzZMMTAuMTU0IDMzLjMwMTdMMTAuODgzIDMxLjExNDVMOS41NDY0NCAzMi4yNjg5QzkuMjQyNjUgMzIuNDUxMSA4LjUzNzkgMzIuODE1NiA4LjE0OTEgMzIuODE1NkM4LjI5NDg5IDMyLjQ3NTQgOC41NzQzOSAzMi4xMDY4IDguNjk1OSAzMS45NjUxTDYuOTM0MDEgMzIuNjMzNEM3LjEzNjUxIDMyLjA0NjEgNy43NzI0MiAzMC43NSA4LjY5NTkgMzAuMjY0QzcuNDMyMTkgMzAuNzUgNi45MTM3OCAzMC44NzE1IDYuODEyNSAzMC44NzE1WiJmaWxsPXdoaXRlIC8+PGRlZnM+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9dXNlclNwYWNlT25Vc2UgaWQ9cGFpbnQwX2xpbmVhcl84MjhfOTUwNiB4MT0yMy44NjEyIHgyPTIzLjg2MTIgeTE9NDEuMjUxNiB5Mj0tNC40MTQyOD48c3RvcCBzdG9wLWNvbG9yPSMwMUQ2RTYgLz48c3RvcCBzdG9wLWNvbG9yPSMwMTgyRTcgb2Zmc2V0PTEgLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz48cCBjbGFzcz1sb2FkaW5nLXRleHQ+TG9hZGluZzxzcGFuPi48L3NwYW4+PHNwYW4+Ljwvc3Bhbj48c3Bhbj4uPC9zcGFuPjwvZGl2Pg==""",
url: StartupSplash.CreateDataUrl(GrayjaySettings.Instance.Appearance.Theme),
minimumWidth: 900,
minimumHeight: 550,
preferredWidth: 1300,
Expand Down Expand Up @@ -512,9 +512,9 @@ static async Task EntryPoint(string[] args)

Logger.i(nameof(Program), "Main: Navigate.");
if (window != null)
await window.LoadUrlAsync($"{server.BaseUrl}/web/index.html");
await window.LoadUrlAsync(StartupSplash.CreateThemedWebUrl(server.BaseUrl, "/web/index.html", GrayjaySettings.Instance.Appearance.Theme));
else if (!isServer)
OSHelper.OpenUrl($"{server.BaseUrl}/web/index.html");
OSHelper.OpenUrl(StartupSplash.CreateThemedWebUrl(server.BaseUrl, "/web/index.html", GrayjaySettings.Instance.Appearance.Theme));

if (window != null)
StateApp.SetMainWindow(new CEFWindowProvider.Window(window));
Expand Down
117 changes: 117 additions & 0 deletions Grayjay.Desktop.CEF/StartupSplash.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Text;

namespace Grayjay.Desktop
{
internal static class StartupSplash
{
private const int ThemeSystem = 0;
private const int ThemeDark = 1;
private const int ThemeLight = 2;

private const string DarkBackground = "#141414";
private const string LightBackground = "#f5f5f3";
private const string DarkText = "#ffffff";
private const string LightText = "#141414";
private const string DarkLoaderGlow = "rgba(1, 155, 231, 0.35)";
private const string LightLoaderGlow = "rgba(20, 20, 20, 0.10)";
private const string Accent = "#019be7";
private const string AccentGradientStop = "#01D6E6";

public static string CreateDataUrl(int theme)
{
var html = CreateHtml(theme);
return "data:text/html;base64," + Convert.ToBase64String(Encoding.UTF8.GetBytes(html));
}


public static string CreateThemedWebUrl(string baseUrl, string indexUrl, int theme)
{
return AppendStartupThemeQuery(baseUrl + indexUrl, theme);
}

public static string AppendStartupThemeQuery(string url, int theme)
{
var fragmentStart = url.IndexOf('#');
var mainUrl = fragmentStart >= 0 ? url[..fragmentStart] : url;
var fragment = fragmentStart >= 0 ? url[fragmentStart..] : string.Empty;
var separator = mainUrl.Contains('?') ? "&" : "?";

return mainUrl + separator + "gjStartupTheme=" + GetStartupThemeSource(theme) + fragment;
}

private static string GetStartupThemeSource(int theme)
{
if (theme == ThemeLight)
return "light";

if (theme == ThemeSystem)
return "system";

return "dark";
}

private static string CreateHtml(int theme)
{
return "<!doctype html><html><head><meta charset=\"utf-8\"><style>" +
"@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap);" +
CreateThemeCss(theme) +
"html,body{width:100%;height:100%;background:var(--gj-bg-root);color:var(--gj-text-primary);margin:0;font-family:Roboto,sans-serif;}" +
".loader-container{display:flex;justify-content:center;flex-direction:column;align-items:center;width:100%;height:100vh;}" +
".loader-svg{width:200px;height:200px;animation:gentle-pulse 3s ease-in-out infinite;filter:drop-shadow(0 0 28px var(--gj-loader-glow));}" +
".loading-text{color:var(--gj-text-primary);font-size:24px;margin-top:20px;font-weight:700;letter-spacing:1px;}" +
".loading-text span{opacity:0;animation:dot 1.5s infinite;}" +
".loading-text span:nth-child(1){animation-delay:0s;}" +
".loading-text span:nth-child(2){animation-delay:.5s;}" +
".loading-text span:nth-child(3){animation-delay:1s;}" +
"@keyframes gentle-pulse{0%,100%{transform:scale(1);opacity:.8;}50%{transform:scale(1.1);opacity:1;}}" +
"@keyframes dot{0%{opacity:0;}50%{opacity:1;}100%{opacity:0;}}" +
"</style></head><body><div class=\"loader-container\">" +
CreateLogoSvg() +
"<p class=\"loading-text\">Loading<span>.</span><span>.</span><span>.</span></p>" +
"</div></body></html>";
}

private static string CreateThemeCss(int theme)
{
if (theme == ThemeLight)
return CreateRootCss("light", LightBackground, LightText, LightLoaderGlow);

if (theme == ThemeSystem)
{
return CreateRootCss("dark", DarkBackground, DarkText, DarkLoaderGlow) +
"@media (prefers-color-scheme: light){" +
CreateRootCss("light", LightBackground, LightText, LightLoaderGlow) +
"}";
}

if (theme == ThemeDark)
return CreateRootCss("dark", DarkBackground, DarkText, DarkLoaderGlow);

return CreateRootCss("dark", DarkBackground, DarkText, DarkLoaderGlow);
}

private static string CreateRootCss(string colorScheme, string background, string text, string loaderGlow)
{
return ":root{" +
"color-scheme:" + colorScheme + ";" +
"--gj-bg-root:" + background + ";" +
"--gj-text-primary:" + text + ";" +
"--gj-loader-glow:" + loaderGlow + ";" +
"--gj-accent:" + Accent + ";" +
"--gj-accent-grad:linear-gradient(267deg," + AccentGradientStop + " -100.57%,var(--gj-accent) 90.96%);" +
"}";
}

private static string CreateLogoSvg()
{
return "<svg class=\"loader-svg\" fill=\"none\" height=\"200\" viewBox=\"0 0 48 48\" width=\"200\" xmlns=\"http://www.w3.org/2000/svg\">" +
"<path d=\"M23.8612 41.2516L46.2225 7.0022H1.5L23.8612 41.2516Z\" fill=\"url(#gj-splash-gradient)\" />" +
"<path d=\"M6.8125 30.8715C7.72381 29.8994 9.98389 27.6758 11.7336 26.5579C13.4833 25.4401 15.5814 22.2444 16.4117 20.7863C18.9431 17.06 24.6135 9.27945 27.0437 7.96713C27.4811 7.62689 28.117 7.09632 28.3803 6.87358C29.2916 4.8484 32.3901 1.40566 37.4934 3.83586C37.9309 3.69003 39.0123 3.65358 39.4983 3.65358C39.1135 3.91686 38.3075 4.6864 38.1617 5.65848C37.7729 8.33164 36.2986 9.89103 35.61 10.3365C35.124 13.435 34.4557 16.169 32.9976 17.141L34.3342 19.5104C36.3391 21.6369 40.4947 26.2299 41.0777 27.5908C39.1338 26.9589 37.8782 26.3554 37.4934 26.1327L41.0777 31.0538C38.9718 30.8918 34.237 29.5228 32.1471 25.3429C32.9733 27.5786 33.7874 30.3652 34.0912 31.479C32.9571 30.5475 30.5188 27.8459 29.8384 24.4923C30.0328 27.7487 30.0004 30.0614 29.9599 30.8107C29.4131 30.3045 28.1494 28.7329 27.4689 26.4972V30.264C26.6529 29.1294 25.0112 26.375 24.8629 24.2966C24.9998 26.6524 24.9164 27.7567 24.8565 28.016L21.7581 25.0999C20.9277 25.5454 18.6961 26.5579 16.4117 27.044C14.8564 28.3563 12.9689 31.6411 12.2196 33.1194V31.236L10.154 33.3017L10.883 31.1145L9.54644 32.2689C9.24265 32.4511 8.5379 32.8156 8.1491 32.8156C8.29489 32.4754 8.57439 32.1068 8.6959 31.9651L6.93401 32.6334C7.13651 32.0461 7.77242 30.75 8.6959 30.264C7.43219 30.75 6.91378 30.8715 6.8125 30.8715Z\" fill=\"white\" />" +
"<defs><linearGradient gradientUnits=\"userSpaceOnUse\" id=\"gj-splash-gradient\" x1=\"23.8612\" x2=\"23.8612\" y1=\"41.2516\" y2=\"-4.41428\">" +
"<stop stop-color=\"" + AccentGradientStop + "\" />" +
"<stop stop-color=\"" + Accent + "\" offset=\"1\" />" +
"</linearGradient></defs></svg>";
}
}
}
24 changes: 22 additions & 2 deletions Grayjay.Desktop.Web/index.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
<!DOCTYPE html>
<html lang="en" style="background-color: #1b1b1b">
<html lang="en" style="background-color: var(--gj-bg-root, #141414)">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="theme-color" content="#141414" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#f5f5f3" media="(prefers-color-scheme: light)" />
<script>
(() => {
const root = document.documentElement;
const source = new URLSearchParams(window.location.search).get('gjStartupTheme') || 'system';
const systemTheme = window.matchMedia?.('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
const theme = source === 'light' ? 'light' : source === 'dark' ? 'dark' : systemTheme;

root.dataset.theme = theme;
root.dataset.themeSource = source === 'light' || source === 'dark' ? source : 'system';
root.style.colorScheme = theme;
})();
</script>
<style id="grayjay-theme-prepaint">
:root { --gj-bg-root: #141414; --gj-bg-sidebar: #1b1b1b; background-color: #141414; color-scheme: dark; }
:root[data-theme="light"] { --gj-bg-root: #f5f5f3; --gj-bg-sidebar: #ecebe7; background-color: #f5f5f3; color-scheme: light; }
:root[data-theme="dark"] { --gj-bg-root: #141414; --gj-bg-sidebar: #1b1b1b; background-color: #141414; color-scheme: dark; }
@media (prefers-color-scheme: light) { :root:not([data-theme]) { --gj-bg-root: #f5f5f3; --gj-bg-sidebar: #ecebe7; background-color: #f5f5f3; color-scheme: light; } }
html, body, #root { background-color: var(--gj-bg-root); }
</style>
<link rel="shortcut icon" type="image/png" href="/src/assets/favicon.png" />
<link rel="stylesheet" href="/src/assets/fonts/inter/inter.css" />
<link rel="stylesheet" href="/src/assets/fonts/sen/sen.css" />
Expand Down
2 changes: 1 addition & 1 deletion Grayjay.Desktop.Web/src/assets/icons/icon_nav_settings.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading