front y back minimos
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
*.db
|
*.db
|
||||||
|
back/data/
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
##
|
##
|
||||||
|
13
back/.config/dotnet-tools.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "9.0.8",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
back/Constants.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public const string Data = "data";
|
||||||
|
}
|
12
back/DTO/PhotoFormModel.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace back.DTO;
|
||||||
|
|
||||||
|
public class PhotoFormModel
|
||||||
|
{
|
||||||
|
public required string Title { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? Tags { get; set; }
|
||||||
|
public string? People { get; set; }
|
||||||
|
public IFormFile? Image { get; set; }
|
||||||
|
public string? Ubicacion { get; set; }
|
||||||
|
public string? Evento { get; set; }
|
||||||
|
}
|
@@ -9,13 +9,22 @@ public class Program
|
|||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
Directory.CreateDirectory(Constants.Data);
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddDbContext<PhotoContext>(options =>options.UseSqlite("Data Source=photos.db"));
|
builder.Services.AddDbContext<PhotoContext>(options => options.UseSqlite($"Data Source={Constants.Data}/photos.db"));
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAll",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader());
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
@@ -29,6 +38,7 @@ public class Program
|
|||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseCors("AllowAll");
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
|
@@ -1,24 +1,14 @@
|
|||||||
using back.ApiService.context;
|
using back.ApiService.context;
|
||||||
using back.ApiService.models;
|
using back.ApiService.models;
|
||||||
|
using back.DTO;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace back.controllers;
|
namespace back.controllers;
|
||||||
|
|
||||||
public class PhotoFormModel
|
|
||||||
{
|
|
||||||
public required string Title { get; set; }
|
|
||||||
public string? Description { get; set; }
|
|
||||||
public string? Tags { get; set; }
|
|
||||||
public string? People { get; set; }
|
|
||||||
public IFormFile? Image { get; set; }
|
|
||||||
public string? Ubicacion { get; set; }
|
|
||||||
public string? Evento { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class PhotoController(PhotoContext photoContext) : ControllerBase
|
public class PhotosController(PhotoContext photoContext) : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly PhotoContext _photoContext = photoContext;
|
private readonly PhotoContext _photoContext = photoContext;
|
||||||
|
|
||||||
@@ -42,13 +32,28 @@ public class PhotoController(PhotoContext photoContext) : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GET api/<PhotoController>/5
|
// GET api/<PhotoController>/5
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}/{res}")]
|
||||||
public async Task<ActionResult<Photo>> Get(Guid id)
|
public async Task<IActionResult> Get(Guid id, string res = "low")
|
||||||
{
|
{
|
||||||
var photo = await _photoContext.Photos.FindAsync(id);
|
var photo = await _photoContext.Photos.FindAsync(id);
|
||||||
if (photo == null)
|
if (photo == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return photo;
|
|
||||||
|
string? filePath = res.ToLower() switch
|
||||||
|
{
|
||||||
|
"low" => photo.LowResUrl,
|
||||||
|
"mid" => photo.MidResUrl,
|
||||||
|
"high" => photo.HighResUrl,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (filePath == null || !System.IO.File.Exists(Path.Combine(Constants.Data, filePath)))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var fileBytes = await System.IO.File.ReadAllBytesAsync(Path.Combine(Constants.Data, filePath));
|
||||||
|
var contentType = "image/jpeg"; // Cambia si usas otro formato
|
||||||
|
|
||||||
|
return File(fileBytes, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST api/<PhotoController>
|
// POST api/<PhotoController>
|
@@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
@@ -10,29 +11,33 @@ public class PhotoBuilder
|
|||||||
public static Photo Build(string? title, string? description, List<string>? tags, List<string>? personsIn, IFormFile image)
|
public static Photo Build(string? title, string? description, List<string>? tags, List<string>? personsIn, IFormFile image)
|
||||||
{
|
{
|
||||||
// Genera un nombre de archivo único
|
// Genera un nombre de archivo único
|
||||||
var fileName = $"{Guid.NewGuid()}{Path.GetExtension(image.FileName)}";
|
var id = Guid.NewGuid();
|
||||||
var photo = new Photo(title, description, tags, personsIn, fileName);
|
var fileName = $"{id}{Path.GetExtension(image.FileName)}";
|
||||||
|
var photo = new Photo(title, description, tags, personsIn, fileName)
|
||||||
|
{
|
||||||
|
Id = id
|
||||||
|
};
|
||||||
|
|
||||||
// Asegura que los directorios existen
|
// Asegura que los directorios existen
|
||||||
Directory.CreateDirectory(Photo.LowResFolder);
|
Directory.CreateDirectory(Path.Join(Constants.Data, Photo.LowResFolder));
|
||||||
Directory.CreateDirectory(Photo.MidResFolder);
|
Directory.CreateDirectory(Path.Join(Constants.Data, Photo.MidResFolder));
|
||||||
Directory.CreateDirectory(Photo.HighResFolder);
|
Directory.CreateDirectory(Path.Join(Constants.Data, Photo.HighResFolder));
|
||||||
|
|
||||||
// Procesa y guarda las imágenes
|
// Procesa y guarda las imágenes
|
||||||
using var stream = image.OpenReadStream();
|
using var stream = image.OpenReadStream();
|
||||||
using var img = Image.Load(stream);
|
using var img = Image.Load(stream);
|
||||||
// Baja resolución (480px)
|
// Baja resolución (480px)
|
||||||
img.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(480, 0), Mode = ResizeMode.Max }));
|
img.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(480, 0), Mode = ResizeMode.Max }));
|
||||||
img.Save(photo.LowResUrl);
|
img.Save(Path.Join(Constants.Data, photo.LowResUrl));
|
||||||
|
|
||||||
// Media resolución (720px)
|
// Media resolución (720px)
|
||||||
img.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(720, 0), Mode = ResizeMode.Max }));
|
img.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(720, 0), Mode = ResizeMode.Max }));
|
||||||
img.Save(photo.MidResUrl);
|
img.Save(Path.Join(Constants.Data, photo.MidResUrl));
|
||||||
|
|
||||||
// Original
|
// Original
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
using var original = Image.Load(stream);
|
using var original = Image.Load(stream);
|
||||||
original.Save(photo.HighResUrl);
|
original.Save(Path.Join(Constants.Data, photo.HighResUrl));
|
||||||
|
|
||||||
return photo;
|
return photo;
|
||||||
}
|
}
|
||||||
@@ -45,7 +50,7 @@ public class Photo
|
|||||||
public const string MidResFolder = "imgs/mid";
|
public const string MidResFolder = "imgs/mid";
|
||||||
public const string HighResFolder = "imgs/high";
|
public const string HighResFolder = "imgs/high";
|
||||||
|
|
||||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[Key]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
BIN
back/photos.db-shm
Normal file
0
back/photos.db-wal
Normal file
3
front/public/assets/config.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"bff": "https://localhost:7273"
|
||||||
|
}
|
Before Width: | Height: | Size: 6.7 MiB |
Before Width: | Height: | Size: 3.6 MiB |
Before Width: | Height: | Size: 10 MiB |
Before Width: | Height: | Size: 16 MiB |
Before Width: | Height: | Size: 12 MiB |
Before Width: | Height: | Size: 8.7 MiB |
Before Width: | Height: | Size: 7.9 MiB |
Before Width: | Height: | Size: 6.6 MiB |
Before Width: | Height: | Size: 5.3 MiB |
Before Width: | Height: | Size: 5.5 MiB |
Before Width: | Height: | Size: 18 MiB |
Before Width: | Height: | Size: 7.1 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 16 MiB |
Before Width: | Height: | Size: 16 MiB |
Before Width: | Height: | Size: 19 MiB |
Before Width: | Height: | Size: 9.4 MiB |
Before Width: | Height: | Size: 5.8 MiB |
Before Width: | Height: | Size: 21 MiB |
Before Width: | Height: | Size: 8.6 MiB |
Before Width: | Height: | Size: 16 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 11 MiB |
Before Width: | Height: | Size: 13 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 6.1 MiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 16 MiB |
Before Width: | Height: | Size: 3.5 MiB |
Before Width: | Height: | Size: 18 MiB |
Before Width: | Height: | Size: 6.7 MiB |
@@ -1,7 +1,7 @@
|
|||||||
<header class="main-header">
|
<header class="main-header">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<!-- Logo/Marca -->
|
<!-- Logo/Marca -->
|
||||||
<div class="logo">
|
<div class="logo" (click)="navigateTo('home')" style="cursor:pointer;">
|
||||||
<h1>{{ brandName }}</h1>
|
<h1>{{ brandName }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -8,11 +8,11 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
background: rgba(variables.$primary-white, 0.95);
|
background: variables.$primary-white;
|
||||||
-webkit-backdrop-filter: blur(20px);
|
-webkit-backdrop-filter: blur(20px);
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
border-bottom: 1px solid variables.$border-grey;
|
border-bottom: 2px solid variables.$border-grey;
|
||||||
box-shadow: 0 4px 20px rgba(42, 41, 38, 0.1);
|
box-shadow: 0 6px 10px rgba(42, 41, 38, 0.15);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.header-container {
|
.header-container {
|
||||||
@@ -133,11 +133,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
// margin-top: 0;
|
|
||||||
// margin-top: calc(
|
|
||||||
// 80px + (gallery.$gap-size * 2)
|
|
||||||
// ); // Space for fixed header + 2rem
|
|
||||||
min-height: calc(100vh - 80px);
|
min-height: calc(100vh - 80px);
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden; /* Sin scroll horizontal */
|
||||||
|
overflow-y: scroll; /* Permite scroll vertical */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Responsive design
|
// Responsive design
|
||||||
@@ -175,8 +176,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
margin-top: calc(70px + 2rem);
|
margin-top: 0;
|
||||||
|
padding: 0;
|
||||||
min-height: calc(100vh - 70px);
|
min-height: calc(100vh - 70px);
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,5 +209,7 @@
|
|||||||
.main-content {
|
.main-content {
|
||||||
margin-top: calc(120px + 2rem);
|
margin-top: calc(120px + 2rem);
|
||||||
min-height: calc(100vh - 120px);
|
min-height: calc(100vh - 120px);
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import { Gallery } from './gallery/gallery';
|
|||||||
import { Button } from './button/button';
|
import { Button } from './button/button';
|
||||||
import { SvgLoader } from './svg/svg';
|
import { SvgLoader } from './svg/svg';
|
||||||
import { UploadImageForm } from './upload-image-form/upload-image-form';
|
import { UploadImageForm } from './upload-image-form/upload-image-form';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@@ -29,7 +30,11 @@ export class App implements OnInit {
|
|||||||
protected searchQuery = '';
|
protected searchQuery = '';
|
||||||
protected isMenuOpen = false;
|
protected isMenuOpen = false;
|
||||||
|
|
||||||
constructor(private titleService: Title, private metaService: Meta) {}
|
constructor(
|
||||||
|
private titleService: Title,
|
||||||
|
private metaService: Meta,
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Set page meta information
|
// Set page meta information
|
||||||
@@ -85,8 +90,10 @@ export class App implements OnInit {
|
|||||||
|
|
||||||
navigateTo(section: string): void {
|
navigateTo(section: string): void {
|
||||||
this.isMenuOpen = false; // Close menu after navigation
|
this.isMenuOpen = false; // Close menu after navigation
|
||||||
// TODO: Implement navigation logic
|
this.showUploadForm = false;
|
||||||
console.log('Navigating to:', section);
|
if (section === 'home') {
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close menu when clicking outside
|
// Close menu when clicking outside
|
||||||
|
@@ -5,8 +5,10 @@ $gap-size: 20px;
|
|||||||
column-gap: $gap-size;
|
column-gap: $gap-size;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin-top: 3%;
|
margin-top: 3%;
|
||||||
min-height: 100vh;
|
min-height: 100lvh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile - 1 column */
|
/* Mobile - 1 column */
|
||||||
@@ -39,7 +41,9 @@ $gap-size: 20px;
|
|||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
.low-res-image-list {
|
.low-res-image-list {
|
||||||
columns: 4;
|
columns: 4;
|
||||||
margin-left: 17lvw;
|
margin-left: 17svw;
|
||||||
margin-right: 17lvw;
|
margin-right: 17svw;
|
||||||
|
max-width: calc(100vw - 34svw);
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,15 +2,16 @@ import { Component, computed } from '@angular/core';
|
|||||||
import { LowResImage } from '../low-res-image/low-res-image';
|
import { LowResImage } from '../low-res-image/low-res-image';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { MidResImage } from '../mid-res-image/mid-res-image';
|
import { MidResImage } from '../mid-res-image/mid-res-image';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gallery',
|
selector: 'gallery',
|
||||||
imports: [LowResImage, MidResImage],
|
imports: [LowResImage, MidResImage],
|
||||||
templateUrl: './gallery.html',
|
templateUrl: './gallery.html',
|
||||||
styleUrl: './gallery.scss'
|
styleUrl: './gallery.scss',
|
||||||
})
|
})
|
||||||
export class Gallery {
|
export class Gallery {
|
||||||
protected images : LowResImage[] = [];
|
protected images: LowResImage[] = [];
|
||||||
thereIsFullscreenImage: boolean = false;
|
thereIsFullscreenImage: boolean = false;
|
||||||
midResImage: MidResImage | null = null;
|
midResImage: MidResImage | null = null;
|
||||||
isAnimatingToFullscreen: boolean = false;
|
isAnimatingToFullscreen: boolean = false;
|
||||||
@@ -35,7 +36,10 @@ export class Gallery {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickedImageWithEvent(data: {midResImage: MidResImage, event: MouseEvent}): void {
|
onClickedImageWithEvent(data: {
|
||||||
|
midResImage: MidResImage;
|
||||||
|
event: MouseEvent;
|
||||||
|
}): void {
|
||||||
this.onClickedImage(data.midResImage, data.event);
|
this.onClickedImage(data.midResImage, data.event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,13 +50,13 @@ export class Gallery {
|
|||||||
x: rect.left + rect.width / 2,
|
x: rect.left + rect.width / 2,
|
||||||
y: rect.top + rect.height / 2,
|
y: rect.top + rect.height / 2,
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height
|
height: rect.height,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Guardar información de transición en el document para uso del mid-res-image
|
// Guardar información de transición en el document para uso del mid-res-image
|
||||||
(document as any).__imageTransition = {
|
(document as any).__imageTransition = {
|
||||||
...initialPosition,
|
...initialPosition,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,17 +68,37 @@ export class Gallery {
|
|||||||
public loadImages(): void {
|
public loadImages(): void {
|
||||||
// when backend is online ask for photos // return this.http.get<string[]>('/api/images');
|
// when backend is online ask for photos // return this.http.get<string[]>('/api/images');
|
||||||
// meanwhile, load examples from assets/fotosPrueba
|
// meanwhile, load examples from assets/fotosPrueba
|
||||||
this.images = this.getImages();
|
this.getImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getImages(): LowResImage[] {
|
private getImages(): void {
|
||||||
var exampleImages : LowResImage[] = []
|
// hacer un get /api/photos para coger la primera página de fotos
|
||||||
for (let i = 1; i <= 33; i++) {
|
axios.get('/photos').then((response) => {
|
||||||
const img = new LowResImage();
|
const photos = response.data;
|
||||||
img.src = `assets/fotosPrueba/${i}.jpg`;
|
this.images = photos.map((photo: PhotoDTO) => {
|
||||||
img.alt = `Image ${i}`;
|
let p = new LowResImage();
|
||||||
exampleImages.push(img);
|
p.id = photo.id;
|
||||||
}
|
p.src = axios.defaults.baseURL + '/photos/' + photo.id + '/low';
|
||||||
return exampleImages;
|
p.alt = photo.description;
|
||||||
|
return p;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PhotoDTO {
|
||||||
|
public id: string = '';
|
||||||
|
public src: string = '';
|
||||||
|
public alt: string = '';
|
||||||
|
public description: string = '';
|
||||||
|
public title: string = '';
|
||||||
|
public tags: string = '';
|
||||||
|
public people: string = '';
|
||||||
|
public createdAt: Date | null = null;
|
||||||
|
public updatedAt: Date | null = null;
|
||||||
|
public createdBy: Date | null = null;
|
||||||
|
public updatedBy: Date | null = null;
|
||||||
|
public evento: string | null = null;
|
||||||
|
public ubicacion: string | null = null;
|
||||||
|
public ranking: number | null = null;
|
||||||
|
}
|
||||||
|
@@ -5,20 +5,23 @@ import { MidResImage } from '../mid-res-image/mid-res-image';
|
|||||||
selector: 'low-res-image',
|
selector: 'low-res-image',
|
||||||
imports: [],
|
imports: [],
|
||||||
templateUrl: './low-res-image.html',
|
templateUrl: './low-res-image.html',
|
||||||
styleUrl: './low-res-image.scss'
|
styleUrl: './low-res-image.scss',
|
||||||
})
|
})
|
||||||
export class LowResImage {
|
export class LowResImage {
|
||||||
@Input({ required: true }) src: string = '';
|
@Input({ required: true }) src: string = '';
|
||||||
@Input({ required: true }) alt: string = '';
|
@Input({ required: true }) alt: string = '';
|
||||||
public id : string = 'low-res-image-' + Math.random().toString(36).substring(2, 15);
|
public id: string | null = null;
|
||||||
|
|
||||||
@Output() clicked = new EventEmitter<{midResImage: MidResImage, event: MouseEvent}>();
|
@Output() clicked = new EventEmitter<{
|
||||||
|
midResImage: MidResImage;
|
||||||
|
event: MouseEvent;
|
||||||
|
}>();
|
||||||
|
|
||||||
openFullscreen(event: MouseEvent): void {
|
openFullscreen(event: MouseEvent): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const midResImage = new MidResImage();
|
const midResImage = new MidResImage();
|
||||||
midResImage.src = this.src.replace('low', 'mid');
|
midResImage.src = this.src.replace('low', 'mid');
|
||||||
midResImage.alt = this.alt;
|
midResImage.alt = this.alt;
|
||||||
this.clicked.emit({midResImage, event});
|
this.clicked.emit({ midResImage, event });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,18 +31,12 @@ export class UploadImageForm {
|
|||||||
// Here you would typically send the formData to your backend API
|
// Here you would typically send the formData to your backend API
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.post('https://localhost:7273/api/photo', formData, {
|
.post('/photos', formData, {
|
||||||
headers: {},
|
headers: {},
|
||||||
validateStatus: (status) => status == 201,
|
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(() => {
|
||||||
console.log('Upload successful:', response.data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Upload failed:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.close.emit();
|
this.close.emit();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import { bootstrapApplication } from '@angular/platform-browser';
|
import { bootstrapApplication } from '@angular/platform-browser';
|
||||||
import { appConfig } from './app/app.config';
|
import { appConfig } from './app/app.config';
|
||||||
import { App } from './app/app';
|
import { App } from './app/app';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
bootstrapApplication(App, appConfig)
|
fetch('/assets/config.json')
|
||||||
.catch((err) => console.error(err));
|
.then((response) => response.json())
|
||||||
|
.then((config) => {
|
||||||
|
axios.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
|
||||||
|
axios.defaults.baseURL = config.bff + '/api'; // Configurar base URL del BFF desde el archivo de configuración
|
||||||
|
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
|
||||||
|
});
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -6,5 +11,29 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow-x: hidden; /* Elimina scroll horizontal */
|
overflow-x: hidden; /* Elimina scroll horizontal */
|
||||||
|
overflow-y: scroll; /* Permite scroll vertical */
|
||||||
|
scroll-behavior: smooth;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
// /* Estilos personalizados para la barra de scroll */
|
||||||
|
// ::-webkit-scrollbar-track {
|
||||||
|
// background: #f1f1f1;
|
||||||
|
// border-radius: 4px;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ::-webkit-scrollbar-thumb {
|
||||||
|
// background: #c1c1c1;
|
||||||
|
// border-radius: 4px;
|
||||||
|
// transition: background 0.3s ease;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ::-webkit-scrollbar-thumb:hover {
|
||||||
|
// background: #a8a8a8;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* Para Firefox */
|
||||||
|
// body {
|
||||||
|
// scrollbar-width: thin;
|
||||||
|
// scrollbar-color: #c1c1c1 #f1f1f1;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|