Migrate to Mantine v8 and Design Changes (#961)

* mantine v8 migration

* various design changes and improvements
This commit is contained in:
Jeff 2025-06-24 00:04:36 -07:00 committed by GitHub
parent bea55d48a8
commit c1330d92b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
473 changed files with 12469 additions and 11607 deletions

View file

@ -1,2 +0,0 @@
body[data-theme='defaultDark'] {
}

View file

@ -1,203 +0,0 @@
:root {
--root-font-size: 13px;
--icon-color: rgb(255, 255, 255);
--primary-color: rgb(53, 116, 252);
--secondary-color: rgb(255, 120, 120);
--success-color: green;
--warning-color: orange;
--danger-color: rgb(204, 50, 50);
--generic-border-color: rgba(50, 50, 50, 30%);
--main-bg: rgb(18, 18, 18);
--main-bg-transparent: 18, 18, 18;
--main-fg: rgb(225, 225, 225);
--main-fg-secondary: rgb(150, 150, 150);
--window-bar-bg: rgb(16, 16, 16);
--window-bar-fg: rgb(255, 255, 255);
--titlebar-fg: rgb(255, 255, 255);
--titlebar-bg: rgb(12, 12, 12);
--titlebar-controls-bg: rgba(0, 0, 0, 0%);
--sidebar-bg: rgb(0, 0, 0);
--sidebar-bg-hover: rgb(50, 50, 50);
--sidebar-fg: rgb(230, 230, 230);
--sidebar-fg-hover: rgb(255, 255, 255);
--sidebar-handle-bg: #4d4d4d;
--sidebar-border: 2px rgba(18, 18, 18, 70%) solid;
--playerbar-bg: rgb(16, 16, 16);
--playerbar-bg-active: rgb(11, 11, 11);
--playerbar-btn-main-fg: rgb(0, 0, 0);
--playerbar-btn-main-fg-hover: rgb(0, 0, 0);
--playerbar-btn-main-bg: rgb(230, 230, 230);
--playerbar-btn-main-bg-hover: rgb(255, 255, 255);
--playerbar-btn-fg: rgba(200, 200, 200, 80%);
--playerbar-btn-fg-hover: rgba(255, 255, 255, 100%);
--playerbar-btn-bg: #c5c5c5;
--playerbar-btn-bg-hover: transparent;
--playerbar-border-top: 1px rgba(50, 50, 50, 30%) solid;
--playerbar-slider-track-bg: #3c3f43;
--playerbar-slider-track-progress-bg: #ccc;
--tooltip-bg: #fff;
--tooltip-fg: #000;
--scrollbar-size: 12px;
--scrollbar-track-bg: transparent;
--scrollbar-thumb-bg: rgba(160, 160, 160, 30%);
--scrollbar-thumb-bg-hover: rgba(160, 160, 160, 60%);
--btn-filled-bg: var(--primary-color);
--btn-filled-bg-hover: rgb(34, 96, 255);
--btn-filled-fg: #fff;
--btn-filled-fg-hover: #fff;
--btn-filled-border: none;
--btn-filled-radius: 4px;
--btn-default-bg: rgb(31, 31, 32);
--btn-default-bg-hover: rgb(63, 63, 63);
--btn-default-fg: rgb(193, 193, 193);
--btn-default-fg-hover: rgb(193, 193, 193);
--btn-default-border: none;
--btn-default-radius: 2px;
--btn-subtle-bg: transparent;
--btn-subtle-bg-hover: transparent;
--btn-subtle-fg: rgb(220, 220, 220);
--btn-subtle-fg-hover: rgb(255, 255, 255);
--btn-subtle-border: none;
--btn-subtle-radius: 4px;
--btn-outline-bg: transparent;
--btn-outline-bg-hover: transparent;
--btn-outline-fg: rgb(220, 220, 220);
--btn-outline-fg-hover: rgb(255, 255, 255);
--btn-outline-border: 1px rgba(140, 140, 140, 50%) solid;
--btn-outline-border-hover: 1px rgba(255, 255, 255, 50%) solid;
--btn-outline-radius: 5rem;
--input-bg: rgb(35, 35, 35);
--input-fg: rgb(193, 193, 193);
--input-placeholder-fg: rgb(107, 108, 109);
--input-active-fg: rgb(193, 193, 193);
--input-active-bg: rgba(255, 255, 255, 10%);
--dropdown-menu-bg: rgba(32, 32, 32, 95%);
--dropdown-menu-fg: rgb(235, 235, 235);
--dropdown-menu-item-padding: 0.8rem;
--dropdown-menu-item-font-size: 1rem;
--dropdown-menu-bg-hover: rgb(62, 62, 62);
--dropdown-menu-border: 1px var(--generic-border-color) solid;
--dropdown-menu-border-radius: 4px;
--switch-track-bg: rgb(50, 50, 50);
--switch-track-enabled-bg: var(--primary-color);
--switch-thumb-bg: rgb(255, 255, 255);
--slider-track-bg: rgb(50, 50, 50);
--slider-thumb-bg: rgb(255, 255, 255);
--skeleton-bg: rgba(255, 255, 255, 8%);
--toast-title-fg: rgb(255, 255, 255);
--toast-description-fg: rgb(193, 194, 197);
--toast-bg: rgb(16, 16, 16);
--modal-bg: var(--main-bg);
--modal-header-bg: var(--paper-bg);
--badge-bg: rgb(80, 80, 80);
--badge-fg: rgb(255, 255, 255);
--badge-radius: 12px;
--paper-bg: rgb(20, 20, 20);
--placeholder-bg: rgba(53, 53, 53, 100%);
--placeholder-fg: rgba(126, 126, 126);
--card-default-bg: rgb(32, 32, 32);
--card-default-bg-hover: rgb(44, 44, 44);
--card-default-radius: 5px;
--card-poster-bg: transparent;
--card-poster-bg-hover: transparent;
--card-poster-radius: 3px;
--background-noise: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIj48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iLjc1IiBzdGl0Y2hUaWxlcz0ic3RpdGNoIi8+PGZlQ29sb3JNYXRyaXggdHlwZT0ic2F0dXJhdGUiIHZhbHVlcz0iMCIvPjwvZmlsdGVyPjxwYXRoIGZpbHRlcj0idXJsKCNhKSIgb3BhY2l0eT0iLjA1IiBkPSJNMCAwaDMwMHYzMDBIMHoiLz48L3N2Zz4=');
--current-song-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2aWV3Qm94PSIxMDAgMTMwIDU3IDgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxyZWN0IHg9IjEwMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iMjAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMDZweCAxNDBweDsiLz4KICA8cmVjdCB4PSIxMTUiIHk9IjEzMCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjYwIiBzdHlsZT0iZmlsbDogcmdiKDIxNiwgMjE2LCAyMTYpOyBzdHJva2U6IHJnYigwLCAwLCAwKTsgdHJhbnNmb3JtLW9yaWdpbjogMTIxcHggMTYwcHg7Ii8+CiAgPHJlY3QgeD0iMTMwIiB5PSIxMzAiIHdpZHRoPSIxMiIgaGVpZ2h0PSI4MCIgc3R5bGU9ImZpbGw6IHJnYigyMTYsIDIxNiwgMjE2KTsgc3Ryb2tlOiByZ2IoMCwgMCwgMCk7IHRyYW5zZm9ybS1vcmlnaW46IDEzNnB4IDE3MHB4OyIvPgogIDxyZWN0IHg9IjE0NSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iNDUiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxNTFweCAxNTIuNXB4OyIvPgo8L3N2Zz4=');
--current-song-image-animated: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2aWV3Qm94PSIxMDAgMTMwIDU3IDgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxyZWN0IHg9IjEwMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMDZweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjgwOzE1OzgwIiBiZWdpbj0iMC4xcyIgZHVyPSIwLjk1cyIga2V5VGltZXM9IjA7IDAuNDczNjg7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQyIDAgMC41OCAxOyAwLjQyIDAgMC41OCAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjExNSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMjFweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjI1OzgwOzI1IiBiZWdpbj0iMC4xcyIgZHVyPSIwLjk1cyIga2V5VGltZXM9IjA7IDAuNDQ0NDQ7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQ1IDAgMC41NSAxOyAwLjQ1IDAgMC41NSAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjEzMCIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxMzZweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjgwOzEwOzgwIiBiZWdpbj0iMC4xcyIgZHVyPSIwLjg1cyIga2V5VGltZXM9IjA7IDAuNDIxMDU7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjY1IDAgMC4zNSAxOyAwLjY1IDAgMC4zNSAxIi8+CiAgPC9yZWN0PgogIDxyZWN0IHg9IjE0NSIgeT0iMTMwIiB3aWR0aD0iMTIiIGhlaWdodD0iODAiIHN0eWxlPSJmaWxsOiByZ2IoMjE2LCAyMTYsIDIxNik7IHN0cm9rZTogcmdiKDAsIDAsIDApOyB0cmFuc2Zvcm0tb3JpZ2luOiAxNTFweCAxNzBweDsiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iaGVpZ2h0IiB2YWx1ZXM9IjMwOzgwOzMwIiBiZWdpbj0iMC4xcyIgZHVyPSIxLjA1cyIga2V5VGltZXM9IjA7IDAuMzE1Nzk7IDEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBjYWxjTW9kZT0ic3BsaW5lIiBrZXlTcGxpbmVzPSIwLjQyIDAgMC41OCAxOyAwLjQyIDAgMC41OCAxIi8+CiAgPC9yZWN0Pgo8L3N2Zz4=');
--bg-header-overlay: linear-gradient(transparent 0%, rgba(0, 0, 0, 75%) 100%),
var(--background-noise);
--bg-subheader-overlay: linear-gradient(180deg, rgba(0, 0, 0, 5%) 0%, var(--main-bg) 100%),
var(--background-noise);
--table-header-bg: rgb(24, 24, 24);
--table-header-fg: rgb(179, 179, 179);
--table-border: none;
--table-border-color: hsla(0deg, 0%, 100%, 10%);
--table-bg: var(--main-bg);
--table-alt-bg: var(--main-bg);
--table-fg: rgb(179, 179, 179);
--table-row-hover-bg: rgba(100, 100, 100, 20%);
--table-row-selected-bg: rgba(100, 100, 100, 40%);
--fullscreen-player-text-shadow: black 0px 0px 10px;
.ag-theme-alpine-dark {
--ag-font-family: var(--content-font-family);
--ag-borders: var(--table-border);
--ag-border-color: var(--table-border-color);
--ag-header-background-color: var(--table-header-bg);
--ag-header-foreground-color: var(--table-header-fg);
--ag-background-color: var(--table-bg);
--ag-odd-row-background-color: var(--table-alt-bg);
--ag-foreground-color: var(--table-fg);
--ag-row-hover-color: var(--table-row-hover-bg);
--ag-selected-row-background-color: var(--table-row-selected-bg);
--ag-cell-horizontal-padding: 0.5rem;
}
.ag-header {
border-bottom: 2px solid var(--table-border-color);
}
.ag-ltr .ag-header-cell-resize {
right: 0;
}
.ag-header:hover .ag-header-cell-resize {
position: absolute;
top: 25%;
width: 0.2em;
height: 50%;
border: 1px var(--table-border-color) solid;
}
.ag-header-cell-label {
font-weight: 500;
font-family: var(--content-font-family);
text-transform: uppercase;
}
.ag-cell-rating,
.ag-cell-favorite {
display: none;
}
.ag-cell-transparent {
opacity: 0;
}
.ag-cell-rating.visible {
display: block;
}
.ag-cell-favorite.visible {
display: block;
}
.ag-row-hover {
.ag-cell-transparent {
opacity: 1;
}
.ag-cell-rating,
.ag-cell-favorite {
display: block;
}
}
.ag-cell-focus {
border: 1px var(--table-border-color) solid !important;
}
.current-song {
background: var(--table-row-hover-bg);
box-shadow: inset 0 0 0 100vmax rgba(0, 0, 0, 0.3);
.current-song-child {
color: var(--primary-color) !important;
font-weight: 800;
}
}
.current-song > .row-index.playing .current-song-index {
display: none;
}
}

View file

@ -1,133 +0,0 @@
body[data-theme='defaultLight'] {
--icon-color: #fff;
--main-bg: rgb(255, 255, 255);
--main-bg-transparent: 255, 255, 255;
--main-fg: rgb(25, 25, 25);
--main-fg-secondary: rgb(80, 80, 80);
--window-bar-bg: rgb(255, 255, 255);
--window-bar-fg: rgb(16, 16, 16);
--titlebar-fg: rgb(25, 25, 25);
--titlebar-bg: rgb(240, 241, 242);
--titlebar-controls-bg: rgba(0, 0, 0, 0%);
--sidebar-bg: rgb(240, 241, 242);
--sidebar-bg-hover: rgb(200, 200, 200);
--sidebar-fg: rgb(0, 0, 0);
--sidebar-fg-hover: rgb(85, 85, 85);
--sidebar-handle-bg: rgb(220, 220, 220);
--sidebar-border: 1px rgba(220, 220, 220, 70%) solid;
--playerbar-bg: rgb(220, 220, 220);
--playerbar-bg-active: rgb(175, 175, 175);
--playerbar-btn-main-fg: rgb(0, 0, 0);
--playerbar-btn-main-fg-hover: rgb(0, 0, 0);
--playerbar-btn-main-bg: transparent;
--playerbar-btn-main-bg-hover: transparent;
--playerbar-btn-fg: #000;
--playerbar-btn-fg-hover: #000;
--playerbar-btn-bg: transparent;
--playerbar-btn-bg-hover: transparent;
--playerbar-border-top: 1px rgba(200, 200, 200, 70%) solid;
--playerbar-slider-track-bg: rgba(50, 50, 50, 20%);
--playerbar-slider-track-progress-bg: rgb(50, 50, 50);
--tooltip-bg: rgb(255, 255, 255);
--tooltip-fg: rgb(0, 0, 0);
--scrollbar-track-bg: transparent;
--scrollbar-thumb-bg: rgba(140, 140, 140, 30%);
--scrollbar-thumb-bg-hover: rgba(140, 140, 140, 60%);
--btn-filled-bg: var(--primary-color);
--btn-filled-fg: #fff;
--btn-filled-fg-hover: #fff;
--btn-default-bg: rgb(220, 220, 220);
--btn-default-bg-hover: rgb(210, 210, 210);
--btn-default-fg: rgb(50, 50, 50);
--btn-default-fg-hover: rgb(50, 50, 50);
--btn-subtle-bg: transparent;
--btn-subtle-bg-hover: transparent;
--btn-subtle-fg: rgb(80, 80, 80);
--btn-subtle-fg-hover: rgb(0, 0, 0);
--btn-outline-bg: transparent;
--btn-outline-bg-hover: transparent;
--btn-outline-fg: rgb(60, 60, 60);
--btn-outline-fg-hover: rgb(0, 0, 0);
--btn-outline-border: 1px rgba(140, 140, 140, 50%) solid;
--btn-outline-border-hover: 1px rgba(255, 255, 255, 50%) solid;
--btn-outline-radius: 5rem;
--input-bg: rgb(240, 241, 242);
--input-fg: rgb(0, 0, 0);
--input-placeholder-fg: rgb(119, 126, 139);
--input-active-fg: rgb(193, 193, 193);
--input-active-bg: rgba(37, 38, 43, 30%);
--dropdown-menu-bg: rgb(255, 255, 255);
--dropdown-menu-fg: rgb(0, 0, 0);
--dropdown-menu-bg-hover: rgba(0, 0, 0, 10%);
--dropdown-menu-border: 1px rgba(150, 150, 150, 70%) solid;
--dropdown-menu-border-radius: 4px;
--switch-track-bg: rgb(114, 118, 125);
--switch-track-enabled-bg: var(--primary-color);
--switch-thumb-bg: rgb(255, 255, 255);
--slider-track-bg: rgba(50, 50, 50, 10%);
--slider-thumb-bg: rgb(100, 100, 100);
--skeleton-bg: rgba(50, 50, 50, 8%);
--toast-title-fg: rgb(255, 255, 255);
--toast-description-fg: rgb(193, 194, 197);
--toast-bg: rgb(16, 16, 16);
--modal-bg: rgb(255, 255, 255);
--modal-header-bg: var(--paper-bg);
--paper-bg: rgb(240, 240, 240);
--placeholder-bg: rgba(204, 204, 204, 50%);
--placeholder-fg: rgb(126, 126, 126);
--card-default-bg: rgba(235, 235, 235, 50%);
--card-default-bg-hover: rgba(200, 200, 200, 80%);
--card-default-radius: 10px;
--card-poster-bg: transparent;
--card-poster-bg-hover: transparent;
--card-poster-radius: 5px;
--bg-header-overlay: linear-gradient(rgba(255, 255, 255, 50%) 0%, rgba(255, 255, 255, 20%)),
var(--background-noise);
--bg-subheader-overlay: linear-gradient(180deg, rgba(255, 255, 255, 5%) 0%, var(--main-bg)),
var(--background-noise);
--table-header-bg: rgb(245, 245, 245);
--table-header-fg: rgb(40, 40, 40);
--table-border: none;
--table-border-color: rgba(50, 50, 50, 30%);
--table-bg: var(--main-bg);
--table-alt-bg: var(--main-bg);
--table-fg: rgb(179, 179, 179);
--table-row-hover-bg: rgba(150, 150, 150, 20%);
--table-row-selected-bg: rgba(150, 150, 150, 30%);
--fullscreen-player-text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
.ag-theme-alpine-dark {
--ag-font-family: var(--content-font-family);
--ag-borders: var(--table-border);
--ag-border-color: rgb(50, 50, 50);
--ag-header-background-color: var(--table-header-bg);
--ag-header-foreground-color: var(--table-header-fg);
--ag-background-color: var(--table-bg);
--ag-odd-row-background-color: var(--table-alt-bg);
--ag-foreground-color: var(--table-fg);
--ag-row-hover-color: var(--table-row-hover-bg);
--ag-selected-row-background-color: var(--table-row-selected-bg);
}
.ag-root ::-webkit-scrollbar-corner {
background: var(--scrollbar-track-bg);
}
.ag-root ::-webkit-scrollbar-track-piece {
background: var(--scrollbar-track-bg);
}
.ag-root ::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb-bg);
}
.current-song {
background: var(--table-row-hover-bg);
box-shadow: inset 0 0 0 100vmax rgba(255, 255, 255, 0.3);
.current-song-child {
color: var(--primary-color) !important;
font-weight: 800;
}
}
}

View file

@ -0,0 +1,143 @@
import type { MantineColorsTuple, MantineThemeOverride } from '@mantine/core';
import { generateColors } from '@mantine/colors-generator';
import { createTheme, rem } from '@mantine/core';
import merge from 'lodash/merge';
import { AppThemeConfiguration } from '/@/shared/themes/app-theme-types';
// const lightColors: MantineColorsTuple = [
// '#f5f5f5',
// '#e7e7e7',
// '#cdcdcd',
// '#b2b2b2',
// '#9a9a9a',
// '#8b8b8b',
// '#848484',
// '#717171',
// '#656565',
// '#575757',
// ];
const darkColors: MantineColorsTuple = [
'#C9C9C9',
'#b8b8b8',
'#828282',
'#696969',
'#424242',
'#3b3b3b',
'#242424',
'#181818',
'#1f1f21',
'#141414',
];
const mantineTheme: MantineThemeOverride = createTheme({
autoContrast: true,
breakpoints: {
'2xl': '120em',
'3xl': '160em',
lg: '75em',
md: '62em',
sm: '48em',
xl: '88em',
xs: '36em',
},
cursorType: 'pointer',
defaultRadius: 'sm',
focusRing: 'never',
fontFamily: 'var(--theme-content-font-family)',
fontSizes: {
'2xl': rem('20px'),
'3xl': rem('24px'),
'4xl': rem('28px'),
'5xl': rem('32px'),
lg: rem('16px'),
md: rem('13px'),
sm: rem('12px'),
xl: rem('18px'),
xs: rem('10px'),
},
fontSmoothing: true,
headings: {
fontFamily: 'var(--theme-content-font-family)',
sizes: {
h1: {
fontSize: rem('36px'),
fontWeight: '600',
lineHeight: rem('44px'),
},
h2: {
fontSize: rem('30px'),
fontWeight: '600',
lineHeight: rem('38px'),
},
h3: {
fontSize: rem('24px'),
fontWeight: '600',
lineHeight: rem('32px'),
},
h4: {
fontSize: rem('20px'),
fontWeight: '600',
lineHeight: rem('30px'),
},
},
},
lineHeights: {
lg: rem('20px'),
md: rem('18px'),
sm: rem('16px'),
xl: rem('24px'),
xs: rem('14px'),
},
luminanceThreshold: 0.3,
primaryColor: 'primary',
primaryShade: { dark: 5, light: 9 },
radius: {
lg: rem('12px'),
md: rem('5px'),
sm: rem('3px'),
xl: rem('16px'),
xs: rem('3px'),
},
scale: 1,
shadows: {
lg: '0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05)',
md: '0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)',
sm: '0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06)',
xl: '0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04)',
xs: '0 1px 2px rgba(0, 0, 0, 0.05)',
xxl: '0 25px 50px rgba(0, 0, 0, 0.25)',
},
spacing: {
'0': rem('0px'),
'2xl': rem('32px'),
'3xl': rem('36px'),
'4xl': rem('40px'),
lg: rem('16px'),
md: rem('12px'),
sm: rem('8px'),
xl: rem('24px'),
xs: rem('4px'),
},
});
export function createMantineTheme(theme: AppThemeConfiguration): MantineThemeOverride {
const primaryColor = theme.colors?.primary ?? '#000';
const mergedTheme: MantineThemeOverride = merge(
{},
{
...mantineTheme,
black: theme.colors?.black,
colors: {
dark: darkColors,
primary: generateColors(primaryColor),
},
white: theme.colors?.white,
},
theme.mantineOverride,
);
return createTheme(mergedTheme);
}

View file

@ -0,0 +1,156 @@
import { useMantineColorScheme } from '@mantine/core';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useSettingsStore } from '/@/renderer/store/settings.store';
import { createMantineTheme } from '/@/renderer/themes/mantine-theme';
import { getAppTheme } from '/@/shared/themes/app-theme';
import { AppTheme, AppThemeConfiguration } from '/@/shared/themes/app-theme-types';
import { FontType } from '/@/shared/types/types';
export const THEME_DATA = [
{ label: 'Default Dark', type: 'dark', value: AppTheme.DEFAULT_DARK },
{ label: 'Default Light', type: 'light', value: AppTheme.DEFAULT_LIGHT },
];
export const useAppTheme = () => {
const accent = useSettingsStore((store) => store.general.accent);
const nativeImageAspect = useSettingsStore((store) => store.general.nativeAspectRatio);
const { builtIn, custom, system, type } = useSettingsStore((state) => state.font);
const textStyleRef = useRef<HTMLStyleElement | null>(null);
const getCurrentTheme = () => window.matchMedia('(prefers-color-scheme: dark)').matches;
const [isDarkTheme, setIsDarkTheme] = useState(getCurrentTheme());
const { followSystemTheme, theme, themeDark, themeLight } = useSettingsStore(
(state) => state.general,
);
const mqListener = (e: any) => {
setIsDarkTheme(e.matches);
};
const getSelectedTheme = () => {
if (followSystemTheme) {
return isDarkTheme ? themeDark : themeLight;
}
return theme;
};
const selectedTheme = getSelectedTheme();
useEffect(() => {
const darkThemeMq = window.matchMedia('(prefers-color-scheme: dark)');
darkThemeMq.addListener(mqListener);
return () => darkThemeMq.removeListener(mqListener);
}, []);
useEffect(() => {
if (type === FontType.SYSTEM && system) {
const root = document.documentElement;
root.style.setProperty('--theme-content-font-family', 'dynamic-font');
if (!textStyleRef.current) {
textStyleRef.current = document.createElement('style');
document.body.appendChild(textStyleRef.current);
}
textStyleRef.current.textContent = `
@font-face {
font-family: "dynamic-font";
src: local("${system}");
}`;
} else if (type === FontType.CUSTOM && custom) {
const root = document.documentElement;
root.style.setProperty('--theme-content-font-family', 'dynamic-font');
if (!textStyleRef.current) {
textStyleRef.current = document.createElement('style');
document.body.appendChild(textStyleRef.current);
}
textStyleRef.current.textContent = `
@font-face {
font-family: "dynamic-font";
src: url("feishin://${custom}");
}`;
} else {
const root = document.documentElement;
root.style.setProperty('--theme-content-font-family', builtIn);
}
}, [builtIn, custom, system, type]);
const appTheme: AppThemeConfiguration = useMemo(() => {
const themeProperties = getAppTheme(selectedTheme);
return {
...themeProperties,
colors: {
...themeProperties.colors,
primary: accent,
},
};
}, [accent, selectedTheme]);
useEffect(() => {
const root = document.documentElement;
root.style.setProperty('--theme-colors-primary', accent);
}, [accent]);
useEffect(() => {
const root = document.documentElement;
root.style.setProperty('--theme-image-fit', nativeImageAspect ? 'contain' : 'cover');
}, [nativeImageAspect]);
const themeVars = useMemo(() => {
return Object.entries(appTheme?.app ?? {})
.map(([key, value]) => {
return [`--theme-${key}`, value];
})
.filter(Boolean) as [string, string][];
}, [appTheme]);
const colorVars = useMemo(() => {
return Object.entries(appTheme?.colors ?? {})
.map(([key, value]) => {
return [`--theme-colors-${key}`, value];
})
.filter(Boolean) as [string, string][];
}, [appTheme]);
useEffect(() => {
document.documentElement.setAttribute('data-theme', selectedTheme);
if (themeVars.length > 0 || colorVars.length > 0) {
let styleElement = document.getElementById('theme-variables');
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.id = 'theme-variables';
document.head.appendChild(styleElement);
}
let cssText = ':root {\n';
for (const [key, value] of themeVars) {
cssText += ` ${key}: ${value};\n`;
}
for (const [key, value] of colorVars) {
cssText += ` ${key}: ${value};\n`;
}
cssText += '}';
styleElement.textContent = cssText;
}
}, [colorVars, selectedTheme, themeVars]);
return {
mode: appTheme?.mode || 'dark',
theme: createMantineTheme(appTheme as AppThemeConfiguration),
};
};
export const useSetColorScheme = () => {
const { setColorScheme } = useMantineColorScheme();
return { setColorScheme };
};