Changeset fa0fbaf for KernelRecordsMVC.Web/Views/Release
- Timestamp:
- 09/01/26 06:11:34 (4 weeks ago)
- Branches:
- main
- Children:
- d2eccb3
- Parents:
- 08aefc6
- Location:
- KernelRecordsMVC.Web/Views/Release
- Files:
-
- 2 edited
-
Details.cshtml (modified) (1 diff)
-
Index.cshtml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
KernelRecordsMVC.Web/Views/Release/Details.cshtml
r08aefc6 rfa0fbaf 1 1 @model KernelRecordsMVC.Models.Release 2 2 3 <div class="row"> 4 5 <div class="col-md-5"> 6 7 <img src="@Model.CoverPhoto" 8 class="img-fluid rounded" 9 alt="@Model.Title" /> 3 @{ 4 ViewData["Title"] = Model.Title; 5 6 var isAlbum = Model.Album != null; 7 var isSingle = Model.SingleRelease != null; 8 9 var releaseType = 10 isAlbum ? "ALBUM" : 11 isSingle ? "SINGLE" : 12 "RELEASE"; 13 14 var artists = string.Join( 15 ", ", 16 Model.ReleaseArtists 17 .OrderBy(x => x.ReleaseOrdinal) 18 .Select(x => x.Artist.ArtistName) 19 ); 20 } 21 22 <div class="release-details-page"> 23 24 <div class="release-hero"> 25 26 <div class="release-hero-cover"> 27 28 @if (!string.IsNullOrWhiteSpace(Model.CoverPhoto)) 29 { 30 <img src="@Model.CoverPhoto" 31 alt="@Model.Title" /> 32 } 33 else 34 { 35 <div class="release-no-cover"> 36 <span>♪</span> 37 </div> 38 } 39 40 </div> 41 42 43 <div class="release-hero-info"> 44 45 <span class="page-eyebrow"> 46 @releaseType 47 </span> 48 49 <h1> 50 @Model.Title 51 </h1> 52 53 <p class="release-artists-main"> 54 @artists 55 </p> 56 57 58 <div class="release-facts"> 59 60 <div> 61 62 <span>Genre</span> 63 64 <strong> 65 @Model.Genre 66 </strong> 67 68 </div> 69 70 <div> 71 72 <span>Released</span> 73 74 <strong> 75 @Model.ReleaseDate.ToString("MMM dd, yyyy") 76 </strong> 77 78 </div> 79 80 <div> 81 82 <span>Label</span> 83 84 <strong> 85 @Model.RecordLabel 86 </strong> 87 88 </div> 89 90 </div> 91 92 93 <div class="artist-section"> 94 95 <span class="section-label"> 96 ARTISTS 97 </span> 98 99 <div class="release-artists"> 100 101 @foreach (var artist in Model.ReleaseArtists 102 .OrderBy(x => x.ReleaseOrdinal)) 103 { 104 <span class="artist-tag"> 105 106 @artist.Artist.ArtistName 107 108 @if (artist.Type.ToString() == "FEATURE") 109 { 110 <span class="artist-role"> 111 Featured 112 </span> 113 } 114 115 </span> 116 } 117 118 </div> 119 120 </div> 121 122 </div> 10 123 11 124 </div> 12 125 13 126 14 <div class="col-md-7"> 15 16 <h1>@Model.Title</h1> 17 18 <p class="lead"> 19 @Model.Genre 20 </p> 21 22 <p> 23 <strong>Record Label:</strong> 24 @Model.RecordLabel 25 </p> 26 27 <p> 28 <strong>Release Date:</strong> 29 @Model.ReleaseDate.ToString("MMMM dd, yyyy") 30 </p> 31 32 33 <h5>Artists</h5> 34 35 <p> 36 37 @string.Join( 38 ", ", 39 Model.ReleaseArtists 40 .OrderBy(x => x.ReleaseOrdinal) 41 .Select(x => x.Artist.ArtistName) 42 ) 43 44 </p> 45 46 </div> 127 <!-- ===================================================== 128 PRODUCTS 129 ===================================================== --> 130 131 <section class="release-section"> 132 133 <div class="section-heading"> 134 135 <div> 136 137 <span class="section-label"> 138 AVAILABLE FORMATS 139 </span> 140 141 <h2> 142 Choose your format 143 </h2> 144 145 </div> 146 147 <span class="track-count"> 148 @Model.Products.Count product(s) 149 </span> 150 151 </div> 152 153 154 @if (!Model.Products.Any()) 155 { 156 <div class="no-products"> 157 No physical products are currently available. 158 </div> 159 } 160 else 161 { 162 <div class="product-grid"> 163 164 @foreach (var product in Model.Products 165 .OrderBy(x => x.Format)) 166 { 167 <div class="store-product-card"> 168 169 <div class="product-card-top"> 170 171 <span class="product-format"> 172 @product.Format 173 </span> 174 175 @if (product.Stock > 0) 176 { 177 <span class="product-stock available"> 178 In stock 179 </span> 180 } 181 else 182 { 183 <span class="product-stock unavailable"> 184 Out of stock 185 </span> 186 } 187 188 </div> 189 190 191 <div class="product-price"> 192 @product.Price.ToString("C") 193 </div> 194 195 196 <p class="product-description"> 197 @product.ProductDescription 198 </p> 199 200 201 @if (product.Stock > 0) 202 { 203 <div class="product-actions"> 204 205 <a asp-controller="Order" 206 asp-action="AddProduct" 207 asp-route-id="@product.ProductId" 208 class="store-button primary"> 209 210 Add to Cart 211 212 </a> 213 214 <a asp-controller="Wishlist" 215 asp-action="Add" 216 asp-route-productId="@product.ProductId" 217 class="store-button secondary"> 218 219 ♡ Wishlist 220 221 </a> 222 223 </div> 224 } 225 else 226 { 227 <div class="product-actions"> 228 229 <a asp-controller="Wishlist" 230 asp-action="Add" 231 asp-route-productId="@product.ProductId" 232 class="store-button secondary full"> 233 234 ♡ Add to Wishlist 235 236 </a> 237 238 </div> 239 } 240 241 </div> 242 } 243 244 </div> 245 } 246 247 </section> 248 249 250 <!-- ===================================================== 251 ALBUM 252 ===================================================== --> 253 254 @if (Model.Album != null) 255 { 256 <section class="release-section"> 257 258 <div class="section-heading"> 259 260 <div> 261 262 <span class="section-label"> 263 ALBUM 264 </span> 265 266 <h2> 267 Track List 268 </h2> 269 270 </div> 271 272 <span class="track-count"> 273 @Model.Album.AlbumSongs.Count tracks 274 </span> 275 276 </div> 277 278 279 <ol class="track-list"> 280 281 @{ 282 var trackNumber = 1; 283 } 284 285 @foreach (var albumSong in Model.Album.AlbumSongs 286 .OrderBy(x => x.SongId)) 287 { 288 <li class="track-row"> 289 290 <span class="track-number"> 291 @trackNumber.ToString("00") 292 </span> 293 294 <div class="track-main"> 295 296 <strong> 297 @albumSong.Song.SongName 298 </strong> 299 300 @if (albumSong.Song.SongArtists.Any()) 301 { 302 <div class="song-artists"> 303 304 @string.Join( 305 ", ", 306 albumSong.Song.SongArtists 307 .OrderBy(x => x.SongOrdinal) 308 .Select(x => x.Artist.ArtistName) 309 ) 310 311 </div> 312 } 313 314 </div> 315 316 <span class="track-duration"> 317 @albumSong.Song.SongDuration 318 </span> 319 320 </li> 321 322 trackNumber++; 323 } 324 325 </ol> 326 327 </section> 328 } 329 330 331 <!-- ===================================================== 332 SINGLE 333 ===================================================== --> 334 335 @if (Model.SingleRelease != null) 336 { 337 <section class="release-section"> 338 339 <div class="section-heading"> 340 341 <div> 342 343 <span class="section-label"> 344 SINGLE 345 </span> 346 347 <h2> 348 Single Information 349 </h2> 350 351 </div> 352 353 </div> 354 355 356 <div class="single-info-card"> 357 358 <div> 359 360 <span class="section-label"> 361 RELEASE TYPE 362 </span> 363 364 <h2> 365 Single 366 </h2> 367 368 </div> 369 370 <div class="single-duration"> 371 372 <span> 373 Duration 374 </span> 375 376 <strong> 377 @Model.SingleRelease.Duration 378 </strong> 379 380 </div> 381 382 </div> 383 384 </section> 385 } 47 386 48 387 </div> 49 50 51 <hr />52 53 54 <h2>Available Products</h2>55 56 <div class="row">57 58 @foreach (var product in Model.Products)59 {60 <div class="col-md-4 mb-3">61 62 <div class="card h-100">63 64 <div class="card-body">65 66 <h4>67 @product.Format68 </h4>69 70 <h5>71 $@product.Price72 </h5>73 74 <p>75 @product.ProductDescription76 </p>77 78 79 @if (product.Stock > 0)80 {81 <p class="text-success">82 In stock: @product.Stock83 </p>84 85 <a asp-controller="Order"86 asp-action="AddProduct"87 asp-route-id="@product.ProductId"88 class="btn btn-success">89 90 Add to Cart91 92 </a>93 }94 else95 {96 <p class="text-danger">97 Out of stock98 </p>99 }100 101 </div>102 103 </div>104 105 </div>106 }107 108 </div>109 110 111 @if (Model.Album != null)112 {113 <hr />114 115 <h2>Track List</h2>116 117 <ol>118 119 @foreach (var albumSong in Model.Album.AlbumSongs120 .OrderBy(x => x.SongId))121 {122 <li>123 124 @albumSong.Song.SongName125 126 <span class="text-muted">127 (@albumSong.Song.SongDuration)128 </span>129 130 </li>131 }132 133 </ol>134 }135 136 137 @if (Model.SingleRelease != null)138 {139 <hr />140 141 <h2>Single</h2>142 143 <p>144 Duration:145 @Model.SingleRelease.Duration146 </p>147 } -
KernelRecordsMVC.Web/Views/Release/Index.cshtml
r08aefc6 rfa0fbaf 1 1 @model IEnumerable<KernelRecordsMVC.Models.Release> 2 2 3 <div class="d-flex justify-content-between align-items-center mb-4"> 4 5 <div> 6 <h1>Music Store</h1> 7 <p class="text-muted"> 8 Browse CDs, vinyl records and cassettes. 9 </p> 3 @{ 4 ViewData["Title"] = "Browse Releases"; 5 } 6 7 <div class="releases-page"> 8 9 <!-- ===================================================== 10 HEADER 11 ===================================================== --> 12 13 <div class="releases-header"> 14 15 <div> 16 <span class="page-eyebrow">KERNEL RECORDS</span> 17 18 <h1>Browse Releases</h1> 19 20 <p> 21 Explore vinyl, CDs and cassettes from our collection. 22 </p> 23 </div> 24 25 <div class="release-count"> 26 @Model.Count() releases 27 </div> 28 10 29 </div> 11 30 31 32 <!-- ===================================================== 33 FILTERS 34 ===================================================== --> 35 36 <form asp-action="Index" 37 method="get" 38 class="release-filters"> 39 40 <div class="filter-search"> 41 42 <label>Search</label> 43 44 <input type="text" 45 name="search" 46 value="@ViewBag.Search" 47 placeholder="Search by title or artist..." /> 48 49 </div> 50 51 52 <div> 53 54 <label>Genre</label> 55 56 <select name="genre"> 57 58 <option value="">All Genres</option> 59 60 @foreach (var item in ViewBag.Genres) 61 { 62 <option value="@item" 63 selected="@(ViewBag.Genre == item ? "selected" : null)"> 64 @item 65 </option> 66 } 67 68 </select> 69 70 </div> 71 72 73 <div> 74 75 <label>Format</label> 76 77 <select name="format"> 78 79 <option value="">All Formats</option> 80 81 @foreach (var item in ViewBag.Formats) 82 { 83 <option value="@item" 84 selected="@(ViewBag.Format == item ? "selected" : null)"> 85 @item 86 </option> 87 } 88 89 </select> 90 91 </div> 92 93 94 <div> 95 96 <label>Type</label> 97 98 <select name="type"> 99 100 <option value="">All Types</option> 101 102 <option value="Album" 103 selected="@(ViewBag.Type == "Album" ? "selected" : null)"> 104 Album 105 </option> 106 107 <option value="Single" 108 selected="@(ViewBag.Type == "Single" ? "selected" : null)"> 109 Single 110 </option> 111 112 </select> 113 114 </div> 115 116 117 <div> 118 119 <label>Sort</label> 120 121 <select name="sort"> 122 123 <option value="">Title A–Z</option> 124 125 <option value="titleDesc" 126 selected="@(ViewBag.Sort == "titleDesc" ? "selected" : null)"> 127 Title Z–A 128 </option> 129 130 <option value="newest" 131 selected="@(ViewBag.Sort == "newest" ? "selected" : null)"> 132 Newest 133 </option> 134 135 <option value="oldest" 136 selected="@(ViewBag.Sort == "oldest" ? "selected" : null)"> 137 Oldest 138 </option> 139 140 <option value="format" 141 selected="@(ViewBag.Sort == "format" ? "selected" : null)"> 142 Format 143 </option> 144 145 <option value="priceAsc" 146 selected="@(ViewBag.Sort == "priceAsc" ? "selected" : null)"> 147 Price: Low to High 148 </option> 149 150 <option value="priceDesc" 151 selected="@(ViewBag.Sort == "priceDesc" ? "selected" : null)"> 152 Price: High to Low 153 </option> 154 155 </select> 156 157 </div> 158 159 160 <div class="filter-button"> 161 162 <button type="submit" 163 class="store-button primary"> 164 165 Apply Filters 166 167 </button> 168 169 </div> 170 171 172 @if (!string.IsNullOrWhiteSpace(ViewBag.Search as string) || 173 !string.IsNullOrWhiteSpace(ViewBag.Genre as string) || 174 !string.IsNullOrWhiteSpace(ViewBag.Format as string) || 175 !string.IsNullOrWhiteSpace(ViewBag.Type as string) || 176 !string.IsNullOrWhiteSpace(ViewBag.Sort as string)) 177 { 178 <div class="clear-filter"> 179 180 <a asp-action="Index"> 181 Clear all filters 182 </a> 183 184 </div> 185 } 186 187 </form> 188 189 190 <!-- ===================================================== 191 RELEASE GRID 192 ===================================================== --> 193 194 @if (!Model.Any()) 195 { 196 <div class="empty-store"> 197 198 <div class="empty-store-icon"> 199 ♪ 200 </div> 201 202 <h2>No releases found</h2> 203 204 <p> 205 Try changing your search or filters. 206 </p> 207 208 <a asp-action="Index" 209 class="store-button primary"> 210 View All Releases 211 </a> 212 213 </div> 214 } 215 else 216 { 217 <div class="release-grid"> 218 219 @foreach (var release in Model) 220 { 221 var isAlbum = release.Album != null; 222 var isSingle = release.SingleRelease != null; 223 224 var releaseType = 225 isAlbum ? "ALBUM" : 226 isSingle ? "SINGLE" : 227 "RELEASE"; 228 229 var artists = string.Join( 230 ", ", 231 release.ReleaseArtists 232 .OrderBy(x => x.ReleaseOrdinal) 233 .Select(x => x.Artist.ArtistName) 234 ); 235 236 var lowestPrice = release.Products 237 .Select(x => (decimal?)x.Price) 238 .Min(); 239 240 <article class="release-card"> 241 242 <a asp-action="Details" 243 asp-route-id="@release.ReleaseId" 244 class="release-card-cover"> 245 246 @if (!string.IsNullOrWhiteSpace(release.CoverPhoto)) 247 { 248 <img src="@release.CoverPhoto" 249 alt="@release.Title" /> 250 } 251 else 252 { 253 <div class="release-no-cover"> 254 <span>♪</span> 255 </div> 256 } 257 258 <span class="release-type-badge"> 259 @releaseType 260 </span> 261 262 </a> 263 264 265 <div class="release-card-body"> 266 267 <div class="release-card-meta"> 268 269 <span> 270 @release.Genre 271 </span> 272 273 <span> 274 @release.ReleaseDate.ToString("yyyy") 275 </span> 276 277 </div> 278 279 280 <h2> 281 282 <a asp-action="Details" 283 asp-route-id="@release.ReleaseId"> 284 285 @release.Title 286 287 </a> 288 289 </h2> 290 291 292 <p class="release-card-artist"> 293 294 @artists 295 296 </p> 297 298 299 <div class="format-list"> 300 301 @foreach (var product in release.Products 302 .GroupBy(x => x.Format) 303 .Select(x => x.First())) 304 { 305 <span class="format-pill"> 306 @product.Format 307 </span> 308 } 309 310 </div> 311 312 313 <div class="release-card-bottom"> 314 315 <div class="release-starting"> 316 317 Starting at 318 319 <strong> 320 @(lowestPrice?.ToString("C") ?? "N/A") 321 </strong> 322 323 </div> 324 325 326 <a asp-action="Details" 327 asp-route-id="@release.ReleaseId" 328 class="store-button primary small"> 329 330 View 331 332 </a> 333 334 </div> 335 336 </div> 337 338 </article> 339 } 340 341 </div> 342 } 343 12 344 </div> 13 14 15 <!-- SEARCH -->16 17 <form asp-action="Index"18 method="get"19 class="row g-2 mb-4">20 21 <div class="col-md-6">22 23 <input type="text"24 name="search"25 value="@ViewBag.Search"26 class="form-control"27 placeholder="Search releases..." />28 29 </div>30 31 32 <div class="col-md-3">33 34 <select name="genre"35 class="form-select">36 37 <option value="">38 All genres39 </option>40 41 @foreach (var genre in ViewBag.Genres)42 {43 <option value="@genre"44 selected="@(ViewBag.Genre == genre)">45 46 @genre47 48 </option>49 }50 51 </select>52 53 </div>54 55 56 <div class="col-md-3">57 58 <button type="submit"59 class="btn btn-primary w-100">60 61 Search62 63 </button>64 65 </div>66 67 </form>68 69 70 <!-- RELEASES -->71 72 <div class="row">73 74 @foreach (var release in Model)75 {76 <div class="col-md-4 mb-4">77 78 <div class="card h-100 shadow-sm">79 80 @if (!string.IsNullOrEmpty(release.CoverPhoto))81 {82 <img src="@release.CoverPhoto"83 class="card-img-top"84 style="height:300px; object-fit:cover;"85 alt="@release.Title" />86 }87 88 <div class="card-body">89 90 <h4 class="card-title">91 @release.Title92 </h4>93 94 <p class="text-muted mb-1">95 @release.Genre96 </p>97 98 <p class="small">99 @release.ReleaseDate.ToString("yyyy")100 </p>101 102 103 <!-- ARTISTS -->104 105 <p>106 107 @string.Join(108 ", ",109 release.ReleaseArtists110 .OrderBy(x => x.ReleaseOrdinal)111 .Select(x => x.Artist.ArtistName)112 )113 114 </p>115 116 117 <!-- AVAILABLE FORMATS -->118 119 <div class="mb-3">120 121 @foreach (var product in release.Products)122 {123 <span class="badge bg-secondary me-1">124 125 @product.Format126 127 </span>128 }129 130 </div>131 132 133 <a asp-action="Details"134 asp-route-id="@release.ReleaseId"135 class="btn btn-primary">136 137 View Release138 139 </a>140 141 </div>142 143 </div>144 145 </div>146 }147 148 </div>
Note:
See TracChangeset
for help on using the changeset viewer.
