Ignore:
Timestamp:
09/01/26 06:11:34 (4 weeks ago)
Author:
mmilevski <markomilevski3@…>
Branches:
main
Children:
d2eccb3
Parents:
08aefc6
Message:

Added major improvements.

Location:
KernelRecordsMVC.Web/Views/Release
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • KernelRecordsMVC.Web/Views/Release/Details.cshtml

    r08aefc6 rfa0fbaf  
    11@model KernelRecordsMVC.Models.Release
    22
    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>
    10123
    11124    </div>
    12125
    13126
    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    }
    47386
    48387</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.Format
    68                 </h4>
    69 
    70                 <h5>
    71                     $@product.Price
    72                 </h5>
    73 
    74                 <p>
    75                     @product.ProductDescription
    76                 </p>
    77 
    78 
    79                 @if (product.Stock > 0)
    80                 {
    81                     <p class="text-success">
    82                         In stock: @product.Stock
    83                     </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 Cart
    91 
    92                     </a>
    93                 }
    94                 else
    95                 {
    96                     <p class="text-danger">
    97                         Out of stock
    98                     </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.AlbumSongs
    120         .OrderBy(x => x.SongId))
    121     {
    122         <li>
    123 
    124             @albumSong.Song.SongName
    125 
    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.Duration
    146     </p>
    147 }
  • KernelRecordsMVC.Web/Views/Release/Index.cshtml

    r08aefc6 rfa0fbaf  
    11@model IEnumerable<KernelRecordsMVC.Models.Release>
    22
    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
    1029    </div>
    1130
     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
    12344</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 genres
    39             </option>
    40 
    41             @foreach (var genre in ViewBag.Genres)
    42             {
    43                 <option value="@genre"
    44                         selected="@(ViewBag.Genre == genre)">
    45 
    46                     @genre
    47 
    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             Search
    62 
    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.Title
    92                 </h4>
    93 
    94                 <p class="text-muted mb-1">
    95                     @release.Genre
    96                 </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.ReleaseArtists
    110                             .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.Format
    126 
    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 Release
    138 
    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.