Skip to content

Commit

Permalink
Merge pull request #451 from organization/feature/styling
Browse files Browse the repository at this point in the history
feat(renderer): improve styling
  • Loading branch information
Su-Yong authored Nov 29, 2023
2 parents 39ce08a + e73fd9d commit 6ab3cb5
Show file tree
Hide file tree
Showing 21 changed files with 483 additions and 226 deletions.
4 changes: 3 additions & 1 deletion common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const DEFAULT_STYLE = {
lyric: {
color: '#FFFFFF',
background: 'rgba(29, 29, 29, .70)',
fontSize: 15,
fontSize: 13,
maxWidth: 700,
stoppedOpacity: 0.5,
containerRowGap: 1,
Expand Down Expand Up @@ -74,3 +74,5 @@ export const DEFAULT_CONFIG = {
streamingMode: false,
provider: LyricProviderList[0].provider as 'alsong',
};

export const PRESET_PREFIX = '__preset__';
6 changes: 6 additions & 0 deletions common/intl/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@
"setting.theme.import-from-file": "Import from file",
"setting.theme.export-as-file": "Export as a file",
"setting.theme.import-theme-failed": "Failed to import a theme",
"setting.theme.built-in-themes": "Built-in themes",
"setting.theme.no-available-themes": "Available themes not found.",
"setting.theme.preset.default": "Default Theme",
"setting.theme.preset.album-cover": "Album Cover Theme",
"setting.theme.preset.multiple-lyric": "Lyric Theme",

"setting.user-css-warning.bold": "Achtung!",
"setting.user-css-warning.0": "Bei Verwendung von benutzerdefinierten Styles könnten diese nach einem Update visuelle fehler verursachen",
"setting.user-css-warning.1": "Das Alspotron-Team garantiert die Stabilität der Styles nicht, da benutzerdefinierte Styles eine experimentelle Funktion sind.",
Expand Down
6 changes: 6 additions & 0 deletions common/intl/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@
"setting.theme.import-from-file": "Import from file",
"setting.theme.export-as-file": "Export as a file",
"setting.theme.import-theme-failed": "Failed to import a theme",
"setting.theme.built-in-themes": "Built-in themes",
"setting.theme.no-available-themes": "Available themes not found.",
"setting.theme.preset.default": "Default Theme",
"setting.theme.preset.album-cover": "Album Cover Theme",
"setting.theme.preset.multiple-lyric": "Lyric Theme",

"setting.user-css-warning.bold": "WARNING!",
"setting.user-css-warning.0": "If you're using custom selectors, CSS settings can break after updates.",
"setting.user-css-warning.1": "Custom CSS is an experimental feature. Alspotron Team does not guarantee custom CSS to work after updates.",
Expand Down
6 changes: 6 additions & 0 deletions common/intl/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@
"setting.theme.import-from-file": "Import from file",
"setting.theme.export-as-file": "Export as a file",
"setting.theme.import-theme-failed": "Failed to import a theme",
"setting.theme.built-in-themes": "Built-in themes",
"setting.theme.no-available-themes": "Available themes not found.",
"setting.theme.preset.default": "Default Theme",
"setting.theme.preset.album-cover": "Album Cover Theme",
"setting.theme.preset.multiple-lyric": "Lyric Theme",

"setting.user-css-warning.bold": "注意!",
"setting.user-css-warning.0": "カスタムCSSセレクタを使用している場合、更新後にCSS設定が壊れてしまうことがあります。",
"setting.user-css-warning.1": "カスタムCSSは実験的な機能です。Alspotron Teamはアップデート後のカスタムCSSの動作を保証しません。",
Expand Down
6 changes: 6 additions & 0 deletions common/intl/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@
"setting.theme.import-from-file": "파일로부터 불러오기",
"setting.theme.export-as-file": "파일로 저장하기",
"setting.theme.import-theme-failed": "테마를 불러오지 못하였습니다.",
"setting.theme.built-in-themes": "내장된 테마",
"setting.theme.no-available-themes": "사용 가능한 테마 없음",
"setting.theme.preset.default": "기본 테마",
"setting.theme.preset.album-cover": "앨범 커버 테마",
"setting.theme.preset.multiple-lyric": "가사 테마",

"setting.user-css-warning.bold": "주의!",
"setting.user-css-warning.0": "제공된 셀렉터, 변수 외의 다른 셀렉터 등을 사용하실 경우 업데이트 시 CSS가 깨질 확률이 높습니다.",
"setting.user-css-warning.1": "사용자 CSS는 어디까지나 실험기능으로, Alspotron 팀에서는 업데이트 시 스타일의 안정성을 보장하지 않습니다.",
Expand Down
36 changes: 36 additions & 0 deletions common/presets/album-cover.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"font": "Pretendard Variable",
"fontWeight": "400",
"animation": "pretty",
"animationAtOnce": false,
"maxHeight": 400,
"proximityOpacity": 0,
"proximitySensitivity": 2,
"rowGap": 2,
"nowPlaying": {
"color": "#FFFFFF",
"background": "rgba(29, 29, 29, .50)",
"backgroundProgress": "rgba(29, 29, 29, .80)",
"fontSize": 13,
"maxWidth": 300,
"visible": true,
"stoppedOpacity": 0.5
},
"lyric": {
"color": "#FFFFFF",
"background": "rgba(29, 29, 29, .70)",
"fontSize": 13,
"maxWidth": 700,
"stoppedOpacity": 0.5,
"containerRowGap": 0.25,
"multipleContainerRowGap": 0.75,
"direction": "column",
"nextLyric": 1,
"previousLyric": 1,
"nextLyricScale": 0.9,
"previousLyricScale": 0.9,
"nextLyricOpacity": 0.5,
"previousLyricOpacity": 0.5
},
"userCSS": "alspotron-wrapper {\n min-height: 400px;\n\n flex-flow: row !important;\n gap: 32px;\n \n background: linear-gradient(\n 315deg,\n rgba(0, 0, 0, 0.5) 0%,\n rgba(0, 0, 0, 0) 25%\n );\n\n padding: 32px;\n}\n\nalspotron-lyrics-item {\n border-radius: 8px;\n padding: 4px 8px;\n}\n\n\nalspotron-nowplaying {\n width: 150px;\n height: 150px;\n max-width: 150px;\n\n border-radius: 12px;\n flex-shrink: 0;\n\n position: relative;\n display: inline-flex;\n flex-flow: column;\n justify-content: flex-end;\n align-items: flex-start;\n\n padding: 0;\n}\nalspotron-nowplaying::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n\n background-image: linear-gradient(\n 0deg,\n rgba(0, 0, 0, 0.75) 0%,\n rgba(0, 0, 0, 0.5) 24px,\n rgba(0, 0, 0, 0) 48px\n );\n z-index: 20;\n}\n\n\nalspotron-nowplaying-progress-bar {\n background: none !important;\n z-index: 21;\n}\nalspotron-nowplaying-progress {\n --color: 29, 29, 29;\n\n opacity: 0.75;\n \n background-image: linear-gradient(\n 135deg,\n rgba(var(--color), 1) 0%,\n rgba(var(--color), 1) 25%,\n rgba(var(--color), 0) 25%,\n rgba(var(--color), 0) 50%,\n rgba(var(--color), 1) 50%,\n rgba(var(--color), 1) 75%,\n rgba(var(--color), 0) 75%,\n rgba(var(--color), 0) 100%\n );\n background-size: 24px 24px;\n\n animation: progress 1.5s linear infinite;\n}\n\n@keyframes progress {\n 0% {\n background-position-x: 0;\n }\n 100% {\n background-position-x: 24px;\n }\n}\n\nalspotron-nowplaying-cover {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n z-index: -1;\n\n object-fit: cover;\n border-radius: 12px;\n padding: 4px;\n\n}\n\nalspotron-wrapper--stopped alspotron-nowplaying-cover {\n transform: scale(0.9);\n}\n\nalspotron-nowplaying-playing-text {\n position: relative;\n z-index: 50;\n margin-top: auto;\n padding: 12px 16px;\n overflow: visible !important;\n}\n\nalspotron-marquee {\n z-index: 50;\n}\n"
}
11 changes: 11 additions & 0 deletions common/presets/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import albumCover from './album-cover.json';
import multipleLyric from './multiple-lyric.json';

import { DEFAULT_STYLE } from '../constants';
import { StyleConfig } from '../schema';

export default {
'default': DEFAULT_STYLE,
'album-cover': albumCover,
'multiple-lyric': multipleLyric,
} as Record<string, StyleConfig>;
36 changes: 36 additions & 0 deletions common/presets/multiple-lyric.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"font": "Pretendard Variable",
"fontWeight": "400",
"animation": "fade",
"animationAtOnce": true,
"maxHeight": 400,
"proximityOpacity": 0,
"proximitySensitivity": 2,
"rowGap": 1,
"nowPlaying": {
"color": "#FFFFFF",
"background": "rgba(29, 29, 29, .50)",
"backgroundProgress": "rgba(29, 29, 29, .80)",
"fontSize": 15,
"maxWidth": 600,
"visible": true,
"stoppedOpacity": 0.5
},
"lyric": {
"color": "#FFFFFF",
"background": "rgba(29, 29, 29, .70)",
"fontSize": 12,
"maxWidth": 700,
"stoppedOpacity": 0.5,
"containerRowGap": 0.25,
"multipleContainerRowGap": 1,
"direction": "column",
"nextLyric": 1,
"previousLyric": 1,
"nextLyricScale": 0.9,
"previousLyricScale": 0.9,
"nextLyricOpacity": 0.5,
"previousLyricOpacity": 0.5
},
"userCSS": ""
}
23 changes: 23 additions & 0 deletions renderer/hooks/useClassStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Accessor, createEffect, on, onCleanup, onMount } from 'solid-js';

export const useClassStyle = (className: string, style: Accessor<string>) => {
const stylesheet = new CSSStyleSheet();


onMount(() => {
const isExist = Array.from(document.adoptedStyleSheets).some((adoptedStyleSheet) => adoptedStyleSheet === stylesheet);
if (isExist) return;

document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
})

createEffect(on(style, () => {
stylesheet.replaceSync(`*:is(.${className}) {\n${style()}\n}`);
}));

onCleanup(() => {
document.adoptedStyleSheets = Array.from(document.adoptedStyleSheets).filter((adoptedStyleSheet) => adoptedStyleSheet !== stylesheet);
});

return stylesheet;
};
16 changes: 10 additions & 6 deletions renderer/hooks/useStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { Accessor, createMemo } from 'solid-js';
import useConfig from './useConfig';
import useThemeList from './useThemeList';

import { DEFAULT_STYLE } from '../../common/constants';
import { DEFAULT_STYLE, PRESET_PREFIX } from '../../common/constants';

import presetThemes from '../../common/presets';

import type { StyleConfig } from '../../common/schema';

Expand All @@ -15,11 +17,13 @@ const useStyle = (): Accessor<StyleConfig> => {
const list = themeList();
const configData = config();

return (
list[configData?.selectedTheme ?? '']
// ?? configData?.style
?? DEFAULT_STYLE
);
let result = list[configData?.selectedTheme ?? ''] ?? DEFAULT_STYLE;
if (configData?.selectedTheme.startsWith(PRESET_PREFIX)) {
const name = configData?.selectedTheme.replace(PRESET_PREFIX, '');
result = presetThemes[name] ?? DEFAULT_STYLE;
}

return result;
});

return style;
Expand Down
42 changes: 2 additions & 40 deletions renderer/main/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import Lyrics from './components/Lyrics';
import PlayingInfoProvider from '../components/PlayingInfoProvider';
import UserCSS from '../components/UserCSS';
import useConfig from '../hooks/useConfig';
import { cx } from '../utils/classNames';
import { userCSSSelectors } from '../utils/userCSSSelectors';
import usePluginsCSS from '../hooks/usePluginsCSS';
import useStyle from '../hooks/useStyle';
Expand Down Expand Up @@ -90,54 +89,17 @@ const App = () => {
usePluginsCSS();

const style = useStyle();

const lyricStyle = () => {
let result = '';
const styleData = style();

if (styleData?.nowPlaying.maxWidth) result += `max-width: ${styleData.nowPlaying.maxWidth}px;`;
if (styleData?.nowPlaying.color) result += `color: ${styleData.nowPlaying.color};`;
if (styleData?.nowPlaying.background) result += `background-color: ${styleData.nowPlaying.background};`;
if (styleData?.font) result += `font-family: ${styleData.font};`;
if (styleData?.fontWeight) result += `font-weight: ${styleData.fontWeight};`;

return result;
};

const textStyle = () => {
let result = '';

const styleData = style();
if (styleData?.nowPlaying.fontSize) result += `font-size: ${styleData.nowPlaying.fontSize}px;`;

return result;
};

const progressStyle = () => {
let result = '';

const styleData = style();
if (styleData?.nowPlaying.backgroundProgress) result += `background-color: ${styleData.nowPlaying.backgroundProgress};`;

return result;
};

const proximityHandles = useProximityStyle();

return (
<PlayingInfoProvider>
<AnchoredView
class={cx('flex flex-col', userCSSSelectors.wrapper)}
style={`row-gap: ${style()?.rowGap ?? 2}rem;`}
class={userCSSSelectors.wrapper}
{...proximityHandles}
>
<Lyrics />
<Show when={style().nowPlaying?.visible ?? true}>
<LyricProgressBar
style={lyricStyle()}
textStyle={textStyle()}
progressStyle={progressStyle()}
/>
<LyricProgressBar />
</Show>
</AnchoredView>
<UserCSS />
Expand Down
57 changes: 42 additions & 15 deletions renderer/main/components/AnchoredView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import useConfig from '../../hooks/useConfig';
import useStyle from '../../hooks/useStyle';

import type { JSX } from 'solid-js/jsx-runtime';
import { userCSSSelectors } from '../../utils/userCSSSelectors';
import { usePlayingInfo } from '../../components/PlayingInfoProvider';
import { useClassStyle } from '../../hooks/useClassStyle';

interface AnchoredViewProps extends JSX.HTMLAttributes<HTMLDivElement> {
class?: string;
Expand All @@ -16,30 +19,54 @@ interface AnchoredViewProps extends JSX.HTMLAttributes<HTMLDivElement> {
const AnchoredView = (props: AnchoredViewProps) => {
const [config] = useConfig();
const style = useStyle();
const { status } = usePlayingInfo();

const [, containerProps] = splitProps(
props,
['class', 'style', 'children'],
);

useClassStyle(userCSSSelectors.wrapper, () => {
const anchor = config()?.windowPosition.anchor ?? 'bottom-right';

return `
position: fixed;
${anchor.includes('top') ? 'top: 0;' : ''}
${anchor.includes('bottom') ? 'bottom: 0;' : ''}
${anchor.includes('left') ? 'left: 0;' : ''}
${anchor.includes('right') ? 'right: 0;' : ''}
--translate-x: 0;
--translate-y: 0;
${['top', 'bottom', 'center'].includes(anchor) ? 'left: 50%; right: 50%; --translate-x: -50%;' : ''}
${['left', 'right', 'center'].includes(anchor) ? 'top: 50%; bottom: 50%; --translate-y: -50%;' : ''}
translate: var(--translate-x) var(--translate-y);
width: 100%;
height: fit-content;
display: flex;
flex-direction: ${style().lyric.direction};
${anchor.includes('top') ? 'justify-content: flex-start;' : ''}
${['left', 'right', 'center'].includes(anchor) ? 'justify-content: center;' : ''}
${anchor.includes('bottom') ? 'justify-content: flex-end;' : ''}
${anchor.includes('left') ? 'align-items: flex-start;' : ''}
${['top', 'bottom', 'center'].includes(anchor) ? 'align-items: center;' : ''}
${anchor.includes('right') ? 'align-items: flex-end;' : ''}
row-gap: ${style()?.rowGap ?? '2'}rem;
`;
});

return (
<div
class={cx('fixed w-full h-fit', props.class)}
classList={{
'top-0': config()?.windowPosition.anchor.includes('top'),
'bottom-0': config()?.windowPosition.anchor.includes('bottom'),
'left-0': config()?.windowPosition.anchor.includes('left'),
'right-0': config()?.windowPosition.anchor.includes('right'),
'left-[50%] right-[50%] translate-x-[-50%]': ['top', 'bottom', 'center'].includes(config()?.windowPosition.anchor ?? 'bottom-right'),
'top-[50%] bottom-[50%] translate-y-[-50%]': ['left', 'right', 'center'].includes(config()?.windowPosition.anchor ?? 'bottom-right'),

'justify-start': config()?.windowPosition.anchor.includes('top'),
'justify-center': ['left', 'right', 'center'].includes(config()?.windowPosition.anchor ?? 'bottom-right'),
'justify-end': config()?.windowPosition.anchor.includes('bottom'),
'items-start': config()?.windowPosition.anchor.includes('left'),
'items-center': ['top', 'bottom', 'center'].includes(config()?.windowPosition.anchor ?? 'bottom-right'),
'items-end': config()?.windowPosition.anchor.includes('right'),
[userCSSSelectors['wrapper']]: true,
[userCSSSelectors['wrapper--stopped']]: status() === 'stopped',
[userCSSSelectors['wrapper--idle']]: status() === 'idle',
[userCSSSelectors['wrapper--playing']]: status() === 'playing',
}}
style={`flex-direction: ${style().lyric.direction}; ${props.style}`}
{...containerProps}
>
{props.children}
Expand Down
Loading

0 comments on commit 6ab3cb5

Please sign in to comment.