Skip to content

Commit 5cc25e8

Browse files
committed
Combine library organization controls (#18)
1 parent 7eb92bb commit 5cc25e8

8 files changed

Lines changed: 63 additions & 48 deletions

File tree

src/PrompterOne.Shared/Library/Components/LibrarySidebar.razor

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,6 @@
5353
</nav>
5454

5555
<div class="lib-folders-section">
56-
<div class="lib-organization-switcher" data-test="@UiTestIds.Library.OrganizationModeGroup">
57-
<span class="lib-organization-label">@Text(UiTextKey.LibraryOrganizationModeLabel)</span>
58-
<div class="lib-organization-options">
59-
@foreach (var option in LibraryOrganizationTerminologyCatalog.All)
60-
{
61-
<button class="@GetOrganizationModeClass(option.Mode)"
62-
type="button"
63-
data-active="@(option.Mode == SelectedOrganizationMode ? ActiveStateValue : InactiveStateValue)"
64-
data-test="@UiTestIds.Library.OrganizationModeOption(option.Value)"
65-
@onclick="() => HandleOrganizationModeChangedAsync(option.Mode)">
66-
@Text(option.OptionLabelKey)
67-
</button>
68-
}
69-
</div>
70-
</div>
7156
<div class="lib-folders-header">
7257
<span data-test="@UiTestIds.Library.SectionFoldersTitle">@Text(OrganizationTerminology.SectionTitleKey)</span>
7358
<TooltipAnchor OwnerTestId="@UiTestIds.Library.FolderCreateStart"
@@ -121,10 +106,6 @@
121106
[Parameter, EditorRequired] public LibraryOrganizationTerminology OrganizationTerminology { get; set; } =
122107
LibraryOrganizationTerminologyCatalog.Resolve(LibraryOrganizationMode.Folders);
123108

124-
[Parameter, EditorRequired] public LibraryOrganizationMode SelectedOrganizationMode { get; set; }
125-
126-
[Parameter, EditorRequired] public EventCallback<LibraryOrganizationMode> OnOrganizationModeChanged { get; set; }
127-
128109
[Parameter, EditorRequired] public EventCallback<string> OnSelectFolder { get; set; }
129110

130111
[Parameter, EditorRequired] public EventCallback OnClose { get; set; }
@@ -137,17 +118,9 @@
137118

138119
private Task HandleSelectFavoritesAsync() => OnSelectFolder.InvokeAsync(LibrarySelectionKeys.Favorites);
139120

140-
private Task HandleOrganizationModeChangedAsync(LibraryOrganizationMode mode) =>
141-
OnOrganizationModeChanged.InvokeAsync(mode);
142-
143121
private Task HandleStartCreateAsync() => OnStartCreateFolder.InvokeAsync();
144122

145123
private Task HandleCloseAsync() => OnClose.InvokeAsync();
146124

147-
private string GetOrganizationModeClass(LibraryOrganizationMode mode) =>
148-
mode == SelectedOrganizationMode
149-
? "lib-organization-option active"
150-
: "lib-organization-option";
151-
152125
private string Text(UiTextKey key) => Localizer[key.ToString()];
153126
}

src/PrompterOne.Shared/Library/Pages/LibraryPage.ViewState.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ private string ResolveProjectSortLabel(LibraryCardViewModel card)
108108

109109
private string? GetSortClass(LibrarySortMode sortMode) => _sortMode == sortMode ? "active" : null;
110110

111+
private string GetOrganizationModeClass(LibraryOrganizationMode mode) =>
112+
mode == _organizationMode
113+
? "lib-organization-option active"
114+
: "lib-organization-option";
115+
111116
private string ResolveSelectedFolderLabel()
112117
{
113118
if (IsAllSelected)

src/PrompterOne.Shared/Library/Pages/LibraryPage.razor

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
IsOpen="_isSidebarOpen"
1717
FavoriteScriptCount="_allCards.Count(card => card.IsFavorite)"
1818
OrganizationTerminology="OrganizationTerminology"
19-
SelectedOrganizationMode="_organizationMode"
20-
OnOrganizationModeChanged="SetOrganizationMode"
2119
OnSelectFolder="SelectFolder"
2220
OnClose="CloseSidebar"
2321
OnStartCreateFolder="StartCreateFolder" />
@@ -47,7 +45,30 @@
4745
@onclick:stopPropagation="true">
4846
<UiIcon Kind="UiIconKind.PanelLeft" Size="16" />
4947
</button>
50-
<span class="sort-label" data-test="@UiTestIds.Library.SortLabel">@Text(UiTextKey.LibrarySortBy)</span>
48+
<span class="sort-label" data-test="@UiTestIds.Library.SortLabel">@Text(UiTextKey.LibraryOrganizationModeLabel)</span>
49+
<div class="lib-organization-switcher" data-test="@UiTestIds.Library.OrganizationModeGroup">
50+
<div class="lib-organization-options">
51+
@foreach (var option in LibraryOrganizationTerminologyCatalog.All)
52+
{
53+
<button class="@GetOrganizationModeClass(option.Mode)"
54+
type="button"
55+
data-active="@(option.Mode == _organizationMode ? ActiveStateValue : InactiveStateValue)"
56+
data-test="@UiTestIds.Library.OrganizationModeOption(option.Value)"
57+
@onclick="() => SetOrganizationMode(option.Mode)">
58+
@Text(option.OptionLabelKey)
59+
</button>
60+
}
61+
</div>
62+
</div>
63+
<span class="lib-arrange-divider" aria-hidden="true"></span>
64+
<button class="sort-btn @GetSortClass(LibrarySortMode.Author)"
65+
@onclick="() => SetSortMode(LibrarySortMode.Author)"
66+
data-active="@(GetSortModeState(LibrarySortMode.Author))"
67+
data-test="@UiTestIds.Library.SortAuthor">@Text(UiTextKey.LibrarySortAuthor)</button>
68+
<button class="sort-btn @GetSortClass(LibrarySortMode.Project)"
69+
@onclick="() => SetSortMode(LibrarySortMode.Project)"
70+
data-active="@(GetSortModeState(LibrarySortMode.Project))"
71+
data-test="@UiTestIds.Library.SortProject">@Text(UiTextKey.LibrarySortProject)</button>
5172
<button class="sort-btn @GetSortClass(LibrarySortMode.Name)"
5273
@onclick="() => SetSortMode(LibrarySortMode.Name)"
5374
data-active="@(GetSortModeState(LibrarySortMode.Name))"
@@ -56,22 +77,14 @@
5677
@onclick="() => SetSortMode(LibrarySortMode.Date)"
5778
data-active="@(GetSortModeState(LibrarySortMode.Date))"
5879
data-test="@UiTestIds.Library.SortDate">@Text(UiTextKey.LibrarySortDate)</button>
59-
<button class="sort-btn @GetSortClass(LibrarySortMode.Duration)"
80+
<button class="sort-btn sort-btn-secondary @GetSortClass(LibrarySortMode.Duration)"
6081
@onclick="() => SetSortMode(LibrarySortMode.Duration)"
6182
data-active="@(GetSortModeState(LibrarySortMode.Duration))"
6283
data-test="@UiTestIds.Library.SortDuration">@Text(UiTextKey.LibrarySortDuration)</button>
63-
<button class="sort-btn @GetSortClass(LibrarySortMode.Wpm)"
84+
<button class="sort-btn sort-btn-secondary @GetSortClass(LibrarySortMode.Wpm)"
6485
@onclick="() => SetSortMode(LibrarySortMode.Wpm)"
6586
data-active="@(GetSortModeState(LibrarySortMode.Wpm))"
6687
data-test="@UiTestIds.Library.SortWpm">@Text(UiTextKey.LibrarySortWpm)</button>
67-
<button class="sort-btn @GetSortClass(LibrarySortMode.Author)"
68-
@onclick="() => SetSortMode(LibrarySortMode.Author)"
69-
data-active="@(GetSortModeState(LibrarySortMode.Author))"
70-
data-test="@UiTestIds.Library.SortAuthor">@Text(UiTextKey.LibrarySortAuthor)</button>
71-
<button class="sort-btn @GetSortClass(LibrarySortMode.Project)"
72-
@onclick="() => SetSortMode(LibrarySortMode.Project)"
73-
data-active="@(GetSortModeState(LibrarySortMode.Project))"
74-
data-test="@UiTestIds.Library.SortProject">@Text(UiTextKey.LibrarySortProject)</button>
7588
<button class="sort-btn tone-toggle @(_showToneMetadata ? "active" : null)"
7689
type="button"
7790
aria-pressed="@(_showToneMetadata ? "true" : "false")"

src/PrompterOne.Shared/wwwroot/design/modules/library/00-sidebar.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
overflow-y: auto;
107107
}
108108
.lib-organization-switcher {
109-
padding: 0 10px 14px;
109+
padding: 0;
110110
}
111111
.lib-organization-label {
112112
display: block;
@@ -118,8 +118,8 @@
118118
color: var(--t4);
119119
}
120120
.lib-organization-options {
121-
display: grid;
122-
grid-template-columns: repeat(2, minmax(0, 1fr));
121+
display: flex;
122+
flex-wrap: wrap;
123123
gap: 4px;
124124
}
125125
.lib-organization-option {

src/PrompterOne.Shared/wwwroot/design/modules/library/20-table.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,28 @@
109109
gap: 6px;
110110
margin-bottom: 20px;
111111
min-width: 0;
112+
flex-wrap: wrap;
112113
}
113114
.sort-label { font-size: 12px; color: var(--t4); margin-right: 4px; }
115+
.lib-sort-bar .lib-organization-switcher {
116+
padding: 0;
117+
min-width: 0;
118+
}
119+
120+
.lib-sort-bar .lib-organization-options {
121+
display: flex;
122+
align-items: center;
123+
flex-wrap: wrap;
124+
gap: 4px;
125+
}
126+
127+
.lib-arrange-divider {
128+
width: 1px;
129+
height: 20px;
130+
margin: 0 3px;
131+
background: var(--gold-07);
132+
}
133+
114134
.sort-btn {
115135
padding: 5px 12px;
116136
font-size: 12px;
@@ -119,6 +139,9 @@
119139
background: transparent;
120140
border-radius: 8px;
121141
}
142+
.sort-btn-secondary {
143+
color: color-mix(in srgb, var(--t4) 78%, transparent);
144+
}
122145
.sort-btn:hover { color: var(--t2); background: var(--gold-05); }
123146
.sort-btn.active {
124147
background: rgba(245,200,80,.06);

tests/PrompterOne.Web.Tests/Library/LibraryFolderInteractionTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ public async Task LibraryPage_OrganizationTerminologySwitch_PreservesFolderRepos
5959
cut.WaitForAssertion(() =>
6060
{
6161
Assert.Equal("Folders", cut.FindByTestId(UiTestIds.Library.SectionFoldersTitle).TextContent.Trim());
62+
Assert.Equal("Organize as", cut.FindByTestId(UiTestIds.Library.SortLabel).TextContent.Trim());
6263
Assert.Contains("Product Launch", cut.Markup);
6364
});
6465

6566
cut.FindByTestId(UiTestIds.Library.OrganizationModeOption("shows")).Click();
6667

6768
cut.WaitForAssertion(() =>
6869
{
70+
Assert.Equal(ActiveStateValue, cut.FindByTestId(UiTestIds.Library.OrganizationModeOption("shows")).GetAttribute("data-active"));
6971
Assert.Equal("Shows", cut.FindByTestId(UiTestIds.Library.SectionFoldersTitle).TextContent.Trim());
7072
Assert.Contains("New show", cut.FindByTestId(UiTestIds.Library.FolderCreateTile).TextContent);
7173
});
@@ -179,6 +181,7 @@ public void LibraryPage_ProjectSortOrdersCardsByFolderName_AndPersistsSelection(
179181
cut.WaitForAssertion(() =>
180182
{
181183
Assert.Equal(ActiveStateValue, cut.FindByTestId(UiTestIds.Library.SortProject).GetAttribute("data-active"));
184+
Assert.Contains(UiTestIds.Library.OrganizationModeGroup, cut.Markup, StringComparison.Ordinal);
182185
Assert.Equal(AppTestData.Scripts.LearnWpmBoundaryTitle, ResolveFirstCardTitle(cut));
183186
});
184187

tests/PrompterOne.Web.Tests/Localization/LocalizationRenderingTests.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ public void LibrarySidebar_RendersUkrainianLabels_WhenCurrentCultureIsUkrainian(
3434
.Add(component => component.IsOpen, true)
3535
.Add(component => component.FavoriteScriptCount, 2)
3636
.Add(component => component.OrganizationTerminology, LibraryOrganizationTerminologyCatalog.Resolve(LibraryOrganizationMode.Folders))
37-
.Add(component => component.SelectedOrganizationMode, LibraryOrganizationMode.Folders)
38-
.Add(component => component.OnOrganizationModeChanged, EventCallback.Factory.Create<LibraryOrganizationMode>(this, _ => Task.CompletedTask))
3937
.Add(component => component.OnSelectFolder, EventCallback.Factory.Create<string>(this, _ => Task.CompletedTask))
4038
.Add(component => component.OnClose, EventCallback.Factory.Create(this, () => Task.CompletedTask))
4139
.Add(component => component.OnStartCreateFolder, EventCallback.Factory.Create(this, () => Task.CompletedTask)));

tests/PrompterOne.Web.UITests/Support/BrowserTestConstants.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,14 +916,14 @@ public static class Diagnostics
916916
public static class Localization
917917
{
918918
public const string CultureStorageKey = BrowserStorageKeys.CultureSetting;
919-
public const string EnglishSortByLabel = "Sort by";
919+
public const string EnglishSortByLabel = "Organize as";
920920
public const string FrenchCultureName = "fr";
921921
public const string FrenchCreateFolderTitle = "Créer un dossier";
922922
public const string FrenchLanguageLabel = "Français";
923923
public const string FrenchFoldersLabel = "Dossiers";
924-
public const string FrenchSortByLabel = "Trier par";
924+
public const string FrenchSortByLabel = "Organiser comme";
925925
public const string GermanCultureName = "de";
926-
public const string GermanSortByLabel = "Sortieren nach";
926+
public const string GermanSortByLabel = "Organisieren als";
927927
public const string RussianCultureName = "ru";
928928
public const string SetLocalStorageScript = "([key, value]) => window.localStorage.setItem(key, value)";
929929

0 commit comments

Comments
 (0)