From 8b7e39fa86370600daca06ded0d421ef579eef6c Mon Sep 17 00:00:00 2001 From: Flaminel Date: Sun, 25 May 2025 19:23:00 +0300 Subject: [PATCH] try sidebar #2 --- .../main-layout/main-layout.component.html | 163 ++-------------- .../main-layout/main-layout.component.scss | 86 ++++----- .../main-layout/main-layout.component.ts | 25 ++- .../sidebar-content.component.html | 70 +++++++ .../sidebar-content.component.scss | 177 ++++++++++++++++++ .../sidebar-content.component.ts | 40 ++++ 6 files changed, 365 insertions(+), 196 deletions(-) create mode 100644 code/UI/src/app/layout/sidebar-content/sidebar-content.component.html create mode 100644 code/UI/src/app/layout/sidebar-content/sidebar-content.component.scss create mode 100644 code/UI/src/app/layout/sidebar-content/sidebar-content.component.ts diff --git a/code/UI/src/app/layout/main-layout/main-layout.component.html b/code/UI/src/app/layout/main-layout/main-layout.component.html index 4b2e9f51..bfcfe49e 100644 --- a/code/UI/src/app/layout/main-layout/main-layout.component.html +++ b/code/UI/src/app/layout/main-layout/main-layout.component.html @@ -5,76 +5,11 @@ - - + +
- -
- -

Cleanuparr

-
- - - + + +
diff --git a/code/UI/src/app/layout/main-layout/main-layout.component.scss b/code/UI/src/app/layout/main-layout/main-layout.component.scss index c7b3c8e4..cf5744ea 100644 --- a/code/UI/src/app/layout/main-layout/main-layout.component.scss +++ b/code/UI/src/app/layout/main-layout/main-layout.component.scss @@ -28,6 +28,18 @@ overflow-y: auto; z-index: 10; + // Top color line + .sidebar-top-line { + height: 3px; + background: linear-gradient(to right, #673ab7, #9b59b6); + margin-bottom: 10px; + } + + // Hide on mobile screens + @media (max-width: 768px) { + display: none; + } + // Collapsed state &.collapsed { width: 70px; @@ -1286,75 +1298,51 @@ flex-direction: column; height: 100%; background: linear-gradient(135deg, #2c1a47 0%, #1a0e29 50%, #1e1230 75%, rgba(30, 18, 48, 0.95) 100%); - + overflow-y: auto; + .sidebar-top-line { position: absolute; top: 0; left: 0; right: 0; - height: 1px; + height: 3px; background: linear-gradient(90deg, rgba(142, 68, 173, 0.6), rgba(103, 58, 183, 0.6)); z-index: 2; box-shadow: 0 0 8px rgba(142, 68, 173, 0.4); } - - .logo-container { - display: flex; - align-items: center; - padding: 15px 20px 10px; - border-bottom: none; - position: relative; - - .logo { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - margin-right: 15px; - border-radius: 50%; - background-color: rgba(142, 68, 173, 0.1); - border: 1px solid rgba(142, 68, 173, 0.3); - animation: logo-glow 10s infinite ease-in-out; - - i { - font-size: 20px; - color: #ffffff; - } - } - - h1 { - font-size: 22px; - font-weight: 700; - margin: 0; - color: #fff; - text-shadow: 0 0 10px rgba(0, 0, 0, 0.5); - letter-spacing: 0.5px; - background: linear-gradient(to right, #fff, #bbb); - -webkit-background-clip: text; - background-clip: text; - -webkit-text-fill-color: transparent; - } - } } /* Media queries for responsiveness */ @media screen and (max-width: 768px) { + .layout-main { + flex-direction: column; + } + .layout-content { + width: 100%; + .layout-content-inner { padding: 1rem; } + + .top-bar { + .topbar-section { + &.center { + display: none; // Hide version bar on mobile to save space + } + } + } } - - // Optimize the PrimeNG sidebar for mobile + + // Style PrimeNG mobile sidebar :host ::ng-deep { - .p-sidebar.p-component.mobile-sidebar { - background: linear-gradient(135deg, #2c1a47 0%, #1a0e29 50%, #1e1230 75%, rgba(30, 18, 48, 0.95) 100%) !important; - border: none !important; - box-shadow: -5px 0 20px rgba(0, 0, 0, 0.5) !important; - + .p-sidebar.mobile-sidebar { + .p-sidebar-header { + display: none; // Hide the header since we're not using it + } + .p-sidebar-content { - padding: 0 !important; + padding: 0; } } } diff --git a/code/UI/src/app/layout/main-layout/main-layout.component.ts b/code/UI/src/app/layout/main-layout/main-layout.component.ts index bbab9860..0c922eb0 100644 --- a/code/UI/src/app/layout/main-layout/main-layout.component.ts +++ b/code/UI/src/app/layout/main-layout/main-layout.component.ts @@ -1,5 +1,5 @@ import { Component, inject, signal } from '@angular/core'; -import { Router, RouterOutlet, RouterLink } from '@angular/router'; +import { Router, RouterOutlet } from '@angular/router'; import { CommonModule } from '@angular/common'; import { Title } from '@angular/platform-browser'; @@ -12,6 +12,9 @@ import { SidebarModule } from 'primeng/sidebar'; import { DividerModule } from 'primeng/divider'; import { RippleModule } from 'primeng/ripple'; +// Custom Components +import { SidebarContentComponent } from '../sidebar-content/sidebar-content.component'; + interface MenuItem { label: string; icon: string; @@ -25,14 +28,14 @@ interface MenuItem { imports: [ CommonModule, RouterOutlet, - RouterLink, ButtonModule, ToolbarModule, FormsModule, MenuModule, SidebarModule, DividerModule, - RippleModule + RippleModule, + SidebarContentComponent ], templateUrl: './main-layout.component.html', styleUrl: './main-layout.component.scss' @@ -56,6 +59,16 @@ export class MainLayoutComponent { constructor() {} + /** + * Handles mobile navigation click events by closing the sidebar + */ + onMobileNavClick(): void { + // Only close sidebar on mobile view + if (window.innerWidth <= 768) { + this.mobileSidebarVisible.set(false); + } + } + /** * Get the current page title based on the active route */ @@ -73,10 +86,16 @@ export class MainLayoutComponent { } } + /** + * Toggle mobile sidebar visibility + */ toggleMobileSidebar(): void { this.mobileSidebarVisible.update(value => !value); } + /** + * Toggle desktop sidebar collapsed state + */ toggleSidebar(): void { this.isSidebarCollapsed.update(value => !value); } diff --git a/code/UI/src/app/layout/sidebar-content/sidebar-content.component.html b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.html new file mode 100644 index 00000000..e2c7d6ad --- /dev/null +++ b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.html @@ -0,0 +1,70 @@ + +
+ + +

Cleanuparr

+
+ + + diff --git a/code/UI/src/app/layout/sidebar-content/sidebar-content.component.scss b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.scss new file mode 100644 index 00000000..19d60014 --- /dev/null +++ b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.scss @@ -0,0 +1,177 @@ +// Logo container +.logo-container { + display: flex; + align-items: center; + padding: 15px 20px; + margin-bottom: 5px; + + .logo { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 15px; + background-color: rgba(142, 68, 173, 0.1); + border: 1px solid rgba(142, 68, 173, 0.3); + animation: logo-glow 10s infinite ease-in-out; + + i { + font-size: 20px; + color: #a569bd; + } + } + + .logo-small { + display: none; + } + + h1 { + font-size: 20px; + font-weight: 700; + margin: 0; + background: linear-gradient(to right, #fff, #bbb); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + } +} + +// Navigation menu +.nav-menu { + display: flex; + flex-direction: column; + padding: 5px 0 20px 0; + flex: 1; + + // Sponsor link + .sponsor-link { + margin-bottom: 15px; + border-bottom: 1px solid rgba(142, 68, 173, 0.15); + padding-bottom: 15px !important; + + .heart-icon i { + color: #ff4d6d !important; + animation: heart-pulse 7.2s infinite ease-in-out; + } + } + + // Nav groups + .nav-group { + margin-bottom: 15px; + + .nav-group-title { + font-size: 12px; + font-weight: 700; + color: rgba(142, 68, 173, 0.8); + text-transform: uppercase; + letter-spacing: 2px; + padding: 0 20px 8px; + margin-top: 10px; + margin-bottom: 5px; + border-bottom: 1px solid rgba(142, 68, 173, 0.2); + text-shadow: 0 0 10px rgba(142, 68, 173, 0.3); + } + } + + // Navigation items + .nav-item { + display: flex; + align-items: center; + padding: 10px 20px; + color: #e0e0e0; + text-decoration: none; + border-radius: 0 6px 6px 0; + margin: 2px 0 2px 0; + position: relative; + overflow: hidden; + transition: all 0.2s ease; + + .nav-icon-wrapper { + width: 32px; + height: 32px; + display: flex; + justify-content: center; + align-items: center; + margin-right: 15px; + border-radius: 8px; + background: rgba(46, 39, 56, 0.3); + border: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.2s ease; + + i { + font-size: 14px; + color: #e0e0e0; + } + } + + span { + white-space: nowrap; + font-size: 14px; + } + + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 3px; + background: transparent; + transition: all 0.2s ease; + } + + &:hover { + background: rgba(142, 68, 173, 0.05); + + .nav-icon-wrapper { + background: rgba(142, 68, 173, 0.2); + transform: scale(1.05); + } + + &::before { + background: linear-gradient(to bottom, rgba(142, 68, 173, 0.4), rgba(103, 58, 183, 0.4)); + } + } + + &.active { + background: linear-gradient(to right, rgba(142, 68, 173, 0.9), rgba(103, 58, 183, 0.7)); + box-shadow: 0 2px 10px rgba(142, 68, 173, 0.3); + + .nav-icon-wrapper { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.2); + } + + &::before { + background: #fff; + } + } + } +} + +// Animation keyframes +@keyframes logo-glow { + 0% { box-shadow: 0 0 15px #8e44ad, 0 0 5px rgba(142, 68, 173, 0.4); } // Purple + 20% { box-shadow: 0 0 15px #9b59b6, 0 0 5px rgba(155, 89, 182, 0.4); } // Lighter purple + 40% { box-shadow: 0 0 15px #673ab7, 0 0 5px rgba(103, 58, 183, 0.4); } // Deep purple + 60% { box-shadow: 0 0 15px #5e35b1, 0 0 5px rgba(94, 53, 177, 0.4); } // Dark deep purple + 80% { box-shadow: 0 0 15px #7e57c2, 0 0 5px rgba(126, 87, 194, 0.4); } // Medium purple + 100% { box-shadow: 0 0 15px #8e44ad, 0 0 5px rgba(142, 68, 173, 0.4); } // Back to purple +} + +@keyframes heart-pulse { + 0% { + transform: scale(1); + opacity: 0.7; + } + 50% { + transform: scale(1.2); + opacity: 1; + } + 100% { + transform: scale(1); + opacity: 0.7; + } +} diff --git a/code/UI/src/app/layout/sidebar-content/sidebar-content.component.ts b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.ts new file mode 100644 index 00000000..f444f6de --- /dev/null +++ b/code/UI/src/app/layout/sidebar-content/sidebar-content.component.ts @@ -0,0 +1,40 @@ +import { Component, Input, inject, Output, EventEmitter } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Router, RouterLink } from '@angular/router'; +import { ButtonModule } from 'primeng/button'; + +interface MenuItem { + label: string; + icon: string; + route: string; + badge?: string; +} + +@Component({ + selector: 'app-sidebar-content', + standalone: true, + imports: [ + CommonModule, + RouterLink, + ButtonModule + ], + templateUrl: './sidebar-content.component.html', + styleUrl: './sidebar-content.component.scss' +}) +export class SidebarContentComponent { + @Input() menuItems: MenuItem[] = []; + @Input() isMobile = false; + @Output() navItemClicked = new EventEmitter(); + + // Inject router for active route styling + public router = inject(Router); + + /** + * Handle navigation item click + */ + onNavItemClick(): void { + if (this.isMobile) { + this.navItemClicked.emit(); + } + } +}