diff --git a/frontend/recorever-frontend/src/app/layout/admin-layout/admin-side-bar/admin-side-bar.scss b/frontend/recorever-frontend/src/app/layout/admin-layout/admin-side-bar/admin-side-bar.scss index 43167e60..4050e782 100644 --- a/frontend/recorever-frontend/src/app/layout/admin-layout/admin-side-bar/admin-side-bar.scss +++ b/frontend/recorever-frontend/src/app/layout/admin-layout/admin-side-bar/admin-side-bar.scss @@ -1,32 +1,31 @@ @use "sass:color"; -$sidebar-width: 250px; -$primary-text: #333; -$secondary-text: #777777; -$active-bg: #f0f0f0; -$border-color: #e0e0e0; - -$dropdown-bg: #333; -$dropdown-text: #fff; -$dropdown-separator: #555; -$dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); +$sidebar-width: 260px; +$primary-color: #2c3e50; +$accent-color: #3498db; +$text-main: #333; +$text-muted: #888; +$bg-hover: #f5f7fa; +$bg-active: #eef5ff; +$border-light: #f0f0f0; .admin-side-bar { - width: 100%; + width: $sidebar-width; height: 100%; - background-color: white; - box-shadow: none; - padding: 0 0 10px 0; + background-color: #ffffff; + border-right: 1px solid $border-light; display: flex; flex-direction: column; - position: relative; + padding: 20px 12px; + box-sizing: border-box; + font-family: 'Inter', sans-serif; .user-profile-header { display: flex; align-items: center; - padding: 15px 15px 15px 15px; + padding: 15px 15px; margin-bottom: 10px; - border-bottom: 1px solid $border-color; + border-bottom: 1px solid $border-light; position: relative; overflow: visible; @@ -36,42 +35,51 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); flex-grow: 1; cursor: pointer; padding: 5px 10px; - margin: -5px 10px -5px -15px; + margin: -5px -10px -5px -15px; + margin-right: 10px; transition: background-color 0.1s ease; border-radius: 8px; + min-width: 0; + &.dropdown-open, &:hover { - background-color: $active-bg; + background-color: $bg-hover; } - } - - .profile-avatar-img { - width: 30px; - height: 30px; - margin-right: 10px; - border-radius: 50%; - } - .profile-info { - display: flex; - align-items: center; - max-height: 30px; - height: 30px; - overflow: hidden; - line-height: 1.2; - - .profile-name { - font-weight: 700; - color: $primary-text; - white-space: nowrap; + .profile-avatar-img { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; + margin-right: 12px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); } - .profile-dropdown-arrow { - margin-left: 5px; - font-size: 10px; - transition: transform 0.2s ease; - transform: rotate(0deg); + .profile-info { + display: flex; + align-items: center; + min-width: 0; + flex: 1; + + .profile-name { + font-weight: bold; + color: $text-main; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + max-width: 100%; + } + + .profile-dropdown-arrow { + margin-left: 5px; + font-size: 10px; + transition: transform 0.2s ease; + transform: rotate(0deg); + flex-shrink: 0; + color: $text-muted; + } } } @@ -81,17 +89,18 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); margin: -8px; border-radius: 50%; transition: background-color 0.1s ease; + flex-shrink: 0; @media (max-width: 768px) { display: none; } &:hover { - background-color: $active-bg; + background-color: $bg-hover; } &:active { - background-color: color.adjust($active-bg, $lightness: -5%); + background-color: color.adjust($bg-hover, $lightness: -5%); } } @@ -107,15 +116,16 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); .profile-dropdown-menu { position: absolute; top: 100%; - left: -5px; + left: 10px; width: 350px; - background-color: $dropdown-bg; + background-color: $text-main; border-radius: 8px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); z-index: 100; padding: 10px 0; margin-top: 5px; - color: $dropdown-text; + color: white; + animation: fadeIn 0.1s ease-out; .dropdown-user-info { display: flex; @@ -123,7 +133,7 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); align-items: center; padding: 10px; margin-bottom: 10px; - border-bottom: 1px solid $dropdown-separator; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); .dropdown-avatar-img { width: 50px; @@ -135,150 +145,156 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); .dropdown-name { font-weight: bold; font-size: 16px; + max-width: 100%; white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 0 10px; } .dropdown-email { font-size: 12px; - color: color.adjust($dropdown-text, $lightness: 20%); + color: color.adjust($text-muted, $lightness: 20%); + max-width: 100%; white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 0 10px; } } - .dropdown-item, - a.dropdown-item, - button.dropdown-item { + .dropdown-item { display: flex; align-items: center; - width: 100%; padding: 10px 15px; cursor: pointer; text-decoration: none; - color: $dropdown-text; - transition: background-color 0.1s ease, box-shadow 0.08s ease; - } - - button.dropdown-item { - appearance: none; - -webkit-appearance: none; + color: white; + transition: background-color 0.1s ease; + background: none; border: none; - background: transparent; - font: inherit; + width: 100%; text-align: left; - padding: 10px 15px; - } + font-size: 14px; - .dropdown-item:hover { - background-color: $dropdown-hover; - } - - .dropdown-item:active { - background-color: color.adjust($dropdown-hover, $lightness: -6%); - } - - .dropdown-item:focus, - .dropdown-item:focus-visible { - outline: none; - box-shadow: 0 0 0 3px color.adjust($dropdown-bg, $lightness: 45%); - } - - .dropdown-item-icon { - width: 20px; - height: 20px; - margin-right: 10px; - flex-shrink: 0; - } + &:hover { + background-color: rgba(255, 255, 255, 0.1); + } - /* keep labels tidy */ - .dropdown-item > :not(.dropdown-item-icon) { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .dropdown-item-icon { + width: 20px; + height: 20px; + margin-right: 10px; + } } .dropdown-divider { height: 1px; - background-color: $dropdown-separator; + background-color: rgba(255, 255, 255, 0.1); margin: 5px 0; } } } - .section-title-link { - display: flex; - align-items: center; - flex-grow: 1; + .nav-section { + overflow-y: auto; + overflow-x: hidden; - font-weight: bold; - color: $primary-text; - font-size: 14px; - } + &::-webkit-scrollbar { width: 4px; } + &::-webkit-scrollbar-thumb { background: #ddd; border-radius: 4px; } - .section-header { - display: flex; - align-items: center; - justify-content: space-between; - cursor: pointer; - padding: 10px 15px 5px; - } + .nav-item { + display: flex; + align-items: center; + padding: 10px 16px; + margin-bottom: 4px; + border-radius: 10px; + color: $text-main; + text-decoration: none; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + font-weight: 500; + font-size: 14px; + cursor: pointer; - .toggle-icon { - transition: transform 0.2s ease; - font-size: 10px; - transform: rotate(0deg); - } + .nav-icon { + width: 20px; + height: 20px; + margin-right: 12px; + opacity: 0.6; + transition: opacity 0.2s; + object-fit: contain; + } - .section-header[aria-expanded="true"] .toggle-icon { - transform: rotate(180deg); - } + &:hover { + background-color: $bg-hover; + color: black; + transform: translateX(3px); + + .nav-icon { opacity: 1; } + } + + &.active { + background-color: $bg-active; + color: $accent-color; + font-weight: 600; + + .nav-icon { + opacity: 1; + filter: invert(47%) sepia(66%) saturate(1996%) hue-rotate(187deg) brightness(96%) contrast(92%); + } + } + } - .nav-section { &.archive-nav { flex-grow: 1; - } - } + margin-top: 10px; - .nav-item { - display: flex; - align-items: center; - text-decoration: none; - color: $primary-text; - padding: 10px 15px; - transition: background-color 0.1s ease; - cursor: pointer; - - .nav-icon { - width: 24px; - height: 24px; - margin-right: 15px; - object-fit: contain; - } + .section-header { + justify-content: space-between; - .tracking-icon-sm { - width: 24px; - height: 24px; - margin-right: 18px; - margin-left: 10px; - } + .section-title-link { + display: flex; + align-items: center; + font-weight: inherit; + } - &.archive-item { - padding-left: 30px; - } + .toggle-icon { + font-size: 10px; + color: $text-muted; + transition: transform 0.2s; + } - &.active, - &:hover { - background-color: $active-bg; - } + &[aria-expanded="true"] .toggle-icon { + transform: rotate(180deg); + } + } + + .archive-list-content { + padding-top: 2px; - &[aria-current="page"] { - background-color: $active-bg; - font-weight: bold; + .nav-item.archive-item { + padding-left: 32px; + font-size: 13px; + + .nav-icon { + width: 18px; + height: 18px; + } + } + } } } .nav-divider-mock { height: 1px; - background: $border-color; + background: linear-gradient(to right, transparent, + $border-light, transparent); margin: 10px 0; + flex-shrink: 0; } +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(-5px); } + to { opacity: 1; transform: translateY(0); } } \ No newline at end of file diff --git a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.html b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.html index 577589d2..769bcb1e 100644 --- a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.html +++ b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.html @@ -31,8 +31,8 @@ @for (item of profileDropdownItems; track item.label) { @if (item.action === 'navigate') { - {{ item.label }} Icon @@ -52,27 +52,34 @@ } diff --git a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.scss b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.scss index d4e7bdcf..af91856b 100644 --- a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.scss +++ b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.scss @@ -1,34 +1,32 @@ @use "sass:color"; -$sidebar-width: 250px; -$primary-text: #333; -$secondary-text: #777777; -$active-bg: #f0f0f0; -$border-color: #e0e0e0; - -$dropdown-bg: #333; -$dropdown-text: #fff; -$dropdown-separator: #555; -$dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); - +$sidebar-width: 260px; +$primary-color: #2c3e50; +$accent-color: #3498db; +$text-main: #333; +$text-muted: #888; +$bg-hover: #f5f7fa; +$bg-active: #eef5ff; +$border-light: #f0f0f0; .user-side-bar { width: $sidebar-width; height: 100%; - background-color: white; - box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05); - padding: 10px 0; + background-color: #ffffff; + border-right: 1px solid $border-light; display: flex; flex-direction: column; + padding: 20px 12px; + box-sizing: border-box; + font-family: 'Inter', sans-serif; position: relative; - overflow: visible; - .user-profile-header { + .user-profile-header { display: flex; align-items: center; padding: 15px 15px; margin-bottom: 10px; - border-bottom: 1px solid $border-color; + border-bottom: 1px solid $border-light; position: relative; overflow: visible; @@ -42,49 +40,48 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); margin-right: 10px; transition: background-color 0.1s ease; border-radius: 8px; - + /* FIX: Allow this container to shrink if text is too long */ - min-width: 0; + min-width: 0; &.dropdown-open, &:hover { - background-color: $active-bg; + background-color: $border-light; } - } - .profile-avatar-img { - width: 30px; - height: 30px; - margin-right: 10px; - border-radius: 50%; - flex-shrink: 0; /* Prevent avatar from shrinking */ - } + .profile-avatar-img { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; + margin-right: 12px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } - .profile-info { - display: flex; + .profile-info { + display: flex; align-items: center; /* FIX: Allow shrinking and take available space */ - min-width: 0; + min-width: 0; flex: 1; - .profile-name { - font-weight: bold; - color: $primary-text; - - /* FIX: Truncate text with ellipsis (...) */ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display: block; - max-width: 100%; /* Force it to respect parent width */ - } + .profile-name { + font-weight: bold; + color: $text-main; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + max-width: 100%; + } - .profile-dropdown-arrow { - margin-left: 5px; - font-size: 10px; - transition: transform 0.2s ease; - transform: rotate(0deg); - flex-shrink: 0; /* Prevent arrow from shrinking */ + .profile-dropdown-arrow { + margin-left: 5px; + font-size: 10px; + transition: transform 0.2s ease; + transform: rotate(0deg); + flex-shrink: 0; + } } } @@ -101,11 +98,11 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); } &:hover { - background-color: $active-bg; + background-color: $bg-hover; } &:active { - background-color: color.adjust($active-bg, $lightness: -5%); + background-color: color.adjust($bg-hover, $lightness: -5%); } } @@ -117,20 +114,19 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); .profile-click-area.dropdown-open .profile-dropdown-arrow { transform: rotate(180deg); } - .profile-dropdown-menu { position: absolute; top: 100%; left: 15px; width: 350px; left: -5px; - background-color: $dropdown-bg; + background-color: $text-main; border-radius: 8px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); z-index: 100; padding: 10px 0; margin-top: 5px; - color: $dropdown-text; + color: white; .dropdown-user-info { display: flex; @@ -138,7 +134,7 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); align-items: center; padding: 10px; margin-bottom: 10px; - border-bottom: 1px solid $dropdown-separator; + border-bottom: 1px solid $border-light; .dropdown-avatar-img { width: 50px; @@ -160,8 +156,7 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); .dropdown-email { font-size: 12px; - color: color.adjust($dropdown-text, $lightness: 20%); - /* FIX: Handle long emails in dropdown */ + color: color.adjust($text-muted, $lightness: 20%); max-width: 100%; white-space: nowrap; overflow: hidden; @@ -176,11 +171,11 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); padding: 10px 15px; cursor: pointer; text-decoration: none; - color: $dropdown-text; + color: white; transition: background-color 0.1s ease; &:hover { - background-color: $dropdown-hover; + background-color: $text-muted; } .dropdown-item-icon { @@ -192,99 +187,102 @@ $dropdown-hover: color.adjust($dropdown-bg, $lightness: 10%); .dropdown-divider { height: 1px; - background-color: $dropdown-separator; + background-color: $border-light; margin: 5px 0; } } } - .section-title { - font-weight: bold; - color: $secondary-text; - font-size: 14px; - } - .section-title-link { - font-weight: bold; - color: $secondary-text; - font-size: 14px; - text-decoration: none; + .nav-section { + flex: 1; + overflow-y: auto; + overflow-x: hidden; - &:hover { - text-decoration: underline; - } - } + &::-webkit-scrollbar { width: 4px; } + &::-webkit-scrollbar-thumb { background: #ddd; border-radius: 4px; } - .section-header { - display: flex; - justify-content: space-between; - align-items: center; - cursor: pointer; - padding: 10px 15px 5px; - } + .nav-group { + margin-bottom: 24px; - .toggle-icon { - transition: transform 0.2s ease; - font-size: 10px; - transform: rotate(0deg); - } + .nav-group-label { + font-size: 11px; + text-transform: uppercase; + color: $text-muted; + font-weight: 700; + letter-spacing: 0.8px; + margin-bottom: 8px; + padding-left: 16px; + } - .section-header[aria-expanded="true"] .toggle-icon { - transform: rotate(180deg); - } + .nav-item { + display: flex; + align-items: center; + padding: 10px 16px; + margin-bottom: 4px; + border-radius: 10px; + color: $text-main; + text-decoration: none; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + font-weight: 500; + font-size: 14px; + cursor: pointer; - .nav-item { - display: flex; - align-items: center; - text-decoration: none; - color: $primary-text; - padding: 10px 15px; - transition: background-color 0.1s ease; - cursor: pointer; - - .nav-icon { - width: 24px; - height: 24px; - margin-right: 15px; - object-fit: contain; - } + .nav-icon { + width: 20px; + height: 20px; + margin-right: 12px; + opacity: 0.6; + transition: opacity 0.2s; + } - .tracking-icon-sm { - width: 18px; - height: 18px; - margin-right: 18px; - } + &:hover { + background-color: $bg-hover; + color: black; + transform: translateX(3px); - &.active, - &:hover { - background-color: $active-bg; - } + .nav-icon { opacity: 1; } + } - &[aria-current="page"] { - background-color: $active-bg; - font-weight: bold; + &.active { + background-color: $bg-active; + color: $accent-color; + font-weight: 600; + + .nav-icon { + opacity: 1; + filter: invert(47%) sepia(66%) saturate(1996%) + hue-rotate(187deg) brightness(96%) contrast(92%); + } + } + } } } .nav-divider-mock { height: 1px; - background: $border-color; + background: linear-gradient(to right, transparent, $border-light, transparent); margin: 10px 0; } .help-link { margin-top: auto; - padding: 40px 15px; - text-align: right; + padding: 10px 16px; a { - color: $secondary-text; + display: block; + text-align: center; + color: $text-muted; + font-size: 13px; text-decoration: none; - font-size: 14px; + transition: color 0.2s; - &:hover { - text-decoration: underline; - } + &:hover { color: $accent-color; text-decoration: underline; } } } +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(-5px); } + to { opacity: 1; transform: translateY(0); } } \ No newline at end of file diff --git a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.ts b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.ts index 4fc10c85..0761783c 100644 --- a/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.ts +++ b/frontend/recorever-frontend/src/app/layout/user-layout/user-side-bar/user-side-bar.ts @@ -13,6 +13,15 @@ import { SettingsModal } from '../../../modal/settings-modal/settings-modal'; import { LogoutResponse } from '../../../models/auth-model'; import { environment } from '../../../../environments/environment'; +interface SidebarNavItem extends NavItem { + fragment?: string; +} + +interface NavGroup { + label: string; + items: SidebarNavItem[]; +} + @Component({ selector: 'app-user-side-bar', standalone: true, @@ -44,24 +53,24 @@ export class UserSideBar implements OnDestroy { protected isLogoutModalOpen = false; protected isProfileDropdownOpen = false; - protected showLoginModal = false; private protectedRoutes = [ AppRoutePaths.REPORT_LOST, - AppRoutePaths.REPORT_FOUND + AppRoutePaths.REPORT_FOUND, + AppRoutePaths.PROFILE ]; private logoutTrigger$ = new Subject(); private destroy$ = new Subject(); protected getProfileImageUrl(path: string | null | undefined): string { - if (!path) { - return 'assets/profile-avatar.png'; - } - if (path.startsWith('http')) { - return path.replace('http://', 'https://'); - } + if (!path) { + return 'assets/profile-avatar.png'; + } + if (path.startsWith('http')) { + return path.replace('http://', 'https://'); + } const secureBaseUrl = environment.apiUrl.replace('http://', 'https://'); return `${secureBaseUrl}/image/download/${path}`; @@ -77,15 +86,36 @@ export class UserSideBar implements OnDestroy { { label: 'Log out', iconPath: 'assets/log-out.png', action: 'logout' }, ]; - protected mainNav: NavItem[] = [ - { label: 'Lost Items', route: AppRoutePaths.LOST_ITEMS, - iconPath: 'assets/lost-items.png' }, - { label: 'Report Lost Item', route: AppRoutePaths.REPORT_LOST, - iconPath: 'assets/reported-lost-items.png' }, - { label: 'Found Items', route: AppRoutePaths.FOUND_ITEMS, - iconPath: 'assets/found-items.png' }, - { label: 'Report Found Item', route: AppRoutePaths.REPORT_FOUND, - iconPath: 'assets/reported-found-item.png' }, + protected navGroups: NavGroup[] = [ + { + label: 'Browse', + items: [ + { label: 'Lost Items', route: AppRoutePaths.LOST_ITEMS, + iconPath: 'assets/lost-items.png' }, + { label: 'Found Items', route: AppRoutePaths.FOUND_ITEMS, + iconPath: 'assets/found-items.png' }, + ] + }, + { + label: 'Submit an Item', + items: [ + { label: 'Report Lost Item', route: AppRoutePaths.REPORT_LOST, + iconPath: 'assets/reported-lost-items.png' }, + { label: 'Report Found Item', route: AppRoutePaths.REPORT_FOUND, + iconPath: 'assets/reported-found-item.png' }, + ] + }, + { + label: 'Manage', + items: [ + { + label: 'My Reports', + route: AppRoutePaths.PROFILE, + iconPath: 'assets/recents.png', + fragment: 'my-reports-section' + } + ] + } ]; protected profileRoute = AppRoutePaths.PROFILE; @@ -157,10 +187,10 @@ export class UserSideBar implements OnDestroy { }); } - public onProtectedLinkClick(route: string): void { + public onProtectedLinkClick(route: string, fragment?: string): void { if (this.currentUser()) { - - this.router.navigate([route]); + const navigationExtras = fragment ? { fragment } : {}; + this.router.navigate([route], navigationExtras); this.closeSidebar.emit(); } else { this.showLoginModal = true; diff --git a/frontend/recorever-frontend/src/app/page/user/profile-page/profile-page.html b/frontend/recorever-frontend/src/app/page/user/profile-page/profile-page.html index 3a22239a..18ee7a10 100644 --- a/frontend/recorever-frontend/src/app/page/user/profile-page/profile-page.html +++ b/frontend/recorever-frontend/src/app/page/user/profile-page/profile-page.html @@ -40,7 +40,7 @@

{{ user.name }}

} -
+