diff --git a/angular.json b/angular.json index 47839e8..93e6b3e 100644 --- a/angular.json +++ b/angular.json @@ -34,6 +34,7 @@ "styles": [ "src/styles.scss", "node_modules/animate.css/animate.min.css", + "node_modules/primeflex/primeflex.css" ], "scripts": [] }, diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 79b54c7..6119fcd 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -13,8 +13,12 @@ export const appConfig: ApplicationConfig = { provideAnimations(), providePrimeNG({ theme: { - preset: Aura + preset: Aura, + options: { + darkModeSelector: false || 'none' + } } + }) ] }; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index a127a54..d763f1a 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,9 +1,20 @@ import { Routes } from '@angular/router'; import { LoginComponent } from './pages/login/login.component'; +import { SidebarComponent } from './components/sidebar/sidebar.component'; +import { LayoutComponent } from './components/layout/layout.component'; +import { HomeComponent } from './pages/home/home.component'; export const routes: Routes = [ - { path: '', redirectTo: 'login', pathMatch: 'full' }, { path: 'login', component: LoginComponent }, - { path: '**', redirectTo: 'login' } + + { + path: '', + component: LayoutComponent, + children: [ + { path: '', redirectTo: 'home', pathMatch: 'full' }, + { path: 'home', component: HomeComponent }, + ] + }, + { path: '**', redirectTo: 'home' } ]; diff --git a/src/app/components/layout/layout.component.html b/src/app/components/layout/layout.component.html new file mode 100644 index 0000000..da62be0 --- /dev/null +++ b/src/app/components/layout/layout.component.html @@ -0,0 +1,29 @@ +
+ + + + +
+ + + + +
+ +
+ + + +
+
\ No newline at end of file diff --git a/src/app/components/layout/layout.component.scss b/src/app/components/layout/layout.component.scss new file mode 100644 index 0000000..2ac6b11 --- /dev/null +++ b/src/app/components/layout/layout.component.scss @@ -0,0 +1,73 @@ +/* src/app/components/layout/layout.component.scss */ +.layout-wrapper { + display: flex; + min-height: 100vh; + } + + .sidebar-wrapper { + flex: 0 0 250px; + width: 250px; + position: fixed; + height: 100vh; + z-index: 100; + box-shadow: 0 0 10px rgba(0,0,0,0.1); + background-color: #0088cc; + transition: transform 0.3s ease, width 0.3s ease; + } + + /* Para pantallas grandes */ + .sidebar-wrapper:not(.sidebar-visible) { + transform: translateX(-250px); + width: 0; + } + + .main-content-wrapper { + flex: 1; + margin-left: 250px; + display: flex; + flex-direction: column; + min-height: 100vh; + background-color: #f8f9fa; + transition: margin-left 0.3s ease; + } + + /* Ajustar el margen cuando el sidebar está oculto */ + .sidebar-wrapper:not(.sidebar-visible) ~ .main-content-wrapper { + margin-left: 0; + } + + .page-content { + flex: 1; + padding: 0; + background-color: #f8f9fa; + } + + .footer { + display: flex; + justify-content: space-between; + background-color: #0088cc; + color: white; + padding: 0.75rem 1rem; + font-size: 0.8rem; + } + + .footer-left, .footer-right { + display: flex; + flex-direction: column; + } + + /* Ajustes para tablets y móviles */ + @media (max-width: 992px) { + .sidebar-wrapper { + transform: translateX(-100%); + transition: transform 0.3s; + } + + .main-content-wrapper { + margin-left: 0; + } + + .sidebar-wrapper.sidebar-visible { + transform: translateX(0); + } + } \ No newline at end of file diff --git a/src/app/components/layout/layout.component.spec.ts b/src/app/components/layout/layout.component.spec.ts new file mode 100644 index 0000000..09aa9fc --- /dev/null +++ b/src/app/components/layout/layout.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LayoutComponent } from './layout.component'; + +describe('LayoutComponent', () => { + let component: LayoutComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [LayoutComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LayoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/layout/layout.component.ts b/src/app/components/layout/layout.component.ts new file mode 100644 index 0000000..e07acbb --- /dev/null +++ b/src/app/components/layout/layout.component.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { NavbarComponent } from '../navbar/navbar.component'; +import { SidebarComponent } from '../sidebar/sidebar.component'; + + +@Component({ + selector: 'app-layout', + imports: [ + CommonModule, + RouterModule, + NavbarComponent, + SidebarComponent + ], + templateUrl: './layout.component.html', + styleUrl: './layout.component.scss', + standalone: true, +}) +export class LayoutComponent { + isSidebarVisible: boolean = true; + toggleSidebar() { + console.log('Toggling sidebar, current state:', this.isSidebarVisible); + this.isSidebarVisible = !this.isSidebarVisible; + console.log('New sidebar state:', this.isSidebarVisible); + + // Aplicar clase al body solo para móviles + if (window.innerWidth <= 992) { + document.body.classList.toggle('sidebar-visible', this.isSidebarVisible); + } + } +} diff --git a/src/app/components/navbar/navbar.component.html b/src/app/components/navbar/navbar.component.html new file mode 100644 index 0000000..bcefa32 --- /dev/null +++ b/src/app/components/navbar/navbar.component.html @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/src/app/components/navbar/navbar.component.scss b/src/app/components/navbar/navbar.component.scss new file mode 100644 index 0000000..63d1a0e --- /dev/null +++ b/src/app/components/navbar/navbar.component.scss @@ -0,0 +1,92 @@ +.navbar-container { + display: flex; + justify-content: space-between; + align-items: center; + background-color: #bcdaef; + height: 48px; + padding: 0 1rem; + width: 100%; + } + + .navbar-left { + display: flex; + align-items: center; + } + + .sidebar-toggle { + color: #343a40; + margin-right: 0.5rem; + } + + .app-title { + font-weight: bold; + color: #0a2847; + font-size: 1rem; + } + + .navbar-right { + display: flex; + align-items: center; + } + + .user-name { + margin-right: 0.5rem; + font-size: 0.9rem; + color: #0a2847; + } + + .logout-button { + color: #0a2847; + } + + /* Page header styles */ + .page-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem; + border-bottom: 1px solid #dee2e6; + background-color: #fff; + } + + .page-title { + font-size: 1.25rem; + font-weight: 500; + color: #495057; + } + + .breadcrumb-container { + font-size: 0.875rem; + color: #6c757d; + } + + .breadcrumb-link { + color: #0088cc; + text-decoration: none; + } + + .breadcrumb-link:hover { + text-decoration: underline; + } + + .breadcrumb-separator { + margin: 0 0.25rem; + } + + .breadcrumb-current { + color: #6c757d; + } + + /* Sobrescribir estilos de PrimeNG para los botones en el navbar */ + :host ::ng-deep .p-button.p-button-text { + padding: 0.5rem; + color: #0a2847; + + &:focus { + box-shadow: none; + } + + .p-button-icon { + font-size: 1rem; + } + } \ No newline at end of file diff --git a/src/app/components/navbar/navbar.component.spec.ts b/src/app/components/navbar/navbar.component.spec.ts new file mode 100644 index 0000000..cfedf9e --- /dev/null +++ b/src/app/components/navbar/navbar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NavbarComponent } from './navbar.component'; + +describe('NavbarComponent', () => { + let component: NavbarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [NavbarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(NavbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/navbar/navbar.component.ts b/src/app/components/navbar/navbar.component.ts new file mode 100644 index 0000000..bb9c46f --- /dev/null +++ b/src/app/components/navbar/navbar.component.ts @@ -0,0 +1,17 @@ +import { Component, EventEmitter, Output } from '@angular/core'; + +@Component({ + selector: 'app-navbar', + imports: [], + templateUrl: './navbar.component.html', + styleUrl: './navbar.component.scss' +}) +export class NavbarComponent { + @Output() sidebarToggle = new EventEmitter(); + pageTitle: string = 'Starter Page'; + + toggleSidebar() { + this.sidebarToggle.emit(); + } + +} diff --git a/src/app/components/sidebar/sidebar.component.html b/src/app/components/sidebar/sidebar.component.html new file mode 100644 index 0000000..0465865 --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.html @@ -0,0 +1,62 @@ + \ No newline at end of file diff --git a/src/app/components/sidebar/sidebar.component.scss b/src/app/components/sidebar/sidebar.component.scss new file mode 100644 index 0000000..366dfe8 --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.scss @@ -0,0 +1,114 @@ +.sidebar { + width: 250px; + height: 100%; + background-color: #bcdaef; + display: flex; + flex-direction: column; +} + +.logo-container { + text-align: center; +} + +.logo-image-container { + position: relative; + display: inline-block; + margin-bottom: 0.5rem; +} + +.logo-image { + width: 100%; + height: auto; + display: block; + margin: 0 auto; +} + +.version-badge { + position: absolute; + top: 0; + right: 20px; + background-color: #0088cc; + color: white; + border-radius: 50%; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.7rem; + font-weight: bold; +} + +.logo-text { + font-size: 1.5rem; + font-weight: bold; + color: #0a2847; + margin-bottom: 0.25rem; +} + +.logo-subtitle { + font-size: 0.7rem; + color: #0a2847; + max-width: 180px; + margin: 0 auto; + line-height: 1.2; +} + +.separator { + height: 1px; + background-color: #a3c5e6; + margin: 0 0.5rem; +} + +.menu-container { + padding: 0.5rem 0; + flex: 1; + overflow-y: auto; +} + +.sidebar-menu { + list-style: none; + padding: 0; + margin: 0; +} + +.menu-item { + margin: 2px 0; + padding: 0 0.5rem; /* Añadimos padding lateral al ítem */ +} + +.menu-link { + display: flex; + align-items: center; + padding: 0.75rem 1rem; + color: #0a2847; + text-decoration: none; + transition: background-color 0.2s, box-shadow 0.3s; + border-left: 3px solid transparent; + border-radius: .25rem; + width: calc(100% - 1rem); /* Reducimos el ancho para crear margen */ +} + +.menu-link:hover { + background-color: #dadada !important; +} + +.menu-icon { + margin-right: 0.75rem; + width: 1.25rem; + text-align: center; + color: #0a2847; +} + +.menu-text { + font-size: 0.9rem; +} + +.menu-item.active .menu-link { + background: linear-gradient(90deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 100%) !important; + border-left: 3px solid white !important; + color: #706f6f !important; + font-weight: 600; + box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.24) !important; + margin: 0 auto; /* Centra el elemento */ +} \ No newline at end of file diff --git a/src/app/components/sidebar/sidebar.component.spec.ts b/src/app/components/sidebar/sidebar.component.spec.ts new file mode 100644 index 0000000..5445f3c --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarComponent } from './sidebar.component'; + +describe('SidebarComponent', () => { + let component: SidebarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar.component.ts b/src/app/components/sidebar/sidebar.component.ts new file mode 100644 index 0000000..4da8bba --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-sidebar', + imports: [], + templateUrl: './sidebar.component.html', + styleUrl: './sidebar.component.scss' +}) +export class SidebarComponent { + +} diff --git a/src/app/pages/home/home.component.html b/src/app/pages/home/home.component.html new file mode 100644 index 0000000..686a623 --- /dev/null +++ b/src/app/pages/home/home.component.html @@ -0,0 +1,38 @@ + +
+ + + +
Simple Card
+
+ +

Lorem ipsum dolor sit amet...

+
+
+ + + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +

+
+ + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. +

+
+ + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +

+
+
+
\ No newline at end of file diff --git a/src/app/pages/home/home.component.scss b/src/app/pages/home/home.component.scss new file mode 100644 index 0000000..0bf0724 --- /dev/null +++ b/src/app/pages/home/home.component.scss @@ -0,0 +1,62 @@ +/* src/app/pages/home/home.component.scss */ +.home-page { + padding: 1rem; + } + + .card-title { + font-size: 1.1rem; + font-weight: 500; + color: #495057; + } + + /* Personalización del estilo de la card */ + :host ::ng-deep .p-card { + border-radius: 0; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + + .p-card-title { + font-size: 1.1rem; + margin-bottom: 0.5rem; + } + + .p-card-content { + padding-top: 0; + } + } + + /* Personalización del estilo del acordeón */ + :host ::ng-deep .p-accordion { + .p-accordion-header { + .p-accordion-header-link { + background-color: #f8f9fa; + color: #495057; + border-radius: 0; + font-weight: 500; + padding: 1rem; + + &:focus { + box-shadow: none; + } + + .p-accordion-toggle-icon { + color: #0088cc; + } + } + + &.p-highlight .p-accordion-header-link { + background-color: #f8f9fa; + color: #495057; + border-color: #dee2e6; + } + } + + .p-accordion-content { + background-color: #ffffff; + border-color: #dee2e6; + padding: 1rem; + } + } + + .mb-4 { + margin-bottom: 1rem; + } \ No newline at end of file diff --git a/src/app/pages/home/home.component.spec.ts b/src/app/pages/home/home.component.spec.ts new file mode 100644 index 0000000..1191557 --- /dev/null +++ b/src/app/pages/home/home.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HomeComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/pages/home/home.component.ts b/src/app/pages/home/home.component.ts new file mode 100644 index 0000000..ef3febf --- /dev/null +++ b/src/app/pages/home/home.component.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +// Importaciones de PrimeNG +import { CardModule } from 'primeng/card'; +import { AccordionModule } from 'primeng/accordion'; +@Component({ + selector: 'app-home', + imports: [ + CommonModule, + CardModule, + AccordionModule + ], + standalone: true, + templateUrl: './home.component.html', + styleUrl: './home.component.scss' +}) +export class HomeComponent { + + +} diff --git a/src/styles.scss b/src/styles.scss index 2811923..b6bea4b 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,69 +1,44 @@ :root { - --primary-color: #0088cc; // Color principal azul SISS - --secondary-color: #0a2847; // Color azul oscuro - --light-blue: #d3e9f7; // Color para el header - --danger-color: #dc3545; // Color rojo para los indicadores en inputs - --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + --primary-color: #0088cc; /* Azul principal SISS */ + --primary-light: #bcdaef; /* Azul claro para fondos */ + --text-color: #0a2847; /* Color texto principal */ + --secondary-text: #6c757d; /* Texto secundario */ + --border-color: #dee2e6; /* Color bordes */ + --background-color: #f8f9fa; /* Fondo gris claro */ } - // Estilos generales + /* Estilos globales */ html, body { margin: 0; padding: 0; height: 100%; - font-family: var(--font-family); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-size: 14px; + color: var(--text-color); } body { - background-color: #f0f0f0; + background-color: var(--background-color); } - // Estilos específicos para inputs - .p-inputtext { - padding: 0.75rem 0.75rem; - font-size: 1rem; + /* Clases de utilidad */ + .mb-1 { margin-bottom: 0.25rem !important; } + .mb-2 { margin-bottom: 0.5rem !important; } + .mb-3 { margin-bottom: 1rem !important; } + .mb-4 { margin-bottom: 1.5rem !important; } + .mt-1 { margin-top: 0.25rem !important; } + .mt-2 { margin-top: 0.5rem !important; } + .mt-3 { margin-top: 1rem !important; } + .mt-4 { margin-top: 1.5rem !important; } + + /* Personalizaciones globales de PrimeNG */ + .p-component { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } - // Sobreescritura de estilos de PrimeNG - .p-button { - padding: 0.75rem 1.25rem; - border-radius: 4px; - - &.p-button-primary { - background-color: var(--primary-color); - border-color: var(--primary-color); - - &:hover { - background-color: darken(#0088cc, 10%); - border-color: darken(#0088cc, 10%); - } + .p-button.p-button-text { + &:focus { + box-shadow: none; } } - - // Clase para fondos rojos en los addons de input - .bg-red-600 { - background-color: var(--danger-color) !important; - border-color: var(--danger-color) !important; - color: white !important; - } - - // Sobreescribe el estilo de los iconos en los input groups - .p-inputgroup-addon { - .pi { - color: #6c757d; - } - } - - // Ajustes para espaciado consistente - .mb-3 { - margin-bottom: 1rem !important; - } - - .mb-4 { - margin-bottom: 1.5rem !important; - } - - // Ajustes para el ancho completo - .w-full { - width: 100% !important; - } \ No newline at end of file + \ No newline at end of file