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
Files:
5 added
9 edited

Legend:

Unmodified
Added
Removed
  • KernelRecordsMVC.Web/Views/Admin/CreateProduct.cshtml

    r08aefc6 rfa0fbaf  
    11@model KernelRecordsMVC.Application.ViewModels.CreateProductViewModel
    22
    3 <h1>New Product</h1>
    4 
    5 <p class="text-muted">
    6     Add a physical product format for an existing release.
    7 </p>
    8 
    9 <form asp-action="CreateProduct"
    10       method="post">
    11 
    12     @Html.AntiForgeryToken()
    13 
    14     <div asp-validation-summary="ModelOnly"
    15          class="text-danger mb-3">
     3@{
     4    ViewData["Title"] = "New Product";
     5}
     6
     7<div class="admin-page admin-form-page">
     8
     9    <!-- HEADER -->
     10
     11    <div class="admin-header">
     12
     13        <div>
     14
     15            <a asp-action="Products"
     16               class="admin-back-link">
     17
     18                ← Products
     19
     20            </a>
     21
     22            <span class="admin-eyebrow">
     23                INVENTORY
     24            </span>
     25
     26            <h1>New Product</h1>
     27
     28            <p>
     29                Add a new physical format to an existing release.
     30            </p>
     31
     32        </div>
     33
    1634    </div>
    1735
    1836
    19     <!-- RELEASE -->
    20 
    21     <div class="mb-3">
    22 
    23         <label asp-for="ReleaseId"
    24                class="form-label">
    25         </label>
    26 
    27         <select asp-for="ReleaseId"
    28                 class="form-select">
    29 
    30             <option value="">
    31                 -- Select Release --
    32             </option>
    33 
    34             @foreach (var release in ViewBag.Releases)
    35             {
    36                 <option value="@release.ReleaseId">
    37 
    38                     @release.Title
    39                     (@release.ReleaseDate.ToString("yyyy"))
    40 
    41                 </option>
    42             }
    43 
    44         </select>
    45 
    46         <span asp-validation-for="ReleaseId"
    47               class="text-danger">
    48         </span>
     37    <div class="admin-form-layout">
     38
     39
     40        <!-- =================================================
     41             FORM
     42             ================================================= -->
     43
     44        <section class="admin-form-card">
     45
     46            <div class="admin-form-card-header">
     47
     48                <span class="admin-eyebrow">
     49                    PRODUCT INFORMATION
     50                </span>
     51
     52                <h2>Product Details</h2>
     53
     54            </div>
     55
     56
     57            <form asp-action="CreateProduct"
     58                  method="post">
     59
     60                @Html.AntiForgeryToken()
     61
     62
     63                <div asp-validation-summary="ModelOnly"
     64                     class="admin-validation">
     65                </div>
     66
     67
     68                <!-- RELEASE -->
     69
     70                <div class="admin-form-field">
     71
     72                    <label asp-for="ReleaseId">
     73                        Release
     74                    </label>
     75
     76                    <select asp-for="ReleaseId">
     77
     78                        <option value="">
     79                            Select a release
     80                        </option>
     81
     82                        @foreach (var release in ViewBag.Releases)
     83                        {
     84                            <option value="@release.ReleaseId">
     85
     86                                @release.Title
     87                                (@release.ReleaseDate.ToString("yyyy"))
     88
     89                            </option>
     90                        }
     91
     92                    </select>
     93
     94                    <span asp-validation-for="ReleaseId"
     95                          class="admin-field-error">
     96                    </span>
     97
     98                    <small>
     99                        Select the release this physical
     100                        product belongs to.
     101                    </small>
     102
     103                </div>
     104
     105
     106                <div class="admin-form-row">
     107
     108
     109                    <!-- FORMAT -->
     110
     111                    <div class="admin-form-field">
     112
     113                        <label asp-for="Format">
     114                            Format
     115                        </label>
     116
     117                        <select asp-for="Format"
     118                                asp-items="Html.GetEnumSelectList<KernelRecordsMVC.Domain.Enums.ProductFormat>()">
     119
     120                            <option value="">
     121                                Select format
     122                            </option>
     123
     124                        </select>
     125
     126                        <span asp-validation-for="Format"
     127                              class="admin-field-error">
     128                        </span>
     129
     130                    </div>
     131
     132
     133                    <!-- PRICE -->
     134
     135                    <div class="admin-form-field">
     136
     137                        <label asp-for="Price">
     138                            Price
     139                        </label>
     140
     141                        <div class="admin-input-prefix">
     142
     143                            <span>$</span>
     144
     145                            <input asp-for="Price"
     146                                   type="number"
     147                                   min="0"
     148                                   step="0.01"
     149                                   placeholder="0.00" />
     150
     151                        </div>
     152
     153                        <span asp-validation-for="Price"
     154                              class="admin-field-error">
     155                        </span>
     156
     157                    </div>
     158
     159                </div>
     160
     161
     162                <!-- STOCK -->
     163
     164                <div class="admin-form-field">
     165
     166                    <label asp-for="Stock">
     167                        Initial Stock
     168                    </label>
     169
     170                    <input asp-for="Stock"
     171                           type="number"
     172                           min="0"
     173                           placeholder="0" />
     174
     175                    <span asp-validation-for="Stock"
     176                          class="admin-field-error">
     177                    </span>
     178
     179                </div>
     180
     181
     182                <!-- DESCRIPTION -->
     183
     184                <div class="admin-form-field">
     185
     186                    <label asp-for="ProductDescription">
     187                        Product Description
     188                    </label>
     189
     190                    <textarea asp-for="ProductDescription"
     191                              rows="5"
     192                              placeholder="Describe this physical edition..."></textarea>
     193
     194                    <span asp-validation-for="ProductDescription"
     195                          class="admin-field-error">
     196                    </span>
     197
     198                </div>
     199
     200
     201                <!-- ACTIONS -->
     202
     203                <div class="admin-form-actions">
     204
     205                    <button type="submit"
     206                            class="admin-button primary">
     207
     208                        Create Product
     209
     210                    </button>
     211
     212
     213                    <a asp-action="Products"
     214                       class="admin-button secondary">
     215
     216                        Cancel
     217
     218                    </a>
     219
     220                </div>
     221
     222            </form>
     223
     224        </section>
     225
     226
     227        <!-- =================================================
     228             SIDE INFO
     229             ================================================= -->
     230
     231        <aside class="admin-help-card">
     232
     233            <span class="admin-eyebrow">
     234                PRODUCT CREATION
     235            </span>
     236
     237            <h3>Before you create</h3>
     238
     239            <div class="admin-help-item">
     240
     241                <strong>01</strong>
     242
     243                <p>
     244                    A release can only have one product
     245                    for each physical format.
     246                </p>
     247
     248            </div>
     249
     250
     251            <div class="admin-help-item">
     252
     253                <strong>02</strong>
     254
     255                <p>
     256                    Stock can be updated later from
     257                    Product Management.
     258                </p>
     259
     260            </div>
     261
     262
     263            <div class="admin-help-item">
     264
     265                <strong>03</strong>
     266
     267                <p>
     268                    Creating the product will automatically
     269                    create a modification record.
     270                </p>
     271
     272            </div>
     273
     274        </aside>
    49275
    50276    </div>
    51277
    52 
    53     <!-- FORMAT -->
    54 
    55     <div class="mb-3">
    56 
    57         <label asp-for="Format"
    58                class="form-label">
    59         </label>
    60 
    61         <select asp-for="Format"
    62                 asp-items="Html.GetEnumSelectList<KernelRecordsMVC.Domain.Enums.ProductFormat>()"
    63                 class="form-select">
    64 
    65             <option value="">
    66                 -- Select Format --
    67             </option>
    68 
    69         </select>
    70 
    71         <span asp-validation-for="Format"
    72               class="text-danger">
    73         </span>
    74 
    75     </div>
    76 
    77 
    78     <!-- PRICE -->
    79 
    80     <div class="mb-3">
    81 
    82         <label asp-for="Price"
    83                class="form-label">
    84         </label>
    85 
    86         <div class="input-group">
    87 
    88             <span class="input-group-text">
    89                 $
    90             </span>
    91 
    92             <input asp-for="Price"
    93                    class="form-control"
    94                    step="0.01"/>
    95 
    96         </div>
    97 
    98         <span asp-validation-for="Price"
    99               class="text-danger">
    100         </span>
    101 
    102     </div>
    103 
    104 
    105     <!-- DESCRIPTION -->
    106 
    107     <div class="mb-3">
    108 
    109         <label asp-for="ProductDescription"
    110                class="form-label">
    111         </label>
    112 
    113         <textarea asp-for="ProductDescription"
    114                   class="form-control"
    115                   rows="4">
    116         </textarea>
    117 
    118         <span asp-validation-for="ProductDescription"
    119               class="text-danger">
    120         </span>
    121 
    122     </div>
    123 
    124 
    125     <!-- STOCK -->
    126 
    127     <div class="mb-3">
    128 
    129         <label asp-for="Stock"
    130                class="form-label">
    131         </label>
    132 
    133         <input asp-for="Stock"
    134                type="number"
    135                min="0"
    136                class="form-control"/>
    137 
    138         <span asp-validation-for="Stock"
    139               class="text-danger">
    140         </span>
    141 
    142     </div>
    143 
    144 
    145     <div class="d-flex gap-2">
    146 
    147         <button type="submit"
    148                 class="btn btn-success">
    149 
    150             Create Product
    151 
    152         </button>
    153 
    154         <a asp-action="Index"
    155            class="btn btn-secondary">
    156 
    157             Cancel
    158 
    159         </a>
    160 
    161     </div>
    162 
    163 </form>
     278</div>
     279
    164280
    165281@section Scripts
    166282{
    167     <partial name="_ValidationScriptsPartial"/>
     283    <partial name="_ValidationScriptsPartial" />
    168284}
  • KernelRecordsMVC.Web/Views/Admin/EditProduct.cshtml

    r08aefc6 rfa0fbaf  
    11@model KernelRecordsMVC.Application.ViewModels.EditProductViewModel
    22
    3 <h1>Modify Product</h1>
    4 
    5 <div class="card mb-4">
    6 
    7     <div class="card-body">
    8 
    9         <h4>@Model.ReleaseTitle</h4>
    10 
    11         <p class="text-muted mb-0">
    12 
    13             Format:
    14 
    15             <strong>
    16                 @Model.Format
    17             </strong>
    18 
    19         </p>
     3@{
     4    ViewData["Title"] = "Modify Product";
     5}
     6
     7<div class="admin-page admin-form-page">
     8
     9    <!-- HEADER -->
     10
     11    <div class="admin-header">
     12
     13        <div>
     14
     15            <a asp-action="Products"
     16               class="admin-back-link">
     17
     18                ← Products
     19
     20            </a>
     21
     22            <span class="admin-eyebrow">
     23                PRODUCT MANAGEMENT
     24            </span>
     25
     26            <h1>Modify Product</h1>
     27
     28            <p>
     29                Update inventory information or apply a discount.
     30            </p>
     31
     32        </div>
    2033
    2134    </div>
    2235
     36
     37    <!-- PRODUCT SUMMARY -->
     38
     39    <div class="admin-product-summary">
     40
     41        <div>
     42
     43            <span class="admin-eyebrow">
     44                SELECTED PRODUCT
     45            </span>
     46
     47            <h2>
     48                @Model.ReleaseTitle
     49            </h2>
     50
     51        </div>
     52
     53        <div class="admin-product-summary-meta">
     54
     55            <div>
     56
     57                <span>FORMAT</span>
     58
     59                <strong>
     60                    @Model.Format
     61                </strong>
     62
     63            </div>
     64
     65            <div>
     66
     67                <span>CURRENT PRICE</span>
     68
     69                <strong>
     70                    @Model.Price.ToString("C")
     71                </strong>
     72
     73            </div>
     74
     75            <div>
     76
     77                <span>STOCK</span>
     78
     79                <strong>
     80                    @Model.Stock
     81                </strong>
     82
     83            </div>
     84
     85        </div>
     86
     87    </div>
     88
     89
     90    <section class="admin-form-card admin-edit-card">
     91
     92        <form asp-action="EditProduct"
     93              method="post"
     94              id="productEditForm">
     95
     96            @Html.AntiForgeryToken()
     97
     98            <input type="hidden"
     99                   asp-for="ProductId" />
     100
     101
     102            <div asp-validation-summary="ModelOnly"
     103                 class="admin-validation">
     104            </div>
     105
     106
     107            <!-- =================================================
     108                 MODIFICATION TYPE
     109                 ================================================= -->
     110
     111            <div class="admin-form-field">
     112
     113                <label asp-for="ModificationType">
     114                    What do you want to do?
     115                </label>
     116
     117                <div class="admin-modification-options">
     118
     119                    <label class="admin-modification-option">
     120
     121                        <input type="radio"
     122                               asp-for="ModificationType"
     123                               value="UPDATE"
     124                               id="updateOption" />
     125
     126                        <span>
     127
     128                            <strong>
     129                                Update Product
     130                            </strong>
     131
     132                            <small>
     133                                Change price, description or stock.
     134                            </small>
     135
     136                        </span>
     137
     138                    </label>
     139
     140
     141                    <label class="admin-modification-option">
     142
     143                        <input type="radio"
     144                               asp-for="ModificationType"
     145                               value="DISCOUNT"
     146                               id="discountOption" />
     147
     148                        <span>
     149
     150                            <strong>
     151                                Apply Discount
     152                            </strong>
     153
     154                            <small>
     155                                Reduce the current selling price.
     156                            </small>
     157
     158                        </span>
     159
     160                    </label>
     161
     162                </div>
     163
     164                <span asp-validation-for="ModificationType"
     165                      class="admin-field-error">
     166                </span>
     167
     168            </div>
     169
     170
     171            <!-- =================================================
     172                 UPDATE FIELDS
     173                 ================================================= -->
     174
     175            <div id="updateFields"
     176                 class="admin-edit-section">
     177
     178                <div class="admin-edit-section-heading">
     179
     180                    <span class="admin-eyebrow">
     181                        PRODUCT UPDATE
     182                    </span>
     183
     184                    <h3>Product Information</h3>
     185
     186                </div>
     187
     188
     189                <div class="admin-form-row">
     190
     191                    <!-- PRICE -->
     192
     193                    <div class="admin-form-field">
     194
     195                        <label asp-for="Price">
     196                            Price
     197                        </label>
     198
     199                        <div class="admin-input-prefix">
     200
     201                            <span>$</span>
     202
     203                            <input asp-for="Price"
     204                                   type="number"
     205                                   min="0"
     206                                   step="0.01" />
     207
     208                        </div>
     209
     210                        <span asp-validation-for="Price"
     211                              class="admin-field-error">
     212                        </span>
     213
     214                    </div>
     215
     216
     217                    <!-- STOCK -->
     218
     219                    <div class="admin-form-field">
     220
     221                        <label asp-for="Stock">
     222                            Stock
     223                        </label>
     224
     225                        <input asp-for="Stock"
     226                               type="number"
     227                               min="0" />
     228
     229                        <span asp-validation-for="Stock"
     230                              class="admin-field-error">
     231                        </span>
     232
     233                    </div>
     234
     235                </div>
     236
     237
     238                <div class="admin-form-field">
     239
     240                    <label asp-for="ProductDescription">
     241                        Description
     242                    </label>
     243
     244                    <textarea asp-for="ProductDescription"
     245                              rows="5"></textarea>
     246
     247                    <span asp-validation-for="ProductDescription"
     248                          class="admin-field-error">
     249                    </span>
     250
     251                </div>
     252
     253            </div>
     254
     255
     256            <!-- =================================================
     257                 DISCOUNT
     258                 ================================================= -->
     259
     260            <div id="discountFields"
     261                 class="admin-edit-section">
     262
     263                <div class="admin-edit-section-heading">
     264
     265                    <span class="admin-eyebrow">
     266                        PROMOTION
     267                    </span>
     268
     269                    <h3>Apply Discount</h3>
     270
     271                    <p>
     272                        The percentage will be deducted
     273                        from the product's current price.
     274                    </p>
     275
     276                </div>
     277
     278
     279                <div class="admin-form-field">
     280
     281                    <label asp-for="Discount">
     282                        Discount Percentage
     283                    </label>
     284
     285                    <div class="admin-input-suffix">
     286
     287                        <input asp-for="Discount"
     288                               type="number"
     289                               min="0.01"
     290                               max="99.99"
     291                               step="0.01"
     292                               placeholder="10" />
     293
     294                        <span>%</span>
     295
     296                    </div>
     297
     298                    <span asp-validation-for="Discount"
     299                          class="admin-field-error">
     300                    </span>
     301
     302                </div>
     303
     304
     305                <div class="admin-discount-preview">
     306
     307                    <span>
     308                        CURRENT PRICE
     309                    </span>
     310
     311                    <strong id="currentPrice"
     312                            data-price="@Model.Price">
     313                        @Model.Price.ToString("C")
     314                    </strong>
     315
     316
     317                    <span>
     318                        NEW PRICE
     319                    </span>
     320
     321                    <strong id="discountedPrice">
     322                        —
     323                    </strong>
     324
     325                </div>
     326
     327            </div>
     328
     329
     330            <!-- ACTIONS -->
     331
     332            <div class="admin-form-actions">
     333
     334                <button type="submit"
     335                        class="admin-button primary">
     336
     337                    Save Changes
     338
     339                </button>
     340
     341                <a asp-action="Products"
     342                   class="admin-button secondary">
     343
     344                    Cancel
     345
     346                </a>
     347
     348            </div>
     349
     350        </form>
     351
     352    </section>
     353
    23354</div>
    24355
    25 
    26 <form asp-action="EditProduct"
    27       method="post">
    28 
    29     @Html.AntiForgeryToken()
    30 
    31     <input type="hidden"
    32            asp-for="ProductId" />
    33 
    34     <div asp-validation-summary="ModelOnly"
    35          class="text-danger mb-3">
    36     </div>
    37 
    38 
    39     <!-- MODIFICATION TYPE -->
    40 
    41     <div class="mb-3">
    42 
    43         <label asp-for="ModificationType"
    44                class="form-label">
    45 
    46             Modification Type
    47 
    48         </label>
    49 
    50         <select asp-for="ModificationType"
    51                 class="form-select">
    52 
    53             <option value="UPDATE">
    54                 Update Product
    55             </option>
    56 
    57             <option value="DISCOUNT">
    58                 Apply Discount
    59             </option>
    60 
    61         </select>
    62 
    63         <span asp-validation-for="ModificationType"
    64               class="text-danger">
    65         </span>
    66 
    67     </div>
    68 
    69 
    70     <!-- PRICE -->
    71 
    72     <div class="mb-3">
    73 
    74         <label asp-for="Price"
    75                class="form-label">
    76 
    77             Price
    78 
    79         </label>
    80 
    81         <div class="input-group">
    82 
    83             <span class="input-group-text">
    84                 $
    85             </span>
    86 
    87             <input asp-for="Price"
    88                    class="form-control"
    89                    step="0.01" />
    90 
    91         </div>
    92 
    93         <span asp-validation-for="Price"
    94               class="text-danger">
    95         </span>
    96 
    97     </div>
    98 
    99 
    100     <!-- DISCOUNT -->
    101 
    102     <div class="mb-3">
    103 
    104         <label asp-for="Discount"
    105                class="form-label">
    106 
    107             Discount Percentage
    108 
    109         </label>
    110 
    111         <div class="input-group">
    112 
    113             <input asp-for="Discount"
    114                    class="form-control"
    115                    type="number"
    116                    min="0"
    117                    max="100"
    118                    step="0.01" />
    119 
    120             <span class="input-group-text">
    121                 %
    122             </span>
    123 
    124         </div>
    125 
    126         <small class="text-muted">
    127             Only used when "Apply Discount" is selected.
    128         </small>
    129 
    130         <span asp-validation-for="Discount"
    131               class="text-danger">
    132         </span>
    133 
    134     </div>
    135 
    136 
    137     <!-- DESCRIPTION -->
    138 
    139     <div class="mb-3">
    140 
    141         <label asp-for="ProductDescription"
    142                class="form-label">
    143 
    144             Description
    145 
    146         </label>
    147 
    148         <textarea asp-for="ProductDescription"
    149                   class="form-control"
    150                   rows="4">
    151         </textarea>
    152 
    153         <span asp-validation-for="ProductDescription"
    154               class="text-danger">
    155         </span>
    156 
    157     </div>
    158 
    159 
    160     <!-- STOCK -->
    161 
    162     <div class="mb-3">
    163 
    164         <label asp-for="Stock"
    165                class="form-label">
    166 
    167             Stock
    168 
    169         </label>
    170 
    171         <input asp-for="Stock"
    172                class="form-control"
    173                type="number"
    174                min="0" />
    175 
    176         <span asp-validation-for="Stock"
    177               class="text-danger">
    178         </span>
    179 
    180     </div>
    181 
    182 
    183     <div class="d-flex gap-2">
    184 
    185         <button type="submit"
    186                 class="btn btn-success">
    187 
    188             Save Changes
    189 
    190         </button>
    191 
    192         <a asp-action="Index"
    193            class="btn btn-secondary">
    194 
    195             Cancel
    196 
    197         </a>
    198 
    199     </div>
    200 
    201 </form>
    202356
    203357@section Scripts
    204358{
    205     <partial name="_ValidationScriptsPartial"/>
     359    <partial name="_ValidationScriptsPartial" />
     360
     361    <script>
     362
     363        document.addEventListener("DOMContentLoaded", function ()
     364        {
     365            const updateOption =
     366                document.getElementById("updateOption");
     367
     368            const discountOption =
     369                document.getElementById("discountOption");
     370
     371            const updateFields =
     372                document.getElementById("updateFields");
     373
     374            const discountFields =
     375                document.getElementById("discountFields");
     376
     377            const discountInput =
     378                document.getElementById("Discount");
     379
     380            const currentPriceElement =
     381                document.getElementById("currentPrice");
     382
     383            const discountedPriceElement =
     384                document.getElementById("discountedPrice");
     385
     386
     387            function updateMode()
     388            {
     389                const isDiscount =
     390                    discountOption.checked;
     391
     392                updateFields.style.display =
     393                    isDiscount ? "none" : "block";
     394
     395                discountFields.style.display =
     396                    isDiscount ? "block" : "none";
     397            }
     398
     399
     400            function updateDiscountPreview()
     401            {
     402                const currentPrice =
     403                    parseFloat(
     404                        currentPriceElement.dataset.price);
     405
     406                const discount =
     407                    parseFloat(discountInput.value);
     408
     409
     410                if (isNaN(discount) ||
     411                    discount <= 0 ||
     412                    discount >= 100)
     413                {
     414                    discountedPriceElement.textContent =
     415                        "—";
     416
     417                    return;
     418                }
     419
     420
     421                const newPrice =
     422                    currentPrice *
     423                    (1 - discount / 100);
     424
     425
     426                discountedPriceElement.textContent =
     427                    "$" + newPrice.toFixed(2);
     428            }
     429
     430
     431            updateOption.addEventListener(
     432                "change",
     433                updateMode);
     434
     435            discountOption.addEventListener(
     436                "change",
     437                updateMode);
     438
     439            discountInput.addEventListener(
     440                "input",
     441                updateDiscountPreview);
     442
     443
     444            updateMode();
     445            updateDiscountPreview();
     446        });
     447
     448    </script>
    206449}
  • KernelRecordsMVC.Web/Views/Admin/Index.cshtml

    r08aefc6 rfa0fbaf  
    33}
    44
    5 <h1>Admin Dashboard</h1>
    6 
    7 @if (TempData["Success"] != null)
    8 {
    9     <div class="alert alert-success">
    10         @TempData["Success"]
     5<div class="admin-page">
     6
     7    <!-- =====================================================
     8         HEADER
     9         ===================================================== -->
     10
     11    <div class="admin-header">
     12
     13        <div>
     14
     15            <span class="admin-eyebrow">
     16                KERNEL RECORDS
     17            </span>
     18
     19            <h1>Admin Dashboard</h1>
     20
     21            <p>
     22                Manage catalog, inventory and store operations.
     23            </p>
     24
     25        </div>
     26
     27
     28        <div class="admin-header-actions">
     29
     30            <a asp-action="CreateRelease"
     31               class="admin-button secondary">
     32
     33                <span>♪</span>
     34                New Release
     35
     36            </a>
     37
     38
     39            <a asp-action="CreateProduct"
     40               class="admin-button primary">
     41
     42                <span>+</span>
     43                New Product
     44
     45            </a>
     46
     47        </div>
     48
    1149    </div>
    12 }
    13 
    14 <div class="row mt-4">
    15 
    16     <div class="col-md-6 mb-3">
    17 
    18         <div class="card h-100">
    19 
    20             <div class="card-body">
    21 
    22                 <h4>Products</h4>
     50
     51
     52    @if (TempData["Success"] != null)
     53    {
     54        <div class="admin-alert success">
     55
     56            <span>✓</span>
     57
     58            @TempData["Success"]
     59
     60        </div>
     61    }
     62
     63
     64    @if (TempData["Error"] != null)
     65    {
     66        <div class="admin-alert danger">
     67
     68            <span>!</span>
     69
     70            @TempData["Error"]
     71
     72        </div>
     73    }
     74
     75
     76    <!-- =====================================================
     77         STATISTICS
     78         ===================================================== -->
     79
     80    <div class="admin-stat-grid">
     81
     82        <div class="admin-stat-card">
     83
     84            <span class="admin-stat-label">
     85                PRODUCTS
     86            </span>
     87
     88            <strong>
     89                @ViewBag.ProductCount
     90            </strong>
     91
     92            <p>
     93                Physical products in the store
     94            </p>
     95
     96        </div>
     97
     98
     99        <div class="admin-stat-card">
     100
     101            <span class="admin-stat-label">
     102                RELEASES
     103            </span>
     104
     105            <strong>
     106                @ViewBag.ReleaseCount
     107            </strong>
     108
     109            <p>
     110                Albums and singles in the catalog
     111            </p>
     112
     113        </div>
     114
     115
     116        <div class="admin-stat-card warning">
     117
     118            <span class="admin-stat-label">
     119                LOW STOCK
     120            </span>
     121
     122            <strong>
     123                @ViewBag.LowStockCount
     124            </strong>
     125
     126            <p>
     127                Products with 5 or fewer remaining
     128            </p>
     129
     130        </div>
     131
     132
     133        <div class="admin-stat-card danger">
     134
     135            <span class="admin-stat-label">
     136                OUT OF STOCK
     137            </span>
     138
     139            <strong>
     140                @ViewBag.OutOfStockCount
     141            </strong>
     142
     143            <p>
     144                Products requiring restocking
     145            </p>
     146
     147        </div>
     148
     149    </div>
     150
     151
     152    <!-- =====================================================
     153         CATALOG MANAGEMENT
     154         ===================================================== -->
     155
     156    <section class="admin-section">
     157
     158        <div class="admin-section-heading">
     159
     160            <div>
     161
     162                <span class="admin-eyebrow">
     163                    CATALOG MANAGEMENT
     164                </span>
     165
     166                <h2>Releases & Products</h2>
    23167
    24168                <p>
    25                     Create and modify products available
    26                     in the music store.
     169                    Create music releases and manage their physical formats.
    27170                </p>
    28171
    29                 <a asp-action="Products"
    30                    class="btn btn-primary">
    31 
    32                     Manage Products
    33 
    34                 </a>
    35 
    36                 <a asp-action="CreateProduct"
    37                    class="btn btn-success">
    38 
    39                     New Product
    40 
    41                 </a>
    42 
    43             </div>
    44 
    45         </div>
    46 
    47     </div>
     172            </div>
     173
     174        </div>
     175
     176
     177        <div class="admin-action-grid">
     178
     179            <!-- CREATE RELEASE -->
     180
     181            <a asp-action="CreateRelease"
     182               class="admin-action-card">
     183
     184                <div class="admin-action-icon">
     185                    ♪
     186                </div>
     187
     188                <div>
     189
     190                    <h3>Create Release</h3>
     191
     192                    <p>
     193                        Create an album or single,
     194                        assign artists and add album tracks.
     195                    </p>
     196
     197                </div>
     198
     199                <span class="admin-action-arrow">
     200                    →
     201                </span>
     202
     203            </a>
     204
     205
     206            <!-- CREATE PRODUCT -->
     207
     208            <a asp-action="CreateProduct"
     209               class="admin-action-card">
     210
     211                <div class="admin-action-icon">
     212                    +
     213                </div>
     214
     215                <div>
     216
     217                    <h3>Create Product</h3>
     218
     219                    <p>
     220                        Add vinyl, CD or cassette
     221                        editions to an existing release.
     222                    </p>
     223
     224                </div>
     225
     226                <span class="admin-action-arrow">
     227                    →
     228                </span>
     229
     230            </a>
     231
     232
     233            <!-- MANAGE PRODUCTS -->
     234
     235            <a asp-action="Products"
     236               class="admin-action-card">
     237
     238                <div class="admin-action-icon">
     239                    ◫
     240                </div>
     241
     242                <div>
     243
     244                    <h3>Manage Products</h3>
     245
     246                    <p>
     247                        Update pricing, inventory,
     248                        descriptions and discounts.
     249                    </p>
     250
     251                </div>
     252
     253                <span class="admin-action-arrow">
     254                    →
     255                </span>
     256
     257            </a>
     258
     259        </div>
     260
     261    </section>
     262
     263
     264    <!-- =====================================================
     265         WORKFLOW INFO
     266         ===================================================== -->
     267
     268    <section class="admin-section">
     269
     270        <div class="admin-section-heading">
     271
     272            <div>
     273
     274                <span class="admin-eyebrow">
     275                    ADMIN WORKFLOW
     276                </span>
     277
     278                <h2>Catalog Process</h2>
     279
     280            </div>
     281
     282        </div>
     283
     284
     285        <div class="admin-workflow-grid">
     286
     287            <div class="admin-workflow-card">
     288
     289                <span class="admin-workflow-number">
     290                    01
     291                </span>
     292
     293                <div>
     294
     295                    <strong>
     296                        Create Release
     297                    </strong>
     298
     299                    <p>
     300                        Add the album or single,
     301                        artists and track information.
     302                    </p>
     303
     304                </div>
     305
     306            </div>
     307
     308
     309            <div class="admin-workflow-card">
     310
     311                <span class="admin-workflow-number">
     312                    02
     313                </span>
     314
     315                <div>
     316
     317                    <strong>
     318                        Create Product
     319                    </strong>
     320
     321                    <p>
     322                        Add its vinyl, CD or cassette
     323                        store edition.
     324                    </p>
     325
     326                </div>
     327
     328            </div>
     329
     330
     331            <div class="admin-workflow-card">
     332
     333                <span class="admin-workflow-number">
     334                    03
     335                </span>
     336
     337                <div>
     338
     339                    <strong>
     340                        Manage Inventory
     341                    </strong>
     342
     343                    <p>
     344                        Change prices, stock,
     345                        descriptions or apply discounts.
     346                    </p>
     347
     348                </div>
     349
     350            </div>
     351
     352        </div>
     353
     354    </section>
    48355
    49356</div>
  • KernelRecordsMVC.Web/Views/Admin/Products.cshtml

    r08aefc6 rfa0fbaf  
    11@model IEnumerable<KernelRecordsMVC.Models.Product>
    22
    3 <div class="d-flex justify-content-between align-items-center mb-4">
    4 
    5     <div>
    6 
    7         <h1>Product Management</h1>
    8 
    9         <p class="text-muted">
    10             Create and modify products in the store.
    11         </p>
     3@{
     4    ViewData["Title"] = "Product Management";
     5}
     6
     7<div class="admin-page">
     8
     9    <!-- HEADER -->
     10
     11    <div class="admin-header">
     12
     13        <div>
     14
     15            <a asp-action="Index"
     16               class="admin-back-link">
     17
     18                ← Dashboard
     19
     20            </a>
     21
     22            <span class="admin-eyebrow">
     23                INVENTORY
     24            </span>
     25
     26            <h1>Product Management</h1>
     27
     28            <p>
     29                Manage formats, prices and inventory.
     30            </p>
     31
     32        </div>
     33
     34
     35        <a asp-action="CreateProduct"
     36           class="admin-button primary">
     37
     38            <span>+</span>
     39            New Product
     40
     41        </a>
    1242
    1343    </div>
    1444
    1545
    16     <a asp-action="CreateProduct"
    17        class="btn btn-success">
    18 
    19         + New Product
    20 
    21     </a>
     46    @if (TempData["Success"] != null)
     47    {
     48        <div class="admin-alert success">
     49
     50            <span>✓</span>
     51
     52            @TempData["Success"]
     53
     54        </div>
     55    }
     56
     57
     58    <!-- SUMMARY -->
     59
     60    <div class="admin-list-summary">
     61
     62        <span>
     63            @Model.Count() products
     64        </span>
     65
     66        <span>
     67            @Model.Count(x => x.Stock <= 0) out of stock
     68        </span>
     69
     70    </div>
     71
     72
     73    <!-- TABLE -->
     74
     75    <div class="admin-table-wrapper">
     76
     77        <table class="admin-table">
     78
     79            <thead>
     80
     81            <tr>
     82
     83                <th>Release</th>
     84
     85                <th>Format</th>
     86
     87                <th>Price</th>
     88
     89                <th>Stock</th>
     90
     91                <th>Status</th>
     92
     93                <th></th>
     94
     95            </tr>
     96
     97            </thead>
     98
     99
     100            <tbody>
     101
     102            @foreach (var product in Model)
     103            {
     104                <tr>
     105
     106                    <!-- RELEASE -->
     107
     108                    <td>
     109
     110                        <div class="admin-product-release">
     111
     112                            <div class="admin-product-cover">
     113
     114                                @if (!string.IsNullOrWhiteSpace(
     115                                    product.Release.CoverPhoto))
     116                                {
     117                                    <img src="@product.Release.CoverPhoto"
     118                                         alt="@product.Release.Title" />
     119                                }
     120                                else
     121                                {
     122                                    <span>♪</span>
     123                                }
     124
     125                            </div>
     126
     127
     128                            <div>
     129
     130                                <strong>
     131                                    @product.Release.Title
     132                                </strong>
     133
     134                                <small>
     135                                    Product #@product.ProductId
     136                                </small>
     137
     138                            </div>
     139
     140                        </div>
     141
     142                    </td>
     143
     144
     145                    <!-- FORMAT -->
     146
     147                    <td>
     148
     149                        <span class="admin-format-badge">
     150                            @product.Format
     151                        </span>
     152
     153                    </td>
     154
     155
     156                    <!-- PRICE -->
     157
     158                    <td class="admin-price">
     159
     160                        @product.Price.ToString("C")
     161
     162                    </td>
     163
     164
     165                    <!-- STOCK -->
     166
     167                    <td>
     168
     169                        <strong>
     170                            @product.Stock
     171                        </strong>
     172
     173                    </td>
     174
     175
     176                    <!-- STATUS -->
     177
     178                    <td>
     179
     180                        @if (product.Stock <= 0)
     181                        {
     182                            <span class="admin-stock danger">
     183                                Out of stock
     184                            </span>
     185                        }
     186                        else if (product.Stock <= 5)
     187                        {
     188                            <span class="admin-stock warning">
     189                                Low stock
     190                            </span>
     191                        }
     192                        else
     193                        {
     194                            <span class="admin-stock success">
     195                                In stock
     196                            </span>
     197                        }
     198
     199                    </td>
     200
     201
     202                    <!-- ACTION -->
     203
     204                    <td class="admin-table-action">
     205
     206                        <a asp-action="EditProduct"
     207                           asp-route-id="@product.ProductId"
     208                           class="admin-button secondary small">
     209
     210                            Modify
     211
     212                        </a>
     213
     214                    </td>
     215
     216                </tr>
     217            }
     218
     219            </tbody>
     220
     221        </table>
     222
     223    </div>
    22224
    23225</div>
    24 
    25 
    26 @if (TempData["Success"] != null)
    27 {
    28     <div class="alert alert-success">
    29 
    30         @TempData["Success"]
    31 
    32     </div>
    33 }
    34 
    35 
    36 <div class="table-responsive">
    37 
    38     <table class="table table-hover align-middle">
    39 
    40         <thead>
    41 
    42         <tr>
    43 
    44             <th>Release</th>
    45 
    46             <th>Format</th>
    47 
    48             <th>Price</th>
    49 
    50             <th>Stock</th>
    51 
    52             <th></th>
    53 
    54         </tr>
    55 
    56         </thead>
    57 
    58 
    59         <tbody>
    60 
    61         @foreach (var product in Model)
    62         {
    63             <tr>
    64 
    65                 <td>
    66 
    67                     <strong>
    68                         @product.Release.Title
    69                     </strong>
    70 
    71                 </td>
    72 
    73 
    74                 <td>
    75 
    76                     <span class="badge bg-secondary">
    77 
    78                         @product.Format
    79 
    80                     </span>
    81 
    82                 </td>
    83 
    84 
    85                 <td>
    86 
    87                     $@product.Price.ToString("0.00")
    88 
    89                 </td>
    90 
    91 
    92                 <td>
    93 
    94                     @if (product.Stock > 0)
    95                     {
    96                         <span class="text-success">
    97 
    98                             @product.Stock
    99 
    100                         </span>
    101                     }
    102                     else
    103                     {
    104                         <span class="text-danger">
    105                             Out of stock
    106                         </span>
    107                     }
    108 
    109                 </td>
    110 
    111 
    112                 <td>
    113 
    114                     <a asp-action="EditProduct"
    115                        asp-route-id="@product.ProductId"
    116                        class="btn btn-outline-primary">
    117 
    118                         Modify
    119 
    120                     </a>
    121 
    122                 </td>
    123 
    124             </tr>
    125         }
    126 
    127         </tbody>
    128 
    129     </table>
    130 
    131 </div>
  • KernelRecordsMVC.Web/Views/Home/Index.cshtml

    r08aefc6 rfa0fbaf  
    1 <div class="text-center py-5">
     1@{
     2    ViewData["Title"] = "Home";
     3}
    24
    3     <h1 class="display-3">
    4         Music Store
    5     </h1>
     5<div class="home-page">
    66
    7     <p class="lead mt-3">
    8         CDs · Vinyl · Cassettes
    9     </p>
     7    <!-- =====================================================
     8         HERO
     9         ===================================================== -->
    1010
    11     <p class="text-muted">
    12         Discover your next favorite release.
    13     </p>
     11    <section class="home-hero">
    1412
    15     <a asp-controller="Release"
    16        asp-action="Index"
    17        class="btn btn-primary btn-lg mt-3">
     13        <div class="home-hero-content">
    1814
    19         Browse Releases
     15            <span class="home-eyebrow">
     16                KERNEL RECORDS
     17            </span>
    2018
    21     </a>
     19            <h1>
     20                MUSIC
     21                <span>FOR</span>
     22                YOUR COLLECTION.
     23            </h1>
     24
     25            <p>
     26                Discover vinyl records, CDs and cassettes
     27                from artists and releases worth keeping.
     28            </p>
     29
     30
     31            <div class="home-hero-actions">
     32
     33                <a asp-controller="Release"
     34                   asp-action="Index"
     35                   class="home-button primary">
     36
     37                    Browse Collection
     38
     39                </a>
     40
     41                <a asp-controller="Sale"
     42                   asp-action="Index"
     43                   class="home-button secondary">
     44
     45                    Shop Sale
     46
     47                </a>
     48
     49            </div>
     50
     51        </div>
     52
     53
     54        <div class="home-hero-mark">
     55            K
     56        </div>
     57
     58    </section>
     59
     60
     61    <!-- =====================================================
     62         QUICK LINKS
     63         ===================================================== -->
     64
     65    <section class="home-section">
     66
     67        <div class="home-section-header">
     68
     69            <div>
     70
     71                <span class="section-label">
     72                    SHOP
     73                </span>
     74
     75                <h2>
     76                    Find something you like.
     77                </h2>
     78
     79            </div>
     80
     81        </div>
     82
     83
     84        <div class="home-feature-grid">
     85
     86            <a asp-controller="Release"
     87               asp-action="Index"
     88               class="home-feature-card">
     89
     90                <span>01</span>
     91
     92                <h3>
     93                    Browse Releases
     94                </h3>
     95
     96                <p>
     97                    Explore albums and singles.
     98                </p>
     99
     100                <strong>
     101                    Explore →
     102                </strong>
     103
     104            </a>
     105
     106
     107            <a asp-controller="TopSellers"
     108               asp-action="Index"
     109               class="home-feature-card">
     110
     111                <span>02</span>
     112
     113                <h3>
     114                    Top Sellers
     115                </h3>
     116
     117                <p>
     118                    See what other collectors are buying.
     119                </p>
     120
     121                <strong>
     122                    View Top Sellers →
     123                </strong>
     124
     125            </a>
     126
     127
     128            <a asp-controller="Sale"
     129               asp-action="Index"
     130               class="home-feature-card sale-feature">
     131
     132                <span>03</span>
     133
     134                <h3>
     135                    Sale
     136                </h3>
     137
     138                <p>
     139                    Find discounted physical releases.
     140                </p>
     141
     142                <strong>
     143                    Shop Sale →
     144                </strong>
     145
     146            </a>
     147
     148        </div>
     149
     150    </section>
     151
     152
     153    <!-- =====================================================
     154         COLLECTION INFO
     155         ===================================================== -->
     156
     157    <section class="home-collection">
     158
     159        <div>
     160
     161            <span class="section-label">
     162                PHYSICAL MUSIC
     163            </span>
     164
     165            <h2>
     166                Vinyl. CDs. Cassettes.
     167            </h2>
     168
     169        </div>
     170
     171        <p>
     172            Build a physical collection with releases
     173            available in the formats you actually want.
     174        </p>
     175
     176    </section>
    22177
    23178</div>
  • KernelRecordsMVC.Web/Views/Order/Cart.cshtml

    r08aefc6 rfa0fbaf  
    11@model KernelRecordsMVC.Application.ViewModels.CartViewModel
    22
    3 <div class="d-flex justify-content-between align-items-center mb-4">
    4 
    5     <h1>Your Cart</h1>
    6 
    7     <a asp-controller="Release"
    8        asp-action="Index"
    9        class="btn btn-outline-primary">
    10 
    11         Continue Shopping
    12 
    13     </a>
    14 
    15 </div>
    16 
    17 
    18 @if (TempData["Error"] != null)
    19 {
    20     <div class="alert alert-danger">
    21 
    22         @TempData["Error"]
    23 
    24     </div>
     3@{
     4    ViewData["Title"] = "Cart";
    255}
    266
    27 
    28 @if (!Model.Items.Any())
    29 {
    30     <div class="text-center py-5">
    31 
    32         <h3>Your cart is empty.</h3>
    33 
    34         <p class="text-muted">
    35             Browse our releases and add something to your order.
    36         </p>
     7<div class="cart-page">
     8
     9    <div class="cart-header">
     10
     11        <div>
     12
     13            <span class="page-eyebrow">
     14                YOUR ORDER
     15            </span>
     16
     17            <h1>Your Cart</h1>
     18
     19            <p>
     20                Review your selected physical releases.
     21            </p>
     22
     23        </div>
    3724
    3825        <a asp-controller="Release"
    3926           asp-action="Index"
    40            class="btn btn-primary">
    41 
    42             Browse Releases
     27           class="store-button secondary">
     28
     29            Continue Shopping
    4330
    4431        </a>
    … …  
    4633    </div>
    4734
    48     return;
    49 }
    50 
    51 
    52 <div class="table-responsive">
    53 
    54     <table class="table align-middle">
    55 
    56         <thead>
    57 
    58         <tr>
    59 
    60             <th>Release</th>
    61 
    62             <th>Format</th>
    63 
    64             <th>Price</th>
    65 
    66             <th>Quantity</th>
    67 
    68             <th>Total</th>
    69 
    70             <th></th>
    71 
    72         </tr>
    73 
    74         </thead>
    75 
    76 
    77         <tbody>
    78 
    79         @foreach (var item in Model.Items)
    80         {
    81             <tr>
    82 
    83                 <td>
    84 
    85                     <a asp-controller="Release"
    86                        asp-action="Details"
    87                        asp-route-id="@item.ReleaseId">
    88 
    89                         @item.ReleaseTitle
    90 
    91                     </a>
    92 
    93                 </td>
    94 
    95 
    96                 <td>
    97 
    98                     <span class="badge bg-secondary">
    99 
    100                         @item.Format
    101 
     35
     36    @if (TempData["Error"] != null)
     37    {
     38        <div class="profile-alert"
     39             style="background:#f9e8e8;color:#a33;">
     40            @TempData["Error"]
     41        </div>
     42    }
     43
     44
     45    @if (!Model.Items.Any())
     46    {
     47        <div class="empty-store">
     48
     49            <div class="empty-store-icon">
     50                🛒
     51            </div>
     52
     53            <h2>Your cart is empty</h2>
     54
     55            <p>
     56                Browse our releases and add something to your order.
     57            </p>
     58
     59            <a asp-controller="Release"
     60               asp-action="Index"
     61               class="store-button primary">
     62
     63                Browse Releases
     64
     65            </a>
     66
     67        </div>
     68    }
     69    else
     70    {
     71        <div class="cart-layout">
     72
     73            <div class="cart-items">
     74
     75                <div class="cart-items-header">
     76                    @Model.Items.Count item(s) in your cart
     77                </div>
     78
     79
     80                @foreach (var item in Model.Items)
     81                {
     82                    <div class="cart-item">
     83
     84                        <a asp-controller="Release"
     85                           asp-action="Details"
     86                           asp-route-id="@item.ReleaseId"
     87                           class="cart-item-cover">
     88
     89                            @if (!string.IsNullOrWhiteSpace(item.CoverPhoto))
     90                            {
     91                                <img src="@item.CoverPhoto"
     92                                     alt="@item.ReleaseTitle" />
     93                            }
     94                            else
     95                            {
     96                                <div class="cart-cover-placeholder">
     97                                    ♪
     98                                </div>
     99                            }
     100
     101                        </a>
     102
     103
     104                        <div class="cart-item-info">
     105
     106                            <span class="cart-item-type">
     107                                @item.Format
     108                            </span>
     109
     110                            <h2>
     111
     112                                <a asp-controller="Release"
     113                                   asp-action="Details"
     114                                   asp-route-id="@item.ReleaseId">
     115
     116                                    @item.ReleaseTitle
     117
     118                                </a>
     119
     120                            </h2>
     121
     122                            <div class="cart-item-price">
     123
     124                                @item.Price.ToString("C")
     125                                each
     126
     127                            </div>
     128
     129                        </div>
     130
     131
     132                        <div class="cart-item-quantity">
     133
     134                            <form asp-action="UpdateQuantity"
     135                                  method="post">
     136
     137                                @Html.AntiForgeryToken()
     138
     139                                <input type="hidden"
     140                                       name="id"
     141                                       value="@item.ProductId" />
     142
     143                                <input type="number"
     144                                       name="quantity"
     145                                       value="@item.Quantity"
     146                                       min="1"
     147                                       max="@item.Stock" />
     148
     149                                <button type="submit">
     150                                    Update
     151                                </button>
     152
     153                            </form>
     154
     155                        </div>
     156
     157
     158                        <div class="cart-item-total">
     159
     160                            @item.Total.ToString("C")
     161
     162                        </div>
     163
     164
     165                        <form asp-action="RemoveProduct"
     166                              method="post">
     167
     168                            @Html.AntiForgeryToken()
     169
     170                            <input type="hidden"
     171                                   name="id"
     172                                   value="@item.ProductId" />
     173
     174                            <button type="submit"
     175                                    class="cart-remove"
     176                                    title="Remove">
     177
     178                                ×
     179
     180                            </button>
     181
     182                        </form>
     183
     184                    </div>
     185                }
     186
     187            </div>
     188
     189
     190            <aside class="cart-summary">
     191
     192                <span class="section-label">
     193                    ORDER SUMMARY
     194                </span>
     195
     196                <h2>
     197                    Your Order
     198                </h2>
     199
     200
     201                <div class="summary-line">
     202
     203                    <span>
     204                        Items
    102205                    </span>
    103206
    104                 </td>
    105 
    106 
    107                 <td>
    108 
    109                     $@item.Price.ToString("0.00")
    110 
    111                 </td>
    112 
    113 
    114                 <td>
    115 
    116                     <form asp-action="UpdateQuantity"
    117                           method="post"
    118                           class="d-flex">
    119 
    120                         @Html.AntiForgeryToken()
    121 
    122                         <input type="hidden"
    123                                name="id"
    124                                value="@item.ProductId" />
    125 
    126                         <input type="number"
    127                                name="quantity"
    128                                value="@item.Quantity"
    129                                min="1"
    130                                max="@item.Stock"
    131                                class="form-control"
    132                                style="width:90px;" />
    133 
    134                         <button type="submit"
    135                                 class="btn btn-outline-secondary ms-2">
    136 
    137                             Update
    138 
    139                         </button>
    140 
    141                     </form>
    142 
    143                 </td>
    144 
    145 
    146                 <td>
    147 
    148207                    <strong>
    149 
    150                         $@item.Total.ToString("0.00")
    151 
     208                        @Model.Items.Sum(x => x.Quantity)
    152209                    </strong>
    153210
    154                 </td>
    155 
    156 
    157                 <td>
    158 
    159                     <form asp-action="RemoveProduct"
    160                           method="post">
    161 
    162                         @Html.AntiForgeryToken()
    163 
    164                         <input type="hidden"
    165                                name="id"
    166                                value="@item.ProductId" />
    167 
    168                         <button type="submit"
    169                                 class="btn btn-outline-danger">
    170 
    171                             Remove
    172 
    173                         </button>
    174 
    175                     </form>
    176 
    177                 </td>
    178 
    179             </tr>
    180         }
    181 
    182         </tbody>
    183 
    184     </table>
     211                </div>
     212
     213
     214                <div class="summary-line total">
     215
     216                    <span>
     217                        Total
     218                    </span>
     219
     220                    <strong>
     221                        @Model.Total.ToString("C")
     222                    </strong>
     223
     224                </div>
     225
     226
     227                <a asp-action="Checkout"
     228                   class="store-button primary full">
     229
     230                    Proceed to Checkout
     231
     232                </a>
     233
     234            </aside>
     235
     236        </div>
     237    }
    185238
    186239</div>
    187 
    188 
    189 <div class="row justify-content-end">
    190 
    191     <div class="col-md-4">
    192 
    193         <div class="card">
    194 
    195             <div class="card-body">
    196 
    197                 <h4>Order Summary</h4>
    198 
    199                 <hr />
    200 
    201                 <div class="d-flex justify-content-between">
    202 
    203                     <span>Total</span>
    204 
    205                     <strong>
    206                         $@Model.Total.ToString("0.00")
    207                     </strong>
    208 
    209                 </div>
    210 
    211 
    212                 <a asp-action="Checkout"
    213                    class="btn btn-success w-100 mt-3">
    214 
    215                     Proceed to Checkout
    216 
    217                 </a>
    218 
    219             </div>
    220 
    221         </div>
    222 
    223     </div>
    224 
    225 </div>
  • 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>
  • KernelRecordsMVC.Web/Views/Shared/_Layout.cshtml

    r08aefc6 rfa0fbaf  
    1 <!DOCTYPE html>
     1@using Microsoft.AspNetCore.Http
     2
     3<!DOCTYPE html>
     4
    25<html lang="en">
    36<head>
    4     <meta charset="utf-8"/>
    5     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    6     <title>@ViewData["Title"] - KernelRecordsMVC</title>
    7     <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css"/>
    8     <link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
    9     <link rel="stylesheet" href="~/KernelRecordsMVC.styles.css" asp-append-version="true"/>
     7    <meta charset="utf-8" />
     8    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     9
     10
     11<title>@ViewData["Title"] - Kernel Records</title>
     12
     13<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
     14
     15
    1016</head>
     17
    1118<body>
    12 <header>
    13     <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
    14         <div class="container-fluid">
    15             <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">KernelRecordsMVC</a>
    16             <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
    17                     aria-expanded="false" aria-label="Toggle navigation">
    18                 <span class="navbar-toggler-icon"></span>
    19             </button>
    20             <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
    21                 <ul class="navbar-nav flex-grow-1">
    22                     <li class="nav-item">
    23                         <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
    24                     </li>
    25                     <li class="nav-item">
    26                         <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
    27                     </li>
    28                 </ul>
     19
     20<header class="site-header">
     21
     22
     23<!-- =====================================================
     24     MAIN NAVBAR
     25     ===================================================== -->
     26
     27<nav class="navbar">
     28
     29    <div class="navbar-container">
     30
     31        <!-- LOGO -->
     32
     33        <a class="brand"
     34           asp-controller="Home"
     35           asp-action="Index">
     36
     37            <span class="brand-main">
     38                KERNEL
     39            </span>
     40
     41            <span class="brand-sub">
     42                RECORDS
     43            </span>
     44
     45        </a>
     46
     47
     48        <!-- MOBILE MENU BUTTON -->
     49
     50        <button class="mobile-menu-button"
     51                type="button"
     52                aria-label="Toggle navigation"
     53                onclick="toggleMobileMenu()">
     54
     55            ☰
     56
     57        </button>
     58
     59
     60        <!-- NAVBAR CONTENT -->
     61
     62        <div class="navbar-content"
     63             id="navbarContent">
     64
     65
     66            <!-- =================================================
     67                 MAIN NAVIGATION
     68                 ================================================= -->
     69
     70            <ul class="nav-links">
     71
     72                <!-- Browse -->
     73
     74                <li>
     75
     76                    <a asp-controller="Release"
     77                       asp-action="Index">
     78
     79                        Browse
     80
     81                    </a>
     82
     83                </li>
     84
     85
     86                <!-- Top Sellers -->
     87
     88                <li>
     89
     90                    <a asp-controller="TopSellers"
     91                       asp-action="Index">
     92
     93                        Top Sellers
     94
     95                    </a>
     96
     97                </li>
     98
     99
     100                <!-- Artists -->
     101
     102                <li>
     103
     104                    <a asp-controller="Artist"
     105                       asp-action="Index">
     106
     107                        Artists
     108
     109                    </a>
     110
     111                </li>
     112
     113
     114                <!-- Genres -->
     115
     116                <li class="nav-dropdown">
     117
     118                    <a href="#"
     119                       class="dropdown-toggle">
     120
     121                        Genres
     122
     123                        <span class="arrow">
     124                            ⌄
     125                        </span>
     126
     127                    </a>
     128
     129
     130                    <div class="dropdown-menu">
     131
     132                        <a asp-controller="Release"
     133                           asp-action="Index"
     134                           asp-route-genre="Rock">
     135
     136                            Rock
     137
     138                        </a>
     139
     140                        <a asp-controller="Release"
     141                           asp-action="Index"
     142                           asp-route-genre="Pop">
     143
     144                            Pop
     145
     146                        </a>
     147
     148                        <a asp-controller="Release"
     149                           asp-action="Index"
     150                           asp-route-genre="Hip-Hop">
     151
     152                            Hip-Hop
     153
     154                        </a>
     155
     156                        <a asp-controller="Release"
     157                           asp-action="Index"
     158                           asp-route-genre="Jazz">
     159
     160                            Jazz
     161
     162                        </a>
     163
     164                        <a asp-controller="Release"
     165                           asp-action="Index"
     166                           asp-route-genre="Electronic">
     167
     168                            Electronic
     169
     170                        </a>
     171
     172                        <a asp-controller="Release"
     173                           asp-action="Index">
     174
     175                            All Genres
     176
     177                        </a>
     178
     179                    </div>
     180
     181                </li>
     182
     183
     184                <!-- Sale -->
     185
     186                <li>
     187
     188                    <a asp-controller="Sale"
     189                       asp-action="Index"
     190                       class="nav-sale">
     191
     192                        Sale
     193
     194                    </a>
     195
     196                </li>
     197
     198            </ul>
     199
     200
     201            <!-- =================================================
     202                 SEARCH
     203                 ================================================= -->
     204
     205            <form class="navbar-search"
     206                  asp-controller="Release"
     207                  asp-action="Index"
     208                  method="get">
     209
     210                <input type="text"
     211                       name="search"
     212                       placeholder="Search releases..."
     213                       autocomplete="off" />
     214
     215                <button type="submit"
     216                        aria-label="Search">
     217
     218                    <span>
     219                        ⌕
     220                    </span>
     221
     222                </button>
     223
     224            </form>
     225
     226
     227            <!-- =================================================
     228                 RIGHT SIDE ACTIONS
     229                 ================================================= -->
     230
     231            <div class="navbar-actions">
     232
     233
     234                <!-- =================================================
     235                     WISHLIST
     236                     ================================================= -->
     237
     238                <a class="nav-icon"
     239                   asp-controller="Wishlist"
     240                   asp-action="Index"
     241                   title="Wishlist">
     242
     243                    <span class="icon">
     244                        ♡
     245                    </span>
     246
     247                    <span class="icon-label">
     248                        Wishlist
     249                    </span>
     250
     251                </a>
     252
     253
     254                <!-- =================================================
     255                     CART
     256                     ================================================= -->
     257
     258                <a class="nav-icon"
     259                   asp-controller="Order"
     260                   asp-action="Cart"
     261                   title="Shopping Cart">
     262
     263                    <span class="icon cart-icon">
     264                        🛒
     265                    </span>
     266
     267                    <span class="icon-label">
     268                        Cart
     269                    </span>
     270
     271                </a>
     272
     273
     274                <!-- =================================================
     275                     ACCOUNT
     276                     ================================================= -->
     277
     278                @if (Context.Session.GetInt32("UserId") != null)
     279                {
     280
     281                    <!-- LOGGED IN -->
     282
     283                    <div class="account-dropdown">
     284
     285
     286                        <button class="account-button"
     287                                type="button">
     288
     289                            <span class="user-icon">
     290                                ●
     291                            </span>
     292
     293                            <span class="account-name">
     294
     295                                @Context.Session.GetString("Username")
     296
     297                            </span>
     298
     299                            <span class="arrow">
     300                                ⌄
     301                            </span>
     302
     303                        </button>
     304
     305
     306                        <!-- ACCOUNT MENU -->
     307
     308                        <div class="account-menu">
     309
     310
     311                            <!-- PROFILE -->
     312
     313                            <a asp-controller="Account"
     314                               asp-action="Profile">
     315
     316                                <span>
     317                                    👤
     318                                </span>
     319
     320                                My Profile
     321
     322                            </a>
     323
     324
     325                            <!-- ORDERS -->
     326
     327                            <a asp-controller="Order"
     328                               asp-action="Cart">
     329
     330                                <span>
     331                                    📦
     332                                </span>
     333
     334                                My Orders
     335
     336                            </a>
     337
     338
     339                            <!-- WISHLIST -->
     340
     341                            <a asp-controller="Wishlist"
     342                               asp-action="Index">
     343
     344                                <span>
     345                                    ♡
     346                                </span>
     347
     348                                My Wishlist
     349
     350                            </a>
     351
     352
     353                            <!-- ADMIN -->
     354
     355                            @if (Context.Session.GetString("Role") == "Admin")
     356                            {
     357
     358                                <div class="menu-divider"></div>
     359
     360
     361                                <a asp-controller="Admin"
     362                                   asp-action="Index"
     363                                   class="admin-link">
     364
     365                                    <span>
     366                                        ⚙
     367                                    </span>
     368
     369                                    Admin Dashboard
     370
     371                                </a>
     372
     373                            }
     374
     375
     376                            <div class="menu-divider"></div>
     377
     378
     379                            <!-- LOGOUT -->
     380
     381                            <form asp-controller="Account"
     382                                  asp-action="Logout"
     383                                  method="post">
     384
     385                                @Html.AntiForgeryToken()
     386
     387                                <button type="submit"
     388                                        class="logout-button">
     389
     390                                    <span>↪</span>
     391
     392                                    Logout
     393
     394                                </button>
     395
     396                            </form>
     397
     398
     399                        </div>
     400
     401                    </div>
     402
     403                }
     404                else
     405                {
     406
     407                    <!-- =================================================
     408                         NOT LOGGED IN
     409                         ================================================= -->
     410
     411                    <div class="auth-buttons">
     412
     413
     414                        <a asp-controller="Account"
     415                           asp-action="Login"
     416                           class="login-button">
     417
     418                            Login
     419
     420                        </a>
     421
     422
     423                        <a asp-controller="Account"
     424                           asp-action="Register"
     425                           class="register-button">
     426
     427                            Register
     428
     429                        </a>
     430
     431
     432                    </div>
     433
     434                }
     435
    29436            </div>
     437
    30438        </div>
    31     </nav>
     439
     440    </div>
     441
     442</nav>
     443
     444
     445<!-- =====================================================
     446     ANNOUNCEMENT BAR
     447     ===================================================== -->
     448
     449<div class="announcement-bar">
     450
     451    <span>
     452        FREE SHIPPING ON ORDERS OVER €50
     453    </span>
     454
     455    <span class="announcement-separator">
     456        •
     457    </span>
     458
     459    <span>
     460        NEW VINYL EVERY WEEK
     461    </span>
     462
     463</div>
     464
     465
    32466</header>
    33 <div class="container">
    34     <main role="main" class="pb-3">
    35         @RenderBody()
    36     </main>
     467
     468<!-- =========================================================
     469     MAIN CONTENT
     470     ========================================================= -->
     471
     472<main class="main-content">
     473
     474
     475@RenderBody()
     476
     477
     478</main>
     479
     480<!-- =========================================================
     481     FOOTER
     482     ========================================================= -->
     483
     484<footer class="site-footer">
     485
     486
     487<div class="footer-container">
     488
     489
     490    <!-- BRAND -->
     491
     492    <div class="footer-brand">
     493
     494        <div class="footer-logo">
     495            KERNEL RECORDS
     496        </div>
     497
     498        <p>
     499            Your destination for vinyl, CDs and cassettes.
     500        </p>
     501
     502    </div>
     503
     504
     505    <!-- SHOP -->
     506
     507    <div class="footer-column">
     508
     509        <h4>
     510            Shop
     511        </h4>
     512
     513
     514        <a asp-controller="Release"
     515           asp-action="Index">
     516
     517            Releases
     518
     519        </a>
     520
     521
     522        <a asp-controller="Release"
     523           asp-action="Index">
     524
     525            New Releases
     526
     527        </a>
     528
     529
     530        <a asp-controller="Artist"
     531           asp-action="Index">
     532
     533            Artists
     534
     535        </a>
     536
     537    </div>
     538
     539
     540    <!-- ACCOUNT -->
     541
     542    <div class="footer-column">
     543
     544        <h4>
     545            Account
     546        </h4>
     547
     548
     549        @if (Context.Session.GetInt32("UserId") != null)
     550        {
     551
     552            <a asp-controller="Account"
     553               asp-action="Profile">
     554
     555                My Profile
     556
     557            </a>
     558
     559
     560            <a asp-controller="Order"
     561               asp-action="Cart">
     562
     563                My Orders
     564
     565            </a>
     566
     567
     568            <a asp-controller="Wishlist"
     569               asp-action="Index">
     570
     571                Wishlist
     572
     573            </a>
     574
     575        }
     576        else
     577        {
     578
     579            <a asp-controller="Account"
     580               asp-action="Login">
     581
     582                Login
     583
     584            </a>
     585
     586
     587            <a asp-controller="Account"
     588               asp-action="Register">
     589
     590                Register
     591
     592            </a>
     593
     594        }
     595
     596    </div>
     597
     598
     599    <!-- HELP -->
     600
     601    <div class="footer-column">
     602
     603        <h4>
     604            Help
     605        </h4>
     606
     607        <a href="#">
     608            Shipping
     609        </a>
     610
     611        <a href="#">
     612            Returns
     613        </a>
     614
     615        <a href="#">
     616            Contact
     617        </a>
     618
     619    </div>
     620
    37621</div>
    38622
    39 <footer class="border-top footer text-muted">
    40     <div class="container">
    41         &copy; 2026 - KernelRecordsMVC - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
    42     </div>
     623
     624<!-- FOOTER BOTTOM -->
     625
     626<div class="footer-bottom">
     627
     628    <span>
     629        © @DateTime.Now.Year Kernel Records
     630    </span>
     631
     632    <span>
     633        All rights reserved.
     634    </span>
     635
     636</div>
     637
     638
    43639</footer>
    44 <script src="~/lib/jquery/dist/jquery.min.js"></script>
    45 <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    46 <script src="~/js/site.js" asp-append-version="true"></script>
    47 @await RenderSectionAsync("Scripts", required: false)
     640
     641<!-- =========================================================
     642     MOBILE NAVIGATION SCRIPT
     643     ========================================================= -->
     644
     645<script>
     646
     647    function toggleMobileMenu()
     648    {
     649        const menu =
     650            document.getElementById("navbarContent");
     651
     652        menu.classList.toggle("mobile-open");
     653    }
     654
     655
     656    // Close mobile menu when clicking outside
     657
     658    document.addEventListener("click", function (event)
     659    {
     660        const menu =
     661            document.getElementById("navbarContent");
     662
     663        const button =
     664            document.querySelector(".mobile-menu-button");
     665
     666
     667        if (!menu.contains(event.target) &&
     668            !button.contains(event.target))
     669        {
     670            menu.classList.remove("mobile-open");
     671        }
     672
     673    });
     674
     675</script>
     676
     677@await RenderSectionAsync(
     678"Scripts",
     679required: false)
     680
    48681</body>
    49682</html>
Note: See TracChangeset for help on using the changeset viewer.