Changeset 595d2e5
- Timestamp:
- 09/02/26 05:22:09 (4 weeks ago)
- Branches:
- main
- Children:
- 1dcdb2c
- Parents:
- d89d25b
- Files:
-
- 63 edited
-
KernelRecordsMVC.Application/ViewModels/CreateTrackViewModel.cs (modified) (1 diff)
-
KernelRecordsMVC.Application/bin/Debug/net8.0/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Application/bin/Debug/net8.0/KernelRecordsMVC.Application.pdb (modified) ( previous)
-
KernelRecordsMVC.Application/bin/Debug/net8.0/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Application/bin/Debug/net8.0/KernelRecordsMVC.Domain.pdb (modified) ( previous)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.AssemblyInfo.cs (modified) (1 diff)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.AssemblyInfoInputs.cache (modified) (1 diff)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.csproj.AssemblyReference.cache (modified) ( previous)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.pdb (modified) ( previous)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.sourcelink.json (modified) (1 diff)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/ref/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Application/obj/Debug/net8.0/refint/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Domain/bin/Debug/net8.0/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Domain/bin/Debug/net8.0/KernelRecordsMVC.Domain.pdb (modified) ( previous)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.AssemblyInfo.cs (modified) (1 diff)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.AssemblyInfoInputs.cache (modified) (1 diff)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.pdb (modified) ( previous)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.sourcelink.json (modified) (1 diff)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/ref/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Domain/obj/Debug/net8.0/refint/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Application.pdb (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Domain.pdb (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Infrastructure.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/bin/Debug/net8.0/KernelRecordsMVC.Infrastructure.pdb (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.AssemblyInfo.cs (modified) (1 diff)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.AssemblyInfoInputs.cache (modified) (1 diff)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.csproj.AssemblyReference.cache (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.pdb (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.sourcelink.json (modified) (1 diff)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/ref/KernelRecordsMVC.Infrastructure.dll (modified) ( previous)
-
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/refint/KernelRecordsMVC.Infrastructure.dll (modified) ( previous)
-
KernelRecordsMVC.Web/Controllers/AdminController.cs (modified) (28 diffs)
-
KernelRecordsMVC.Web/Controllers/ReleaseController.cs (modified) (1 diff)
-
KernelRecordsMVC.Web/Views/Admin/CreateRelease.cshtml (modified) (3 diffs)
-
KernelRecordsMVC.Web/Views/Admin/Index.cshtml (modified) (2 diffs)
-
KernelRecordsMVC.Web/Views/Release/Details.cshtml (modified) (4 diffs)
-
KernelRecordsMVC.Web/Views/Release/Index.cshtml (modified) (1 diff)
-
KernelRecordsMVC.Web/Views/Shared/_Layout.cshtml (modified) (10 diffs)
-
KernelRecordsMVC.Web/Views/Wishlist/Index.cshtml (modified) (9 diffs)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Application.dll (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Application.pdb (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Domain.dll (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Domain.pdb (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Infrastructure.dll (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Infrastructure.pdb (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Web.dll (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Web.exe (modified) ( previous)
-
KernelRecordsMVC.Web/bin/Debug/net8.0/KernelRecordsMVC.Web.pdb (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.AssemblyInfo.cs (modified) (1 diff)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.AssemblyInfoInputs.cache (modified) (1 diff)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.csproj.AssemblyReference.cache (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.dll (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.pdb (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.sourcelink.json (modified) (1 diff)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/apphost.exe (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/ref/KernelRecordsMVC.Web.dll (modified) ( previous)
-
KernelRecordsMVC.Web/obj/Debug/net8.0/refint/KernelRecordsMVC.Web.dll (modified) ( previous)
-
KernelRecordsMVC.Web/wwwroot/css/site.css (modified) (25 diffs)
Legend:
- Unmodified
- Added
- Removed
-
KernelRecordsMVC.Application/ViewModels/CreateTrackViewModel.cs
rd89d25b r595d2e5 5 5 public class CreateTrackViewModel 6 6 { 7 [Required ]7 [Required(ErrorMessage = "Track name is required.")] 8 8 [Display(Name = "Track Name")] 9 9 public string SongName { get; set; } = string.Empty; 10 10 11 11 12 [Required] 12 [Required(ErrorMessage = "Track duration is required.")] 13 [RegularExpression( 14 @"^\d{1,2}:[0-5]\d$", 15 ErrorMessage = "Track duration must be in MM:SS format, for example 03:42.")] 13 16 [Display(Name = "Duration")] 14 17 public string SongDuration { get; set; } = string.Empty; 15 18 16 19 17 [Display(Name = "Track Artists")]18 20 public List<long> ArtistIds { get; set; } = new(); 19 21 } -
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.AssemblyInfo.cs
rd89d25b r595d2e5 14 14 [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 15 15 [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63")]16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d89d25b3a7f785676877cf198c9cc706308ab4a3")] 17 17 [assembly: System.Reflection.AssemblyProductAttribute("KernelRecordsMVC.Application")] 18 18 [assembly: System.Reflection.AssemblyTitleAttribute("KernelRecordsMVC.Application")] -
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.AssemblyInfoInputs.cache
rd89d25b r595d2e5 1 0a806091492b419d863bcf31dc25ce545b03be1d3b3d188a337ab3ca6889ac3f 1 1de1e67b21e6555460bba54dec4600f29627ec11612fbabaf75aead1668384fb -
KernelRecordsMVC.Application/obj/Debug/net8.0/KernelRecordsMVC.Application.sourcelink.json
rd89d25b r595d2e5 1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63/*"}}1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d89d25b3a7f785676877cf198c9cc706308ab4a3/*"}} -
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.AssemblyInfo.cs
rd89d25b r595d2e5 14 14 [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 15 15 [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63")]16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d89d25b3a7f785676877cf198c9cc706308ab4a3")] 17 17 [assembly: System.Reflection.AssemblyProductAttribute("KernelRecordsMVC.Domain")] 18 18 [assembly: System.Reflection.AssemblyTitleAttribute("KernelRecordsMVC.Domain")] -
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.AssemblyInfoInputs.cache
rd89d25b r595d2e5 1 9ac54125bd905265e26e18e6c5ad395dc962c3187cbd749ef37d34bb164ca220 1 2c5c6269aac41449bcb50d10a12b287cb457ef35a5d93683092ccb6ff4c72e0c -
KernelRecordsMVC.Domain/obj/Debug/net8.0/KernelRecordsMVC.Domain.sourcelink.json
rd89d25b r595d2e5 1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63/*"}}1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d89d25b3a7f785676877cf198c9cc706308ab4a3/*"}} -
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.AssemblyInfo.cs
rd89d25b r595d2e5 14 14 [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 15 15 [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63")]16 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d89d25b3a7f785676877cf198c9cc706308ab4a3")] 17 17 [assembly: System.Reflection.AssemblyProductAttribute("KernelRecordsMVC.Infrastructure")] 18 18 [assembly: System.Reflection.AssemblyTitleAttribute("KernelRecordsMVC.Infrastructure")] -
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.AssemblyInfoInputs.cache
rd89d25b r595d2e5 1 0a244f365ce2ab97b7911a45cd06642ace0b6002cc3788b6ed779b9b4d4fb537 1 5ec5e89a0b05a9fba0312a8736adff239c38327d3e73e894fad14b10b6985769 -
KernelRecordsMVC.Infrastructure/obj/Debug/net8.0/KernelRecordsMVC.Infrastructure.sourcelink.json
rd89d25b r595d2e5 1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63/*"}}1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d89d25b3a7f785676877cf198c9cc706308ab4a3/*"}} -
KernelRecordsMVC.Web/Controllers/AdminController.cs
rd89d25b r595d2e5 497 497 498 498 499 // ===================================================== 500 // RELEASE TYPE VALIDATION 501 // ===================================================== 499 // ========================================================= 500 // NORMALIZE RELEASE TYPE 501 // ========================================================= 502 503 model.ReleaseType = 504 model.ReleaseType?.Trim().ToUpperInvariant() 505 ?? string.Empty; 506 502 507 503 508 if (model.ReleaseType != "ALBUM" && … … 510 515 511 516 512 // ===================================================== 517 // ========================================================= 513 518 // MAIN ARTIST VALIDATION 514 // ===================================================== 519 // ========================================================= 515 520 516 521 var mainArtistExists = 517 522 _context.Artists.Any(a => 518 a.ArtistId == 519 model.MainArtistId); 523 a.ArtistId == model.MainArtistId); 520 524 521 525 … … 528 532 529 533 530 // ===================================================== 534 // ========================================================= 531 535 // FEATURED ARTISTS 532 // ===================================================== 536 // ========================================================= 533 537 534 538 model.FeaturedArtistIds ??= … … 539 543 model.FeaturedArtistIds 540 544 .Distinct() 545 .Where(id => 546 id != model.MainArtistId) 541 547 .ToList(); 542 548 543 549 544 // Do not allow the main artist545 // to also be a featured artist.546 model.FeaturedArtistIds.Remove(547 model.MainArtistId);548 549 550 // Validate that featured artists exist.551 550 if (model.FeaturedArtistIds.Count > 0) 552 551 { … … 567 566 568 567 569 // ===================================================== 568 // ========================================================= 570 569 // SINGLE VALIDATION 571 // ===================================================== 570 // ========================================================= 572 571 573 572 if (model.ReleaseType == "SINGLE") 574 573 { 574 // Album track values do not apply to a single. 575 model.Tracks = 576 new List<CreateTrackViewModel>(); 577 578 579 var trackModelStateKeys = 580 ModelState.Keys 581 .Where(key => 582 key.StartsWith( 583 "Tracks[", 584 StringComparison.OrdinalIgnoreCase)) 585 .ToList(); 586 587 588 foreach (var key in trackModelStateKeys) 589 { 590 ModelState.Remove(key); 591 } 592 593 575 594 if (string.IsNullOrWhiteSpace( 576 model.SingleDuration))595 model.SingleDuration)) 577 596 { 578 597 ModelState.AddModelError( … … 580 599 "Duration is required for a single."); 581 600 } 582 } 583 584 585 // ===================================================== 601 else if (!System.Text.RegularExpressions.Regex.IsMatch( 602 model.SingleDuration.Trim(), 603 @"^\d{1,2}:[0-5]\d$")) 604 { 605 ModelState.AddModelError( 606 nameof(model.SingleDuration), 607 "Duration must be in MM:SS format, for example 03:42."); 608 } 609 } 610 611 612 // ========================================================= 586 613 // ALBUM VALIDATION 587 // ===================================================== 614 // ========================================================= 588 615 589 616 if (model.ReleaseType == "ALBUM") 590 617 { 618 // Single duration does not apply to an album. 619 ModelState.Remove( 620 nameof(model.SingleDuration)); 621 622 model.SingleDuration = 623 null; 624 625 591 626 model.Tracks ??= 592 627 new List<CreateTrackViewModel>(); 593 628 594 629 595 // Remove completely empty rows. 630 // The model binder may already have added validation 631 // errors for blank track rows. Remove those and validate 632 // the cleaned list ourselves. 633 var existingTrackKeys = 634 ModelState.Keys 635 .Where(key => 636 key.StartsWith( 637 "Tracks[", 638 StringComparison.OrdinalIgnoreCase)) 639 .ToList(); 640 641 642 foreach (var key in existingTrackKeys) 643 { 644 ModelState.Remove(key); 645 } 646 647 596 648 model.Tracks = 597 649 model.Tracks … … 625 677 ModelState.AddModelError( 626 678 $"Tracks[{i}].SongName", 627 "Trackname is required.");679 $"Track {i + 1}: name is required."); 628 680 } 629 681 … … 634 686 ModelState.AddModelError( 635 687 $"Tracks[{i}].SongDuration", 636 "Trackduration is required.");688 $"Track {i + 1}: duration is required."); 637 689 } 638 690 … … 648 700 649 701 650 // Validate selected track artists.651 702 if (track.ArtistIds.Count > 0) 652 703 { … … 662 713 ModelState.AddModelError( 663 714 $"Tracks[{i}].ArtistIds", 664 "One or more selected trackartists are invalid.");715 $"Track {i + 1}: one or more artists are invalid."); 665 716 } 666 717 } … … 669 720 670 721 722 // ========================================================= 723 // VALIDATION FAILED 724 // ========================================================= 725 671 726 if (!ModelState.IsValid) 672 727 { … … 676 731 } 677 732 733 734 // ========================================================= 735 // DATABASE TRANSACTION 736 // ========================================================= 678 737 679 738 using var transaction = … … 683 742 try 684 743 { 685 // ================================================= 686 // CREATERELEASE687 // ================================================= 744 // ===================================================== 745 // RELEASE 746 // ===================================================== 688 747 689 748 var release = … … 719 778 720 779 721 // ================================================= 722 // MAIN RELEASE ARTIST723 // ================================================= 724 725 var mainReleaseArtist =780 // ===================================================== 781 // RELEASE ARTISTS 782 // ===================================================== 783 784 _context.ReleaseArtists.Add( 726 785 new ReleaseArtist 727 786 { … … 732 791 model.MainArtistId, 733 792 734 ReleaseOrdinal = 1, 793 ReleaseOrdinal = 794 1, 735 795 736 796 Type = 737 797 ArtistReleaseType.MAIN 738 }; 739 740 741 _context.ReleaseArtists.Add( 742 mainReleaseArtist); 743 744 745 // ================================================= 746 // FEATURED RELEASE ARTISTS 747 // ================================================= 798 }); 799 748 800 749 801 long releaseOrdinal = 2; … … 753 805 in model.FeaturedArtistIds) 754 806 { 755 var featuredArtist =807 _context.ReleaseArtists.Add( 756 808 new ReleaseArtist 757 809 { … … 767 819 Type = 768 820 ArtistReleaseType.FEATURE 769 }; 770 771 772 _context.ReleaseArtists.Add( 773 featuredArtist); 821 }); 774 822 } 775 823 … … 778 826 779 827 780 // ================================================= 828 // ===================================================== 781 829 // ALBUM 782 // ================================================= 830 // ===================================================== 783 831 784 832 if (model.ReleaseType == "ALBUM") … … 798 846 799 847 800 // ============================================= 801 // TRACKS 802 // ============================================= 848 // Get the next song ID once for this request. 849 // Each track then gets a unique incremented ID. 850 var nextSongId = 851 GetNextSongId(); 852 803 853 804 854 foreach (var trackModel … … 809 859 { 810 860 SongId = 811 GetNextSongId(),861 nextSongId++, 812 862 813 863 SongName = 814 trackModel 815 .SongName 816 .Trim(), 864 trackModel.SongName.Trim(), 817 865 818 866 SongDuration = 819 trackModel 820 .SongDuration 821 .Trim() 867 trackModel.SongDuration.Trim() 822 868 }; 823 869 … … 829 875 830 876 831 // ========================================= 832 // LINK SONG TO ALBUM 833 // ========================================= 834 835 var albumSong = 877 _context.AlbumSongs.Add( 836 878 new AlbumSong 837 879 { … … 841 883 SongId = 842 884 song.SongId 843 }; 844 845 846 _context.AlbumSongs.Add( 847 albumSong); 848 849 850 // ========================================= 851 // SONG ARTISTS 852 // ========================================= 885 }); 886 853 887 854 888 var trackArtistIds = … … 858 892 859 893 860 // If no track artists were selected, 861 // automatically use the release's 862 // main artist. 894 // Default to the main release artist when 895 // no track-specific artists were selected. 863 896 if (trackArtistIds.Count == 0) 864 897 { … … 874 907 in trackArtistIds) 875 908 { 876 var songArtist =909 _context.SongArtists.Add( 877 910 new SongArtist 878 911 { … … 885 918 SongOrdinal = 886 919 songOrdinal++ 887 }; 888 889 890 _context.SongArtists.Add( 891 songArtist); 920 }); 892 921 } 893 922 … … 898 927 899 928 900 // ================================================= 929 // ===================================================== 901 930 // SINGLE 902 // ================================================= 931 // ===================================================== 903 932 904 933 else 905 934 { 906 var single =935 _context.SingleReleases.Add( 907 936 new SingleRelease 908 937 { … … 911 940 912 941 Duration = 913 model.SingleDuration! 914 .Trim() 915 }; 916 917 918 _context.SingleReleases.Add( 919 single); 942 model.SingleDuration!.Trim() 943 }); 944 920 945 921 946 _context.SaveChanges(); … … 931 956 932 957 return RedirectToAction( 933 nameof( Index));934 } 935 catch 958 nameof(Releases)); 959 } 960 catch (Exception ex) 936 961 { 937 962 transaction.Rollback(); 938 963 939 throw; 964 965 Console.WriteLine( 966 "CREATE RELEASE FAILED:"); 967 968 Console.WriteLine(ex); 969 970 971 ModelState.AddModelError( 972 string.Empty, 973 ex.InnerException?.Message 974 ?? ex.Message); 975 976 977 LoadArtists(); 978 979 980 return View(model); 940 981 } 941 982 } -
KernelRecordsMVC.Web/Controllers/ReleaseController.cs
rd89d25b r595d2e5 139 139 { 140 140 var release = _context.Releases 141 .Include(r => r.ReleaseArtists) 142 .ThenInclude(ra => ra.Artist) 143 141 144 .Include(r => r.Products) 142 143 .Include(r => r.ReleaseArtists) 144 .ThenInclude(ra => ra.Artist) 145 .ThenInclude(p => p.ModificationProducts) 146 .ThenInclude(mp => mp.Modification) 145 147 146 148 .Include(r => r.Album) 147 .ThenInclude(a => a!.AlbumSongs)148 .ThenInclude(x => x.Song)149 .ThenInclude(s => s.SongArtists)150 .ThenInclude(sa => sa.Artist)149 .ThenInclude(a => a.AlbumSongs) 150 .ThenInclude(albumSong => albumSong.Song) 151 .ThenInclude(song => song.SongArtists) 152 .ThenInclude(songArtist => songArtist.Artist) 151 153 152 154 .Include(r => r.SingleRelease) -
KernelRecordsMVC.Web/Views/Admin/CreateRelease.cshtml
rd89d25b r595d2e5 43 43 44 44 45 <div asp-validation-summary=" ModelOnly"45 <div asp-validation-summary="All" 46 46 class="admin-validation"> 47 47 </div> 48 49 48 50 49 <!-- ================================================= … … 489 488 <input asp-for="Tracks[i].SongDuration" 490 489 data-field="SongDuration" 491 placeholder="03:42" /> 490 placeholder="03:42" 491 inputmode="numeric" 492 maxlength="5" /> 492 493 493 494 <span asp-validation-for="Tracks[i].SongDuration" … … 645 646 <input type="text" 646 647 data-field="SongDuration" 647 placeholder="03:42" /> 648 placeholder="03:42" 649 inputmode="numeric" 650 maxlength="5" 651 pattern="\d{1,2}:[0-5]\d" 652 title="Enter a duration like 03:42" /> 648 653 649 654 </div> -
KernelRecordsMVC.Web/Views/Admin/Index.cshtml
rd89d25b r595d2e5 13 13 <div> 14 14 15 <img src="~/images/logo.png"16 asp-append-version="true"17 alt="Kernel Records"18 class="admin-page-logo" />19 20 15 <h1>Admin Dashboard</h1> 21 16 … … 310 305 </section> 311 306 312 313 <!-- =====================================================314 WORKFLOW INFO315 ===================================================== -->316 317 <section class="admin-section">318 319 <div class="admin-section-heading">320 321 <div>322 323 <span class="admin-eyebrow">324 ADMIN WORKFLOW325 </span>326 327 <h2>Catalog Process</h2>328 329 </div>330 331 </div>332 333 334 <div class="admin-workflow-grid">335 336 <div class="admin-workflow-card">337 338 <span class="admin-workflow-number">339 01340 </span>341 342 <div>343 344 <strong>345 Create Release346 </strong>347 348 <p>349 Add the album or single,350 artists and track information.351 </p>352 353 </div>354 355 </div>356 357 358 <div class="admin-workflow-card">359 360 <span class="admin-workflow-number">361 02362 </span>363 364 <div>365 366 <strong>367 Create Product368 </strong>369 370 <p>371 Add its vinyl, CD or cassette372 store edition.373 </p>374 375 </div>376 377 </div>378 379 380 <div class="admin-workflow-card">381 382 <span class="admin-workflow-number">383 03384 </span>385 386 <div>387 388 <strong>389 Manage Inventory390 </strong>391 392 <p>393 Change prices, stock,394 descriptions or apply discounts.395 </p>396 397 </div>398 399 </div>400 401 </div>402 403 </section>404 405 307 </div> -
KernelRecordsMVC.Web/Views/Release/Details.cshtml
rd89d25b r595d2e5 1 @model KernelRecordsMVC.Models.Release 1 @using KernelRecordsMVC.Domain.Enums 2 @model KernelRecordsMVC.Models.Release 2 3 3 4 @{ … … 172 173 .OrderBy(x => x.Format)) 173 174 { 175 var latestModification = 176 product.ModificationProducts? 177 .Select(mp => mp.Modification) 178 .OrderByDescending(m => m.DateModified) 179 .ThenByDescending(m => m.ModificationId) 180 .FirstOrDefault(); 181 182 var isDiscounted = 183 latestModification != null && 184 latestModification.TypeOfModification == 185 ModificationType.DISCOUNT && 186 latestModification.Discount.HasValue && 187 latestModification.Discount.Value > 0 && 188 latestModification.Discount.Value < 100; 189 190 decimal? originalPrice = null; 191 decimal? discountPercentage = null; 192 193 if (isDiscounted) 194 { 195 discountPercentage = 196 latestModification!.Discount!.Value; 197 198 originalPrice = 199 Math.Round( 200 product.Price / 201 (1m - 202 discountPercentage.Value / 100m), 203 2, 204 MidpointRounding.AwayFromZero); 205 } 206 207 174 208 <div class="store-product-card"> 175 209 … … 197 231 198 232 199 <div class="product-price"> 200 @product.Price.ToString("C") 201 </div> 233 <!-- PRICE --> 234 235 @if (isDiscounted && 236 originalPrice.HasValue && 237 discountPercentage.HasValue) 238 { 239 <div class="product-sale-price"> 240 241 <div class="product-price-row"> 242 243 <span class="product-original-price"> 244 @originalPrice.Value.ToString("C") 245 </span> 246 247 <span class="product-current-price"> 248 @product.Price.ToString("C") 249 </span> 250 251 </div> 252 253 <span class="product-discount-badge"> 254 -@discountPercentage.Value.ToString("0.##")% 255 </span> 256 257 </div> 258 } 259 else 260 { 261 <div class="product-price"> 262 @product.Price.ToString("C") 263 </div> 264 } 202 265 203 266 … … 249 312 { 250 313 <div class="product-actions"> 251 252 <!-- OUT OF STOCK: WISHLIST ONLY -->253 314 254 315 <form asp-controller="Wishlist" -
KernelRecordsMVC.Web/Views/Release/Index.cshtml
rd89d25b r595d2e5 318 318 319 319 <strong> 320 @(lowestPrice?.ToString("C") ?? " N/A")320 @(lowestPrice?.ToString("C") ?? "Coming soon!") 321 321 </strong> 322 322 -
KernelRecordsMVC.Web/Views/Shared/_Layout.cshtml
rd89d25b r595d2e5 1 1 @using Microsoft.AspNetCore.Http 2 @using Microsoft.EntityFrameworkCore 3 @using KernelRecordsMVC.Infrastructure.Data 4 @using KernelRecordsMVC.Domain.Enums 5 @inject KernelRecordsContext DbContext 6 7 @{ 8 long cartCount = 0; 9 10 var sessionUserId = Context.Session.GetInt32("UserId"); 11 12 if (sessionUserId.HasValue) 13 { 14 var userId = (long)sessionUserId.Value; 15 16 cartCount = await DbContext.OrderProducts 17 .Where(op => 18 op.Order.UserId == userId && 19 op.Order.Status == OrderStatusType.PENDING) 20 .SumAsync(op => (long?)op.Quantity) ?? 0; 21 } 22 } 2 23 3 24 <!DOCTYPE html> 4 5 25 <html lang="en"> 6 26 <head> … … 8 28 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 29 10 11 <title>@ViewData["Title"] - Kernel Records</title> 12 13 <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> 14 15 30 <title>@ViewData["Title"] - Kernel Records</title> 31 32 <link rel="stylesheet" 33 href="~/css/site.css" 34 asp-append-version="true" /> 16 35 </head> 17 36 … … 20 39 <header class="site-header"> 21 40 22 23 <!-- ===================================================== 24 MAIN NAVBAR 25 ===================================================== --> 26 27 <nav class="navbar"> 28 29 <div class="navbar-container"> 30 31 <!-- LOGO --> 32 33 <a asp-controller="Home" 34 asp-action="Index" 35 class="navbar-brand logo-brand"> 36 37 <img src="~/images/logo.png" 38 asp-append-version="true" 39 alt="Kernel Records" 40 class="site-logo" /> 41 42 </a> 43 44 45 <!-- MOBILE MENU BUTTON --> 46 47 <button class="mobile-menu-button" 48 type="button" 49 aria-label="Toggle navigation" 50 onclick="toggleMobileMenu()"> 51 52 ☰ 53 54 </button> 55 56 57 <!-- NAVBAR CONTENT --> 58 59 <div class="navbar-content" 60 id="navbarContent"> 61 62 63 <!-- ================================================= 64 MAIN NAVIGATION 65 ================================================= --> 66 67 <ul class="nav-links"> 68 69 <!-- Browse --> 70 71 <li> 72 73 <a asp-controller="Release" 74 asp-action="Index"> 75 76 Browse 77 78 </a> 79 80 </li> 81 82 83 <!-- Top Sellers --> 84 85 <li> 86 87 <a asp-controller="TopSellers" 88 asp-action="Index"> 89 90 Top Sellers 91 92 </a> 93 94 </li> 95 96 97 <!-- Artists --> 98 99 <li> 100 101 <a asp-controller="Artist" 102 asp-action="Index"> 103 104 Artists 105 106 </a> 107 108 </li> 109 110 111 <!-- Genres --> 112 113 <li class="nav-dropdown"> 114 115 <a href="#" 116 class="dropdown-toggle"> 117 118 Genres 119 120 <span class="arrow"> 121 ⌄ 122 </span> 123 124 </a> 125 126 127 <div class="dropdown-menu"> 128 129 <a asp-controller="Release" 130 asp-action="Index" 131 asp-route-genre="Rock"> 132 133 Rock 134 135 </a> 136 137 <a asp-controller="Release" 138 asp-action="Index" 139 asp-route-genre="Pop"> 140 141 Pop 142 143 </a> 144 145 <a asp-controller="Release" 146 asp-action="Index" 147 asp-route-genre="Hip-Hop"> 148 149 Hip-Hop 150 151 </a> 152 153 <a asp-controller="Release" 154 asp-action="Index" 155 asp-route-genre="Jazz"> 156 157 Jazz 158 159 </a> 160 161 <a asp-controller="Release" 162 asp-action="Index" 163 asp-route-genre="Electronic"> 164 165 Electronic 166 167 </a> 168 41 <!-- ===================================================== 42 MAIN NAVBAR 43 ===================================================== --> 44 45 <nav class="navbar"> 46 47 <div class="navbar-container"> 48 49 <!-- LOGO --> 50 51 <a asp-controller="Home" 52 asp-action="Index" 53 class="navbar-brand logo-brand"> 54 55 <img src="~/images/logo.png" 56 asp-append-version="true" 57 alt="Kernel Records" 58 class="site-logo" /> 59 60 </a> 61 62 63 <!-- MOBILE MENU BUTTON --> 64 65 <button class="mobile-menu-button" 66 type="button" 67 aria-label="Toggle navigation" 68 onclick="toggleMobileMenu()"> 69 ☰ 70 </button> 71 72 73 <!-- NAVBAR CONTENT --> 74 75 <div class="navbar-content" 76 id="navbarContent"> 77 78 <!-- ================================================= 79 MAIN NAVIGATION 80 ================================================= --> 81 82 <ul class="nav-links"> 83 84 <li> 169 85 <a asp-controller="Release" 170 86 asp-action="Index"> 171 172 All Genres 173 87 Browse 174 88 </a> 175 176 </div> 177 178 </li> 179 180 181 <!-- Sale --> 182 183 <li> 184 185 <a asp-controller="Sale" 89 </li> 90 91 <li> 92 <a asp-controller="TopSellers" 93 asp-action="Index"> 94 Top Sellers 95 </a> 96 </li> 97 98 <li> 99 <a asp-controller="Artist" 100 asp-action="Index"> 101 Artists 102 </a> 103 </li> 104 105 <li class="nav-dropdown"> 106 107 <a href="#" 108 class="dropdown-toggle"> 109 Genres 110 <span class="arrow">⌄</span> 111 </a> 112 113 <div class="dropdown-menu"> 114 115 <a asp-controller="Release" 116 asp-action="Index" 117 asp-route-genre="Rock"> 118 Rock 119 </a> 120 121 <a asp-controller="Release" 122 asp-action="Index" 123 asp-route-genre="Pop"> 124 Pop 125 </a> 126 127 <a asp-controller="Release" 128 asp-action="Index" 129 asp-route-genre="Hip-Hop"> 130 Hip-Hop 131 </a> 132 133 <a asp-controller="Release" 134 asp-action="Index" 135 asp-route-genre="Jazz"> 136 Jazz 137 </a> 138 139 <a asp-controller="Release" 140 asp-action="Index" 141 asp-route-genre="Electronic"> 142 Electronic 143 </a> 144 145 <a asp-controller="Release" 146 asp-action="Index"> 147 All Genres 148 </a> 149 150 </div> 151 152 </li> 153 154 <li> 155 <a asp-controller="Sale" 156 asp-action="Index" 157 class="nav-sale"> 158 Sale 159 </a> 160 </li> 161 162 </ul> 163 164 165 <!-- ================================================= 166 SEARCH 167 ================================================= --> 168 169 <form class="navbar-search" 170 asp-controller="Release" 171 asp-action="Index" 172 method="get"> 173 174 <input type="text" 175 name="search" 176 placeholder="Search releases..." 177 autocomplete="off" /> 178 179 <button type="submit" 180 aria-label="Search"> 181 <span>⌕</span> 182 </button> 183 184 </form> 185 186 187 <!-- ================================================= 188 RIGHT SIDE ACTIONS 189 ================================================= --> 190 191 <div class="navbar-actions"> 192 193 <!-- WISHLIST --> 194 195 <a class="nav-icon" 196 asp-controller="Wishlist" 186 197 asp-action="Index" 187 class="nav-sale"> 188 189 Sale 198 title="Wishlist"> 199 200 <span class="icon">♡</span> 201 202 <span class="icon-label"> 203 Wishlist 204 </span> 190 205 191 206 </a> 192 207 193 </li> 194 195 </ul> 196 197 198 <!-- ================================================= 199 SEARCH 200 ================================================= --> 201 202 <form class="navbar-search" 203 asp-controller="Release" 204 asp-action="Index" 205 method="get"> 206 207 <input type="text" 208 name="search" 209 placeholder="Search releases..." 210 autocomplete="off" /> 211 212 <button type="submit" 213 aria-label="Search"> 214 215 <span> 216 ⌕ 217 </span> 218 219 </button> 220 221 </form> 222 223 224 <!-- ================================================= 225 RIGHT SIDE ACTIONS 226 ================================================= --> 227 228 <div class="navbar-actions"> 229 230 231 <!-- ================================================= 232 WISHLIST 233 ================================================= --> 234 235 <a class="nav-icon" 236 asp-controller="Wishlist" 237 asp-action="Index" 238 title="Wishlist"> 239 240 <span class="icon"> 241 ♡ 242 </span> 243 244 <span class="icon-label"> 245 Wishlist 246 </span> 247 248 </a> 249 250 251 <!-- ================================================= 252 CART 253 ================================================= --> 254 255 <a class="nav-icon" 256 asp-controller="Order" 257 asp-action="Cart" 258 title="Shopping Cart"> 259 260 <span class="icon cart-icon"> 261 🛒 262 </span> 263 264 <span class="icon-label"> 265 Cart 266 </span> 267 268 </a> 269 270 271 <!-- ================================================= 272 ACCOUNT 273 ================================================= --> 274 275 @if (Context.Session.GetInt32("UserId") != null) 276 { 277 278 <!-- LOGGED IN --> 279 280 <div class="account-dropdown"> 281 282 283 <button class="account-button" 284 type="button"> 285 286 <span class="user-icon"> 287 ● 208 209 <!-- CART --> 210 211 <a class="nav-icon nav-cart-link" 212 asp-controller="Order" 213 asp-action="Cart" 214 title="Shopping Cart"> 215 216 <span class="nav-cart-icon-wrap"> 217 218 <span class="icon cart-icon"> 219 🛒 288 220 </span> 289 221 290 <span class="account-name"> 291 292 @Context.Session.GetString("Username") 293 294 </span> 295 296 <span class="arrow"> 297 ⌄ 298 </span> 299 300 </button> 301 302 303 <!-- ACCOUNT MENU --> 304 305 <div class="account-menu"> 306 307 308 <!-- PROFILE --> 222 @if (cartCount > 0) 223 { 224 <span class="nav-cart-count" 225 aria-label="@cartCount item(s) in cart"> 226 @(cartCount > 99 ? "99+" : cartCount.ToString()) 227 </span> 228 } 229 230 </span> 231 232 <span class="icon-label"> 233 Cart 234 </span> 235 236 </a> 237 238 239 <!-- ACCOUNT --> 240 241 @if (Context.Session.GetInt32("UserId") != null) 242 { 243 <div class="account-dropdown"> 244 245 <button class="account-button" 246 type="button"> 247 248 <span class="user-icon">●</span> 249 250 <span class="account-name"> 251 @Context.Session.GetString("Username") 252 </span> 253 254 <span class="arrow">⌄</span> 255 256 </button> 257 258 <div class="account-menu"> 259 260 <a asp-controller="Account" 261 asp-action="Profile"> 262 <span>👤</span> 263 My Profile 264 </a> 265 266 <a asp-controller="Order" 267 asp-action="Cart"> 268 <span>📦</span> 269 My Orders 270 </a> 271 272 <a asp-controller="Wishlist" 273 asp-action="Index"> 274 <span>♡</span> 275 My Wishlist 276 </a> 277 278 @if (Context.Session.GetString("Role") == "Admin") 279 { 280 <div class="menu-divider"></div> 281 282 <a asp-controller="Admin" 283 asp-action="Index" 284 class="admin-link"> 285 <span>⚙</span> 286 Admin Dashboard 287 </a> 288 } 289 290 <div class="menu-divider"></div> 291 292 <form asp-controller="Account" 293 asp-action="Logout" 294 method="post"> 295 296 @Html.AntiForgeryToken() 297 298 <button type="submit" 299 class="logout-button"> 300 <span>↪</span> 301 Logout 302 </button> 303 304 </form> 305 306 </div> 307 308 </div> 309 } 310 else 311 { 312 <div class="auth-buttons"> 309 313 310 314 <a asp-controller="Account" 311 asp-action="Profile"> 312 313 <span> 314 👤 315 </span> 316 317 My Profile 318 319 </a> 320 321 322 <!-- ORDERS --> 323 324 <a asp-controller="Order" 325 asp-action="Cart"> 326 327 <span> 328 📦 329 </span> 330 331 My Orders 332 333 </a> 334 335 336 <!-- WISHLIST --> 337 338 <a asp-controller="Wishlist" 339 asp-action="Index"> 340 341 <span> 342 ♡ 343 </span> 344 345 My Wishlist 346 347 </a> 348 349 350 <!-- ADMIN --> 351 352 @if (Context.Session.GetString("Role") == "Admin") 353 { 354 355 <div class="menu-divider"></div> 356 357 358 <a asp-controller="Admin" 359 asp-action="Index" 360 class="admin-link"> 361 362 <span> 363 ⚙ 364 </span> 365 366 Admin Dashboard 367 368 </a> 369 370 } 371 372 373 <div class="menu-divider"></div> 374 375 376 <!-- LOGOUT --> 377 378 <form asp-controller="Account" 379 asp-action="Logout" 380 method="post"> 381 382 @Html.AntiForgeryToken() 383 384 <button type="submit" 385 class="logout-button"> 386 387 <span>↪</span> 388 389 Logout 390 391 </button> 392 393 </form> 394 315 asp-action="Login" 316 class="login-button"> 317 Login 318 </a> 319 320 <a asp-controller="Account" 321 asp-action="Register" 322 class="register-button"> 323 Register 324 </a> 395 325 396 326 </div> 397 398 </div> 399 400 } 401 else 402 { 403 404 <!-- ================================================= 405 NOT LOGGED IN 406 ================================================= --> 407 408 <div class="auth-buttons"> 409 410 411 <a asp-controller="Account" 412 asp-action="Login" 413 class="login-button"> 414 415 Login 416 417 </a> 418 419 420 <a asp-controller="Account" 421 asp-action="Register" 422 class="register-button"> 423 424 Register 425 426 </a> 427 428 429 </div> 430 431 } 327 } 328 329 </div> 432 330 433 331 </div> … … 435 333 </div> 436 334 335 </nav> 336 337 338 <!-- ===================================================== 339 ANNOUNCEMENT BAR 340 ===================================================== --> 341 342 <div class="announcement-bar"> 343 344 <span> 345 FREE SHIPPING ON ORDERS OVER $100 346 </span> 347 437 348 </div> 438 439 </nav> 440 441 442 <!-- ===================================================== 443 ANNOUNCEMENT BAR 444 ===================================================== --> 445 446 <div class="announcement-bar"> 447 448 <span> 449 FREE SHIPPING ON ORDERS OVER €50 450 </span> 451 452 <span class="announcement-separator"> 453 • 454 </span> 455 456 <span> 457 NEW VINYL EVERY WEEK 458 </span> 459 460 </div> 461 349 462 350 463 351 </header> 352 464 353 465 354 <!-- ========================================================= … … 468 357 469 358 <main class="main-content"> 470 471 472 @RenderBody() 473 474 359 @RenderBody() 475 360 </main> 361 476 362 477 363 <!-- ========================================================= … … 481 367 <footer class="site-footer"> 482 368 483 484 <div class="footer-container"> 485 486 487 <!-- BRAND --> 488 489 <div class="footer-brand"> 490 491 <div class="footer-logo"> 492 KERNEL RECORDS 369 <div class="footer-container"> 370 371 <div class="footer-brand"> 372 373 <div class="footer-logo"> 374 KERNEL RECORDS 375 </div> 376 377 <p> 378 Your destination for vinyl, CDs and cassettes. 379 </p> 380 493 381 </div> 494 382 495 <p> 496 Your destination for vinyl, CDs and cassettes. 497 </p> 383 384 <div class="footer-column"> 385 386 <h4>Shop</h4> 387 388 <a asp-controller="Release" 389 asp-action="Index"> 390 Releases 391 </a> 392 393 <a asp-controller="Release" 394 asp-action="Index"> 395 New Releases 396 </a> 397 398 <a asp-controller="Artist" 399 asp-action="Index"> 400 Artists 401 </a> 402 403 </div> 404 405 406 <div class="footer-column"> 407 408 <h4>Account</h4> 409 410 @if (Context.Session.GetInt32("UserId") != null) 411 { 412 <a asp-controller="Account" 413 asp-action="Profile"> 414 My Profile 415 </a> 416 417 <a asp-controller="Order" 418 asp-action="Cart"> 419 My Orders 420 </a> 421 422 <a asp-controller="Wishlist" 423 asp-action="Index"> 424 Wishlist 425 </a> 426 } 427 else 428 { 429 <a asp-controller="Account" 430 asp-action="Login"> 431 Login 432 </a> 433 434 <a asp-controller="Account" 435 asp-action="Register"> 436 Register 437 </a> 438 } 439 440 </div> 441 442 443 <div class="footer-column"> 444 445 <h4>Help</h4> 446 447 <a href="#"> 448 Shipping 449 </a> 450 451 <a href="#"> 452 Returns 453 </a> 454 455 <a href="#"> 456 Contact 457 </a> 458 459 </div> 498 460 499 461 </div> 500 462 501 463 502 <!-- SHOP --> 503 504 <div class="footer-column"> 505 506 <h4> 507 Shop 508 </h4> 509 510 511 <a asp-controller="Release" 512 asp-action="Index"> 513 514 Releases 515 516 </a> 517 518 519 <a asp-controller="Release" 520 asp-action="Index"> 521 522 New Releases 523 524 </a> 525 526 527 <a asp-controller="Artist" 528 asp-action="Index"> 529 530 Artists 531 532 </a> 464 <div class="footer-bottom"> 465 466 <span> 467 © @DateTime.Now.Year Kernel Records 468 </span> 469 470 <span> 471 All rights reserved. 472 </span> 533 473 534 474 </div> 535 475 536 537 <!-- ACCOUNT -->538 539 <div class="footer-column">540 541 <h4>542 Account543 </h4>544 545 546 @if (Context.Session.GetInt32("UserId") != null)547 {548 549 <a asp-controller="Account"550 asp-action="Profile">551 552 My Profile553 554 </a>555 556 557 <a asp-controller="Order"558 asp-action="Cart">559 560 My Orders561 562 </a>563 564 565 <a asp-controller="Wishlist"566 asp-action="Index">567 568 Wishlist569 570 </a>571 572 }573 else574 {575 576 <a asp-controller="Account"577 asp-action="Login">578 579 Login580 581 </a>582 583 584 <a asp-controller="Account"585 asp-action="Register">586 587 Register588 589 </a>590 591 }592 593 </div>594 595 596 <!-- HELP -->597 598 <div class="footer-column">599 600 <h4>601 Help602 </h4>603 604 <a href="#">605 Shipping606 </a>607 608 <a href="#">609 Returns610 </a>611 612 <a href="#">613 Contact614 </a>615 616 </div>617 618 </div>619 620 621 <!-- FOOTER BOTTOM -->622 623 <div class="footer-bottom">624 625 <span>626 © @DateTime.Now.Year Kernel Records627 </span>628 629 <span>630 All rights reserved.631 </span>632 633 </div>634 635 636 476 </footer> 477 637 478 638 479 <!-- ========================================================= … … 641 482 642 483 <script> 643 644 484 function toggleMobileMenu() 645 485 { … … 650 490 } 651 491 652 653 // Close mobile menu when clicking outside654 655 492 document.addEventListener("click", function (event) 656 493 { … … 661 498 document.querySelector(".mobile-menu-button"); 662 499 500 if (!menu || !button) 501 return; 663 502 664 503 if (!menu.contains(event.target) && … … 667 506 menu.classList.remove("mobile-open"); 668 507 } 669 670 508 }); 671 672 509 </script> 673 510 674 511 @await RenderSectionAsync( 675 "Scripts",676 required: false)512 "Scripts", 513 required: false) 677 514 678 515 </body> -
KernelRecordsMVC.Web/Views/Wishlist/Index.cshtml
rd89d25b r595d2e5 8 8 9 9 <div class="page-header"> 10 10 11 <div> 11 <span class="page-eyebrow">YOUR COLLECTION</span> 12 13 <span class="page-eyebrow"> 14 YOUR COLLECTION 15 </span> 16 12 17 <h1>My Wishlist</h1> 13 <p>Save releases and physical formats you want to get later.</p> 14 </div> 18 19 <p> 20 Save releases and physical formats you want to get later. 21 </p> 22 23 </div> 24 15 25 </div> 26 16 27 17 28 @if (TempData["Success"] != null) … … 35 46 </div> 36 47 } 48 37 49 38 50 @if (Model.WishlistProducts == null || … … 45 57 </div> 46 58 47 <h2>Your wishlist is empty</h2> 59 <h2> 60 Your wishlist is empty 61 </h2> 48 62 49 63 <p> … … 54 68 <a asp-controller="Release" 55 69 asp-action="Index" 56 class="btn-primary"> 70 class="store-button primary"> 71 57 72 Browse Releases 73 58 74 </a> 59 75 … … 69 85 var release = product.Release; 70 86 87 71 88 <div class="wishlist-card"> 89 90 <!-- COVER --> 72 91 73 92 <a asp-controller="Release" … … 76 95 class="wishlist-cover"> 77 96 78 <img src="@release.CoverPhoto" 79 alt="@release.Title" /> 97 @if (!string.IsNullOrWhiteSpace( 98 release.CoverPhoto)) 99 { 100 <img src="@release.CoverPhoto" 101 alt="@release.Title" /> 102 } 103 else 104 { 105 <div class="release-no-cover"> 106 <span>♪</span> 107 </div> 108 } 80 109 81 110 </a> 111 112 113 <!-- CONTENT --> 82 114 83 115 <div class="wishlist-info"> … … 87 119 </span> 88 120 121 89 122 <h2> 123 90 124 <a asp-controller="Release" 91 125 asp-action="Details" 92 126 asp-route-id="@release.ReleaseId"> 127 93 128 @release.Title 129 94 130 </a> 131 95 132 </h2> 133 96 134 97 135 <p class="wishlist-genre"> … … 99 137 </p> 100 138 101 <div class="wishlist-price"> 102 @product.Price.ToString("C") 103 </div> 104 105 @if (product.Stock > 0) 106 { 107 <span class="stock available"> 108 In stock 109 </span> 110 } 111 else 112 { 113 <span class="stock unavailable"> 114 Out of stock 115 </span> 116 } 117 118 <div class="wishlist-actions"> 119 120 @if (product.Stock > 0) 121 { 139 140 <!-- PRICE + BUTTONS --> 141 142 <div class="wishlist-bottom"> 143 144 <div class="wishlist-price-area"> 145 146 <div class="wishlist-price"> 147 @product.Price.ToString("C") 148 </div> 149 150 151 @if (product.Stock > 0) 152 { 153 <span class="stock available"> 154 In stock 155 </span> 156 } 157 else 158 { 159 <span class="stock unavailable"> 160 Out of stock 161 </span> 162 } 163 164 </div> 165 166 167 <div class="wishlist-actions"> 168 169 @if (product.Stock > 0) 170 { 171 <form asp-controller="Wishlist" 172 asp-action="AddToCart" 173 method="post"> 174 175 @Html.AntiForgeryToken() 176 177 <input type="hidden" 178 name="productId" 179 value="@product.ProductId" /> 180 181 <button type="submit" 182 class="store-button"> 183 184 Add to Cart 185 186 </button> 187 188 </form> 189 } 190 191 122 192 <form asp-controller="Wishlist" 123 asp-action=" AddToCart"193 asp-action="Remove" 124 194 method="post"> 125 195 … … 131 201 132 202 <button type="submit" 133 class="btn-primary"> 134 Add to Cart 203 class="btn-remove"> 204 205 Remove 206 135 207 </button> 136 208 137 209 </form> 138 } 139 140 <form asp-controller="Wishlist" 141 asp-action="Remove" 142 method="post"> 143 144 @Html.AntiForgeryToken() 145 146 <input type="hidden" 147 name="productId" 148 value="@product.ProductId" /> 149 150 <button type="submit" 151 class="btn-remove"> 152 Remove 153 </button> 154 155 </form> 210 211 </div> 156 212 157 213 </div> -
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.AssemblyInfo.cs
rd89d25b r595d2e5 15 15 [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 16 [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63")]17 [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d89d25b3a7f785676877cf198c9cc706308ab4a3")] 18 18 [assembly: System.Reflection.AssemblyProductAttribute("KernelRecordsMVC.Web")] 19 19 [assembly: System.Reflection.AssemblyTitleAttribute("KernelRecordsMVC.Web")] -
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.AssemblyInfoInputs.cache
rd89d25b r595d2e5 1 c7c64d4b5585be3def76ca8244acd21f3a41a4886ee5b2db049d2b6c7160a3f4 1 5c4ef787946962959a0ba14b7ffc3cd723d328624707161e0bc37e6293c6f25c -
KernelRecordsMVC.Web/obj/Debug/net8.0/KernelRecordsMVC.Web.sourcelink.json
rd89d25b r595d2e5 1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d 2eccb3e3d4db7d262fc57179b8ce6f7fb060d63/*"}}1 {"documents":{"C:\\Users\\Marko\\RiderProjects\\KernelRecordsMVC\\*":"https://raw.githubusercontent.com/mmilevski/kernelrecords/d89d25b3a7f785676877cf198c9cc706308ab4a3/*"}} -
KernelRecordsMVC.Web/wwwroot/css/site.css
rd89d25b r595d2e5 76 76 } 77 77 78 .brand {79 display: flex;80 flex-direction: column;81 flex-shrink: 0;82 83 line-height: .9;84 letter-spacing: 2px;85 }86 87 .brand-main {88 font-size: 25px;89 font-weight: 900;90 }91 92 .brand-sub {93 margin-top: 6px;94 95 font-size: 11px;96 font-weight: 600;97 letter-spacing: 5px;98 99 opacity: .65;100 }101 102 78 .navbar-content { 103 79 flex: 1; … … 484 460 } 485 461 462 /* ========================================================= 463 NAVBAR CART COUNT 464 ========================================================= */ 465 466 .nav-cart-link { 467 position: relative; 468 } 469 470 .nav-cart-icon-wrap { 471 position: relative; 472 473 display: inline-flex; 474 align-items: center; 475 justify-content: center; 476 } 477 478 .nav-cart-count { 479 position: absolute; 480 481 top: -10px; 482 right: -13px; 483 484 min-width: 18px; 485 height: 18px; 486 487 display: inline-flex; 488 align-items: center; 489 justify-content: center; 490 491 padding: 0 5px; 492 493 border: 2px solid #111; 494 border-radius: 999px; 495 496 background: white; 497 color: #111; 498 499 font-size: 9px; 500 font-weight: 900; 501 line-height: 1; 502 } 486 503 487 504 /* ========================================================= … … 504 521 letter-spacing: 1.3px; 505 522 } 506 507 .announcement-separator {508 opacity: .45;509 }510 511 523 512 524 /* ========================================================= … … 1570 1582 } 1571 1583 1572 1573 1584 /* ========================================================= 1574 1585 WISHLIST … … 1577 1588 .wishlist-page { 1578 1589 max-width: 1250px; 1579 1580 1590 margin: 0 auto; 1581 1582 1591 padding: 55px 30px 80px; 1583 1592 } … … 1589 1598 .page-header h1 { 1590 1599 margin-top: 7px; 1591 1592 1600 font-size: 44px; 1593 1601 font-weight: 900; 1594 1595 1602 letter-spacing: -1.5px; 1596 1603 } … … 1598 1605 .page-header p { 1599 1606 margin-top: 8px; 1600 1601 1607 color: #777; 1602 1603 1608 font-size: 14px; 1604 1609 } … … 1606 1611 .wishlist-grid { 1607 1612 display: grid; 1608 1609 grid-template-columns: 1610 repeat(2, minmax(0, 1fr)); 1611 1613 grid-template-columns: repeat(2, minmax(0, 1fr)); 1612 1614 gap: 20px; 1613 1615 } 1614 1616 1615 1617 .wishlist-card { 1618 min-width: 0; 1619 min-height: 190px; 1620 1616 1621 display: grid; 1617 1618 grid-template-columns: 1619 190px 1fr; 1622 grid-template-columns: 190px minmax(0, 1fr); 1620 1623 1621 1624 overflow: hidden; 1622 1625 1623 1626 background: white; 1624 1625 1627 border: 1px solid #ddd; 1626 border-radius: 9px; 1628 border-radius: 10px; 1629 1630 transition: 1631 transform .2s ease, 1632 box-shadow .2s ease, 1633 border-color .2s ease; 1634 } 1635 1636 .wishlist-card:hover { 1637 transform: translateY(-2px); 1638 border-color: #ccc; 1639 box-shadow: 0 12px 30px rgba(0,0,0,.06); 1627 1640 } 1628 1641 1629 1642 .wishlist-cover { 1630 aspect-ratio: 1 / 1; 1643 width: 190px; 1644 height: 190px; 1645 1646 display: block; 1631 1647 1632 1648 overflow: hidden; 1633 1634 1649 background: #ddd; 1635 1650 } 1636 1651 1652 .wishlist-cover img, 1653 .wishlist-cover .release-no-cover { 1654 width: 190px; 1655 height: 190px; 1656 display: block; 1657 } 1658 1637 1659 .wishlist-cover img { 1638 width: 100%; 1639 height: 100%; 1640 1660 object-fit: cover; 1661 object-position: center; 1662 transition: transform .35s ease; 1663 } 1664 1665 .wishlist-card:hover .wishlist-cover img { 1666 transform: scale(1.035); 1667 } 1668 1669 .wishlist-info { 1670 min-width: 0; 1671 1672 display: flex; 1673 flex-direction: column; 1674 justify-content: center; 1675 1676 padding: 22px 24px; 1677 } 1678 1679 .wishlist-format { 1641 1680 display: block; 1642 1643 object-fit: cover; 1644 1645 transition: transform .35s ease; 1646 } 1647 1648 .wishlist-card:hover .wishlist-cover img { 1649 transform: scale(1.04); 1650 } 1651 1652 .wishlist-info { 1653 padding: 22px; 1654 } 1655 1656 .wishlist-format { 1681 margin-bottom: 7px; 1682 1657 1683 color: #888; 1658 1684 1659 1685 font-size: 9px; 1660 1686 font-weight: 900; 1661 1662 1687 text-transform: uppercase; 1663 1688 letter-spacing: 1px; … … 1665 1690 1666 1691 .wishlist-info h2 { 1667 margin-top: 7px; 1668 1692 margin: 0; 1669 1693 font-size: 20px; 1670 1694 font-weight: 900; 1695 line-height: 1.2; 1671 1696 } 1672 1697 … … 1677 1702 .wishlist-genre { 1678 1703 margin-top: 6px; 1679 1680 1704 color: #777; 1681 1682 1705 font-size: 12px; 1683 1706 } 1684 1707 1708 .wishlist-bottom { 1709 display: flex; 1710 align-items: center; 1711 justify-content: space-between; 1712 1713 gap: 18px; 1714 margin-top: 20px; 1715 } 1716 1717 .wishlist-price-area { 1718 min-width: 90px; 1719 flex-shrink: 0; 1720 } 1721 1685 1722 .wishlist-price { 1686 margin -top: 18px;1687 1688 font- size: 22px;1689 font-weight: 900;1723 margin: 0; 1724 font-size: 23px; 1725 font-weight: 900; 1726 line-height: 1; 1690 1727 } 1691 1728 1692 1729 .stock { 1693 display: inline-block; 1694 1730 display: block; 1695 1731 margin-top: 7px; 1696 1697 1732 font-size: 10px; 1698 1733 font-weight: 800; … … 1709 1744 .wishlist-actions { 1710 1745 display: flex; 1746 align-items: center; 1747 justify-content: flex-end; 1711 1748 flex-wrap: wrap; 1712 1749 1713 1750 gap: 8px; 1714 1715 margin-top: 20px; 1716 } 1717 1718 .btn-remove { 1719 min-height: 42px; 1720 1721 padding: 0 17px; 1751 margin: 0; 1752 } 1753 1754 .wishlist-actions form { 1755 margin: 0; 1756 } 1757 1758 .wishlist-actions .store-button, 1759 .wishlist-actions .btn-remove { 1760 min-height: 40px; 1761 1762 display: inline-flex; 1763 align-items: center; 1764 justify-content: center; 1765 1766 padding: 0 15px; 1767 1768 border-radius: 6px; 1769 1770 font-size: 10px; 1771 font-weight: 900; 1772 line-height: 1; 1773 white-space: nowrap; 1774 } 1775 1776 .wishlist-actions .store-button { 1777 border: 1px solid #171717; 1778 background: #171717; 1779 color: white; 1780 } 1781 1782 .wishlist-actions .store-button:hover { 1783 background: #333; 1784 color: white; 1785 } 1786 1787 .btn-remove, 1788 .wishlist-actions .btn-remove { 1789 min-height: 40px; 1790 1791 padding: 0 15px; 1722 1792 1723 1793 border: 1px solid #ccc; … … 1725 1795 1726 1796 background: white; 1797 color: #666; 1798 1799 font-size: 10px; 1800 font-weight: 900; 1801 } 1802 1803 .btn-remove:hover, 1804 .wishlist-actions .btn-remove:hover { 1805 border-color: #a33; 1806 background: #fff7f7; 1807 color: #a33; 1808 } 1809 1810 .empty-wishlist { 1811 padding: 75px 25px; 1812 1813 text-align: center; 1814 1815 background: white; 1816 1817 border: 1px solid #ddd; 1818 border-radius: 10px; 1819 } 1820 1821 .empty-wishlist .empty-icon { 1822 margin-bottom: 15px; 1727 1823 color: #777; 1728 1729 font-size: 12px; 1730 font-weight: 800; 1731 } 1732 1733 .btn-remove:hover { 1734 border-color: #a33; 1735 color: #a33; 1736 } 1737 1824 font-size: 48px; 1825 } 1826 1827 .empty-wishlist h2 { 1828 margin-bottom: 8px; 1829 font-size: 25px; 1830 } 1831 1832 .empty-wishlist p { 1833 margin-bottom: 22px; 1834 color: #777; 1835 } 1836 1837 @media (max-width: 1000px) { 1838 .wishlist-grid { 1839 grid-template-columns: 1fr; 1840 } 1841 } 1842 1843 @media (max-width: 650px) { 1844 .wishlist-card { 1845 grid-template-columns: 140px minmax(0, 1fr); 1846 min-height: 140px; 1847 } 1848 1849 .wishlist-cover, 1850 .wishlist-cover img, 1851 .wishlist-cover .release-no-cover { 1852 width: 140px; 1853 height: 140px; 1854 } 1855 1856 .wishlist-info { 1857 padding: 18px; 1858 } 1859 1860 .wishlist-bottom { 1861 align-items: flex-start; 1862 flex-direction: column; 1863 gap: 13px; 1864 margin-top: 16px; 1865 } 1866 1867 .wishlist-actions { 1868 justify-content: flex-start; 1869 } 1870 } 1871 1872 @media (max-width: 500px) { 1873 .wishlist-card { 1874 grid-template-columns: 1fr; 1875 } 1876 1877 .wishlist-cover, 1878 .wishlist-cover img, 1879 .wishlist-cover .release-no-cover { 1880 width: 100%; 1881 height: auto; 1882 aspect-ratio: 1 / 1; 1883 } 1884 1885 .wishlist-info { 1886 padding: 20px; 1887 } 1888 1889 .wishlist-actions { 1890 width: 100%; 1891 flex-direction: row; 1892 } 1893 1894 .wishlist-actions form { 1895 flex: 1; 1896 } 1897 1898 .wishlist-actions .store-button, 1899 .wishlist-actions .btn-remove { 1900 width: 100%; 1901 } 1902 } 1738 1903 1739 1904 /* ========================================================= … … 1953 2118 } 1954 2119 1955 .home-eyebrow {1956 color: #aaa;1957 1958 font-size: 11px;1959 font-weight: 900;1960 1961 letter-spacing: 3px;1962 }1963 1964 2120 .home-hero h1 { 1965 2121 margin-top: 16px; … … 2027 2183 .home-button.secondary:hover { 2028 2184 background: #292929; 2029 }2030 2031 .home-hero-mark {2032 position: absolute;2033 2034 right: 5%;2035 bottom: -60px;2036 2037 color: #1e1e1e;2038 2039 font-size: 420px;2040 font-weight: 900;2041 2042 line-height: 1;2043 2185 } 2044 2186 … … 2534 2676 grid-template-columns: 2535 2677 repeat(2, minmax(0, 1fr)); 2536 }2537 2538 .wishlist-grid {2539 grid-template-columns: 1fr;2540 2678 } 2541 2679 … … 2805 2943 } 2806 2944 2807 .wishlist-grid {2808 grid-template-columns: 1fr;2809 }2810 2811 .wishlist-card {2812 grid-template-columns:2813 120px 1fr;2814 }2815 2816 2945 .home-hero { 2817 2946 min-height: 500px; … … 2819 2948 padding: 45px 30px; 2820 2949 } 2821 2822 .home-hero-mark {2823 font-size: 250px;2824 }2825 2826 2950 .home-feature-grid { 2827 2951 grid-template-columns: 1fr; … … 2865 2989 @media (max-width: 500px) { 2866 2990 2867 .wishlist-card {2868 grid-template-columns: 1fr;2869 }2870 2871 .wishlist-cover {2872 max-height: 300px;2873 }2874 2875 .wishlist-actions {2876 flex-direction: column;2877 }2878 2879 .wishlist-actions .store-button,2880 .wishlist-actions .btn-remove {2881 width: 100%;2882 }2883 2884 2991 .home-hero { 2885 2992 padding: 35px 22px; … … 2910 3017 } 2911 3018 } 2912 3019 /* ========================================================= 3020 RELEASE PRODUCT DISCOUNT PRICE 3021 ========================================================= */ 3022 3023 .product-sale-price { 3024 margin-bottom: 12px; 3025 } 3026 3027 .product-price-row { 3028 display: flex; 3029 align-items: baseline; 3030 flex-wrap: wrap; 3031 3032 gap: 10px; 3033 } 3034 3035 .product-original-price { 3036 color: #999; 3037 3038 font-size: 16px; 3039 font-weight: 700; 3040 3041 text-decoration: line-through; 3042 } 3043 3044 .product-current-price { 3045 color: #171717; 3046 3047 font-size: 28px; 3048 font-weight: 900; 3049 } 3050 3051 .product-discount-badge { 3052 width: fit-content; 3053 3054 display: inline-flex; 3055 align-items: center; 3056 justify-content: center; 3057 3058 margin-top: 7px; 3059 padding: 5px 8px; 3060 3061 border-radius: 4px; 3062 3063 background: #171717; 3064 color: white; 3065 3066 font-size: 9px; 3067 font-weight: 900; 3068 3069 letter-spacing: .5px; 3070 } 2913 3071 /* ========================================================= 2914 3072 ADMIN … … 3043 3201 font-size: 10px; 3044 3202 } 3045 3203 /* ========================================================= 3204 ADMIN ARTIST LIST 3205 ========================================================= */ 3206 3207 .admin-artist-cell { 3208 display: flex; 3209 align-items: center; 3210 3211 gap: 14px; 3212 3213 min-width: 220px; 3214 } 3215 3216 .admin-artist-thumb { 3217 width: 70px; 3218 height: 70px; 3219 3220 min-width: 70px; 3221 max-width: 70px; 3222 3223 flex: 0 0 70px; 3224 3225 display: block; 3226 3227 overflow: hidden; 3228 3229 border-radius: 8px; 3230 3231 background: #eee; 3232 3233 object-fit: cover; 3234 object-position: center; 3235 } 3236 3237 .admin-artist-thumb.placeholder { 3238 width: 70px; 3239 height: 70px; 3240 3241 min-width: 70px; 3242 max-width: 70px; 3243 3244 flex: 0 0 70px; 3245 3246 display: flex; 3247 align-items: center; 3248 justify-content: center; 3249 3250 background: #171717; 3251 color: white; 3252 3253 font-size: 24px; 3254 font-weight: 900; 3255 } 3256 3257 .admin-artist-cell strong { 3258 min-width: 0; 3259 3260 font-size: 13px; 3261 font-weight: 900; 3262 3263 overflow-wrap: anywhere; 3264 } 3265 3266 .admin-table-actions { 3267 white-space: nowrap; 3268 3269 text-align: right; 3270 } 3271 3272 .admin-table-actions .admin-button { 3273 margin-left: 6px; 3274 } 3275 3276 3277 /* ========================================================= 3278 ADMIN ARTISTS RESPONSIVE 3279 ========================================================= */ 3280 3281 @media (max-width: 700px) { 3282 3283 .admin-artist-thumb, 3284 .admin-artist-thumb.placeholder { 3285 width: 58px; 3286 height: 58px; 3287 3288 min-width: 58px; 3289 max-width: 58px; 3290 3291 flex-basis: 58px; 3292 } 3293 3294 .admin-artist-cell { 3295 min-width: 180px; 3296 } 3297 3298 } 3046 3299 3047 3300 /* ========================================================= … … 4139 4392 4140 4393 } 4394 4141 4395 /* ========================================================= 4142 4396 KERNEL RECORDS LOGO … … 4144 4398 4145 4399 .logo-brand { 4400 width: 170px; 4401 height: 72px; 4402 4403 flex: 0 0 170px; 4404 4146 4405 display: flex; 4147 4406 align-items: center; 4407 justify-content: flex-start; 4148 4408 4149 4409 padding: 0; 4150 4410 4411 overflow: hidden; 4151 4412 text-decoration: none; 4152 4413 } 4153 4414 4154 .site-logo { 4415 .logo-brand > .site-logo { 4416 width: 160px !important; 4417 height: 64px !important; 4418 4419 max-width: 160px !important; 4420 max-height: 64px !important; 4421 4155 4422 display: block; 4156 4423 4157 width: auto;4158 height: 72px;4159 4160 4424 object-fit: contain; 4161 } 4162 4163 @media (max-width: 700px) { 4164 4165 .site-logo { 4166 height: 55px; 4167 } 4168 4169 } 4170 .admin-page-logo { 4171 display: block; 4172 4173 width: auto; 4174 height: 80px; 4175 4176 margin-bottom: 12px; 4177 4178 object-fit: contain; 4179 } 4425 object-position: left center; 4426 4427 transform: none !important; 4428 } 4429 4180 4430 .hero-logo { 4181 4431 display: flex; … … 4187 4437 width: min(520px, 90%); 4188 4438 height: auto; 4439 4189 4440 display: block; 4441 4190 4442 object-fit: contain; 4443 4191 4444 transform: translate(55px, 55px); 4445 } 4446 4447 @media (max-width: 950px) { 4448 .logo-brand { 4449 width: 145px; 4450 height: 60px; 4451 flex-basis: 145px; 4452 } 4453 4454 .logo-brand > .site-logo { 4455 width: 135px !important; 4456 height: 52px !important; 4457 4458 max-width: 135px !important; 4459 max-height: 52px !important; 4460 } 4461 } 4462 4463 @media (max-width: 700px) { 4464 .hero-logo-image { 4465 width: min(360px, 92%); 4466 transform: translate(0, 0); 4467 } 4192 4468 } 4193 4469 … … 4236 4512 .artist-grid { 4237 4513 display: grid; 4238 grid-template-columns: repeat( auto-fill, 200px);4514 grid-template-columns: repeat(6, 200px); 4239 4515 gap: 24px; 4240 4516 align-items: start; 4241 justify-content: s tart;4517 justify-content: space-between; 4242 4518 } 4243 4519 … … 4330 4606 text-transform: uppercase; 4331 4607 } 4608 @media (max-width: 1450px) { 4609 .artist-grid { 4610 grid-template-columns: repeat(5, 200px); 4611 justify-content: space-between; 4612 } 4613 } 4614 4615 @media (max-width: 1200px) { 4616 .artist-grid { 4617 grid-template-columns: repeat(4, 200px); 4618 } 4619 } 4620 4621 @media (max-width: 950px) { 4622 .artist-grid { 4623 grid-template-columns: repeat(3, 200px); 4624 } 4625 } 4626 4627 @media (max-width: 700px) { 4628 .artist-grid { 4629 grid-template-columns: repeat(2, 200px); 4630 justify-content: center; 4631 } 4632 } 4633 4634 @media (max-width: 430px) { 4635 .artist-grid { 4636 grid-template-columns: 200px; 4637 } 4638 } 4332 4639 4333 4640 /* Artist details: fixed 200 x 200 profile image */
Note:
See TracChangeset
for help on using the changeset viewer.
