Merge pull request #423 from afonsojramos/rework-titlebar-drag-region
refactor: rework window drag regions and text selection model
This commit is contained in:
54 files changed
+135
-150
No files matched your search
+22
@@ -1547,6 +1547,28 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
/* App-wide non-selection. Music app text (titles, artists, headers) is
|
||||||
|
not meant to be selected — and selectable text breaks window drag
|
||||||
|
regions, since native text selection preempts the drag gesture.
|
||||||
|
Exceptions below opt specific elements back into selectability. */
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-input controls always get native selection back. */
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
[contenteditable]:not([contenteditable='false']) {
|
||||||
|
user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Escape hatch: add class="selectable" to any element whose text users
|
||||||
|
should be able to copy (error messages, tokens, release notes, etc.). */
|
||||||
|
.selectable,
|
||||||
|
.selectable * {
|
||||||
|
user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbar Styling */
|
/* Scrollbar Styling */
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<div class="modal-backdrop" onclick={onClose} role="presentation">
|
<div class="modal-backdrop" onclick={onClose} role="presentation">
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions, a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_no_static_element_interactions, a11y_click_events_have_key_events -->
|
||||||
<div class="modal" onclick={(e) => e.stopPropagation()}>
|
<div class="modal selectable" onclick={(e) => e.stopPropagation()}>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div class="app-branding">
|
<div class="app-branding">
|
||||||
|
|||||||
@@ -173,7 +173,7 @@
|
|||||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
||||||
<div class="modal-overlay" onclick={onClose} role="presentation">
|
<div class="modal-overlay" onclick={onClose} role="presentation">
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<div class="credits-modal" role="dialog" aria-modal="true" tabindex="-1" onclick={(e) => e.stopPropagation()}>
|
<div class="credits-modal selectable" role="dialog" aria-modal="true" tabindex="-1" onclick={(e) => e.stopPropagation()}>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="loading-state">
|
<div class="loading-state">
|
||||||
<LoaderCircle size={32} class="spinner" />
|
<LoaderCircle size={32} class="spinner" />
|
||||||
|
|||||||
@@ -305,7 +305,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div class="booklet-content" bind:this={containerEl}>
|
<div class="booklet-content selectable" bind:this={containerEl}>
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<div class="booklet-loading">
|
<div class="booklet-loading">
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
|
|||||||
@@ -74,7 +74,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
|
||||||
color: var(--text-secondary, var(--text-muted));
|
color: var(--text-secondary, var(--text-muted));
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,7 +490,6 @@
|
|||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
|
|||||||
@@ -461,7 +461,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="diagnostics-panel">
|
<div class="diagnostics-panel selectable">
|
||||||
<button class="section-toggle panel-toggle" onclick={togglePanel}>
|
<button class="section-toggle panel-toggle" onclick={togglePanel}>
|
||||||
{#if panelOpen}<ChevronDown size={14} />{:else}<ChevronRight size={14} />{/if}
|
{#if panelOpen}<ChevronDown size={14} />{:else}<ChevronRight size={14} />{/if}
|
||||||
<h4 class="subsection-title" style="margin:0">{$t('settings.developer.diagnostics.title')}</h4>
|
<h4 class="subsection-title" style="margin:0">{$t('settings.developer.diagnostics.title')}</h4>
|
||||||
|
|||||||
@@ -243,7 +243,6 @@
|
|||||||
.playlist-card {
|
.playlist-card {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.artwork-container {
|
.artwork-container {
|
||||||
|
|||||||
@@ -189,12 +189,6 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
/* Never select text inside carousels: drag-to-scroll would otherwise
|
|
||||||
highlight titles/artists in the first few pixels before the drag
|
|
||||||
threshold kicks in. Text is still selectable in the dedicated
|
|
||||||
album/artist/playlist views. */
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-container.dragging {
|
.scroll-container.dragging {
|
||||||
|
|||||||
@@ -90,7 +90,7 @@
|
|||||||
>
|
>
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<div
|
<div
|
||||||
class="modal"
|
class="modal selectable"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-labelledby="shortcuts-modal-title"
|
aria-labelledby="shortcuts-modal-title"
|
||||||
|
|||||||
@@ -326,7 +326,6 @@
|
|||||||
min-height: 22px;
|
min-height: 22px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
user-select: none;
|
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
transition: background 100ms ease;
|
transition: background 100ms ease;
|
||||||
/* Extend to natural content width when names are long; fill the
|
/* Extend to natural content width when names are long; fill the
|
||||||
|
|||||||
@@ -294,7 +294,6 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-list {
|
.error-list {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
aria-labelledby="musician-modal-title"
|
aria-labelledby="musician-modal-title"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
<div class="modal">
|
<div class="modal selectable">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div class="musician-info">
|
<div class="musician-info">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
const TERMS_URL = 'https://www.qobuz.com/us-en/legal/terms';
|
const TERMS_URL = 'https://www.qobuz.com/us-en/legal/terms';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={`qobuz-legal ${className}`}>
|
<div class={`qobuz-legal selectable ${className}`}>
|
||||||
{#if showBrandingLine}
|
{#if showBrandingLine}
|
||||||
<p class="branding-line">
|
<p class="branding-line">
|
||||||
{$t('legal.brandingLine')}
|
{$t('legal.brandingLine')}
|
||||||
@@ -74,7 +74,6 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tos-line input {
|
.tos-line input {
|
||||||
|
|||||||
@@ -242,7 +242,6 @@
|
|||||||
.playlist-card {
|
.playlist-card {
|
||||||
width: 162px;
|
width: 162px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.artwork-container {
|
.artwork-container {
|
||||||
|
|||||||
@@ -1650,9 +1650,14 @@
|
|||||||
|
|
||||||
<svelte:window onclick={handleGlobalClick} />
|
<svelte:window onclick={handleGlobalClick} />
|
||||||
|
|
||||||
<aside class="sidebar" class:collapsed={!isExpanded} class:no-titlebar={!showTitleBar}>
|
<aside
|
||||||
|
class="sidebar"
|
||||||
|
class:collapsed={!isExpanded}
|
||||||
|
class:no-titlebar={!showTitleBar}
|
||||||
|
data-tauri-drag-region={!showTitleBar ? '' : undefined}
|
||||||
|
>
|
||||||
<!-- Scrollable Content Area -->
|
<!-- Scrollable Content Area -->
|
||||||
<div class="content">
|
<div class="content" data-tauri-drag-region="false">
|
||||||
<!-- Search Bar (hidden when search is in titlebar) -->
|
<!-- Search Bar (hidden when search is in titlebar) -->
|
||||||
{#if !searchInTitlebar}
|
{#if !searchInTitlebar}
|
||||||
<div
|
<div
|
||||||
@@ -2256,6 +2261,7 @@
|
|||||||
class="toggle-btn"
|
class="toggle-btn"
|
||||||
onclick={onToggle}
|
onclick={onToggle}
|
||||||
title={isExpanded ? $t('actions.collapse') : $t('actions.expand')}
|
title={isExpanded ? $t('actions.collapse') : $t('actions.expand')}
|
||||||
|
data-tauri-drag-region="false"
|
||||||
>
|
>
|
||||||
{#if isExpanded}
|
{#if isExpanded}
|
||||||
<ChevronLeft size={16} />
|
<ChevronLeft size={16} />
|
||||||
@@ -2265,7 +2271,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Fixed User Profile at Bottom -->
|
<!-- Fixed User Profile at Bottom -->
|
||||||
<div class="user-section" class:collapsed={!isExpanded}>
|
<div class="user-section" class:collapsed={!isExpanded} data-tauri-drag-region="false">
|
||||||
<UserCard
|
<UserCard
|
||||||
username={userName}
|
username={userName}
|
||||||
{subscription}
|
{subscription}
|
||||||
@@ -2515,7 +2521,12 @@
|
|||||||
height: calc(100vh - 104px); /* Only 104px NowPlayingBar, no title bar */
|
height: calc(100vh - 104px); /* Only 104px NowPlayingBar, no title bar */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macOS: pad top of sidebar to clear native traffic light buttons */
|
/* macOS: pad top of sidebar to clear native traffic light buttons.
|
||||||
|
This 32px band is also the only visible drag surface: the <aside>
|
||||||
|
carries `data-tauri-drag-region` (set in the template when there's
|
||||||
|
no custom titlebar), while each direct child carries
|
||||||
|
`data-tauri-drag-region="false"` so clicks inside .content / the
|
||||||
|
collapse toggle / the user section never start a window drag. */
|
||||||
:global(html.macos) .sidebar.no-titlebar {
|
:global(html.macos) .sidebar.no-titlebar {
|
||||||
padding-top: 32px;
|
padding-top: 32px;
|
||||||
}
|
}
|
||||||
@@ -3487,7 +3498,6 @@
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 150ms ease, background-color 150ms ease;
|
transition: color 150ms ease, background-color 150ms ease;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.my-qbz-parent:hover {
|
.my-qbz-parent:hover {
|
||||||
|
|||||||
@@ -305,7 +305,6 @@
|
|||||||
color: var(--color-success, #22c55e);
|
color: var(--color-success, #22c55e);
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
user-select: none;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -288,10 +288,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 2px 0 0 0;
|
padding: 2px 0 0 0;
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
app-region: drag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3-zone layout: left and right zones are equal width, center is fixed */
|
/* 3-zone layout: left and right zones are equal width, center is fixed */
|
||||||
@@ -321,7 +317,6 @@
|
|||||||
.drag-region {
|
.drag-region {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search bar in titlebar */
|
/* Search bar in titlebar */
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
||||||
<div class="modal-overlay" onclick={onClose} role="presentation">
|
<div class="modal-overlay" onclick={onClose} role="presentation">
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
||||||
<div class="track-modal" onclick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" tabindex="-1">
|
<div class="track-modal selectable" onclick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" tabindex="-1">
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="loading-state">
|
<div class="loading-state">
|
||||||
<LoaderCircle size={32} class="spinner" />
|
<LoaderCircle size={32} class="spinner" />
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="track-info-panel" class:centered-layout={centeredLayout}>
|
<div class="track-info-panel selectable" class:centered-layout={centeredLayout}>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="loading-state">
|
<div class="loading-state">
|
||||||
<LoaderCircle size={28} class="spinner" />
|
<LoaderCircle size={28} class="spinner" />
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside class="lyrics-sidebar">
|
<aside class="lyrics-sidebar">
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
<div class="header-icon">
|
<div class="header-icon">
|
||||||
<MicVocal size={18} />
|
<MicVocal size={18} />
|
||||||
</div>
|
</div>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel">
|
<div class="panel selectable">
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<div class="state">
|
<div class="state">
|
||||||
<div class="loading-spinner"></div>
|
<div class="loading-spinner"></div>
|
||||||
|
|||||||
@@ -664,7 +664,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Album Metadata -->
|
<!-- Album Metadata -->
|
||||||
<div class="metadata" class:no-description={!album.description}>
|
<div class="metadata selectable" class:no-description={!album.description}>
|
||||||
<h1 class="album-title">{album.title}</h1>
|
<h1 class="album-title">{album.title}</h1>
|
||||||
<div class="artist-line">
|
<div class="artist-line">
|
||||||
{#if album.parentalWarning}
|
{#if album.parentalWarning}
|
||||||
@@ -819,8 +819,8 @@
|
|||||||
<!-- Track List -->
|
<!-- Track List -->
|
||||||
<div class="track-list">
|
<div class="track-list">
|
||||||
<!-- Table Header -->
|
<!-- Table Header -->
|
||||||
<div class="tracklist-toolbar">
|
<div class="tracklist-toolbar" data-tauri-drag-region="deep">
|
||||||
<div class="tracklist-toolbar-left">
|
<div class="tracklist-toolbar-left" data-tauri-drag-region="false">
|
||||||
<QualityBadgeStatic
|
<QualityBadgeStatic
|
||||||
bare
|
bare
|
||||||
quality={album.quality}
|
quality={album.quality}
|
||||||
@@ -828,7 +828,7 @@
|
|||||||
samplingRate={album.samplingRate}
|
samplingRate={album.samplingRate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="tracklist-toolbar-search">
|
<div class="tracklist-toolbar-search" data-tauri-drag-region="false">
|
||||||
<Search size={14} />
|
<Search size={14} />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -1789,7 +1789,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="artist-detail" class:has-art-bg={!!headerColor} style={headerStyle} bind:this={artistDetailEl} onscroll={(e) => saveScrollPosition('artist', (e.target as HTMLElement).scrollTop, artist.id)}>
|
<div class="artist-detail" class:has-art-bg={!!headerColor} style={headerStyle} bind:this={artistDetailEl} onscroll={(e) => saveScrollPosition('artist', (e.target as HTMLElement).scrollTop, artist.id)} data-tauri-drag-region>
|
||||||
<!-- Back Navigation -->
|
<!-- Back Navigation -->
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
@@ -1826,7 +1826,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Artist Info -->
|
<!-- Artist Info -->
|
||||||
<div class="artist-info">
|
<div class="artist-info selectable">
|
||||||
<h1 class="artist-name">{artist.name}</h1>
|
<h1 class="artist-name">{artist.name}</h1>
|
||||||
|
|
||||||
<!-- Biography -->
|
<!-- Biography -->
|
||||||
@@ -2145,7 +2145,7 @@
|
|||||||
<!-- Top Tracks Section -->
|
<!-- Top Tracks Section -->
|
||||||
{#if topTracks.length > 0 || tracksLoading}
|
{#if topTracks.length > 0 || tracksLoading}
|
||||||
<div class="top-tracks-section section-anchor" bind:this={topTracksSection}>
|
<div class="top-tracks-section section-anchor" bind:this={topTracksSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.popularTracks')}</h2>
|
<h2 class="section-title">{$t('artist.popularTracks')}</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -2391,7 +2391,7 @@
|
|||||||
|
|
||||||
<!-- Discography Section -->
|
<!-- Discography Section -->
|
||||||
<div class="discography section-anchor" bind:this={discographySection}>
|
<div class="discography section-anchor" bind:this={discographySection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.discography')}</h2>
|
<h2 class="section-title">{$t('artist.discography')}</h2>
|
||||||
{#if artist.albums.length > 0}
|
{#if artist.albums.length > 0}
|
||||||
@@ -2493,7 +2493,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="discography section-anchor" bind:this={epsSinglesSection}>
|
<div class="discography section-anchor" bind:this={epsSinglesSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.epsSingles')}</h2>
|
<h2 class="section-title">{$t('artist.epsSingles')}</h2>
|
||||||
<span class="section-count">{artist.epsSingles.length}</span>
|
<span class="section-count">{artist.epsSingles.length}</span>
|
||||||
@@ -2557,7 +2557,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="discography section-anchor" bind:this={liveAlbumsSection}>
|
<div class="discography section-anchor" bind:this={liveAlbumsSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.liveAlbums')}</h2>
|
<h2 class="section-title">{$t('artist.liveAlbums')}</h2>
|
||||||
<span class="section-count">{artist.liveAlbums.length}</span>
|
<span class="section-count">{artist.liveAlbums.length}</span>
|
||||||
@@ -2621,7 +2621,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="discography section-anchor" bind:this={compilationsSection}>
|
<div class="discography section-anchor" bind:this={compilationsSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.compilations')}</h2>
|
<h2 class="section-title">{$t('artist.compilations')}</h2>
|
||||||
<span class="section-count">{artist.compilations.length}</span>
|
<span class="section-count">{artist.compilations.length}</span>
|
||||||
@@ -2678,7 +2678,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="discography section-anchor" bind:this={othersSection}>
|
<div class="discography section-anchor" bind:this={othersSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.others')}</h2>
|
<h2 class="section-title">{$t('artist.others')}</h2>
|
||||||
<span class="section-count">{artist.others.length}</span>
|
<span class="section-count">{artist.others.length}</span>
|
||||||
@@ -2742,7 +2742,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="playlists-section section-anchor" bind:this={playlistsSection}>
|
<div class="playlists-section section-anchor" bind:this={playlistsSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.playlists')}</h2>
|
<h2 class="section-title">{$t('artist.playlists')}</h2>
|
||||||
<span class="section-count">{artist.playlists.length}</span>
|
<span class="section-count">{artist.playlists.length}</span>
|
||||||
@@ -2789,7 +2789,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="discography section-anchor" bind:this={tributesSection}>
|
<div class="discography section-anchor" bind:this={tributesSection}>
|
||||||
<div class="section-header">
|
<div class="section-header" data-tauri-drag-region="deep">
|
||||||
<div class="section-header-left">
|
<div class="section-header-left">
|
||||||
<h2 class="section-title">{$t('artist.tributes')}</h2>
|
<h2 class="section-title">{$t('artist.tributes')}</h2>
|
||||||
<span class="section-count">{artist.tributes.length}</span>
|
<span class="section-count">{artist.tributes.length}</span>
|
||||||
|
|||||||
@@ -422,7 +422,7 @@
|
|||||||
<div class="scene-view">
|
<div class="scene-view">
|
||||||
{#if !loading}
|
{#if !loading}
|
||||||
<!-- Back button (always visible) -->
|
<!-- Back button (always visible) -->
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
@@ -431,7 +431,7 @@
|
|||||||
|
|
||||||
<!-- Compact sticky header (appears when hero scrolls out) -->
|
<!-- Compact sticky header (appears when hero scrolls out) -->
|
||||||
{#if heroScrolledPast}
|
{#if heroScrolledPast}
|
||||||
<div class="compact-header">
|
<div class="compact-header" data-tauri-drag-region="deep">
|
||||||
{#if flagUrl}
|
{#if flagUrl}
|
||||||
<img src={flagUrl} alt="" class="compact-flag" />
|
<img src={flagUrl} alt="" class="compact-flag" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -163,8 +163,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="award-albums-view">
|
<div class="award-albums-view">
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<div class="top-bar-left">
|
<div class="top-bar-left" data-tauri-drag-region="false">
|
||||||
<button class="back-btn" onclick={onBack} title={$t('actions.back')}>
|
<button class="back-btn" onclick={onBack} title={$t('actions.back')}>
|
||||||
<ChevronLeft size={20} />
|
<ChevronLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
<h1 class="page-title">{$t('award.section.releases')}</h1>
|
<h1 class="page-title">{$t('award.section.releases')}</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-bar-right">
|
<div class="top-bar-right" data-tauri-drag-region="false">
|
||||||
<div class="search-wrapper">
|
<div class="search-wrapper">
|
||||||
<Search size={16} />
|
<Search size={16} />
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -227,13 +227,13 @@
|
|||||||
const heroImage = $derived(page?.image || page?.magazine?.image || '');
|
const heroImage = $derived(page?.image || page?.magazine?.image || '');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="award-detail-view">
|
<div class="award-detail-view" data-tauri-drag-region>
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<header class="award-header">
|
<header class="award-header" data-tauri-drag-region="deep">
|
||||||
<div class="award-image-wrapper">
|
<div class="award-image-wrapper">
|
||||||
{#if heroImage && !heroImageFailed}
|
{#if heroImage && !heroImageFailed}
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
|
|
||||||
<ViewTransition duration={200} distance={12} direction="down">
|
<ViewTransition duration={200} distance={12} direction="down">
|
||||||
<div class="blacklist-manager">
|
<div class="blacklist-manager">
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
|
|||||||
@@ -181,9 +181,9 @@
|
|||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="view-header">
|
<header class="view-header" data-tauri-drag-region="deep">
|
||||||
<h1>{$t('collections.nav')}</h1>
|
<h1>{$t('collections.nav')}</h1>
|
||||||
<div class="header-actions">
|
<div class="header-actions" data-tauri-drag-region="false">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="primary-cta"
|
class="primary-cta"
|
||||||
|
|||||||
@@ -567,7 +567,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="builder-view">
|
<div class="builder-view">
|
||||||
<div class="builder-scroll">
|
<div class="builder-scroll" data-tauri-drag-region>
|
||||||
{#if onBack}
|
{#if onBack}
|
||||||
<button class="back-btn" onclick={() => onBack?.()}>
|
<button class="back-btn" onclick={() => onBack?.()}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
@@ -575,7 +575,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<header class="builder-header">
|
<header class="builder-header" data-tauri-drag-region="deep">
|
||||||
{#if artistAvatarUrl}
|
{#if artistAvatarUrl}
|
||||||
<img class="avatar" src={artistAvatarUrl} alt="" />
|
<img class="avatar" src={artistAvatarUrl} alt="" />
|
||||||
{:else}
|
{:else}
|
||||||
@@ -1157,7 +1157,6 @@
|
|||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
user-select: none;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,14 +234,14 @@
|
|||||||
|
|
||||||
<div class="discover-browse">
|
<div class="discover-browse">
|
||||||
<!-- Top bar -->
|
<!-- Top bar -->
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<div class="top-bar-left">
|
<div class="top-bar-left" data-tauri-drag-region="false">
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ChevronLeft size={20} />
|
<ChevronLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
<h1 class="page-title">{$t(titleKey)}</h1>
|
<h1 class="page-title">{$t(titleKey)}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-bar-right">
|
<div class="top-bar-right" data-tauri-drag-region="false">
|
||||||
<div class="search-wrapper">
|
<div class="search-wrapper">
|
||||||
<Search size={16} />
|
<Search size={16} />
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -163,14 +163,14 @@
|
|||||||
|
|
||||||
<div class="discover-playlists">
|
<div class="discover-playlists">
|
||||||
<!-- Top bar -->
|
<!-- Top bar -->
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<div class="top-bar-left">
|
<div class="top-bar-left" data-tauri-drag-region="false">
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ChevronLeft size={20} />
|
<ChevronLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
<h1 class="page-title">{$t('discover.qobuzPlaylists')}</h1>
|
<h1 class="page-title">{$t('discover.qobuzPlaylists')}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-bar-right">
|
<div class="top-bar-right" data-tauri-drag-region="false">
|
||||||
<div class="search-wrapper">
|
<div class="search-wrapper">
|
||||||
<Search size={16} />
|
<Search size={16} />
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -514,7 +514,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="playlist-header">
|
<div class="playlist-header" data-tauri-drag-region="deep">
|
||||||
<div class="artwork-container">
|
<div class="artwork-container">
|
||||||
<div class="artwork artwork-daily"></div>
|
<div class="artwork artwork-daily"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -594,7 +594,7 @@
|
|||||||
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
||||||
{:else if result}
|
{:else if result}
|
||||||
<div class="track-list">
|
<div class="track-list">
|
||||||
<div class="track-list-header">
|
<div class="track-list-header" data-tauri-drag-region="deep">
|
||||||
{#if multiSelectMode}
|
{#if multiSelectMode}
|
||||||
<div class="col-select-all">
|
<div class="col-select-all">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -442,7 +442,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="playlist-header">
|
<div class="playlist-header" data-tauri-drag-region="deep">
|
||||||
<div class="artwork-container">
|
<div class="artwork-container">
|
||||||
<div class="artwork artwork-favq"></div>
|
<div class="artwork artwork-favq"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -525,7 +525,7 @@
|
|||||||
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
||||||
{:else if tracks.length > 0}
|
{:else if tracks.length > 0}
|
||||||
<div class="track-list">
|
<div class="track-list">
|
||||||
<div class="track-list-header">
|
<div class="track-list-header" data-tauri-drag-region="deep">
|
||||||
{#if multiSelectMode}
|
{#if multiSelectMode}
|
||||||
<div class="col-select-all">
|
<div class="col-select-all">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -1439,7 +1439,7 @@
|
|||||||
|
|
||||||
<ViewTransition duration={200} distance={12} direction="down">
|
<ViewTransition duration={200} distance={12} direction="down">
|
||||||
<div class="favorites-view" class:no-outer-scroll={(activeTab === 'tracks' && !loading && filteredTracks.length > 0) || (activeTab === 'albums' && !loading && filteredAlbums.length > 0) || (activeTab === 'artists' && !loading && filteredArtists.length > 0)} bind:this={scrollContainer} onscroll={handleFavoritesScroll}>
|
<div class="favorites-view" class:no-outer-scroll={(activeTab === 'tracks' && !loading && filteredTracks.length > 0) || (activeTab === 'albums' && !loading && filteredAlbums.length > 0) || (activeTab === 'artists' && !loading && filteredArtists.length > 0)} bind:this={scrollContainer} onscroll={handleFavoritesScroll}>
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
{#if onBack}
|
{#if onBack}
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
@@ -1451,10 +1451,10 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
<h1>{$t('favorites.title')}</h1>
|
<h1>{$t('favorites.title')}</h1>
|
||||||
{#if activeTab === 'tracks' && !loading && filteredTracks.length > 0}
|
{#if activeTab === 'tracks' && !loading && filteredTracks.length > 0}
|
||||||
<div class="header-actions">
|
<div class="header-actions" data-tauri-drag-region="false">
|
||||||
<button class="action-btn-circle" onclick={handlePlayAllTracks} title={$t('actions.playAll')}>
|
<button class="action-btn-circle" onclick={handlePlayAllTracks} title={$t('actions.playAll')}>
|
||||||
<Play size={18} fill="currentColor" color="currentColor" />
|
<Play size={18} fill="currentColor" color="currentColor" />
|
||||||
</button>
|
</button>
|
||||||
@@ -1483,20 +1483,20 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if activeTab === 'albums' && !loading && filteredAlbums.length > 0}
|
{#if activeTab === 'albums' && !loading && filteredAlbums.length > 0}
|
||||||
<div class="header-actions">
|
<div class="header-actions" data-tauri-drag-region="false">
|
||||||
<button class="action-btn-circle" onclick={handleRandomAlbum} title={$t('favorites.randomAlbum')}>
|
<button class="action-btn-circle" onclick={handleRandomAlbum} title={$t('favorites.randomAlbum')}>
|
||||||
<Shuffle size={18} />
|
<Shuffle size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if activeTab === 'artists' && !loading && filteredArtists.length > 0}
|
{#if activeTab === 'artists' && !loading && filteredArtists.length > 0}
|
||||||
<div class="header-actions">
|
<div class="header-actions" data-tauri-drag-region="false">
|
||||||
<button class="action-btn-circle" onclick={handleRandomArtist} title={$t('favorites.randomArtist')}>
|
<button class="action-btn-circle" onclick={handleRandomArtist} title={$t('favorites.randomArtist')}>
|
||||||
<Shuffle size={18} />
|
<Shuffle size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="header-search">
|
<div class="header-search" data-tauri-drag-region="false">
|
||||||
{#if !searchExpanded}
|
{#if !searchExpanded}
|
||||||
<button class="search-icon-btn" onclick={() => searchExpanded = true} title={$t('nav.search')}>
|
<button class="search-icon-btn" onclick={() => searchExpanded = true} title={$t('nav.search')}>
|
||||||
<Search size={16} />
|
<Search size={16} />
|
||||||
@@ -1522,8 +1522,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Navigation Bar (Artist-style) -->
|
<!-- Navigation Bar (Artist-style) -->
|
||||||
<div class="favorites-nav">
|
<div class="favorites-nav" data-tauri-drag-region="deep">
|
||||||
<div class="nav-left">
|
<div class="nav-left" data-tauri-drag-region="false">
|
||||||
{#each favoritesPreferences.tab_order as tab}
|
{#each favoritesPreferences.tab_order as tab}
|
||||||
{@const Icon = getTabIcon(tab as TabType)}
|
{@const Icon = getTabIcon(tab as TabType)}
|
||||||
<button
|
<button
|
||||||
@@ -1536,7 +1536,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-right">
|
<div class="nav-right" data-tauri-drag-region="false">
|
||||||
<span class="results-count">
|
<span class="results-count">
|
||||||
{#if activeTab === 'tracks'}
|
{#if activeTab === 'tracks'}
|
||||||
{filteredTracks.length}{trackSearch ? ` / ${favoriteTracks.length}` : ''} {$t('favorites.tracks').toLowerCase()}
|
{filteredTracks.length}{trackSearch ? ` / ${favoriteTracks.length}` : ''} {$t('favorites.tracks').toLowerCase()}
|
||||||
|
|||||||
@@ -345,7 +345,7 @@
|
|||||||
|
|
||||||
<div class="label-view" onscroll={handleScroll}>
|
<div class="label-view" onscroll={handleScroll}>
|
||||||
<!-- Back button -->
|
<!-- Back button -->
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
@@ -353,7 +353,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="label-header">
|
<header class="label-header" data-tauri-drag-region="deep">
|
||||||
<div class="label-image-wrapper">
|
<div class="label-image-wrapper">
|
||||||
{#if getLabelImage()}
|
{#if getLabelImage()}
|
||||||
<img src={getLabelImage()} alt={label?.name || labelName} class="label-image" loading="lazy" decoding="async" />
|
<img src={getLabelImage()} alt={label?.name || labelName} class="label-image" loading="lazy" decoding="async" />
|
||||||
|
|||||||
@@ -862,7 +862,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="label-detail-view" bind:this={labelDetailEl}>
|
<div class="label-detail-view" bind:this={labelDetailEl} data-tauri-drag-region>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="loading-state">
|
<div class="loading-state">
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
@@ -882,7 +882,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="label-header section-anchor" bind:this={headerSection}>
|
<header class="label-header section-anchor" bind:this={headerSection} data-tauri-drag-region="deep">
|
||||||
<div class="label-image-wrapper">
|
<div class="label-image-wrapper">
|
||||||
{#if getLabelImage(pageData)}
|
{#if getLabelImage(pageData)}
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -5740,7 +5740,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Main Library View -->
|
<!-- Main Library View -->
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<h1>{$t('library.title')}</h1>
|
<h1>{$t('library.title')}</h1>
|
||||||
{#if stats}
|
{#if stats}
|
||||||
@@ -5753,7 +5753,7 @@
|
|||||||
<p class="subtitle">{$t('library.yourCollection')}</p>
|
<p class="subtitle">{$t('library.yourCollection')}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions" data-tauri-drag-region="false">
|
||||||
{#if hasPlexConfig()}
|
{#if hasPlexConfig()}
|
||||||
<button
|
<button
|
||||||
class="icon-btn plex-sync-btn"
|
class="icon-btn plex-sync-btn"
|
||||||
@@ -8188,7 +8188,6 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-all-checkbox input[type='checkbox'] {
|
.select-all-checkbox input[type='checkbox'] {
|
||||||
@@ -9288,9 +9287,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
/* Block selection bleed on the handle itself; the global override
|
|
||||||
on <body> during drag handles the rest of the page. */
|
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-sidebar-resize-handle:hover,
|
.tree-sidebar-resize-handle:hover,
|
||||||
|
|||||||
@@ -1412,7 +1412,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="detail-header">
|
<header class="detail-header" data-tauri-drag-region="deep">
|
||||||
{#if onBack}
|
{#if onBack}
|
||||||
<button class="back-btn" onclick={() => onBack()}>
|
<button class="back-btn" onclick={() => onBack()}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
|
|||||||
@@ -153,7 +153,7 @@
|
|||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="view-header">
|
<header class="view-header" data-tauri-drag-region="deep">
|
||||||
<h1>{$t('mixtapes.nav')}</h1>
|
<h1>{$t('mixtapes.nav')}</h1>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
|
|
||||||
<div class="musician-page">
|
<div class="musician-page">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="page-header">
|
<header class="page-header" data-tauri-drag-region="deep">
|
||||||
<button class="back-btn" onclick={onBack} title={ $t('actions.back') }>
|
<button class="back-btn" onclick={onBack} title={ $t('actions.back') }>
|
||||||
<ArrowLeft size={20} />
|
<ArrowLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -212,7 +212,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="offline-cache-manager">
|
<div class="offline-cache-manager">
|
||||||
<header class="ocm-header">
|
<header class="ocm-header" data-tauri-drag-region="deep">
|
||||||
<button type="button" class="back-btn" onclick={onBack} aria-label={$t('actions.back')}>
|
<button type="button" class="back-btn" onclick={onBack} aria-label={$t('actions.back')}>
|
||||||
<ArrowLeft size={18} />
|
<ArrowLeft size={18} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2420,7 +2420,7 @@
|
|||||||
{#if playlist.description}
|
{#if playlist.description}
|
||||||
<p class="playlist-description">{@html sanitizeHtml(playlist.description)}</p>
|
<p class="playlist-description">{@html sanitizeHtml(playlist.description)}</p>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="playlist-info">
|
<div class="playlist-info selectable">
|
||||||
<span class="owner">{playlist.owner.name}</span>
|
<span class="owner">{playlist.owner.name}</span>
|
||||||
<span class="separator">•</span>
|
<span class="separator">•</span>
|
||||||
<span>{totalTrackCount} {$t('playlist.tracks')}{#if hasLocalTracks} <span class="local-count">({localTracks.length} local)</span>{/if}</span>
|
<span>{totalTrackCount} {$t('playlist.tracks')}{#if hasLocalTracks} <span class="local-count">({localTracks.length} local)</span>{/if}</span>
|
||||||
@@ -2518,9 +2518,9 @@
|
|||||||
tall as the virtualized content, so the header pins for the whole
|
tall as the virtualized content, so the header pins for the whole
|
||||||
scroll range. -->
|
scroll range. -->
|
||||||
<div class="track-list" bind:this={trackListEl}>
|
<div class="track-list" bind:this={trackListEl}>
|
||||||
<div class="tracks-sticky-header">
|
<div class="tracks-sticky-header" data-tauri-drag-region="deep">
|
||||||
<!-- Track List Controls -->
|
<!-- Track List Controls -->
|
||||||
<div class="track-controls">
|
<div class="track-controls" data-tauri-drag-region="false">
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<Search size={16} class="search-icon" />
|
<Search size={16} class="search-icon" />
|
||||||
@@ -3450,7 +3450,6 @@
|
|||||||
.track-row-wrapper.unavailable {
|
.track-row-wrapper.unavailable {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.track-row-wrapper.unavailable :global(.track-row) {
|
.track-row-wrapper.unavailable :global(.track-row) {
|
||||||
|
|||||||
@@ -890,14 +890,14 @@
|
|||||||
<span>{$t('actions.back')}</span>
|
<span>{$t('actions.back')}</span>
|
||||||
</button>
|
</button>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
<h1>{$t('playlistManager.heading')}</h1>
|
<h1>{$t('playlistManager.heading')}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Breadcrumb Navigation (when inside a folder, only in folder mode and not tree) -->
|
<!-- Breadcrumb Navigation (when inside a folder, only in folder mode and not tree) -->
|
||||||
{#if folderMode && viewMode !== 'tree' && currentFolderId && currentFolder}
|
{#if folderMode && viewMode !== 'tree' && currentFolderId && currentFolder}
|
||||||
{@const breadcrumbFolder = currentFolder}
|
{@const breadcrumbFolder = currentFolder}
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb" data-tauri-drag-region="deep">
|
||||||
<button class="breadcrumb-item" onclick={navigateToRoot}>
|
<button class="breadcrumb-item" onclick={navigateToRoot}>
|
||||||
{$t('playlist.allPlaylists')}
|
{$t('playlist.allPlaylists')}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ViewTransition duration={200} distance={12} direction="up">
|
<ViewTransition duration={200} distance={12} direction="up">
|
||||||
<div class="purchase-album-detail">
|
<div class="purchase-album-detail" data-tauri-drag-region>
|
||||||
<!-- Back Navigation -->
|
<!-- Back Navigation -->
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if album}
|
{:else if album}
|
||||||
<!-- Album Header -->
|
<!-- Album Header -->
|
||||||
<div class="album-header">
|
<div class="album-header" data-tauri-drag-region="deep">
|
||||||
<div class="artwork" class:unavailable={!album.downloadable}>
|
<div class="artwork" class:unavailable={!album.downloadable}>
|
||||||
<img src={getQobuzImage(album.image)} alt={album.title} />
|
<img src={getQobuzImage(album.image)} alt={album.title} />
|
||||||
{#if !album.downloadable}
|
{#if !album.downloadable}
|
||||||
|
|||||||
@@ -502,7 +502,7 @@
|
|||||||
|
|
||||||
<div class="purchases-view">
|
<div class="purchases-view">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
<div class="header-icon">
|
<div class="header-icon">
|
||||||
<ShoppingBag size={32} color="var(--accent-primary)" />
|
<ShoppingBag size={32} color="var(--accent-primary)" />
|
||||||
</div>
|
</div>
|
||||||
@@ -521,8 +521,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Sticky Navigation Bar -->
|
<!-- Sticky Navigation Bar -->
|
||||||
<div class="purchases-nav">
|
<div class="purchases-nav" data-tauri-drag-region="deep">
|
||||||
<div class="nav-left">
|
<div class="nav-left" data-tauri-drag-region="false">
|
||||||
<button
|
<button
|
||||||
class="nav-link"
|
class="nav-link"
|
||||||
class:active={activeTab === 'albums'}
|
class:active={activeTab === 'albums'}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="release-watch">
|
<div class="release-watch">
|
||||||
<div class="top-bar">
|
<div class="top-bar" data-tauri-drag-region="deep">
|
||||||
<button class="back-btn" onclick={onBack} title={$t('actions.back')}>
|
<button class="back-btn" onclick={onBack} title={$t('actions.back')}>
|
||||||
<ChevronLeft size={20} />
|
<ChevronLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tabs">
|
<div class="tabs" data-tauri-drag-region="deep">
|
||||||
{#each tabs as tab}
|
{#each tabs as tab}
|
||||||
{@const Icon = tab.icon}
|
{@const Icon = tab.icon}
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1136,9 +1136,9 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Sticky Header Container -->
|
<!-- Sticky Header Container -->
|
||||||
<div class="sticky-header" class:scrolled={isScrolled}>
|
<div class="sticky-header" class:scrolled={isScrolled} data-tauri-drag-region="deep">
|
||||||
{#if !searchInTitlebar}
|
{#if !searchInTitlebar}
|
||||||
<div class="search-input-container" class:compact={isScrolled}>
|
<div class="search-input-container" class:compact={isScrolled} data-tauri-drag-region="false">
|
||||||
<Search size={isScrolled ? 18 : 20} class="search-icon" />
|
<Search size={isScrolled ? 18 : 20} class="search-icon" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -1157,7 +1157,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Tabs and Filters Row -->
|
<!-- Tabs and Filters Row -->
|
||||||
<div class="tabs-row">
|
<div class="tabs-row" data-tauri-drag-region="false">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
|
|||||||
@@ -4181,7 +4181,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header" data-tauri-drag-region="deep">
|
||||||
{#if onBack}
|
{#if onBack}
|
||||||
<button class="back-btn" onclick={onBack}>
|
<button class="back-btn" onclick={onBack}>
|
||||||
<ArrowLeft size={16} />
|
<ArrowLeft size={16} />
|
||||||
@@ -7157,7 +7157,6 @@ flatpak override --user --filesystem=/home/USUARIO/Música com.blitzfc.qbz</pre>
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.discord-rpc-override > summary::-webkit-details-marker {
|
.discord-rpc-override > summary::-webkit-details-marker {
|
||||||
|
|||||||
@@ -570,7 +570,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="playlist-header">
|
<div class="playlist-header" data-tauri-drag-region="deep">
|
||||||
<div class="artwork-container">
|
<div class="artwork-container">
|
||||||
<div class="artwork artwork-topq"></div>
|
<div class="artwork artwork-topq"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -653,7 +653,7 @@
|
|||||||
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
||||||
{:else if result}
|
{:else if result}
|
||||||
<div class="track-list">
|
<div class="track-list">
|
||||||
<div class="track-list-header">
|
<div class="track-list-header" data-tauri-drag-region="deep">
|
||||||
{#if multiSelectMode}
|
{#if multiSelectMode}
|
||||||
<div class="col-select-all">
|
<div class="col-select-all">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -512,7 +512,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="playlist-header">
|
<div class="playlist-header" data-tauri-drag-region="deep">
|
||||||
<div class="artwork-container">
|
<div class="artwork-container">
|
||||||
<div class="artwork artwork-weekly"></div>
|
<div class="artwork artwork-weekly"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -589,7 +589,7 @@
|
|||||||
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
<div class="empty">{$t('qobuzMixes.result.empty')}</div>
|
||||||
{:else if result}
|
{:else if result}
|
||||||
<div class="track-list">
|
<div class="track-list">
|
||||||
<div class="track-list-header">
|
<div class="track-list-header" data-tauri-drag-region="deep">
|
||||||
{#if multiSelectMode}
|
{#if multiSelectMode}
|
||||||
<div class="col-select-all">
|
<div class="col-select-all">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -251,7 +251,5 @@
|
|||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px 16px;
|
gap: 8px 16px;
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -249,7 +249,5 @@
|
|||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -364,8 +364,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="discovery">
|
<div class="discovery">
|
||||||
<div class="toolbar">
|
<div class="toolbar" data-tauri-drag-region>
|
||||||
<div class="tabs">
|
<div class="tabs" data-tauri-drag-region="false">
|
||||||
{#each tabs as tab (tab.id)}
|
{#each tabs as tab (tab.id)}
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
@@ -377,7 +377,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="genre-slot">
|
<div class="genre-slot" data-tauri-drag-region="false">
|
||||||
<GenreFilterButton
|
<GenreFilterButton
|
||||||
onFilterChange={handleGenreFilterChange}
|
onFilterChange={handleGenreFilterChange}
|
||||||
context="home"
|
context="home"
|
||||||
|
|||||||
+9
-26
@@ -5910,10 +5910,15 @@
|
|||||||
class:match-chrome={matchSystemChrome && showTitleBar && windowTransparent}
|
class:match-chrome={matchSystemChrome && showTitleBar && windowTransparent}
|
||||||
style="--chrome-radius: {chromeRadiusPx}px;"
|
style="--chrome-radius: {chromeRadiusPx}px;"
|
||||||
>
|
>
|
||||||
<!-- macOS: drag region for window movement (overlay title bar has no native drag area) -->
|
<!--
|
||||||
{#if !showTitleBar && platform === 'macos'}
|
macOS overlay title bar: drag handling lives on the existing
|
||||||
<div class="macos-drag-region" data-tauri-drag-region></div>
|
.sidebar element. It already has a 32px top padding band (to
|
||||||
{/if}
|
clear the traffic lights) — that's the area we reuse as the
|
||||||
|
window drag surface, by tagging the <aside> as a drag region
|
||||||
|
and tagging each of its direct children as no-drag. No new
|
||||||
|
elements added, no spacing added — just attributes.
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- Custom Title Bar (CSD) -->
|
<!-- Custom Title Bar (CSD) -->
|
||||||
{#if showTitleBar}
|
{#if showTitleBar}
|
||||||
<TitleBar
|
<TitleBar
|
||||||
@@ -7382,28 +7387,6 @@
|
|||||||
height: calc(100vh - var(--player-bar-height, 104px));
|
height: calc(100vh - var(--player-bar-height, 104px));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macOS: pad main content to clear native overlay title bar */
|
|
||||||
:global(html.macos) .main-content {
|
|
||||||
padding-top: 16px;
|
|
||||||
height: calc(100vh - 104px - 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* macOS: home view handles its own spacing */
|
|
||||||
:global(html.macos) .main-content :global(.home-view) {
|
|
||||||
margin-top: -16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* macOS: invisible drag region for window movement (overlay title bar) */
|
|
||||||
:global(html.macos) .macos-drag-region {
|
|
||||||
height: 28px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 9999;
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-error {
|
.view-error {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in new issue
Block a user