Skip to content

Commit b4100ac

Browse files
authored
Merge pull request #134 from Darkatek7/broadcast-studio-redesign-v2
Replace mixed emoji/Font Awesome/Open Iconic with unified SVG icon system
2 parents 53dec0f + c2599aa commit b4100ac

16 files changed

Lines changed: 323 additions & 120 deletions

.github/workflows/opencode.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: opencode
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
9+
jobs:
10+
opencode:
11+
if: |
12+
contains(github.event.comment.body, ' /oc') ||
13+
startsWith(github.event.comment.body, '/oc') ||
14+
contains(github.event.comment.body, ' /opencode') ||
15+
startsWith(github.event.comment.body, '/opencode')
16+
runs-on: ubuntu-latest
17+
permissions:
18+
id-token: write
19+
contents: read
20+
pull-requests: read
21+
issues: read
22+
steps:
23+
- name: Checkout repository
24+
uses: actions/checkout@v6
25+
with:
26+
persist-credentials: false
27+
28+
- name: Run opencode
29+
uses: anomalyco/opencode/github@latest
30+
env:
31+
MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
32+
with:
33+
model: minimax/MiniMax-M2.7

SonosControl.Web/Pages/Index/Components/MediaLists.razor

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
<div class="d-grid gap-3">
66
<section class="card media-section">
77
<div class="card-header d-flex align-items-center justify-content-between gap-3">
8-
<div>
9-
<h5 class="mb-0">📻 TuneIn Stations</h5>
8+
<div class="d-flex align-items-center gap-2">
9+
<AppIcon Icon="AppIcon.AppIconType.Radio" Width="18" Height="18" />
10+
<h5 class="mb-0">TuneIn Stations</h5>
1011
</div>
1112
<div class="d-flex align-items-center gap-2">
1213
<button type="button" class="btn btn-outline-secondary btn-sm"
1314
@onclick="ShuffleStation"
1415
title="Shuffle stations"
1516
aria-label="Shuffle stations">
16-
🔀
17+
<AppIcon Icon="AppIcon.AppIconType.Shuffle" Width="15" Height="15" />
1718
</button>
1819
<button type="button" class="btn btn-outline-secondary btn-sm"
1920
@onclick="ToggleStationEditMode"
@@ -58,7 +59,7 @@
5859
<button type="button" class="btn btn-sm btn-outline-danger"
5960
@onclick="() => RemoveStation.InvokeAsync(station)"
6061
aria-label="Remove station">
61-
<i class="fa fa-times" aria-hidden="true"></i>
62+
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
6263
</button>
6364
</li>
6465
}
@@ -79,11 +80,14 @@
7980

8081
<section class="card media-section">
8182
<div class="card-header d-flex align-items-center justify-content-between gap-3">
82-
<h5 class="mb-0">🎧 Spotify Tracks</h5>
83+
<div class="d-flex align-items-center gap-2">
84+
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="18" Height="18" />
85+
<h5 class="mb-0">Spotify Tracks</h5>
86+
</div>
8387
<button type="button" class="btn btn-outline-secondary btn-sm"
8488
@onclick="ToggleSpotifyEditMode"
8589
aria-label="Toggle Spotify playlists">
86-
<i class="fa @(IsSpotifyEditMode ? "fa-check" : "fa-pencil")" aria-hidden="true"></i>
90+
<AppIcon Icon="@(IsSpotifyEditMode ? AppIcon.AppIconType.Check : AppIcon.AppIconType.Pencil)" Width="14" Height="14" />
8791
<span class="visually-hidden">@(IsSpotifyEditMode ? "Exit edit mode" : "Edit Spotify tracks")</span>
8892
</button>
8993
</div>
@@ -121,7 +125,7 @@
121125
<button type="button" class="btn btn-sm btn-outline-danger"
122126
@onclick="() => RemoveSpotifyTrack.InvokeAsync(track)"
123127
aria-label="Remove track">
124-
<i class="fa fa-times" aria-hidden="true"></i>
128+
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
125129
</button>
126130
</li>
127131
}
@@ -142,11 +146,14 @@
142146

143147
<section class="card media-section">
144148
<div class="card-header d-flex align-items-center justify-content-between gap-3">
145-
<h5 class="mb-0">▶️ YouTube Music</h5>
149+
<div class="d-flex align-items-center gap-2">
150+
<AppIcon Icon="AppIcon.AppIconType.Video" Width="18" Height="18" />
151+
<h5 class="mb-0">YouTube Music</h5>
152+
</div>
146153
<button type="button" class="btn btn-outline-secondary btn-sm"
147154
@onclick="ToggleYouTubeEditMode"
148155
aria-label="Toggle YouTube edit mode">
149-
<i class="fa @(IsYouTubeEditMode ? "fa-check" : "fa-pencil")" aria-hidden="true"></i>
156+
<AppIcon Icon="@(IsYouTubeEditMode ? AppIcon.AppIconType.Check : AppIcon.AppIconType.Pencil)" Width="14" Height="14" />
150157
<span class="visually-hidden">@(IsYouTubeEditMode ? "Exit edit mode" : "Edit YouTube links")</span>
151158
</button>
152159
</div>
@@ -184,7 +191,7 @@
184191
<button type="button" class="btn btn-sm btn-outline-danger"
185192
@onclick="() => RemoveYouTubeEntry.InvokeAsync(entry)"
186193
aria-label="Remove YouTube link">
187-
<i class="fa fa-times" aria-hidden="true"></i>
194+
<AppIcon Icon="AppIcon.AppIconType.X" Width="14" Height="14" />
188195
</button>
189196
</li>
190197
}
@@ -204,8 +211,9 @@
204211
</section>
205212

206213
<section class="card media-section">
207-
<div class="card-header">
208-
<h5 class="mb-0">🎧 Play Spotify URL</h5>
214+
<div class="card-header d-flex align-items-center gap-2">
215+
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="18" Height="18" />
216+
<h5 class="mb-0">Play Spotify URL</h5>
209217
</div>
210218
<div class="card-body">
211219
<div class="input-group">

SonosControl.Web/Pages/Index/Components/MediaTabs.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
<div class="media-tabs-container">
44
<div class="nav nav-tabs" role="tablist">
55
<button class="@GetTabClass("stations")" @onclick="@(() => SetActiveTab("stations"))" role="tab">
6-
📻 Stations
6+
<AppIcon Icon="AppIcon.AppIconType.Radio" Width="15" Height="15" /> Stations
77
</button>
88
<button class="@GetTabClass("spotify")" @onclick="@(() => SetActiveTab("spotify"))" role="tab">
9-
🎧 Spotify
9+
<AppIcon Icon="AppIcon.AppIconType.Spotify" Width="15" Height="15" /> Spotify
1010
</button>
1111
<button class="@GetTabClass("youtube")" @onclick="@(() => SetActiveTab("youtube"))" role="tab">
12-
▶️ YouTube
12+
<AppIcon Icon="AppIcon.AppIconType.Video" Width="15" Height="15" /> YouTube
1313
</button>
1414
</div>
1515

SonosControl.Web/Pages/Index/Components/MediaTabs.razor.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
color: var(--text-muted);
77
border-radius: var(--bs-border-radius-lg) var(--bs-border-radius-lg) 0 0;
88
border-color: transparent;
9-
border-bottom-color: transparent;
9+
border-bottom-color: transparent;
10+
display: inline-flex;
11+
align-items: center;
12+
gap: 0.375rem;
1013
}
1114

1215
.media-tabs-container .nav-link.active {

SonosControl.Web/Pages/Index/Components/PlaybackCard.razor

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,44 @@
11
@using Microsoft.AspNetCore.Components
22

33
<div class="card playback-card" style="@GradientStyle">
4-
<div class="card-body playback-card__body">
4+
<div class="card-body">
55
<div class="d-flex flex-column flex-lg-row align-items-start gap-3">
66
<div class="d-flex align-items-start gap-3 flex-grow-1">
77
<div class="playback-card__icon" aria-hidden="true">
8-
<i class="fa fa-music"></i>
8+
<AppIcon Icon="AppIcon.AppIconType.Music" Width="22" Height="22" />
99
</div>
1010
<div>
11-
<h5 class="mb-1 playback-card__title">@StatusTitle</h5>
12-
<p class="mb-0 text-muted playback-card__subtitle">@StatusDescription</p>
11+
<h5 class="mb-1">@StatusTitle</h5>
12+
<p class="mb-0 text-muted" style="font-size: 0.875rem;">@StatusDescription</p>
1313
</div>
1414
</div>
15-
<div class="d-flex flex-wrap align-items-center gap-2 playback-card__actions">
15+
<div class="d-flex flex-wrap align-items-center gap-2">
1616
<button type="button"
17-
class="btn btn-light btn-sm playback-card__toggle"
17+
class="btn btn-light btn-sm"
1818
@onclick="TogglePlayback"
1919
title="@PlayToggleLabel"
20-
aria-label="@PlayToggleLabel"
21-
disabled="@IsLoading">
22-
@if (IsLoading)
23-
{
24-
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
25-
}
26-
else
27-
{
28-
<i class="fa @PlayToggleIcon" aria-hidden="true"></i>
29-
}
20+
aria-label="@PlayToggleLabel"
21+
disabled="@IsLoading">
22+
@if (IsLoading)
23+
{
24+
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
25+
}
26+
else
27+
{
28+
<AppIcon Icon="@PlayToggleIcon" Width="16" Height="16" />
29+
}
3030
</button>
3131
<button type="button"
32-
class="btn btn-outline-secondary btn-sm playback-card__action"
32+
class="btn btn-outline-light btn-sm"
3333
@onclick="OpenTimer"
3434
title="Schedule playback"
3535
aria-label="Schedule playback">
36-
<i class="fa fa-clock-o" aria-hidden="true"></i>
36+
<AppIcon Icon="AppIcon.AppIconType.Clock" Width="16" Height="16" />
3737
</button>
3838
@if (ShowNextTrack)
3939
{
4040
<button type="button"
41-
class="btn btn-outline-secondary btn-sm playback-card__action"
41+
class="btn btn-outline-light btn-sm"
4242
@onclick="NextTrack"
4343
title="Skip track"
4444
aria-label="Skip track"
@@ -50,23 +50,23 @@
5050
}
5151
else
5252
{
53-
<i class="fa fa-forward" aria-hidden="true"></i>
53+
<AppIcon Icon="AppIcon.AppIconType.SkipNext" Width="16" Height="16" />
5454
}
5555
</button>
5656
}
5757
</div>
5858
</div>
5959

60-
<div class="playback-card__volume">
61-
<i class="fa fa-volume-up" aria-hidden="true"></i>
60+
<div class="playback-card__volume mt-3">
61+
<AppIcon Icon="AppIcon.AppIconType.Volume" Width="16" Height="16" />
6262
<input type="range"
6363
class="form-range"
6464
min="0"
6565
max="@MaxVolumeLimit"
6666
@bind-value="VolumeValue"
6767
@bind-value:event="oninput"
6868
aria-label="Volume" />
69-
<span class="badge bg-secondary playback-card__volume-label">@VolumeLabel</span>
69+
<span class="badge bg-light text-dark" style="font-size: 0.75rem;">@VolumeLabel</span>
7070
</div>
7171
</div>
7272
</div>
@@ -135,7 +135,7 @@
135135

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

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

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

SonosControl.Web/Pages/Index/Components/PlaybackCard.razor.css

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,53 +5,29 @@
55
box-shadow: var(--shadow-lg);
66
position: relative;
77
overflow: hidden;
8-
min-height: 220px;
9-
}
10-
11-
.playback-card__body {
12-
display: flex;
13-
flex-direction: column;
14-
gap: var(--spacing-lg);
158
}
169

1710
.playback-card__icon {
18-
width: 48px;
19-
height: 48px;
20-
border-radius: 0.75rem;
11+
width: 40px;
12+
height: 40px;
13+
border-radius: 0.625rem;
2114
background-color: rgba(255, 255, 255, 0.15);
2215
display: inline-flex;
2316
align-items: center;
2417
justify-content: center;
25-
font-size: 1.25rem;
26-
}
27-
28-
.playback-card__actions {
29-
margin-left: auto;
18+
flex-shrink: 0;
3019
}
3120

3221
.playback-card__volume {
3322
display: flex;
3423
align-items: center;
35-
gap: var(--spacing-md);
36-
padding: 0.65rem 0.75rem;
37-
border-radius: 0.75rem;
24+
gap: 0.75rem;
25+
padding: 0.5rem 0.75rem;
26+
border-radius: 0.625rem;
3827
background: rgba(255, 255, 255, 0.08);
3928
}
4029

4130
.playback-card__volume input[type="range"] {
4231
flex: 1;
43-
min-width: 160px;
44-
}
45-
46-
.playback-card__volume-label {
47-
min-width: 3rem;
48-
text-align: center;
49-
}
50-
51-
.playback-card__title {
52-
color: var(--text-primary);
53-
}
54-
55-
.playback-card__subtitle {
56-
color: var(--text-muted);
32+
min-width: 120px;
5733
}

SonosControl.Web/Pages/Index/Components/QueuePanel.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
@onclick="Refresh"
3535
disabled="@IsLoading"
3636
aria-label="Refresh queue now">
37-
<i class="fa fa-refresh @(IsLoading ? "fa-spin" : string.Empty)" aria-hidden="true"></i>
37+
<AppIcon Icon="AppIcon.AppIconType.Refresh" Width="15" Height="15" class="@(IsLoading ? "icon-spin" : "")" />
3838
Refresh
3939
</button>
4040
</div>

SonosControl.Web/Pages/Index/Components/QueuePanel.razor.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,12 @@
4141
align-items: center;
4242
gap: var(--spacing-sm);
4343
}
44+
45+
.icon-spin {
46+
animation: spin 1s linear infinite;
47+
}
48+
49+
@keyframes spin {
50+
from { transform: rotate(0deg); }
51+
to { transform: rotate(360deg); }
52+
}

0 commit comments

Comments
 (0)