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