mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 14:55:43 +00:00
feat: Update Notification system and UI refinements (v1.0.7)
This commit is contained in:
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.7] - 2026-03-13
|
||||
|
||||
### Added
|
||||
- **Update Notifications**: Integrated a native update check system in the sidebar that notifies you when a new version is available on GitHub.
|
||||
- **Improved Settings**: Refined layout and styling for a cleaner settings experience.
|
||||
|
||||
### Fixed
|
||||
- **UI/UX Refinements**: Polished sidebar animations and layout for better visual consistency.
|
||||
- **i18n**: Added missing translations for update notifications and system status.
|
||||
|
||||
## [1.0.6] - 2026-03-13
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "psysonic",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "psysonic"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
description = "Psysonic Desktop Music Player"
|
||||
authors = []
|
||||
license = ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Psysonic",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"identifier": "dev.psysonic.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Disc3, Users, Music4, Radio, Settings, Heart, BarChart3, Shuffle, ListMusic,
|
||||
PanelLeftClose, PanelLeft, HelpCircle, Dices
|
||||
PanelLeftClose, PanelLeft, HelpCircle, Dices, ArrowUpCircle
|
||||
} from 'lucide-react';
|
||||
|
||||
const PsysonicLogo = () => (
|
||||
@@ -21,14 +21,74 @@ const navItems = [
|
||||
{ icon: Heart, labelKey: 'sidebar.favorites', to: '/favorites' },
|
||||
];
|
||||
|
||||
export default function Sidebar({
|
||||
isCollapsed = false,
|
||||
toggleCollapse
|
||||
}: {
|
||||
function isNewer(latest: string, current: string): boolean {
|
||||
const parse = (v: string) => v.replace(/^v/, '').split('.').map(Number);
|
||||
const [lMaj, lMin, lPat] = parse(latest);
|
||||
const [cMaj, cMin, cPat] = parse(current);
|
||||
if (lMaj !== cMaj) return lMaj > cMaj;
|
||||
if (lMin !== cMin) return lMin > cMin;
|
||||
return lPat > cPat;
|
||||
}
|
||||
|
||||
function UpdateToast({ isCollapsed, latestVersion }: { isCollapsed: boolean; latestVersion: string }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (isCollapsed) {
|
||||
return (
|
||||
<div className="update-toast-icon" style={{ marginTop: 'auto' }} title={`${t('sidebar.updateAvailable')}: ${latestVersion}`}>
|
||||
<ArrowUpCircle size={20} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="update-toast">
|
||||
<div className="update-toast-header">
|
||||
<ArrowUpCircle size={14} />
|
||||
<span className="update-toast-label">{t('sidebar.updateAvailable')}</span>
|
||||
</div>
|
||||
<div className="update-toast-version">{t('sidebar.updateReady', { version: latestVersion })}</div>
|
||||
<a
|
||||
className="update-toast-link"
|
||||
href="https://github.com/Psychotoxical/psysonic/releases"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t('sidebar.updateLink')}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Sidebar({
|
||||
isCollapsed = false,
|
||||
toggleCollapse
|
||||
}: {
|
||||
isCollapsed?: boolean;
|
||||
toggleCollapse?: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [latestVersion, setLatestVersion] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
const timer = setTimeout(async () => {
|
||||
try {
|
||||
const { getVersion } = await import('@tauri-apps/api/app');
|
||||
const current = await getVersion();
|
||||
const res = await fetch('https://api.github.com/repos/Psychotoxical/psysonic/releases/latest');
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
const tag: string = data.tag_name ?? '';
|
||||
if (!cancelled && tag && isNewer(tag, current)) {
|
||||
setLatestVersion(tag.startsWith('v') ? tag : `v${tag}`);
|
||||
}
|
||||
} catch {
|
||||
// network unavailable or not running in Tauri — silently skip
|
||||
}
|
||||
}, 1500);
|
||||
return () => { cancelled = true; clearTimeout(timer); };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<aside className={`sidebar animate-slide-in ${isCollapsed ? 'collapsed' : ''}`}>
|
||||
@@ -61,10 +121,11 @@ export default function Sidebar({
|
||||
))}
|
||||
|
||||
{!isCollapsed && <span className="nav-section-label" style={{ marginTop: 'auto' }}>{t('sidebar.system')}</span>}
|
||||
{latestVersion && <UpdateToast isCollapsed={isCollapsed} latestVersion={latestVersion} />}
|
||||
<NavLink
|
||||
to="/statistics"
|
||||
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
|
||||
style={isCollapsed ? { marginTop: 'auto' } : undefined}
|
||||
style={isCollapsed && !latestVersion ? { marginTop: 'auto' } : undefined}
|
||||
title={isCollapsed ? t('sidebar.statistics') : undefined}
|
||||
>
|
||||
<BarChart3 size={isCollapsed ? 22 : 18} />
|
||||
|
||||
+8
-2
@@ -18,7 +18,10 @@ const enTranslation = {
|
||||
settings: 'Settings',
|
||||
help: 'Help',
|
||||
expand: 'Expand Sidebar',
|
||||
collapse: 'Collapse Sidebar'
|
||||
collapse: 'Collapse Sidebar',
|
||||
updateAvailable: 'Update available',
|
||||
updateReady: '{{version}} is ready',
|
||||
updateLink: 'Go to release →'
|
||||
},
|
||||
home: {
|
||||
starred: 'Personal Favorites',
|
||||
@@ -372,7 +375,10 @@ const deTranslation = {
|
||||
settings: 'Einstellungen',
|
||||
help: 'Hilfe',
|
||||
expand: 'Sidebar einblenden',
|
||||
collapse: 'Sidebar ausblenden'
|
||||
collapse: 'Sidebar ausblenden',
|
||||
updateAvailable: 'Update verfügbar',
|
||||
updateReady: '{{version}} ist bereit',
|
||||
updateLink: 'Zum Release →'
|
||||
},
|
||||
home: {
|
||||
starred: 'Persönliche Favoriten',
|
||||
|
||||
@@ -374,7 +374,7 @@ export default function Settings() {
|
||||
Psysonic
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>
|
||||
{t('settings.aboutVersion')} 1.0.6
|
||||
{t('settings.aboutVersion')} 1.0.7
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -164,6 +164,70 @@
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* ─── Update Toast ─── */
|
||||
@keyframes update-toast-in {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.update-toast {
|
||||
margin: 0 var(--space-1) var(--space-2);
|
||||
padding: var(--space-3) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
animation: update-toast-in 0.35s ease both;
|
||||
}
|
||||
|
||||
.update-toast-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.update-toast-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.update-toast-version {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
padding-left: 22px;
|
||||
}
|
||||
|
||||
.update-toast-link {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
padding-left: 22px;
|
||||
opacity: 0.8;
|
||||
transition: opacity var(--transition-fast);
|
||||
}
|
||||
|
||||
.update-toast-link:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.update-toast-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-2) 0;
|
||||
color: var(--accent);
|
||||
animation: update-toast-in 0.35s ease both;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* ─── Main Content ─── */
|
||||
.main-content {
|
||||
grid-area: main;
|
||||
|
||||
Reference in New Issue
Block a user