feat(ui): tabbed settings and onboarding prompts

This commit is contained in:
2025-10-01 10:40:10 -04:00
parent 6af3603c7d
commit de04dbc323
2 changed files with 180 additions and 99 deletions

View File

@@ -1,8 +1,38 @@
<script lang="ts">
import { settings } from '$lib/stores/settings';
</script>
<div>
<img src="/Square150x150Logo.png" alt="cat" style="width: 128px; height: 128px;" />
<h2>Welcome to Shark!</h2>
<p>Your music library manager and player.</p>
{#if !$settings.musicFolder}
<div class="window welcome-prompt">
<div class="title-bar">
<div class="title-bar-text">Ahoy!</div>
</div>
<div class="window-body">
<p>It seems you're new here! To get started, set up your music downloads folder.</p>
<div class="button-row">
<a href="/settings"><button>Go to Settings</button></a>
</div>
</div>
</div>
{:else if !$settings.playlistsFolder}
<div class="window welcome-prompt">
<div class="title-bar">
<div class="title-bar-text">Welcome Back!</div>
</div>
<div class="window-body">
<p>Head to settings to set up your playlists folder! Life is more fun with playlists.</p>
<div class="button-row">
<a href="/settings"><button>Go to Settings</button></a>
</div>
</div>
</div>
{/if}
<section class="quick-stats">
<div class="field-row-stacked">
</div>
@@ -17,4 +47,20 @@
.quick-stats {
margin-top: 20px;
}
.welcome-prompt {
margin-top: 20px;
max-width: 500px;
}
.welcome-prompt p {
line-height: 1.5;
letter-spacing: 0.01em;
word-spacing: normal;
}
.button-row {
margin-top: 12px;
text-align: center;
}
</style>

View File

@@ -16,6 +16,7 @@
let currentDeezerConcurrency = $state<number>(1);
let currentDeezerFormat = $state<'FLAC' | 'MP3_320' | 'MP3_128'>('FLAC');
let currentDeezerOverwrite = $state<boolean>(false);
let activeTab = $state<'library' | 'deezer' | 'advanced'>('library');
onMount(async () => {
await loadSettings();
@@ -57,11 +58,32 @@
await setPlaylistsFolder(selected);
}
}
async function clearAllPaths() {
await setMusicFolder(null);
await setPlaylistsFolder(null);
}
</script>
<div>
<h2>Settings</h2>
<section class="library-content">
<menu role="tablist">
<li role="tab" aria-selected={activeTab === 'library'}>
<a href="#library" onclick={(e) => { e.preventDefault(); activeTab = 'library'; }}>Library</a>
</li>
<li role="tab" aria-selected={activeTab === 'deezer'}>
<a href="#deezer" onclick={(e) => { e.preventDefault(); activeTab = 'deezer'; }}>Deezer</a>
</li>
<li role="tab" aria-selected={activeTab === 'advanced'}>
<a href="#advanced" onclick={(e) => { e.preventDefault(); activeTab = 'advanced'; }}>Advanced</a>
</li>
</menu>
<div class="window" role="tabpanel">
<div class="window-body">
{#if activeTab === 'library'}
<section class="tab-content">
<h3>Library Folders</h3>
<p class="info-note">
<strong>Note:</strong> Music and Playlists folders should be in the same parent directory for playlists to work properly in other apps.
@@ -105,8 +127,8 @@
{/if}
</div>
</section>
<section class="library-content">
{:else if activeTab === 'deezer'}
<section class="tab-content">
<h3>Deezer Download Settings</h3>
<div class="field-row-stacked">
@@ -124,7 +146,7 @@
</div>
<div class="field-row-stacked">
<label for="deezer-concurrency">Download Concurrency (tracks within album/playlist)</label>
<label for="deezer-concurrency">Download Concurrency</label>
<div class="slider-container">
<input
id="deezer-concurrency"
@@ -136,11 +158,10 @@
/>
<span class="slider-value">{currentDeezerConcurrency}</span>
</div>
<small class="help-text">
Number of tracks to download simultaneously within collections (default: 1)
</small>
<small class="help-text">Number of tracks to download simultaneously (default: 1)</small>
</div>
<div class="field-row-stacked">
<div class="field-row">
<input
id="deezer-overwrite"
@@ -150,12 +171,27 @@
/>
<label for="deezer-overwrite">Overwrite existing files</label>
</div>
</div>
</section>
{:else if activeTab === 'advanced'}
<section class="tab-content">
<h3>Advanced Settings</h3>
<div class="field-row-stacked">
<label>Clear All Paths</label>
<small class="help-text">This will reset your music and playlists folder paths. You'll need to set them up again.</small>
<button onclick={clearAllPaths}>Clear All Paths</button>
</div>
</section>
{/if}
</div>
</div>
</div>
<style>
h2 {
margin-top: 0;
margin-bottom: 12px;
}
h3 {
@@ -164,8 +200,12 @@
font-size: 1.1em;
}
.library-content {
margin-top: 20px;
menu[role="tablist"] {
margin-bottom: 0;
}
.tab-content {
margin: 0;
}
.info-note {
@@ -173,7 +213,8 @@
padding: 12px;
margin-bottom: 20px;
border-left: 3px solid var(--button-highlight, #606060);
font-size: 0.9em;
font-size: 11px;
line-height: 1.4;
}
.info-note strong {
@@ -202,17 +243,11 @@
.help-text {
color: var(--text-color, #FFFFFF);
opacity: 0.7;
font-size: 0.9em;
font-size: 11px;
line-height: 1.4;
}
.field-row {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
.field-row label {
.field-row-stacked .field-row {
margin: 0;
}