feat: add cyan-orange color scheme with enhanced visual effects

- Add new CSS animations (hologramGlow, float, shimmer, scanline)
- Introduce cyan and orange color palette variants
- Update scrollbar styling with orange theme colors
- Modify player components with new gradient backgrounds
- Update global theme colors and surface styling
- Adjust default settings for enhanced visual experience
This commit is contained in:
Ante Budimir 2025-11-15 21:17:54 +02:00
parent 7a12e4657f
commit 228fc8e82b
12 changed files with 261 additions and 40 deletions

View file

@ -22,7 +22,10 @@
aspect-ratio: 1/1;
overflow: hidden;
background: var(--theme-card-default-bg);
border-radius: var(--theme-card-poster-radius);
border-radius: var(--theme-radius-md);
border: 2px solid var(--theme-orange-transparent-40);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--theme-shadow-orange-glow-soft);
&::before {
position: absolute;
@ -39,6 +42,14 @@
}
&:hover {
border-color: var(--theme-orange-transparent-70);
box-shadow:
var(--theme-shadow-orange-glow-medium),
0 0 5px var(--theme-orange-transparent-30),
0 0 5px var(--theme-orange-transparent-20);
transform: scale(1.03);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&::before {
opacity: 0.5;
}

View file

@ -23,6 +23,10 @@
display: flex;
grid-area: image;
align-items: flex-end;
img {
border-radius: var(--theme-radius-md);
}
}
.info-column {

View file

@ -3,6 +3,8 @@
z-index: 190;
width: 100%;
height: 65px;
border-bottom: 2px solid var(--theme-orange-transparent-30);
box-shadow: 0 4px 12px var(--theme-orange-transparent-10);
}
.header {

View file

@ -25,6 +25,11 @@
align-items: center;
aspect-ratio: 1/1;
overflow: hidden;
border-radius: var(--theme-radius-md);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: var(--theme-card-default-bg);
border: 2px solid var(--theme-orange-transparent-40);
box-shadow: var(--theme-shadow-orange-glow-soft);
&::before {
position: absolute;
@ -41,6 +46,13 @@
}
&:hover {
border-color: var(--theme-orange-transparent-70);
box-shadow:
var(--theme-shadow-orange-glow-medium),
0 0 5px var(--theme-orange-transparent-30),
0 0 5px var(--theme-orange-transparent-20);
transform: scale(1.03);
&::before {
opacity: 0.5;
}
@ -72,7 +84,6 @@
height: 100% !important;
max-height: 100%;
border: 0;
border-radius: var(--theme-radius-md);
img {
height: 100%;

View file

@ -38,3 +38,30 @@
background: var(--theme-overlay-header);
backdrop-filter: blur(var(--image-blur));
}
.scanline-overlay {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: linear-gradient(
0deg,
transparent 0%,
var(--album-color, rgba(0, 255, 255, 0.15)) 50%,
transparent 100%
);
background-size: 100% 200%;
animation: scanline 6s linear infinite;
pointer-events: none;
}
@keyframes scanline {
0% {
background-position: 0 -100vh;
}
100% {
background-position: 0 100vh;
}
}

View file

@ -428,6 +428,9 @@ export const FullScreenPlayer = () => {
srcLoaded: true,
});
// Convert RGB to RGB with opacity for scanline effect
const scanlineColor = background ? background.replace('rgb', 'rgba').replace(')', ', 0.15)') : 'rgba(0, 255, 255, 0.15)';
const imageUrl = currentSong?.imageUrl && currentSong.imageUrl.replace(/size=\d+/g, 'size=500');
const backgroundImage =
imageUrl && dynamicIsImage
@ -457,6 +460,14 @@ export const FullScreenPlayer = () => {
}
/>
)}
<div
className={styles.scanlineOverlay}
style={
{
'--album-color': scanlineColor,
} as CSSProperties
}
/>
<div className={styles.responsiveContainer}>
<FullScreenPlayerImage />
<FullScreenPlayerQueue />

View file

@ -12,13 +12,20 @@
width: 100%;
padding: 0.5rem;
overflow: visible;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
button {
display: flex;
}
&:focus-visible {
outline: 1px var(--theme-colors-primary-filled) solid;
outline: 2px var(--theme-orange-base) solid;
box-shadow: var(--theme-shadow-orange-glow-soft);
}
&:hover {
transform: scale(1.1);
filter: drop-shadow(0 0 8px var(--theme-orange-transparent-40));
}
&:disabled {
@ -32,13 +39,21 @@
.player-button.active {
svg {
fill: var(--theme-colors-primary-filled);
fill: var(--theme-orange-base);
filter: drop-shadow(0 0 6px var(--theme-orange-transparent-50));
}
}
.main {
background: var(--theme-colors-foreground) !important;
background: linear-gradient(135deg, var(--theme-orange-base), var(--theme-orange-medium)) !important;
border-radius: 50%;
box-shadow: var(--theme-shadow-orange-glow-soft);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
box-shadow: var(--theme-shadow-orange-glow-medium);
transform: scale(1.15);
}
svg {
display: flex;

View file

@ -1,7 +1,13 @@
.container {
width: 100vw;
height: 100%;
border-top: var(--theme-colors-border);
border-top: 2px solid var(--theme-orange-transparent-40);
background: linear-gradient(
180deg,
var(--theme-colors-background) 0%,
rgba(2, 26, 26, 0.95) 100%
);
box-shadow: 0 -4px 12px var(--theme-orange-transparent-15);
}
.controls-grid {

View file

@ -530,51 +530,51 @@ const initialState: SettingsState = {
font: {
builtIn: 'Poppins',
custom: null,
system: null,
type: FontType.BUILT_IN,
system: 'Noto Sans Regular',
type: FontType.SYSTEM,
},
general: {
accent: 'rgb(53, 116, 252)',
accent: 'rgb(214, 46, 83)',
albumArtRes: undefined,
albumBackground: false,
albumBackgroundBlur: 6,
albumBackground: true,
albumBackgroundBlur: 50,
artistBackground: false,
artistBackgroundBlur: 6,
artistItems,
buttonSize: 15,
buttonSize: 25,
disabledContextMenu: {},
doubleClickQueueAll: true,
doubleClickQueueAll: false,
externalLinks: true,
followSystemTheme: false,
genreTarget: GenreTarget.TRACK,
genreTarget: GenreTarget.ALBUM,
homeFeature: true,
homeItems,
language: 'en',
lastFM: true,
lastfmApiKey: '',
musicBrainz: true,
nativeAspectRatio: false,
nativeAspectRatio: true,
passwordStore: undefined,
playButtonBehavior: Play.NOW,
playerbarOpenDrawer: false,
resume: true,
showQueueDrawerButton: false,
showQueueDrawerButton: true,
sidebarCollapsedNavigation: true,
sidebarCollapseShared: false,
sidebarItems,
sidebarPlaylistList: true,
sideQueueType: 'sideQueue',
sideQueueType: 'sideDrawerQueue',
skipButtons: {
enabled: false,
enabled: true,
skipBackwardSeconds: 5,
skipForwardSeconds: 10,
skipForwardSeconds: 5,
},
theme: AppTheme.DEFAULT_DARK,
themeDark: AppTheme.DEFAULT_DARK,
themeLight: AppTheme.DEFAULT_LIGHT,
volumeWheelStep: 5,
volumeWidth: 70,
zoomFactor: 100,
volumeWidth: 200,
zoomFactor: 145,
},
hotkeys: {
bindings: {
@ -620,7 +620,7 @@ const initialState: SettingsState = {
delayMs: 0,
enableAutoTranslation: false,
enableNeteaseTranslation: false,
fetch: false,
fetch: true,
follow: true,
fontSize: 24,
fontSizeUnsync: 24,
@ -636,8 +636,8 @@ const initialState: SettingsState = {
},
playback: {
audioDeviceId: undefined,
crossfadeDuration: 5,
crossfadeStyle: CrossfadeStyle.EQUALPOWER,
crossfadeDuration: 75,
crossfadeStyle: CrossfadeStyle.DIPPED,
mediaSession: false,
mpvExtraParameters: [],
mpvProperties: {
@ -666,7 +666,7 @@ const initialState: SettingsState = {
webAudio: true,
},
remote: {
enabled: false,
enabled: true,
password: randomString(8),
port: 4333,
username: 'feishin',

View file

@ -33,6 +33,48 @@ html {
background: var(--theme-colors-background);
}
body::before,
html::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
105deg,
transparent 40%,
rgba(0, 183, 255, 0.1) 45%,
rgba(0, 183, 255, 0.2) 50%,
rgba(0, 183, 255, 0.1) 55%,
transparent 60%
);
background-size: 200% 100%;
animation: shimmer 8s infinite;
pointer-events: none;
z-index: 1;
}
body::after,
html::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
0deg,
transparent 0%,
rgba(0, 255, 255, 0.03) 50%,
transparent 100%
);
background-size: 100% 200%;
animation: scanline 6s linear infinite;
pointer-events: none;
z-index: 2;
}
input,
button,
textarea,
@ -59,6 +101,8 @@ img {
#app {
height: inherit;
position: relative;
z-index: 10;
}
::-webkit-scrollbar {
@ -120,6 +164,50 @@ button {
}
}
@keyframes hologramGlow {
0%,
100% {
box-shadow:
0 0 10px rgba(0, 183, 255, 0.2),
0 0 20px rgba(0, 183, 255, 0.1),
0 0 40px rgba(0, 255, 255, 0.05);
}
50% {
box-shadow:
0 0 20px rgba(0, 183, 255, 0.4),
0 0 40px rgba(0, 183, 255, 0.2),
0 0 80px rgba(0, 255, 255, 0.1);
}
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
@keyframes shimmer {
0% {
background-position: -100% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes scanline {
0% {
background-position: 0 -100vh;
}
100% {
background-position: 0 100vh;
}
}
@font-face {
font-family: Archivo;
font-weight: 100 1000;
@ -224,6 +312,51 @@ button {
:root {
--theme-background-noise: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIj48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iLjc1IiBzdGl0Y2hUaWxlcz0ic3RpdGNoIi8+PGZlQ29sb3JNYXRyaXggdHlwZT0ic2F0dXJhdGUiIHZhbHVlcz0iMCIvPjwvZmlsdGVyPjxwYXRoIGZpbHRlcj0idXJsKCNhKSIgb3BhY2l0eT0iLjA1IiBkPSJNMCAwaDMwMHYzMDBIMHoiLz48L3N2Zz4=');
--theme-fullscreen-player-text-shadow: black 0px 0px 10px;
/* Intro-inspired color palette */
--theme-orange-base: rgb(255, 142, 83);
--theme-orange-medium: rgb(255, 123, 52);
--theme-orange-dark: rgb(255, 89, 0);
--theme-orange-transparent-70: rgba(255, 142, 83, 0.7);
--theme-orange-transparent-40: rgba(255, 142, 83, 0.4);
--theme-orange-transparent-30: rgba(255, 142, 83, 0.3);
--theme-orange-transparent-20: rgba(255, 142, 83, 0.2);
--theme-orange-transparent-15: rgba(255, 142, 83, 0.15);
--theme-orange-transparent-10: rgba(255, 142, 83, 0.1);
--theme-cyan-primary: rgb(0, 183, 255);
--theme-cyan-secondary: rgb(0, 255, 255);
--theme-cyan-transparent-80: rgba(0, 183, 255, 0.8);
--theme-cyan-transparent-70: rgba(0, 183, 255, 0.7);
--theme-cyan-transparent-60: rgba(0, 183, 255, 0.6);
--theme-cyan-transparent-50: rgba(0, 183, 255, 0.5);
--theme-cyan-transparent-40: rgba(0, 183, 255, 0.4);
--theme-cyan-transparent-30: rgba(0, 183, 255, 0.3);
--theme-cyan-transparent-20: rgba(0, 183, 255, 0.2);
--theme-cyan-transparent-10: rgba(0, 183, 255, 0.1);
--theme-cyan-transparent-05: rgba(0, 183, 255, 0.05);
--theme-cyan-transparent-03: rgba(0, 183, 255, 0.03);
/* Gradients */
--theme-primary-gradient: linear-gradient(
45deg,
var(--theme-orange-dark),
var(--theme-orange-medium),
var(--theme-orange-base)
);
--theme-cyan-gradient: linear-gradient(
90deg,
var(--theme-cyan-primary),
var(--theme-cyan-secondary)
);
/* Shadows */
--theme-shadow-cyan-glow: 0 0 10px var(--theme-cyan-transparent-30);
--theme-shadow-cyan-glow-medium: 0 0 15px var(--theme-cyan-transparent-20);
--theme-shadow-orange-glow-soft: 0 4px 12px var(--theme-orange-transparent-15);
--theme-shadow-orange-glow-medium:
0 6px 20px var(--theme-orange-transparent-30), 0 0 20px var(--theme-orange-transparent-20);
--theme-text-shadow-cyan: 0 0 20px var(--theme-cyan-transparent-30);
--theme-font-size-xs: var(--mantine-font-size-xs);
--theme-font-size-sm: var(--mantine-font-size-sm);
--theme-font-size-md: var(--mantine-font-size-md);

View file

@ -7,10 +7,10 @@ export const defaultTheme: AppThemeConfiguration = {
'overlay-subheader':
'linear-gradient(180deg, rgb(0 0 0 / 5%) 0%, var(--theme-colors-background) 100%), var(--theme-background-noise)',
'root-font-size': '16px',
'scrollbar-handle-active-background': 'rgba(160, 160, 160, 60%)',
'scrollbar-handle-background': 'rgba(160, 160, 160, 30%)',
'scrollbar-handle-border-radius': '0px',
'scrollbar-handle-hover-background': 'rgba(160, 160, 160, 60%)',
'scrollbar-handle-active-background': 'rgba(255, 142, 83, 0.7)',
'scrollbar-handle-background': 'rgba(255, 142, 83, 0.4)',
'scrollbar-handle-border-radius': '0.3rem',
'scrollbar-handle-hover-background': 'rgba(255, 142, 83, 0.9)',
'scrollbar-size': '12px',
'scrollbar-track-active-background': 'transparent',
'scrollbar-track-background': 'transparent',
@ -18,17 +18,18 @@ export const defaultTheme: AppThemeConfiguration = {
'scrollbar-track-hover-background': 'transparent',
},
colors: {
background: 'rgb(16, 16, 16)',
'background-alternate': 'rgb(0, 0, 0)',
background: 'rgb(2, 26, 26)',
'background-alternate': 'rgb(19, 16, 16)',
black: 'rgb(0, 0, 0)',
foreground: 'rgb(225, 225, 225)',
'foreground-muted': 'rgb(150, 150, 150)',
'state-error': 'rgb(204, 50, 50)',
'state-info': 'rgb(53, 116, 252)',
'state-success': 'rgb(50, 204, 50)',
'state-warning': 'rgb(255, 120, 120)',
surface: 'rgb(24, 24, 24)',
'surface-foreground': 'rgb(215, 215, 215)',
foreground: 'rgb(240, 240, 240)',
'foreground-muted': 'rgb(187, 187, 187)',
primary: 'rgb(255, 142, 83)',
'state-error': 'rgb(255, 0, 0)',
'state-info': 'rgb(0, 183, 255)',
'state-success': 'rgb(0, 255, 255)',
'state-warning': 'rgb(255, 142, 83)',
surface: 'rgba(2, 26, 26, 0.8)',
'surface-foreground': 'rgb(240, 240, 240)',
white: 'rgb(255, 255, 255)',
},
mode: 'dark',