This commit is contained in:
2025-08-06 01:20:52 +02:00
parent a21513943f
commit dc68641cfe
7 changed files with 404 additions and 13 deletions

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 12H21M3 6H21M3 18H21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 225 B

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.9536 14.9458L21 21M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 457 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 21L16.514 16.506L21 21ZM19 10.5C19 15.194 15.194 19 10.5 19C5.806 19 2 15.194 2 10.5C2 5.806 5.806 2 10.5 2C15.194 2 19 5.806 19 10.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 340 B

View File

@@ -1 +1,86 @@
<gallery></gallery>
<header class="main-header">
<div class="header-container">
<!-- Logo/Marca -->
<div class="logo">
<h1>{{ brandName }}</h1>
</div>
<!-- Buscador -->
<div class="search-container">
<div class="search-box">
<input
type="text"
placeholder="Buscar fotos..."
[(ngModel)]="searchQuery"
(input)="onSearch($event)"
class="search-input"
/>
<app-button
label="Search"
icon="assets/icons/search-alt-1-svgrepo-com.svg"
class="search-button"
(click)="performSearch()"
tooltip="Buscar"
></app-button>
</div>
</div>
<!-- Iconos de navegación -->
<div class="nav-icons">
<!-- Icono de perfil -->
<app-button
label="Profile"
icon="assets/icons/user-svgrepo-com.svg"
class="profile-button"
(click)="openProfile()"
tooltip="Mi perfil"
></app-button>
<!-- Menú hamburguesa -->
<app-button
label="Menu"
icon="assets/icons/menu-svgrepo-com.svg"
class="menu-button"
(click)="toggleMenu()"
tooltip="Menú"
[class.active]="isMenuOpen"
></app-button>
</div>
</div>
<!-- Menú desplegable -->
@if(isMenuOpen) {
<div class="dropdown-menu" (click)="$event.stopPropagation()">
<nav class="menu-nav">
<a href="#" class="menu-item" (click)="navigateTo('gallery')">
<svg-loader
src="assets/icons/browsers-svgrepo-com.svg"
></svg-loader>
Galería
</a>
<a href="#" class="menu-item" (click)="navigateTo('about')">
<svg-loader
src="assets/icons/bubble-square-svgrepo-com.svg"
></svg-loader>
Acerca de
</a>
<a href="#" class="menu-item" (click)="navigateTo('contact')">
<svg-loader
src="assets/icons/bell-svgrepo-com.svg"
></svg-loader>
Contacto
</a>
<a href="#" class="menu-item" (click)="navigateTo('services')">
<svg-loader
src="assets/icons/cart-shopping-fast-svgrepo-com.svg"
></svg-loader>
Servicios
</a>
</nav>
</div>
}
</header>
<main class="main-content">
<gallery></gallery>
</main>

View File

@@ -0,0 +1,207 @@
@use "../styles.scss" as *;
@use "variables";
@use "gallery/gallery";
.main-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
background: rgba(variables.$primary-white, 0.95);
-webkit-backdrop-filter: blur(20px);
backdrop-filter: blur(20px);
border-bottom: 1px solid variables.$border-grey;
box-shadow: 0 2px 20px rgba(42, 41, 38, 0.1);
.header-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 2rem;
max-width: 1400px;
margin: 0 auto;
gap: 2rem;
.logo {
flex-shrink: 0;
h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 700;
color: variables.$text-dark;
letter-spacing: 0.5px;
text-transform: uppercase;
}
}
.search-container {
flex: 1;
max-width: 600px;
margin: 0 2rem;
.search-box {
position: relative;
display: flex;
align-items: center;
background: variables.$primary-white;
border: 2px solid variables.$border-grey;
border-radius: 12px;
overflow: hidden;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
&:focus-within {
border-color: variables.$edit-color;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
.search-input {
flex: 1;
padding: 0.75rem 1rem;
border: none;
background: transparent;
font-size: 1rem;
color: variables.$text-dark;
outline: none;
&::placeholder {
color: variables.$text-muted;
}
}
}
}
.nav-icons {
display: flex;
align-items: center;
gap: 1.75rem;
flex-shrink: 0;
}
}
.dropdown-menu {
position: absolute;
top: 100%;
right: 2rem;
background: variables.$primary-white;
border: 1px solid variables.$border-grey;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(42, 41, 38, 0.15);
min-width: 200px;
overflow: hidden;
animation: slideDown 0.3s ease;
.menu-nav {
padding: 0.5rem 0;
.menu-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1.5rem;
color: variables.$text-dark;
text-decoration: none;
transition: background-color 0.2s ease;
font-weight: 500;
&:hover {
background: rgba(variables.$edit-color, 0.1);
color: variables.$edit-color;
}
svg-loader {
width: 20px;
height: 20px;
color: currentColor;
}
}
}
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.main-content {
margin-top: calc(
80px + (gallery.$gap-size * 2)
); // Space for fixed header + 2rem
min-height: calc(100vh - 80px);
}
// Responsive design
@media (max-width: 768px) {
.main-header {
.header-container {
padding: 1rem;
gap: 1rem;
.logo h1 {
font-size: 1.2rem;
}
.search-container {
margin: 0;
max-width: none;
flex: 1;
.search-box .search-input {
padding: 0.15rem;
font-size: 0.9rem;
}
}
.nav-icons {
gap: 0.25rem;
}
}
.dropdown-menu {
right: 1rem;
left: 1rem;
min-width: auto;
}
}
.main-content {
margin-top: calc(70px + 2rem);
min-height: calc(100vh - 70px);
}
}
@media (max-width: 480px) {
.main-header {
.header-container {
flex-wrap: wrap;
gap: 0.5rem;
.logo {
order: 1;
}
.nav-icons {
order: 2;
}
.search-container {
order: 3;
width: 100%;
margin: 0;
}
}
}
.main-content {
margin-top: calc(120px + 2rem);
min-height: calc(100vh - 120px);
}
}

View File

@@ -1,19 +1,99 @@
import { Component } from '@angular/core';
import { Component, OnInit, HostListener } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { Title, Meta } from '@angular/platform-browser';
import { Gallery } from './gallery/gallery';
import { Button } from './button/button';
import { SvgLoader } from './svg/svg';
@Component({
selector: 'app-root',
imports: [ Gallery ],
templateUrl: './app.html',
styleUrl: './app.scss'
selector: 'app-root',
imports: [Gallery, Button, SvgLoader, FormsModule],
templateUrl: './app.html',
styleUrl: './app.scss',
})
export class App {
protected title = 'mmorales.photo';
protected description = 'Portfolio of Manuel Morales, a photographer based in La Vila Joiosa, Alicante, Spain.';
protected keywords = 'photography, portfolio, Manuel Morales, La Vila Joiosa, Alicante, Spain';
protected author = 'Manuel Morales';
protected copyright = '© ' + new Date().getFullYear() + ' Manuel Morales. All rights reserved.';
export class App implements OnInit {
protected title = 'mmorales.photo';
protected description =
'Portfolio of Manuel Morales, a photographer based in La Vila Joiosa, Alicante, Spain.';
protected keywords =
'photography, portfolio, Manuel Morales, La Vila Joiosa, Alicante, Spain';
protected author = 'Manuel Morales';
protected copyright =
'© ' +
new Date().getFullYear() +
' Manuel Morales. All rights reserved.';
protected gallery: Gallery = new Gallery();
// Header properties
protected brandName = 'MMORALES PHOTO';
protected searchQuery = '';
protected isMenuOpen = false;
constructor(private titleService: Title, private metaService: Meta) {}
ngOnInit(): void {
// Set page meta information
this.titleService.setTitle(this.title);
this.metaService.updateTag({
name: 'description',
content: this.description,
});
this.metaService.updateTag({
name: 'keywords',
content: this.keywords,
});
this.metaService.updateTag({ name: 'author', content: this.author });
this.metaService.updateTag({
name: 'copyright',
content: this.copyright,
});
}
// Search functionality
onSearch(event: Event): void {
const target = event.target as HTMLInputElement;
this.searchQuery = target.value;
// TODO: Implement real-time search filtering
console.log('Searching for:', this.searchQuery);
}
performSearch(): void {
if (this.searchQuery.trim()) {
// TODO: Implement search logic
console.log('Performing search for:', this.searchQuery);
}
}
// Navigation functionality
openProfile(): void {
// TODO: Implement profile functionality
console.log('Opening profile...');
}
toggleMenu(): void {
this.isMenuOpen = !this.isMenuOpen;
}
navigateTo(section: string): void {
this.isMenuOpen = false; // Close menu after navigation
// TODO: Implement navigation logic
console.log('Navigating to:', section);
}
// Close menu when clicking outside
@HostListener('document:click', ['$event'])
onDocumentClick(event: Event): void {
const target = event.target as HTMLElement;
if (!target.closest('.main-header')) {
this.isMenuOpen = false;
}
}
// Close menu on escape key
@HostListener('document:keydown', ['$event'])
onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Escape' && this.isMenuOpen) {
this.isMenuOpen = false;
}
}
}

View File

@@ -118,4 +118,13 @@ button {
fill: variables.$buy-color;
}
}
&.search-button {
border: none;
&:hover {
color: variables.$edit-color;
transform: none;
box-shadow: none;
}
}
}