Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions SonosControl.Web/Pages/Index/Components/MediaLists.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
<div class="d-grid gap-3">
<section class="card media-section">
<div class="card-header d-flex align-items-center justify-content-between gap-3">
<div>
<h5 class="mb-0">📻 TuneIn Stations</h5>
<div class="d-flex align-items-center gap-2">
<AppIcon Icon="AppIcon.AppIconType.Radio" Width="18" Height="18" />
<h5 class="mb-0">TuneIn Stations</h5>
</div>
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-outline-secondary btn-sm"
@onclick="ShuffleStation"
title="Shuffle stations"
aria-label="Shuffle stations">
🔀
<AppIcon Icon="AppIcon.AppIconType.Shuffle" Width="15" Height="15" />
</button>
<button type="button" class="btn btn-outline-secondary btn-sm"
@onclick="ToggleStationEditMode"
Expand Down Expand Up @@ -58,7 +59,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
@onclick="() => RemoveStation.InvokeAsync(station)"
aria-label="Remove station">
<i class="fa fa-times" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
</button>
</li>
}
Expand All @@ -79,7 +80,10 @@

<section class="card media-section">
<div class="card-header d-flex align-items-center justify-content-between gap-3">
<h5 class="mb-0">🎧 Spotify Tracks</h5>
<div class="d-flex align-items-center gap-2">
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="18" Height="18" />
<h5 class="mb-0">Spotify Tracks</h5>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm"
@onclick="ToggleSpotifyEditMode"
aria-label="Toggle Spotify playlists">
Expand Down Expand Up @@ -121,7 +125,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
@onclick="() => RemoveSpotifyTrack.InvokeAsync(track)"
aria-label="Remove track">
<i class="fa fa-times" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
</button>
</li>
}
Expand All @@ -142,12 +146,15 @@

<section class="card media-section">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - YouTube Music section incorrectly uses Spotify icon. Should be AppIconType.Video or AppIconType.Youtube.

<div class="card-header d-flex align-items-center justify-content-between gap-3">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - Section header shows "Spotify Tracks" but this is the YouTube Music section. Should say "YouTube Music".

<h5 class="mb-0">▶️ YouTube Music</h5>
<div class="d-flex align-items-center gap-2">
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="18" Height="18" />
<h5 class="mb-0">Spotify Tracks</h5>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - YouTube Music section incorrectly calls ToggleSpotifyEditMode instead of ToggleYouTubeEditMode.

</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - aria-label says "Toggle Spotify playlists" but this is the YouTube Music section.

<button type="button" class="btn btn-outline-secondary btn-sm"
@onclick="ToggleYouTubeEditMode"
aria-label="Toggle YouTube edit mode">
<i class="fa @(IsYouTubeEditMode ? "fa-check" : "fa-pencil")" aria-hidden="true"></i>
<span class="visually-hidden">@(IsYouTubeEditMode ? "Exit edit mode" : "Edit YouTube links")</span>
@onclick="ToggleSpotifyEditMode"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - Uses IsSpotifyEditMode but this section body uses IsYouTubeEditMode (line 161), causing the edit toggle to not work correctly.

aria-label="Toggle Spotify playlists">
<AppIcon Icon="@(IsSpotifyEditMode ? AppIcon.AppIconType.Check : AppIcon.AppIconType.Pencil)" Width="14" Height="14" />
<span class="visually-hidden">@(IsSpotifyEditMode ? "Exit edit mode" : "Edit Spotify tracks")</span>
</button>
</div>
<div class="card-body">
Expand Down Expand Up @@ -184,7 +191,7 @@
<button type="button" class="btn btn-sm btn-outline-danger"
@onclick="() => RemoveYouTubeEntry.InvokeAsync(entry)"
aria-label="Remove YouTube link">
<i class="fa fa-times" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
</button>
</li>
}
Expand All @@ -204,8 +211,17 @@
</section>

<section class="card media-section">
<div class="card-header">
<h5 class="mb-0">🎧 Play Spotify URL</h5>
<div class="card-header d-flex align-items-center justify-content-between gap-3">
<div class="d-flex align-items-center gap-2">
<AppIcon Icon="AppIcon.AppIconType.Video" Width="18" Height="18" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Copy-paste error - Uses Video icon (YouTube) but this is the "Play Spotify URL" section. Should use Spotify icon instead.

<h5 class="mb-0">YouTube Music</h5>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm"
@onclick="ToggleYouTubeEditMode"
aria-label="Toggle YouTube edit mode">
<AppIcon Icon="@(IsYouTubeEditMode ? AppIcon.AppIconType.Check : AppIcon.AppIconType.Pencil)" Width="14" Height="14" />
<span class="visually-hidden">@(IsYouTubeEditMode ? "Exit edit mode" : "Edit YouTube links")</span>
</button>
</div>
<div class="card-body">
<div class="input-group">
Expand Down
6 changes: 3 additions & 3 deletions SonosControl.Web/Pages/Index/Components/MediaTabs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<div class="media-tabs-container">
<div class="nav nav-tabs" role="tablist">
<button class="@GetTabClass("stations")" @onclick="@(() => SetActiveTab("stations"))" role="tab">
📻 Stations
<AppIcon Icon="AppIcon.AppIconType.Radio" Width="15" Height="15" /> Stations
</button>
<button class="@GetTabClass("spotify")" @onclick="@(() => SetActiveTab("spotify"))" role="tab">
🎧 Spotify
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="15" Height="15" /> Spotify
</button>
<button class="@GetTabClass("youtube")" @onclick="@(() => SetActiveTab("youtube"))" role="tab">
▶️ YouTube
<AppIcon Icon="AppIcon.AppIconType.Video" Width="15" Height="15" /> YouTube
</button>
</div>

Expand Down
5 changes: 4 additions & 1 deletion SonosControl.Web/Pages/Index/Components/MediaTabs.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
color: var(--text-muted);
border-radius: var(--bs-border-radius-lg) var(--bs-border-radius-lg) 0 0;
border-color: transparent;
border-bottom-color: transparent;
border-bottom-color: transparent;
display: inline-flex;
align-items: center;
gap: 0.375rem;
}

.media-tabs-container .nav-link.active {
Expand Down
48 changes: 24 additions & 24 deletions SonosControl.Web/Pages/Index/Components/PlaybackCard.razor
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
@using Microsoft.AspNetCore.Components

<div class="card playback-card" style="@GradientStyle">
<div class="card-body playback-card__body">
<div class="card-body">
<div class="d-flex flex-column flex-lg-row align-items-start gap-3">
<div class="d-flex align-items-start gap-3 flex-grow-1">
<div class="playback-card__icon" aria-hidden="true">
<i class="fa fa-music"></i>
<AppIcon Icon="AppIcon.AppIconType.Music" Width="22" Height="22" />
</div>
<div>
<h5 class="mb-1 playback-card__title">@StatusTitle</h5>
<p class="mb-0 text-muted playback-card__subtitle">@StatusDescription</p>
<h5 class="mb-1">@StatusTitle</h5>
<p class="mb-0 text-muted" style="font-size: 0.875rem;">@StatusDescription</p>
</div>
</div>
<div class="d-flex flex-wrap align-items-center gap-2 playback-card__actions">
<div class="d-flex flex-wrap align-items-center gap-2">
<button type="button"
class="btn btn-light btn-sm playback-card__toggle"
class="btn btn-light btn-sm"
@onclick="TogglePlayback"
title="@PlayToggleLabel"
aria-label="@PlayToggleLabel"
disabled="@IsLoading">
@if (IsLoading)
{
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
}
else
{
<i class="fa @PlayToggleIcon" aria-hidden="true"></i>
}
aria-label="@PlayToggleLabel"
disabled="@IsLoading">
@if (IsLoading)
{
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
}
else
{
<AppIcon Icon="@PlayToggleIcon" Width="16" Height="16" />
}
</button>
<button type="button"
class="btn btn-outline-secondary btn-sm playback-card__action"
class="btn btn-outline-light btn-sm"
@onclick="OpenTimer"
title="Schedule playback"
aria-label="Schedule playback">
<i class="fa fa-clock-o" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.Clock" Width="16" Height="16" />
</button>
@if (ShowNextTrack)
{
<button type="button"
class="btn btn-outline-secondary btn-sm playback-card__action"
class="btn btn-outline-light btn-sm"
@onclick="NextTrack"
title="Skip track"
aria-label="Skip track"
Expand All @@ -50,23 +50,23 @@
}
else
{
<i class="fa fa-forward" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.SkipNext" Width="16" Height="16" />
}
</button>
}
</div>
</div>

<div class="playback-card__volume">
<i class="fa fa-volume-up" aria-hidden="true"></i>
<div class="playback-card__volume mt-3">
<AppIcon Icon="AppIcon.AppIconType.Volume" Width="16" Height="16" />
<input type="range"
class="form-range"
min="0"
max="@MaxVolumeLimit"
@bind-value="VolumeValue"
@bind-value:event="oninput"
aria-label="Volume" />
<span class="badge bg-secondary playback-card__volume-label">@VolumeLabel</span>
<span class="badge bg-light text-dark" style="font-size: 0.75rem;">@VolumeLabel</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -135,7 +135,7 @@

private string PlayToggleLabel => IsPlaying ? "Pause playback" : "Start playback";

private string PlayToggleIcon => IsPlaying ? "fa-pause" : "fa-play";
private AppIcon.AppIconType PlayToggleIcon => IsPlaying ? AppIcon.AppIconType.Pause : AppIcon.AppIconType.Play;

private string VolumeLabel => $"{Volume}%";

Expand Down
40 changes: 8 additions & 32 deletions SonosControl.Web/Pages/Index/Components/PlaybackCard.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,29 @@
box-shadow: var(--shadow-lg);
position: relative;
overflow: hidden;
min-height: 220px;
}

.playback-card__body {
display: flex;
flex-direction: column;
gap: var(--spacing-lg);
}

.playback-card__icon {
width: 48px;
height: 48px;
border-radius: 0.75rem;
width: 40px;
height: 40px;
border-radius: 0.625rem;
background-color: rgba(255, 255, 255, 0.15);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
}

.playback-card__actions {
margin-left: auto;
flex-shrink: 0;
}

.playback-card__volume {
display: flex;
align-items: center;
gap: var(--spacing-md);
padding: 0.65rem 0.75rem;
border-radius: 0.75rem;
gap: 0.75rem;
padding: 0.5rem 0.75rem;
border-radius: 0.625rem;
background: rgba(255, 255, 255, 0.08);
}

.playback-card__volume input[type="range"] {
flex: 1;
min-width: 160px;
}

.playback-card__volume-label {
min-width: 3rem;
text-align: center;
}

.playback-card__title {
color: var(--text-primary);
}

.playback-card__subtitle {
color: var(--text-muted);
min-width: 120px;
}
2 changes: 1 addition & 1 deletion SonosControl.Web/Pages/Index/Components/QueuePanel.razor
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
@onclick="Refresh"
disabled="@IsLoading"
aria-label="Refresh queue now">
<i class="fa fa-refresh @(IsLoading ? "fa-spin" : string.Empty)" aria-hidden="true"></i>
<AppIcon Icon="AppIcon.AppIconType.Refresh" Width="15" Height="15" class="@(IsLoading ? "icon-spin" : "")" />
Refresh
</button>
</div>
Expand Down
9 changes: 9 additions & 0 deletions SonosControl.Web/Pages/Index/Components/QueuePanel.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@
align-items: center;
gap: var(--spacing-sm);
}

.icon-spin {
animation: spin 1s linear infinite;
}

@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
Loading