feat: add default theme option and fix toast z-index, add error styling to start screen inputs

This commit is contained in:
2026-01-25 02:48:33 +00:00
committed by GitHub
parent 88c31c5082
commit f1957c7d91
3 changed files with 18 additions and 62 deletions

View File

@@ -1 +1 @@
NEXT_PUBLIC_COMMIT_SHA=4721c05 NEXT_PUBLIC_COMMIT_SHA=88c31c5

View File

@@ -82,9 +82,9 @@ jobs:
type=gha,mode=max,scope=deps-only type=gha,mode=max,scope=deps-only
# - name: Docker Hub Description - name: Docker Hub Description
# uses: peter-evans/dockerhub-description@v4 uses: peter-evans/dockerhub-description@v4
# with: with:
# username: ${{ vars.DOCKERHUB_USERNAME }} username: sillyangel
# password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
# repository: sillyangel/mice repository: sillyangel/mice

View File

@@ -36,6 +36,7 @@ export function LoginForm({
}); });
const [isTesting, setIsTesting] = useState(false); const [isTesting, setIsTesting] = useState(false);
const [hasError, setHasError] = useState(false);
// Settings for step 2 // Settings for step 2
const [scrobblingEnabled, setScrobblingEnabled] = useState(() => { const [scrobblingEnabled, setScrobblingEnabled] = useState(() => {
@@ -45,21 +46,7 @@ export function LoginForm({
return true; return true;
}); });
// Sidebar shortcuts setting - default to 'playlists' // New settings - removed sidebar and standalone lastfm options
const [sidebarShortcuts, setSidebarShortcuts] = useState(() => {
if (typeof window !== 'undefined') {
const saved = localStorage.getItem('sidebar-layout-settings');
if (saved) {
try {
const parsed = JSON.parse(saved);
return parsed.shortcuts || 'playlists';
} catch (e) {
return 'playlists';
}
}
}
return 'playlists';
});
// Check if Navidrome is configured via environment variables // Check if Navidrome is configured via environment variables
const hasEnvConfig = React.useMemo(() => { const hasEnvConfig = React.useMemo(() => {
@@ -133,6 +120,7 @@ export function LoginForm({
e.preventDefault(); e.preventDefault();
if (!formData.serverUrl || !formData.username || !formData.password) { if (!formData.serverUrl || !formData.username || !formData.password) {
setHasError(true);
toast({ toast({
title: "Missing Information", title: "Missing Information",
description: "Please fill in all fields before proceeding.", description: "Please fill in all fields before proceeding.",
@@ -142,6 +130,7 @@ export function LoginForm({
} }
setIsTesting(true); setIsTesting(true);
setHasError(false);
try { try {
// Strip trailing slash from server URL before testing // Strip trailing slash from server URL before testing
const cleanServerUrl = formData.serverUrl.replace(/\/+$/, ''); const cleanServerUrl = formData.serverUrl.replace(/\/+$/, '');
@@ -168,6 +157,7 @@ export function LoginForm({
// Move to settings step // Move to settings step
setStep('settings'); setStep('settings');
} else { } else {
setHasError(true);
toast({ toast({
title: "Connection Failed", title: "Connection Failed",
description: "Could not connect to the server. Please check your settings.", description: "Could not connect to the server. Please check your settings.",
@@ -175,6 +165,7 @@ export function LoginForm({
}); });
} }
} catch (error) { } catch (error) {
setHasError(true);
toast({ toast({
title: "Connection Error", title: "Connection Error",
description: "An error occurred while testing the connection.", description: "An error occurred while testing the connection.",
@@ -189,23 +180,6 @@ export function LoginForm({
// Save all settings // Save all settings
localStorage.setItem('lastfm-scrobbling-enabled', scrobblingEnabled.toString()); localStorage.setItem('lastfm-scrobbling-enabled', scrobblingEnabled.toString());
// Save sidebar settings with default items
const defaultItems = [
{"id":"home","label":"Home","visible":true,"icon":"home","href":"/"},
{"id":"queue","label":"Queue","visible":true,"icon":"queue","href":"/queue"},
{"id":"artists","label":"Artists","visible":true,"icon":"artists","href":"/library/artists"},
{"id":"albums","label":"Albums","visible":true,"icon":"albums","href":"/library/albums"},
{"id":"playlists","label":"Playlists","visible":true,"icon":"playlists","href":"/library/playlists"},
{"id":"favorites","label":"Favorites","visible":true,"icon":"favorites","href":"/favorites"},
{"id":"settings","label":"Settings","visible":true,"icon":"settings","href":"/settings"}
];
localStorage.setItem('sidebar-layout-settings', JSON.stringify({
items: defaultItems,
shortcuts: sidebarShortcuts,
showIcons: true
}));
// Mark onboarding as complete // Mark onboarding as complete
localStorage.setItem('onboarding-completed', '1.1.0'); localStorage.setItem('onboarding-completed', '1.1.0');
@@ -286,11 +260,12 @@ export function LoginForm({
<span> <span>
<Label htmlFor="theme">Theme</Label> <Label htmlFor="theme">Theme</Label>
</span> </span>
<Select value={theme || "blue"} onValueChange={setTheme}> <Select value={theme} onValueChange={setTheme}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select a theme" /> <SelectValue placeholder="Select a theme" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="default">Default</SelectItem>
<SelectItem value="blue">Blue</SelectItem> <SelectItem value="blue">Blue</SelectItem>
<SelectItem value="violet">Violet</SelectItem> <SelectItem value="violet">Violet</SelectItem>
<SelectItem value="red">Red</SelectItem> <SelectItem value="red">Red</SelectItem>
@@ -327,28 +302,6 @@ export function LoginForm({
</p> </p>
</div> </div>
{/* Sidebar Shortcuts Selection */}
<div className="grid gap-3">
<Label htmlFor="sidebar-shortcuts">Sidebar Shortcuts</Label>
<Select value={sidebarShortcuts} onValueChange={setSidebarShortcuts}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="playlists">Playlists Only</SelectItem>
<SelectItem value="both">Playlists + Artists</SelectItem>
<SelectItem value="none">None</SelectItem>
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground">
{sidebarShortcuts === 'playlists'
? "Show only playlist shortcuts in the sidebar"
: sidebarShortcuts === 'both'
? "Show both playlist and artist shortcuts in the sidebar"
: "Hide all shortcuts from the sidebar"}
</p>
</div>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<Button onClick={handleFinishSetup} className="w-full"> <Button onClick={handleFinishSetup} className="w-full">
<FaCheck className="w-4 h-4 mr-2" /> <FaCheck className="w-4 h-4 mr-2" />
@@ -402,6 +355,7 @@ export function LoginForm({
placeholder="https://your-navidrome-server.com" placeholder="https://your-navidrome-server.com"
value={formData.serverUrl} value={formData.serverUrl}
onChange={(e) => handleInputChange('serverUrl', e.target.value)} onChange={(e) => handleInputChange('serverUrl', e.target.value)}
className={hasError ? "border-destructive focus-visible:ring-destructive" : ""}
required required
/> />
</div> </div>
@@ -416,6 +370,7 @@ export function LoginForm({
placeholder="your-username" placeholder="your-username"
value={formData.username} value={formData.username}
onChange={(e) => handleInputChange('username', e.target.value)} onChange={(e) => handleInputChange('username', e.target.value)}
className={hasError ? "border-destructive focus-visible:ring-destructive" : ""}
required required
/> />
</div> </div>
@@ -429,6 +384,7 @@ export function LoginForm({
type="password" type="password"
value={formData.password} value={formData.password}
onChange={(e) => handleInputChange('password', e.target.value)} onChange={(e) => handleInputChange('password', e.target.value)}
className={hasError ? "border-destructive focus-visible:ring-destructive" : ""}
required required
/> />
</div> </div>