From 634050c06fb283163c1a8911d9221f8aea4b489e Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Sat, 15 Nov 2025 02:34:15 -0500 Subject: [PATCH] Updated CI for Blazor WebAssembly. Added styles for product cards. --- .gitea/workflows/ci.yml | 3 + .../Queries/Search/VoiceWorkSortField.cs | 3 +- .../VoiceWorks/VoiceWorkSearchProvider.cs | 1 + JSMR.UI.Blazor/Components/JProduct.razor | 25 ++++ .../Components/JProductCollection.razor | 24 ++++ JSMR.UI.Blazor/Enums/ImageSize.cs | 17 +++ JSMR.UI.Blazor/Pages/Circles.razor | 25 +++- JSMR.UI.Blazor/Pages/Home.razor | 118 ++++++++++-------- JSMR.UI.Blazor/Pages/VoiceWorks.razor | 29 +---- JSMR.UI.Blazor/Services/ImageUrlProvider.cs | 10 +- JSMR.UI.Blazor/wwwroot/css/app.css | 98 ++++++++++++++- JSMR.UI.Blazor/wwwroot/css/theme-frozen.css | 26 +++- JSMR.sln | 4 +- 13 files changed, 289 insertions(+), 94 deletions(-) create mode 100644 JSMR.UI.Blazor/Components/JProduct.razor create mode 100644 JSMR.UI.Blazor/Components/JProductCollection.razor create mode 100644 JSMR.UI.Blazor/Enums/ImageSize.cs diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 666ce3f..6488dc5 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -36,6 +36,9 @@ jobs: - name: Docker sanity (ensures socket mount is working) run: docker version + - name: Install WASM workload + run: dotnet workload install wasm-tools --skip-sign-check + - run: dotnet restore - run: dotnet build --configuration Release --no-restore - run: dotnet test --configuration Release --no-build --logger "trx;LogFileName=test-results.trx" diff --git a/JSMR.Application/VoiceWorks/Queries/Search/VoiceWorkSortField.cs b/JSMR.Application/VoiceWorks/Queries/Search/VoiceWorkSortField.cs index 83708d3..13bd52a 100644 --- a/JSMR.Application/VoiceWorks/Queries/Search/VoiceWorkSortField.cs +++ b/JSMR.Application/VoiceWorks/Queries/Search/VoiceWorkSortField.cs @@ -7,5 +7,6 @@ public enum VoiceWorkSortField Downloads, WishlistCount, SalesToWishlistRatio, - StarRating + StarRating, + FavoriteCircle } \ No newline at end of file diff --git a/JSMR.Infrastructure/Data/Repositories/VoiceWorks/VoiceWorkSearchProvider.cs b/JSMR.Infrastructure/Data/Repositories/VoiceWorks/VoiceWorkSearchProvider.cs index a8c4298..9965094 100644 --- a/JSMR.Infrastructure/Data/Repositories/VoiceWorks/VoiceWorkSearchProvider.cs +++ b/JSMR.Infrastructure/Data/Repositories/VoiceWorks/VoiceWorkSearchProvider.cs @@ -324,6 +324,7 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea VoiceWorkSortField.Downloads => x => x.VoiceWork.Downloads ?? 0, VoiceWorkSortField.WishlistCount => x => x.VoiceWork.WishlistCount ?? 0, VoiceWorkSortField.StarRating => x => x.VoiceWork.StarRating ?? 0, + VoiceWorkSortField.FavoriteCircle => x => !x.Circle.Favorite, _ => x => x.VoiceWork.ProductId }; diff --git a/JSMR.UI.Blazor/Components/JProduct.razor b/JSMR.UI.Blazor/Components/JProduct.razor new file mode 100644 index 0000000..714f934 --- /dev/null +++ b/JSMR.UI.Blazor/Components/JProduct.razor @@ -0,0 +1,25 @@ +@using JSMR.Application.VoiceWorks.Queries.Search +@using JSMR.UI.Blazor.Services + +
+
+ +
+
+
@Product.ProductName
+
@Product.Description
+
+ @foreach (var tag in Product.Tags) + { +
@tag.Name
+ } +
+
+
+
+
+ +@code { + [Parameter] + public required VoiceWorkSearchResult Product { get; set; } +} diff --git a/JSMR.UI.Blazor/Components/JProductCollection.razor b/JSMR.UI.Blazor/Components/JProductCollection.razor new file mode 100644 index 0000000..4d1944b --- /dev/null +++ b/JSMR.UI.Blazor/Components/JProductCollection.razor @@ -0,0 +1,24 @@ +@using JSMR.Application.VoiceWorks.Queries.Search + +@if (Products is null) +{ +

Loading…

+} +else if (Products.Length == 0) +{ +

No results.

+} +else +{ +
+ @foreach (var product in Products) + { + + } +
+} + +@code { + [Parameter] + public VoiceWorkSearchResult[]? Products { get; set; } +} diff --git a/JSMR.UI.Blazor/Enums/ImageSize.cs b/JSMR.UI.Blazor/Enums/ImageSize.cs new file mode 100644 index 0000000..5ca8082 --- /dev/null +++ b/JSMR.UI.Blazor/Enums/ImageSize.cs @@ -0,0 +1,17 @@ +namespace JSMR.UI.Blazor.Enums; + +/// Image size selector for DLsite assets. +public enum ImageSize +{ + /// 100×100 square thumbnail (DLsite: "sam"). + Thumb100, + + /// 240×240 square (DLsite: "main_240x240"). + Square240, + + /// 300×300 square (DLsite: "main_300x300"). + Square300, + + /// Native “main” image (typically ~560×420). + Main +} \ No newline at end of file diff --git a/JSMR.UI.Blazor/Pages/Circles.razor b/JSMR.UI.Blazor/Pages/Circles.razor index e4eb6b7..4f5d7fc 100644 --- a/JSMR.UI.Blazor/Pages/Circles.razor +++ b/JSMR.UI.Blazor/Pages/Circles.razor @@ -40,11 +40,13 @@ else @foreach (var item in searchResults.Items) {
- @* *@ + +
@item.Name
@item.MakerId
+ @if (item.Favorite) { Favorite @@ -195,7 +197,7 @@ else .circle-item { display: flex; align-items: center; - padding: 1rem; + padding: .5rem; border-width: 2px; border-top-color: #353B4C; border-left-color: #212630; @@ -204,8 +206,23 @@ else border-radius: 30px; background-image: linear-gradient(0deg, #1C2029, #1C1F28); display: grid; - grid-template-columns: 1fr 100px 100px 100px 100px; - grid-column-gap: 2rem; + grid-template-columns: auto 1fr 100px 100px 100px 100px; + grid-column-gap: 1rem; + } + + .j-circle-image-container-2 { + height: auto; + } + + .j-circle-image-2 { + display: block; + object-fit: cover; + background-color: black; + border: 1px solid #949494; + box-sizing: border-box; + border-radius: 100%; + width: 70px; + height: 70px; } .circle-name { diff --git a/JSMR.UI.Blazor/Pages/Home.razor b/JSMR.UI.Blazor/Pages/Home.razor index 7052351..1daf45a 100644 --- a/JSMR.UI.Blazor/Pages/Home.razor +++ b/JSMR.UI.Blazor/Pages/Home.razor @@ -1,70 +1,84 @@ @page "/" @inject VoiceWorksClient Client @using JSMR.Application.VoiceWorks.Queries.Search +@using JSMR.UI.Blazor.Components @using JSMR.UI.Blazor.Services Home - @if (availableVoiceWorks is null) - { -

Loading…

- } - else if (availableVoiceWorks.Length == 0) - { -

No results.

- } - else - { -
    - @foreach (var v in availableVoiceWorks) - { -
  • @v.ProductId – @v.ProductName
  • - } -
- } +
- @if (upcomingVoiceWorks is null) - { -

Loading…

- } - else if (upcomingVoiceWorks.Length == 0) - { -

No results.

- } - else - { -
    - @foreach (var v in upcomingVoiceWorks) - { -
  • @v.ProductId – @v.ProductName
  • - } -
- } +
- @if (announcedVoiceWorks is null) - { -

Loading…

- } - else if (announcedVoiceWorks.Length == 0) - { -

No results.

- } - else - { -
    - @foreach (var v in announcedVoiceWorks) - { -
  • @v.ProductId – @v.ProductName
  • - } -
- } +
+ + @code { VoiceWorkSearchResult[]? availableVoiceWorks; VoiceWorkSearchResult[]? upcomingVoiceWorks; @@ -143,7 +157,7 @@ }, SortOptions = [ - //new(VoiceWorkSortField.Fa, Application.Common.Search.SortDirection.Ascending), + new(VoiceWorkSortField.FavoriteCircle, Application.Common.Search.SortDirection.Ascending), new(VoiceWorkSortField.WishlistCount, Application.Common.Search.SortDirection.Descending) ] } diff --git a/JSMR.UI.Blazor/Pages/VoiceWorks.razor b/JSMR.UI.Blazor/Pages/VoiceWorks.razor index 942a663..ad69973 100644 --- a/JSMR.UI.Blazor/Pages/VoiceWorks.razor +++ b/JSMR.UI.Blazor/Pages/VoiceWorks.razor @@ -1,5 +1,6 @@ @page "/voiceworks" @using JSMR.Application.VoiceWorks.Queries.Search +@using JSMR.UI.Blazor.Components @using JSMR.UI.Blazor.Services @inject VoiceWorksClient Client @@ -7,26 +8,10 @@

VoiceWorks

-@if (items is null) -{ -

Loading…

-} -else if (items.Count == 0) -{ -

No results.

-} -else -{ -
    - @foreach (var v in items) - { -
  • @v.ProductId – @v.ProductName
  • - } -
-} + @code { - List? items; + VoiceWorkSearchResult[]? items; protected override async Task OnInitializedAsync() { @@ -36,12 +21,6 @@ else var result = await Client.SearchAsync(request); - // if (result.Ok) - // { - // items = result.Value!.Results.Items.ToList(); - // } - //items = result.Value?.Results.Items ?? []; - - items = result.Results.Items.ToList(); + items = result?.Results.Items ?? []; } } \ No newline at end of file diff --git a/JSMR.UI.Blazor/Services/ImageUrlProvider.cs b/JSMR.UI.Blazor/Services/ImageUrlProvider.cs index 67f69e9..66ec006 100644 --- a/JSMR.UI.Blazor/Services/ImageUrlProvider.cs +++ b/JSMR.UI.Blazor/Services/ImageUrlProvider.cs @@ -41,19 +41,15 @@ public static class ImageUrlProvider var imageUrlTemplate = "//img.dlsite.jp/[folder]/images2/[imageType1]/[imageWorkType]/[fullRoundedProductId]/[productId][imageType2]_img_[imageSize].jpg"; - var productIdWithoutPrefixString = productId.Substring(2); + string productIdWithoutPrefixString = productId.Substring(2); int productIdWithoutPrefix = Convert.ToInt32(productId.Substring(2)); string productIdPrefix = productId.Substring(0, 2); - double something = (double)((productIdWithoutPrefix / 1000) * 1000); int roundedProductId = (int)Math.Round(Math.Ceiling((double)productIdWithoutPrefix / 1000) * 1000); - //string actualRoundedProductId = ("000000" + roundedProductId.ToString()).Substring(roundedProductId.ToString().Length); - //string fullRoundedProductId = productIdPrefix + actualRoundedProductId; - - var productIdWithPrefixStringLength = productIdWithoutPrefixString.Length; - var zeroPadLength = productIdWithPrefixStringLength - roundedProductId.ToString().Length; + int productIdWithPrefixStringLength = productIdWithoutPrefixString.Length; + int zeroPadLength = productIdWithPrefixStringLength - roundedProductId.ToString().Length; var fullRoundedProductId = productIdPrefix.PadRight(productIdPrefix.Length + zeroPadLength, '0') + roundedProductId; diff --git a/JSMR.UI.Blazor/wwwroot/css/app.css b/JSMR.UI.Blazor/wwwroot/css/app.css index ae9fdf5..8c9dce4 100644 --- a/JSMR.UI.Blazor/wwwroot/css/app.css +++ b/JSMR.UI.Blazor/wwwroot/css/app.css @@ -17,7 +17,7 @@ a, .btn-link { } .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { - box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; } .content { @@ -304,4 +304,100 @@ code { .star_rating.mini.star_45::before { background-position: 0 -16px; +} + +/* Card */ +.j-card { + padding-top: var(--card-padding-top); + padding-bottom: var(--card-padding-bottom); + padding-left: var(--card-padding-left); + padding-right: var(--card-padding-right); + border-width: var(--card-border-width); + border-top-color: var(--card-border-top-color); + border-left-color: var(--card-border-left-color); + border-right-color: var(--card-border-right-color); + border-bottom-color: var(--card-border-bottom-color); + border-radius: var(--card-border-radius); + background-image: var(--card-background-image); +} + +/* Image */ +.j-image-container { + +} + +.j-image { + width: 100%; +} + +/* Product */ + +.j-product-items-container { + display: flex; + flex-direction: column; + gap: 2rem; +} + +.j-voice-work-card { + display: flex; + gap: 1rem; + background-image: linear-gradient(0deg, rgb(30, 53, 69), rgb(39, 59, 73)); + border-color: rgb(63, 78, 88); + background-image: linear-gradient(0deg, rgb(30, 53, 69), rgb(57, 79, 94)); +} + +.j-voice-work-image-container { + width: 240px; + width: 300px; +} + +.j-voice-work-card > .j-voice-work-image-container { + flex-shrink: 0; +} + +.j-voice-work-image { + border-radius: 20px; +} + +.j-voice-work-content { + display: flex; + flex-direction: column; + gap: .5rem; +} + +.j-voice-work-card > .j-voice-work-content { + flex-grow: 1; +} + +.j-product-title { + font-size: 1.25rem; + font-weight: 600; + font-family: "Poppins", "M+ 1p"; + color: #d2dce6; + text-shadow: 1px 1px 2px black; +} + +.j-product-description { + /* color: #7C8099; */ + font-size: 1rem; + font-family: "Poppins", "M+ 1p"; +} + +.j-voice-work-card > .j-voice-work-content > .j-product-description { + flex-grow: 1; +} + +.j-voice-work-info { + width: 240px; +} + +.j-voice-work-card > .j-voice-work-info { + flex-shrink: 0; +} + +/* Tags */ +.j-tags { + display: flex; + gap: 1rem; + flex-wrap: wrap; } \ No newline at end of file diff --git a/JSMR.UI.Blazor/wwwroot/css/theme-frozen.css b/JSMR.UI.Blazor/wwwroot/css/theme-frozen.css index 30e350f..43a87d6 100644 --- a/JSMR.UI.Blazor/wwwroot/css/theme-frozen.css +++ b/JSMR.UI.Blazor/wwwroot/css/theme-frozen.css @@ -1,7 +1,7 @@ :root { --font-family: 'Poppins'; - --background-color: #131419; - --background-color-original: rgb(16, 36, 50); + --background-color-backup: #131419; + --background-color: rgb(16, 36, 50); --input-background-color: rgb(0,20,34); --input-border-color: #304562; --primary-text-color: rgb(180,200, 214); @@ -22,4 +22,26 @@ --product-footer-text-color: rgb(220,230,234); --expected-date-text-color: #ffe073; --planned-date-text-color: #73bdff; + --card-padding-top: .5rem; + --card-padding-bottom: .5rem; + --card-padding-left: .5rem; + --card-padding-right: .5rem; + --card-background-image: linear-gradient(0deg, #1C2029, #1C1F28); + --card-border-radius: 30px; + --card-border-width: 2px; + --card-border-top-color: #353B4C; + --card-border-left-color: #212630; + --card-border-right-color: #212531; + --card-border-bottom-color: #212530; } + +/* + padding: .5rem; + border-width: 2px; + border-top-color: #353B4C; + border-left-color: #212630; + border-right-color: #212531; + border-bottom-color: #212530; + border-radius: 30px; + background-image: linear-gradient(0deg, #1C2029, #1C1F28); +*/ \ No newline at end of file diff --git a/JSMR.sln b/JSMR.sln index 8009e8e..040053f 100644 --- a/JSMR.sln +++ b/JSMR.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.14.36408.4 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11205.157 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JSMR.Domain", "JSMR.Domain\JSMR.Domain.csproj", "{BC16F228-63B0-4EE6-9B96-19A38A31C125}" EndProject