mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 14:55:43 +00:00
feat(settings): add "Square Corners" appearance toggle (#1215)
* feat(settings): add "Square Corners" appearance toggle A Display toggle in Settings → Appearance → Visual Options that overrides the active theme to render cards and cover art with square (non-rounded) corners, for a sharper, boxy look. Covered surfaces: grid cards (album/playlist/artist/song/because) and their covers, detail-header heros (album/playlist/tracks), the Now Playing / Radio view, the fullscreen player, the cover lightbox, the queue panel cover, and the mini player. Persisted in themeStore and driven by an `html[data-square-corners]` attribute set in App.tsx — applied in both the main and mini-player webviews (the mini player rehydrates the theme store on the shared `storage` event). Strings added for all 12 locales. * docs(changelog): add Square Corners to 1.50.0 CHANGELOG and What's New
This commit is contained in:
@@ -9,6 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
>
|
||||
|
||||
|
||||
## [1.50.0]
|
||||
|
||||
## Added
|
||||
|
||||
### Square corners — sharp-edged cards and covers
|
||||
|
||||
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1215](https://github.com/Psychotoxical/psysonic/pull/1215)**
|
||||
|
||||
* New **Square Corners** toggle under **Settings → Appearance → Visual Options → Display** overrides the active theme to render cards and cover art with square, non-rounded corners. Covers album, playlist, artist and song cards, detail-page cover art, the Now Playing / Radio and fullscreen views, the cover lightbox, the queue cover, and the mini player. Off by default; buttons, inputs and dialogs keep the theme's corners.
|
||||
|
||||
|
||||
## [1.49.0] - 2026-06-29
|
||||
|
||||
## Added
|
||||
|
||||
@@ -8,6 +8,15 @@ Within each section, order by **user impact** (most noticeable first) — not PR
|
||||
`CHANGELOG.md` keeps strict PR order inside Added / Changed / Fixed.
|
||||
|
||||
|
||||
## [1.50.0]
|
||||
|
||||
## Highlights
|
||||
|
||||
### Square corners — a sharper, boxier look
|
||||
|
||||
- New **Square Corners** toggle under **Settings → Appearance → Visual Options** strips the rounded corners off cards and cover art across the app — handy when a theme's rounding doesn't suit your album covers. Off by default; everything else stays the way your theme defines it.
|
||||
|
||||
|
||||
## [1.49.0]
|
||||
|
||||
## Highlights
|
||||
|
||||
@@ -86,6 +86,15 @@ export default function App() {
|
||||
document.documentElement.setAttribute('data-button-size', buttonSize);
|
||||
}, [buttonSize]);
|
||||
|
||||
// Strip rounded corners off grid cards when the user opts in — single CSS
|
||||
// hook (`html[data-square-corners]`) overriding whatever radius the theme set.
|
||||
const squareCorners = useThemeStore(s => s.squareCorners);
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (squareCorners) root.setAttribute('data-square-corners', '');
|
||||
else root.removeAttribute('data-square-corners');
|
||||
}, [squareCorners]);
|
||||
|
||||
// Hide all inline track-preview buttons when the user opts out — single
|
||||
// CSS hook (`html[data-track-previews="off"]`) instead of conditional
|
||||
// rendering in every tracklist. Per-location toggles use additional
|
||||
|
||||
@@ -104,6 +104,13 @@ export function AppearanceTab() {
|
||||
onChange={theme.setFloatingPlayerBar}
|
||||
/>
|
||||
<div className="settings-section-divider" />
|
||||
<SettingsToggle
|
||||
label={t('settings.squareCorners')}
|
||||
desc={t('settings.squareCornersSub')}
|
||||
checked={theme.squareCorners}
|
||||
onChange={theme.setSquareCorners}
|
||||
/>
|
||||
<div className="settings-section-divider" />
|
||||
<SettingsToggle
|
||||
label={t('settings.showArtistImages')}
|
||||
desc={t('settings.showArtistImagesDesc')}
|
||||
|
||||
@@ -698,6 +698,8 @@ export const settings = {
|
||||
showBitrateSub: 'Audio-Bitrate in Track-Listen anzeigen',
|
||||
floatingPlayerBar: 'Schwebende Player-Leiste',
|
||||
floatingPlayerBarSub: 'Player-Leiste über dem Inhalt schweben lassen',
|
||||
squareCorners: 'Eckige Ecken',
|
||||
squareCornersSub: 'Abgerundete Ecken bei Karten entfernen – kantige, eckige Optik',
|
||||
uiScaleTitle: 'Interface-Skalierung',
|
||||
uiScaleLabel: 'Zoom',
|
||||
waveformCacheClearBtn: 'Waveform-Cache leeren',
|
||||
|
||||
@@ -765,6 +765,8 @@ export const settings = {
|
||||
showBitrateSub: 'Display audio bitrate in track listings',
|
||||
floatingPlayerBar: 'Floating Player Bar',
|
||||
floatingPlayerBarSub: 'Keep the player bar floating above content',
|
||||
squareCorners: 'Square Corners',
|
||||
squareCornersSub: 'Remove rounded corners from cards for a sharp, square look',
|
||||
uiScaleTitle: 'Interface Scale',
|
||||
uiScaleLabel: 'Zoom',
|
||||
};
|
||||
|
||||
@@ -697,6 +697,8 @@ export const settings = {
|
||||
showBitrateSub: 'Mostrar bitrate de audio en las listas de pistas',
|
||||
floatingPlayerBar: 'Barra del Reproductor Flotante',
|
||||
floatingPlayerBarSub: 'Mantener la barra del reproductor flotando sobre el contenido',
|
||||
squareCorners: 'Esquinas rectas',
|
||||
squareCornersSub: 'Quitar las esquinas redondeadas de las tarjetas para un aspecto nítido y cuadrado',
|
||||
uiScaleTitle: 'Escala de Interfaz',
|
||||
uiScaleLabel: 'Zoom',
|
||||
confirmDeleteServerLibrary: '¿También quieres eliminar el índice local de biblioteca de este servidor? Pulsa Cancelar para conservar la copia en caché para uso sin conexión.',
|
||||
|
||||
@@ -685,6 +685,8 @@ export const settings = {
|
||||
showBitrateSub: 'Afficher le débit audio dans les listes de pistes',
|
||||
floatingPlayerBar: 'Barre de Lecteur Flottante',
|
||||
floatingPlayerBarSub: 'Garder la barre du lecteur flottante au-dessus du contenu',
|
||||
squareCorners: 'Coins carrés',
|
||||
squareCornersSub: 'Supprimer les coins arrondis des cartes pour un rendu net et anguleux',
|
||||
uiScaleTitle: "Mise à l'échelle de l'interface",
|
||||
uiScaleLabel: 'Zoom',
|
||||
confirmDeleteServerLibrary: 'Supprimer aussi l’index local de bibliothèque de ce serveur ? Cliquez sur Annuler pour conserver la copie en cache pour un usage hors ligne.',
|
||||
|
||||
@@ -764,6 +764,8 @@ export const settings = {
|
||||
showBitrateSub: 'A hang bitrátájának megjelenítése a számlistákban',
|
||||
floatingPlayerBar: 'Lebegő lejátszósáv',
|
||||
floatingPlayerBarSub: 'A lejátszósáv lebegve tartása a tartalom felett',
|
||||
squareCorners: 'Szögletes sarkok',
|
||||
squareCornersSub: 'A kártyák lekerekített sarkainak eltávolítása éles, szögletes megjelenésért',
|
||||
uiScaleTitle: 'Felület méretezése',
|
||||
uiScaleLabel: 'Nagyítás',
|
||||
};
|
||||
|
||||
@@ -758,6 +758,8 @@ export const settings = {
|
||||
showBitrateSub: 'トラック一覧に音声ビットレートを表示',
|
||||
floatingPlayerBar: 'フローティングプレイヤーバー',
|
||||
floatingPlayerBarSub: 'コンテンツの上にプレイヤーバーを浮かせて表示',
|
||||
squareCorners: '角を四角に',
|
||||
squareCornersSub: 'カードの角の丸みをなくして、シャープで角ばった見た目にする',
|
||||
uiScaleTitle: 'インターフェース倍率',
|
||||
uiScaleLabel: 'ズーム',
|
||||
};
|
||||
|
||||
@@ -684,6 +684,8 @@ export const settings = {
|
||||
showBitrateSub: 'Vis audio-bitrate i sporlister',
|
||||
floatingPlayerBar: 'Flytende Spillerlinje',
|
||||
floatingPlayerBarSub: 'Hold spillerlinjen flytende over innholdet',
|
||||
squareCorners: 'Firkantede hjørner',
|
||||
squareCornersSub: 'Fjern avrundede hjørner på kort for et skarpt, kantete utseende',
|
||||
uiScaleTitle: 'Grensesnittskala',
|
||||
uiScaleLabel: 'Zoom',
|
||||
confirmDeleteServerLibrary: 'Vil du også slette denne serverens lokale bibliotekindeks? Klikk Avbryt for å beholde den bufrede kopien for offline bruk.',
|
||||
|
||||
@@ -685,6 +685,8 @@ export const settings = {
|
||||
showBitrateSub: 'Toon audio bitrate in tracklijsten',
|
||||
floatingPlayerBar: 'Zwevende Spelerbalk',
|
||||
floatingPlayerBarSub: 'Houd de spelerbalk zwevend boven de inhoud',
|
||||
squareCorners: 'Rechte hoeken',
|
||||
squareCornersSub: 'Verwijder afgeronde hoeken van kaarten voor een strakke, hoekige look',
|
||||
uiScaleTitle: 'Interface schaal',
|
||||
uiScaleLabel: 'Zoom',
|
||||
confirmDeleteServerLibrary: 'Ook de lokale bibliotheekindex van deze server verwijderen? Klik op Annuleren om de gecachte kopie voor offline gebruik te behouden.',
|
||||
|
||||
@@ -765,5 +765,7 @@ export const settings = {
|
||||
showBitrateSub: 'Wyświetlaj bitrate audio na listach utworów',
|
||||
floatingPlayerBar: 'Pasek odtwarzacza jako nakładka',
|
||||
floatingPlayerBarSub: 'Wyświetlaj pasek odtwarzacza jako nakładkę nad zawartością',
|
||||
squareCorners: 'Proste rogi',
|
||||
squareCornersSub: 'Usuń zaokrąglone rogi kart, aby uzyskać ostry, kanciasty wygląd',
|
||||
uiScaleTitle: 'Skala interfejsu',
|
||||
uiScaleLabel: 'Przybliżenie',};
|
||||
|
||||
@@ -700,6 +700,8 @@ export const settings = {
|
||||
showBitrateSub: 'Arată bitrate-ul audio în listările de piese',
|
||||
floatingPlayerBar: 'Bară Player plutitoare',
|
||||
floatingPlayerBarSub: 'Păstrează bara playerului plutind deasupra conținutului',
|
||||
squareCorners: 'Colțuri drepte',
|
||||
squareCornersSub: 'Elimină colțurile rotunjite ale cardurilor pentru un aspect clar, unghiular',
|
||||
uiScaleTitle: 'Scara interfaței',
|
||||
uiScaleLabel: 'Zoom',
|
||||
confirmDeleteServerLibrary: 'Ștergi și indexul local al bibliotecii pentru acest server? Apasă Anulează pentru a păstra copia din cache pentru utilizare offline.',
|
||||
|
||||
@@ -785,6 +785,8 @@ export const settings = {
|
||||
showBitrateSub: 'Отображать битрейт аудио в списках треков',
|
||||
floatingPlayerBar: 'Плавающая панель плеера',
|
||||
floatingPlayerBarSub: 'Держать панель плеера плавающей над содержимым',
|
||||
squareCorners: 'Прямые углы',
|
||||
squareCornersSub: 'Убрать скруглённые углы у карточек для чёткого, прямоугольного вида',
|
||||
uiScaleTitle: 'Масштаб интерфейса',
|
||||
uiScaleLabel: 'Масштаб',
|
||||
confirmDeleteServerLibrary: 'Также удалить локальный индекс библиотеки этого сервера? Нажмите «Отмена», чтобы сохранить кэш-копию для офлайн-использования.',
|
||||
|
||||
@@ -684,6 +684,8 @@ export const settings = {
|
||||
showBitrateSub: '在曲目列表中显示音频比特率',
|
||||
floatingPlayerBar: '浮动播放栏',
|
||||
floatingPlayerBarSub: '保持播放栏悬浮在内容上方',
|
||||
squareCorners: '直角边角',
|
||||
squareCornersSub: '移除卡片的圆角,呈现利落的方正外观',
|
||||
uiScaleTitle: '界面缩放',
|
||||
uiScaleLabel: '缩放',
|
||||
confirmDeleteServerLibrary: '是否同时删除该服务器的本地库索引?点击“取消”可保留缓存副本以供离线使用。',
|
||||
|
||||
@@ -83,6 +83,10 @@ interface ThemeState {
|
||||
setExpandReplayGain: (v: boolean) => void;
|
||||
floatingPlayerBar: boolean;
|
||||
setFloatingPlayerBar: (v: boolean) => void;
|
||||
/** Strip rounded corners off all grid cards (and their covers), overriding the
|
||||
* active theme. Drives `html[data-square-corners]` in App.tsx. */
|
||||
squareCorners: boolean;
|
||||
setSquareCorners: (v: boolean) => void;
|
||||
/** Master toggle for external artist artwork (fanart.tv). Off by default (§20). */
|
||||
externalArtworkEnabled: boolean;
|
||||
setExternalArtworkEnabled: (v: boolean) => void;
|
||||
@@ -149,6 +153,8 @@ export const useThemeStore = create<ThemeState>()(
|
||||
setExpandReplayGain: (v) => set({ expandReplayGain: v }),
|
||||
floatingPlayerBar: false,
|
||||
setFloatingPlayerBar: (v) => set({ floatingPlayerBar: v }),
|
||||
squareCorners: false,
|
||||
setSquareCorners: (v) => set({ squareCorners: v }),
|
||||
externalArtworkEnabled: false,
|
||||
setExternalArtworkEnabled: (v) => set({ externalArtworkEnabled: v }),
|
||||
externalArtworkByok: '',
|
||||
|
||||
@@ -96,3 +96,4 @@
|
||||
@import './back-to-top.css';
|
||||
@import './error-boundary.css';
|
||||
@import './backdrop-source-list.css';
|
||||
@import './square-corners.css';
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/* ── Square Corners override ──
|
||||
*
|
||||
* Toggled by `html[data-square-corners]` (themeStore `squareCorners`, set in
|
||||
* App.tsx). A global, theme-independent override that strips the rounded
|
||||
* corners off the grid cards (album / playlist / artist / song / "because")
|
||||
* and their cover artwork, for users who prefer a sharp, boxy look.
|
||||
*
|
||||
* Scope is deliberately limited to cards + their covers — buttons, inputs,
|
||||
* dialogs and the player bar keep whatever radius the active theme defines.
|
||||
* `!important` is required because some themes set card radii with their own
|
||||
* `!important` (see e.g. `.artist-card-avatar-initial`).
|
||||
*
|
||||
* The fallback artist initials avatar (`.artist-card-avatar-initial`) stays a
|
||||
* circle on purpose — it is an avatar placeholder, not a card corner. */
|
||||
|
||||
/* Grid cards + their covers. */
|
||||
html[data-square-corners] :is(
|
||||
.card,
|
||||
.album-card,
|
||||
.artist-card,
|
||||
.song-card,
|
||||
.because-card,
|
||||
.album-card-cover,
|
||||
.because-card-cover-wrap,
|
||||
.artist-card-avatar,
|
||||
.album-card-cover img,
|
||||
.artist-card-avatar img
|
||||
) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* Large cover art in the album / playlist / tracks detail headers (heros). */
|
||||
html[data-square-corners] :is(
|
||||
.album-detail-cover,
|
||||
.album-detail-cover-btn,
|
||||
.hero-cover,
|
||||
.playlist-hero-cover,
|
||||
.tracks-hero-cover,
|
||||
.tracks-hero-cover img
|
||||
) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* Now Playing / Radio full view cover art. */
|
||||
html[data-square-corners] :is(
|
||||
.np-dash-hero-cover,
|
||||
.np-cover
|
||||
) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* Fullscreen player, the cover lightbox, and the queue panel's current cover. */
|
||||
html[data-square-corners] :is(
|
||||
.fsp-cover,
|
||||
.cover-lightbox-img,
|
||||
.queue-current-cover
|
||||
) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* Mini player cover. The mini player is a separate webview, but the
|
||||
* `data-square-corners` attribute is applied in both window kinds (the App.tsx
|
||||
* attribute effects run in each webview, and the mini player rehydrates the
|
||||
* theme store on the shared-localStorage `storage` event). */
|
||||
html[data-square-corners] :is(
|
||||
.mp-cover,
|
||||
.mp-album-cover
|
||||
) {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
Reference in New Issue
Block a user