This commit is contained in:
2025-08-09 03:38:22 +02:00
parent b677b5f711
commit 679427a6f9
280 changed files with 12578 additions and 47 deletions

17
front/v2/.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false
[*.md]
max_line_length = off
trim_trailing_whitespace = false

42
front/v2/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

4
front/v2/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

20
front/v2/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,20 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
}
]
}

42
front/v2/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,42 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

59
front/v2/README.md Normal file
View File

@@ -0,0 +1,59 @@
# V2
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.0.2.
## Development server
To start a local development server, run:
```bash
ng serve
```
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
## Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
```bash
ng generate component component-name
```
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
```bash
ng generate --help
```
## Building
To build the project run:
```bash
ng build
```
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
## Running unit tests
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
```bash
ng test
```
## Running end-to-end tests
For end-to-end (e2e) testing, run:
```bash
ng e2e
```
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
## Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

92
front/v2/angular.json Normal file
View File

@@ -0,0 +1,92 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"v2": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"],
"stylePreprocessorOptions": {
"includePaths": ["src/app"]
}
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "v2:build:production"
},
"development": {
"buildTarget": "v2:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular/build:karma",
"options": {
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": ["src/styles.scss"]
}
}
}
}
}
}

9733
front/v2/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
front/v2/package.json Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "v2",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/cdk": "^20.1.5",
"@angular/common": "^20.0.0",
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@angular/material": "^20.1.5",
"@angular/platform-browser": "^20.0.0",
"@angular/router": "^20.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"uuid": "^11.1.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular/build": "^20.0.2",
"@angular/cli": "^20.0.2",
"@angular/compiler-cli": "^20.0.0",
"@types/jasmine": "~5.1.0",
"axios": "^1.11.0",
"jasmine-core": "~5.7.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.8.2"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,12 @@
const fs = require('fs');
const path = require('path');
const iconsDir = __dirname;
fs.readdirSync(iconsDir).forEach(file => {
if (file.endsWith('.svg')) {
const filePath = path.join(iconsDir, file);
let content = fs.readFileSync(filePath, 'utf8');
content = content.replace(/stroke="#[0-9a-fA-F]{3,6}"/g, 'stroke="currentColor"');
fs.writeFileSync(filePath, content, 'utf8');
}
});

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="M5 19V6.2C5 5.0799 5 4.51984 5.21799 4.09202C5.40973 3.71569 5.71569 3.40973 6.09202 3.21799C6.51984 3 7.0799 3 8.2 3H15.8C16.9201 3 17.4802 3 17.908 3.21799C18.2843 3.40973 18.5903 3.71569 18.782 4.09202C19 4.51984 19 5.0799 19 6.2V17H7C5.89543 17 5 17.8954 5 19ZM5 19C5 20.1046 5.89543 21 7 21H19M18 17V21M14.5 8V7.91667C14.5 6.85812 13.6419 6 12.5833 6H11.5C10.3954 6 9.5 6.89543 9.5 8C9.5 9.10457 10.3954 10 11.5 10H12.5C13.6046 10 14.5 10.8954 14.5 12C14.5 13.1046 13.6046 14 12.5 14H11.4583C10.3768 14 9.5 13.1232 9.5 12.0417V12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 860 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="M3 9H21M7 3V5M17 3V5M6 12H10V16H6V12ZM6.2 21H17.8C18.9201 21 19.4802 21 19.908 20.782C20.2843 20.5903 20.5903 20.2843 20.782 19.908C21 19.4802 21 18.9201 21 17.8V8.2C21 7.07989 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.07989 21 6.2 21Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 832 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="M13 11L21 3M13 11L17.5 11M13 11V6.5M3 21L11 13M11 13H6.5M11 13V17.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 393 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="M3 21.0001L14 21V5.98924C14 4.6252 14 3.94318 13.7187 3.47045C13.472 3.05596 13.0838 2.74457 12.6257 2.59368C12.1032 2.42159 11.4374 2.56954 10.1058 2.86544L7.50582 3.44322C6.6117 3.64191 6.16464 3.74126 5.83093 3.98167C5.53658 4.19373 5.30545 4.48186 5.1623 4.8152C5 5.19312 5 5.65108 5 6.56702V21.0001M13.994 5.00007H15.8C16.9201 5.00007 17.4802 5.00007 17.908 5.21805C18.2843 5.4098 18.5903 5.71576 18.782 6.09209C19 6.51991 19 7.07996 19 8.20007V21.0001H21M11 12.0001H11.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 803 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 8V5M11 5H17M6 12H3M3 9V15M21 11V19M9 12H9.01M12 12H12.01M15 12H15.01M6 8V16H8L10 19H18V10L16 8H6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 427 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="M13 13L16 8M8 8H8.01M12 6H12.01M18 12H18.01M6 12H6.01M14 15C14 16.1046 13.1046 17 12 17C10.8954 17 10 16.1046 10 15C10 13.8954 10.8954 13 12 13C13.1046 13 14 13.8954 14 15ZM21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 611 B

View File

@@ -0,0 +1,5 @@
<?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="M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.9046 3.06005C12.6988 3 12.4659 3 12 3C11.5341 3 11.3012 3 11.0954 3.06005C10.7942 3.14794 10.5281 3.32808 10.3346 3.57511C10.2024 3.74388 10.1159 3.96016 9.94291 4.39272C9.69419 5.01452 9.00393 5.33471 8.36857 5.123L7.79779 4.93281C7.3929 4.79785 7.19045 4.73036 6.99196 4.7188C6.70039 4.70181 6.4102 4.77032 6.15701 4.9159C5.98465 5.01501 5.83376 5.16591 5.53197 5.4677C5.21122 5.78845 5.05084 5.94882 4.94896 6.13189C4.79927 6.40084 4.73595 6.70934 4.76759 7.01551C4.78912 7.2239 4.87335 7.43449 5.04182 7.85566C5.30565 8.51523 5.05184 9.26878 4.44272 9.63433L4.16521 9.80087C3.74031 10.0558 3.52786 10.1833 3.37354 10.3588C3.23698 10.5141 3.13401 10.696 3.07109 10.893C3 11.1156 3 11.3658 3 11.8663C3 12.4589 3 12.7551 3.09462 13.0088C3.17823 13.2329 3.31422 13.4337 3.49124 13.5946C3.69158 13.7766 3.96395 13.8856 4.50866 14.1035C5.06534 14.3261 5.35196 14.9441 5.16236 15.5129L4.94721 16.1584C4.79819 16.6054 4.72367 16.829 4.7169 17.0486C4.70875 17.3127 4.77049 17.5742 4.89587 17.8067C5.00015 18.0002 5.16678 18.1668 5.5 18.5C5.83323 18.8332 5.99985 18.9998 6.19325 19.1041C6.4258 19.2295 6.68733 19.2913 6.9514 19.2831C7.17102 19.2763 7.39456 19.2018 7.84164 19.0528L8.36862 18.8771C9.00393 18.6654 9.6942 18.9855 9.94291 19.6073C10.1159 20.0398 10.2024 20.2561 10.3346 20.4249C10.5281 20.6719 10.7942 20.8521 11.0954 20.94C11.3012 21 11.5341 21 12 21C12.4659 21 12.6988 21 12.9046 20.94C13.2058 20.8521 13.4719 20.6719 13.6654 20.4249C13.7976 20.2561 13.8841 20.0398 14.0571 19.6073C14.3058 18.9855 14.9961 18.6654 15.6313 18.8773L16.1579 19.0529C16.605 19.2019 16.8286 19.2764 17.0482 19.2832C17.3123 19.2913 17.5738 19.2296 17.8063 19.1042C17.9997 18.9999 18.1664 18.8333 18.4996 18.5001C18.8328 18.1669 18.9994 18.0002 19.1037 17.8068C19.2291 17.5743 19.2908 17.3127 19.2827 17.0487C19.2759 16.8291 19.2014 16.6055 19.0524 16.1584L18.8374 15.5134C18.6477 14.9444 18.9344 14.3262 19.4913 14.1035C20.036 13.8856 20.3084 13.7766 20.5088 13.5946C20.6858 13.4337 20.8218 13.2329 20.9054 13.0088C21 12.7551 21 12.4589 21 11.8663C21 11.3658 21 11.1156 20.9289 10.893C20.866 10.696 20.763 10.5141 20.6265 10.3588C20.4721 10.1833 20.2597 10.0558 19.8348 9.80087L19.5569 9.63416C18.9478 9.26867 18.6939 8.51514 18.9578 7.85558C19.1262 7.43443 19.2105 7.22383 19.232 7.01543C19.2636 6.70926 19.2003 6.40077 19.0506 6.13181C18.9487 5.94875 18.7884 5.78837 18.4676 5.46762C18.1658 5.16584 18.0149 5.01494 17.8426 4.91583C17.5894 4.77024 17.2992 4.70174 17.0076 4.71872C16.8091 4.73029 16.6067 4.79777 16.2018 4.93273L15.6314 5.12287C14.9961 5.33464 14.3058 5.0145 14.0571 4.39272C13.8841 3.96016 13.7976 3.74388 13.6654 3.57511C13.4719 3.32808 13.2058 3.14794 12.9046 3.06005Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

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="M17 14V20M14 17H20M15.6 10H18.4C18.9601 10 19.2401 10 19.454 9.89101C19.6422 9.79513 19.7951 9.64215 19.891 9.45399C20 9.24008 20 8.96005 20 8.4V5.6C20 5.03995 20 4.75992 19.891 4.54601C19.7951 4.35785 19.6422 4.20487 19.454 4.10899C19.2401 4 18.9601 4 18.4 4H15.6C15.0399 4 14.7599 4 14.546 4.10899C14.3578 4.20487 14.2049 4.35785 14.109 4.54601C14 4.75992 14 5.03995 14 5.6V8.4C14 8.96005 14 9.24008 14.109 9.45399C14.2049 9.64215 14.3578 9.79513 14.546 9.89101C14.7599 10 15.0399 10 15.6 10ZM5.6 10H8.4C8.96005 10 9.24008 10 9.45399 9.89101C9.64215 9.79513 9.79513 9.64215 9.89101 9.45399C10 9.24008 10 8.96005 10 8.4V5.6C10 5.03995 10 4.75992 9.89101 4.54601C9.79513 4.35785 9.64215 4.20487 9.45399 4.10899C9.24008 4 8.96005 4 8.4 4H5.6C5.03995 4 4.75992 4 4.54601 4.10899C4.35785 4.20487 4.20487 4.35785 4.10899 4.54601C4 4.75992 4 5.03995 4 5.6V8.4C4 8.96005 4 9.24008 4.10899 9.45399C4.20487 9.64215 4.35785 9.79513 4.54601 9.89101C4.75992 10 5.03995 10 5.6 10ZM5.6 20H8.4C8.96005 20 9.24008 20 9.45399 19.891C9.64215 19.7951 9.79513 19.6422 9.89101 19.454C10 19.2401 10 18.9601 10 18.4V15.6C10 15.0399 10 14.7599 9.89101 14.546C9.79513 14.3578 9.64215 14.2049 9.45399 14.109C9.24008 14 8.96005 14 8.4 14H5.6C5.03995 14 4.75992 14 4.54601 14.109C4.35785 14.2049 4.20487 14.3578 4.10899 14.546C4 14.7599 4 15.0399 4 15.6V18.4C4 18.9601 4 19.2401 4.10899 19.454C4.20487 19.6422 4.35785 19.7951 4.54601 19.891C4.75992 20 5.03995 20 5.6 20Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

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="M20 20L18.2678 18.2678M18.2678 18.2678C18.7202 17.8154 19 17.1904 19 16.5C19 15.1193 17.8807 14 16.5 14C15.1193 14 14 15.1193 14 16.5C14 17.8807 15.1193 19 16.5 19C17.1904 19 17.8154 18.7202 18.2678 18.2678ZM15.6 10H18.4C18.9601 10 19.2401 10 19.454 9.89101C19.6422 9.79513 19.7951 9.64215 19.891 9.45399C20 9.24008 20 8.96005 20 8.4V5.6C20 5.03995 20 4.75992 19.891 4.54601C19.7951 4.35785 19.6422 4.20487 19.454 4.10899C19.2401 4 18.9601 4 18.4 4H15.6C15.0399 4 14.7599 4 14.546 4.10899C14.3578 4.20487 14.2049 4.35785 14.109 4.54601C14 4.75992 14 5.03995 14 5.6V8.4C14 8.96005 14 9.24008 14.109 9.45399C14.2049 9.64215 14.3578 9.79513 14.546 9.89101C14.7599 10 15.0399 10 15.6 10ZM5.6 10H8.4C8.96005 10 9.24008 10 9.45399 9.89101C9.64215 9.79513 9.79513 9.64215 9.89101 9.45399C10 9.24008 10 8.96005 10 8.4V5.6C10 5.03995 10 4.75992 9.89101 4.54601C9.79513 4.35785 9.64215 4.20487 9.45399 4.10899C9.24008 4 8.96005 4 8.4 4H5.6C5.03995 4 4.75992 4 4.54601 4.10899C4.35785 4.20487 4.20487 4.35785 4.10899 4.54601C4 4.75992 4 5.03995 4 5.6V8.4C4 8.96005 4 9.24008 4.10899 9.45399C4.20487 9.64215 4.35785 9.79513 4.54601 9.89101C4.75992 10 5.03995 10 5.6 10ZM5.6 20H8.4C8.96005 20 9.24008 20 9.45399 19.891C9.64215 19.7951 9.79513 19.6422 9.89101 19.454C10 19.2401 10 18.9601 10 18.4V15.6C10 15.0399 10 14.7599 9.89101 14.546C9.79513 14.3578 9.64215 14.2049 9.45399 14.109C9.24008 14 8.96005 14 8.4 14H5.6C5.03995 14 4.75992 14 4.54601 14.109C4.35785 14.2049 4.20487 14.3578 4.10899 14.546C4 14.7599 4 15.0399 4 15.6V18.4C4 18.9601 4 19.2401 4.10899 19.454C4.20487 19.6422 4.35785 19.7951 4.54601 19.891C4.75992 20 5.03995 20 5.6 20Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,7 @@
<?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="M4 5.6C4 5.03995 4 4.75992 4.10899 4.54601C4.20487 4.35785 4.35785 4.20487 4.54601 4.10899C4.75992 4 5.03995 4 5.6 4H8.4C8.96005 4 9.24008 4 9.45399 4.10899C9.64215 4.20487 9.79513 4.35785 9.89101 4.54601C10 4.75992 10 5.03995 10 5.6V10.4C10 10.9601 10 11.2401 9.89101 11.454C9.79513 11.6422 9.64215 11.7951 9.45399 11.891C9.24008 12 8.96005 12 8.4 12H5.6C5.03995 12 4.75992 12 4.54601 11.891C4.35785 11.7951 4.20487 11.6422 4.10899 11.454C4 11.2401 4 10.9601 4 10.4V5.6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 13.6C14 13.0399 14 12.7599 14.109 12.546C14.2049 12.3578 14.3578 12.2049 14.546 12.109C14.7599 12 15.0399 12 15.6 12H18.4C18.9601 12 19.2401 12 19.454 12.109C19.6422 12.2049 19.7951 12.3578 19.891 12.546C20 12.7599 20 13.0399 20 13.6V18.4C20 18.9601 20 19.2401 19.891 19.454C19.7951 19.6422 19.6422 19.7951 19.454 19.891C19.2401 20 18.9601 20 18.4 20H15.6C15.0399 20 14.7599 20 14.546 19.891C14.3578 19.7951 14.2049 19.6422 14.109 19.454C14 19.2401 14 18.9601 14 18.4V13.6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 17.6C4 17.0399 4 16.7599 4.10899 16.546C4.20487 16.3578 4.35785 16.2049 4.54601 16.109C4.75992 16 5.03995 16 5.6 16H8.4C8.96005 16 9.24008 16 9.45399 16.109C9.64215 16.2049 9.79513 16.3578 9.89101 16.546C10 16.7599 10 17.0399 10 17.6V18.4C10 18.9601 10 19.2401 9.89101 19.454C9.79513 19.6422 9.64215 19.7951 9.45399 19.891C9.24008 20 8.96005 20 8.4 20H5.6C5.03995 20 4.75992 20 4.54601 19.891C4.35785 19.7951 4.20487 19.6422 4.10899 19.454C4 19.2401 4 18.9601 4 18.4V17.6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 5.6C14 5.03995 14 4.75992 14.109 4.54601C14.2049 4.35785 14.3578 4.20487 14.546 4.10899C14.7599 4 15.0399 4 15.6 4H18.4C18.9601 4 19.2401 4 19.454 4.10899C19.6422 4.20487 19.7951 4.35785 19.891 4.54601C20 4.75992 20 5.03995 20 5.6V6.4C20 6.96005 20 7.24008 19.891 7.45399C19.7951 7.64215 19.6422 7.79513 19.454 7.89101C19.2401 8 18.9601 8 18.4 8H15.6C15.0399 8 14.7599 8 14.546 7.89101C14.3578 7.79513 14.2049 7.64215 14.109 7.45399C14 7.24008 14 6.96005 14 6.4V5.6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

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="M4 12L20 12M12 4L12 20M6.2 20H17.8C18.9201 20 19.4802 20 19.908 19.782C20.2843 19.5903 20.5903 19.2843 20.782 18.908C21 18.4802 21 17.9201 21 16.8V7.2C21 6.0799 21 5.51984 20.782 5.09202C20.5903 4.71569 20.2843 4.40973 19.908 4.21799C19.4802 4 18.9201 4 17.8 4H6.2C5.0799 4 4.51984 4 4.09202 4.21799C3.71569 4.40973 3.40973 4.71569 3.21799 5.09202C3 5.51984 3 6.07989 3 7.2V16.8C3 17.9201 3 18.4802 3.21799 18.908C3.40973 19.2843 3.71569 19.5903 4.09202 19.782C4.51984 20 5.07989 20 6.2 20Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 816 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="M7.0498 7.0498H7.0598M10.5118 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V10.5118C3 11.2455 3 11.6124 3.08289 11.9577C3.15638 12.2638 3.27759 12.5564 3.44208 12.8249C3.6276 13.1276 3.88703 13.387 4.40589 13.9059L9.10589 18.6059C10.2939 19.7939 10.888 20.388 11.5729 20.6105C12.1755 20.8063 12.8245 20.8063 13.4271 20.6105C14.112 20.388 14.7061 19.7939 15.8941 18.6059L18.6059 15.8941C19.7939 14.7061 20.388 14.112 20.6105 13.4271C20.8063 12.8245 20.8063 12.1755 20.6105 11.5729C20.388 10.888 19.7939 10.2939 18.6059 9.10589L13.9059 4.40589C13.387 3.88703 13.1276 3.6276 12.8249 3.44208C12.5564 3.27759 12.2638 3.15638 11.9577 3.08289C11.6124 3 11.2455 3 10.5118 3ZM7.5498 7.0498C7.5498 7.32595 7.32595 7.5498 7.0498 7.5498C6.77366 7.5498 6.5498 7.32595 6.5498 7.0498C6.5498 6.77366 6.77366 6.5498 7.0498 6.5498C7.32595 6.5498 7.5498 6.77366 7.5498 7.0498Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

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="M8.5 3H11.5118C12.2455 3 12.6124 3 12.9577 3.08289C13.2638 3.15638 13.5564 3.27759 13.8249 3.44208C14.1276 3.6276 14.387 3.88703 14.9059 4.40589L20.5 10M7.5498 10.0498H7.5598M9.51178 6H8.3C6.61984 6 5.77976 6 5.13803 6.32698C4.57354 6.6146 4.1146 7.07354 3.82698 7.63803C3.5 8.27976 3.5 9.11984 3.5 10.8V12.0118C3.5 12.7455 3.5 13.1124 3.58289 13.4577C3.65638 13.7638 3.77759 14.0564 3.94208 14.3249C4.1276 14.6276 4.38703 14.887 4.90589 15.4059L8.10589 18.6059C9.29394 19.7939 9.88796 20.388 10.5729 20.6105C11.1755 20.8063 11.8245 20.8063 12.4271 20.6105C13.112 20.388 13.7061 19.7939 14.8941 18.6059L16.1059 17.3941C17.2939 16.2061 17.888 15.612 18.1105 14.9271C18.3063 14.3245 18.3063 13.6755 18.1105 13.0729C17.888 12.388 17.2939 11.7939 16.1059 10.6059L12.9059 7.40589C12.387 6.88703 12.1276 6.6276 11.8249 6.44208C11.5564 6.27759 11.2638 6.15638 10.9577 6.08289C10.6124 6 10.2455 6 9.51178 6ZM8.0498 10.0498C8.0498 10.3259 7.82595 10.5498 7.5498 10.5498C7.27366 10.5498 7.0498 10.3259 7.0498 10.0498C7.0498 9.77366 7.27366 9.5498 7.5498 9.5498C7.82595 9.5498 8.0498 9.77366 8.0498 10.0498Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

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="M4 6H20M16 6L15.7294 5.18807C15.4671 4.40125 15.3359 4.00784 15.0927 3.71698C14.8779 3.46013 14.6021 3.26132 14.2905 3.13878C13.9376 3 13.523 3 12.6936 3H11.3064C10.477 3 10.0624 3 9.70951 3.13878C9.39792 3.26132 9.12208 3.46013 8.90729 3.71698C8.66405 4.00784 8.53292 4.40125 8.27064 5.18807L8 6M18 6V16.2C18 17.8802 18 18.7202 17.673 19.362C17.3854 19.9265 16.9265 20.3854 16.362 20.673C15.7202 21 14.8802 21 13.2 21H10.8C9.11984 21 8.27976 21 7.63803 20.673C7.07354 20.3854 6.6146 19.9265 6.32698 19.362C6 18.7202 6 17.8802 6 16.2V6M14 10V17M10 10V17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 879 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="M4.9996 7V11M9.9996 2V6M17.9996 16V20M2.9996 9H6.9996M7.9996 4H11.9996M15.9996 18H19.9996M13.9996 7L16.828 9.82843M19.5162 3.74612L20.0819 4.3118C20.4779 4.70782 20.6759 4.90583 20.7501 5.13416C20.8154 5.335 20.8154 5.55135 20.7501 5.75219C20.6759 5.98052 20.4779 6.17853 20.0819 6.57454L6.52508 20.1314C6.12906 20.5274 5.93105 20.7254 5.70272 20.7996C5.50188 20.8649 5.28553 20.8649 5.08469 20.7996C4.85636 20.7254 4.65835 20.5274 4.26234 20.1314L3.69665 19.5657C3.30063 19.1697 3.10262 18.9717 3.02844 18.7433C2.96318 18.5425 2.96318 18.3262 3.02844 18.1253C3.10262 17.897 3.30063 17.699 3.69665 17.303L17.2535 3.74612C17.6495 3.3501 17.8475 3.15209 18.0758 3.0779C18.2767 3.01265 18.493 3.01265 18.6939 3.0779C18.9222 3.15209 19.1202 3.3501 19.5162 3.74612Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1,31 @@
{
"$schema": "config.schema.json",
"version": "1.0.0",
"baseApiUrl": "https://back.mmorales.photo/api",
"defaultTheme": "light",
"logoAlt": "MMORALES PHOTO",
"title": "MMORALES PHOTO",
"faviconSrc": "assets/favicon.ico",
"metaTags": {
"description": "Manuel Morales Workshop.",
"keywords": "MMORALES, photo, photography, workshop, Manuel Morales",
"author": "Manuel Juan Morales Amat"
},
"socialLinks": {
"instagram": "https://www.instagram.com/mmorales_photo/"
},
"fonts": {
"preconnect": [
{
"href": "https://fonts.googleapis.com"
},
{
"href": "https://fonts.googleapis.com",
"crossorigin": true
}
],
"stylesheets": [
"https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Mono:ital,wght@0,200..800;1,200..800&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap"
]
}
}

View File

@@ -0,0 +1,106 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"version": {
"type": "string"
},
"baseApiUrl": {
"type": "string"
},
"defaultTheme": {
"type": "string"
},
"logoSrc": {
"type": "string"
},
"logoAlt": {
"type": "string"
},
"title": {
"type": "string"
},
"faviconSrc": {
"type": "string"
},
"metaTags": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"keywords": {
"type": "string"
},
"author": {
"type": "string"
}
},
"required": ["description", "keywords", "author"]
},
"socialLinks": {
"type": "object",
"properties": {
"instagram": {
"type": "string"
},
"facebook": {
"type": "string"
},
"twitter": {
"type": "string"
}
}
},
"fonts": {
"type": "object",
"properties": {
"preconnect": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"href": {
"type": "string"
}
},
"required": ["href"]
},
{
"type": "object",
"properties": {
"href": {
"type": "string"
},
"crossorigin": {
"type": "boolean"
}
},
"required": ["href", "crossorigin"]
}
]
},
"stylesheets": {
"type": "array",
"items": [
{
"type": "string"
}
]
}
},
"required": ["stylesheets"]
}
},
"required": [
"version",
"baseApiUrl",
"logoSrc",
"logoAlt",
"title",
"faviconSrc",
"metaTags",
"fonts"
]
}

View File

@@ -0,0 +1,9 @@
export class dataApi {
static readonly Photos = {
getAll: '/photos',
getById: (id: string) => `/photos/${id}`,
create: '/photos',
update: (id: string) => `/photos/${id}`,
delete: (id: string) => `/photos/${id}`,
};
}

View File

@@ -0,0 +1,12 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes)
]
};

View File

@@ -0,0 +1,2 @@
<custom-header></custom-header>
<router-outlet></router-outlet>

View File

@@ -0,0 +1,23 @@
import { Routes } from '@angular/router';
import { HomeView } from './views/home-view/home-view';
import { LoginView } from './views/login-view/login-view';
import { UserProfileView } from './views/user-profile-view/user-profile-view';
import { AdminView } from './views/admin-view/admin-view';
import { ContentManagerView } from './views/content-manager-view/content-manager-view';
import { ServicesView } from './views/services-view/services-view';
import { UserGalleriesView } from './views/user-galleries-view/user-galleries-view';
import { TagsView } from './views/tags-view/tags-view';
import { EventsView } from './views/events-view/events-view';
export const routes: Routes = [
{ path: '', component: HomeView },
{ path: 'login', component: LoginView },
{ path: 'tags', component: TagsView },
{ path: 'events', component: EventsView },
{ path: 'services', component: ServicesView },
{ path: 'my-profile', component: UserProfileView },
{ path: 'my-galleries', component: UserGalleriesView },
{ path: 'content-management', component: ContentManagerView },
{ path: 'admin', component: AdminView },
{ path: '**', redirectTo: '' },
];

View File

View File

@@ -0,0 +1,23 @@
import { TestBed } from '@angular/core/testing';
import { App } from './app';
describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [App],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it('should render title', () => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, v2');
});
});

14
front/v2/src/app/app.ts Normal file
View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Header } from './global-components/header/header';
import { HomeView } from './views/home-view/home-view';
@Component({
selector: 'app-root',
imports: [Header, HomeView, RouterOutlet],
templateUrl: './app.html',
styleUrl: './app.scss',
})
export class App {
protected isHomeView = true;
}

View File

@@ -0,0 +1,3 @@
<div class="admin-panel-link">
<a href="/admin">Admin</a>
</div>

View File

@@ -0,0 +1,79 @@
@use "../../../styles/variables" as *;
.admin-panel-link {
a {
display: inline-flex;
align-items: center;
padding: 0.75rem 1.5rem;
text-decoration: none;
color: $text-dark;
font-size: 0.95rem;
font-weight: 500;
letter-spacing: 0.5px;
border-radius: 8px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
// Hover effect with special admin color
&:hover {
color: $warning;
background: rgba($warning, 0.08);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba($warning, 0.15);
}
// Active state
&:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba($warning, 0.2);
}
// Focus state for accessibility
&:focus {
outline: 2px solid $warning;
outline-offset: 2px;
}
// Subtle animation on hover with admin color
&::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba($warning, 0.1),
transparent
);
transition: left 0.5s ease;
}
&:hover::before {
left: 100%;
}
}
}
// Responsive adjustments
@media (max-width: 768px) {
.admin-panel-link {
a {
padding: 0.6rem 1.2rem;
font-size: 0.9rem;
}
}
}
@media (max-width: 480px) {
.admin-panel-link {
a {
padding: 0.5rem 1rem;
font-size: 0.85rem;
letter-spacing: 0.25px;
}
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminPanelLink } from './admin-panel-link';
describe('AdminPanelLink', () => {
let component: AdminPanelLink;
let fixture: ComponentFixture<AdminPanelLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AdminPanelLink]
})
.compileComponents();
fixture = TestBed.createComponent(AdminPanelLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'admin-panel-link',
imports: [],
templateUrl: './admin-panel-link.html',
styleUrl: './admin-panel-link.scss'
})
export class AdminPanelLink {
}

View File

@@ -0,0 +1,3 @@
<div class="content-manager-panel-link">
<a href="/content-manager">Contenido</a>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentManagerPanelLink } from './content-manager-panel-link';
describe('ContentManagerPanelLink', () => {
let component: ContentManagerPanelLink;
let fixture: ComponentFixture<ContentManagerPanelLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ContentManagerPanelLink]
})
.compileComponents();
fixture = TestBed.createComponent(ContentManagerPanelLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'content-manager-panel-link',
imports: [],
templateUrl: './content-manager-panel-link.html',
styleUrl: './content-manager-panel-link.scss'
})
export class ContentManagerPanelLink {
}

View File

@@ -0,0 +1,6 @@
<svg-button
label="Eventos"
routerLink="/events"
textAtRight="Eventos"
icon="assets/icons/calendar-day-svgrepo-com.svg"
></svg-button>

After

Width:  |  Height:  |  Size: 143 B

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EventsLink } from './events-link';
describe('EventsLink', () => {
let component: EventsLink;
let fixture: ComponentFixture<EventsLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [EventsLink]
})
.compileComponents();
fixture = TestBed.createComponent(EventsLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { SvgButton } from '../../../utils/svg-button/svg-button';
@Component({
selector: 'events-link',
imports: [SvgButton],
templateUrl: './events-link.html',
styleUrl: './events-link.scss',
})
export class EventsLink {}

View File

@@ -0,0 +1,17 @@
<header>
<logo></logo>
<events-link></events-link>
<tags-link></tags-link>
<services-link></services-link>
@if (user.isLoggedIn) {
<user-galleries-link></user-galleries-link>
} @if (user.isContentManager) {
<content-manager-panel-link></content-manager-panel-link>
} @if (user.isAdmin) {
<admin-panel-link></admin-panel-link>
} @if (user.isLoggedIn) {
<user-profile-link></user-profile-link>
} @else {
<login-link></login-link>
}
</header>

View File

@@ -0,0 +1,25 @@
header {
position: sticky;
top: 0;
z-index: 1000;
background: transparent;
margin: 0;
padding: 0;
width: 100%;
height: 7%;
display: flex;
flex-direction: row;
align-items: baseline;
align-content: center;
justify-content: space-evenly;
gap: 0;
logo {
width: 10%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
order: 0;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Header } from './header';
describe('Header', () => {
let component: Header;
let fixture: ComponentFixture<Header>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Header]
})
.compileComponents();
fixture = TestBed.createComponent(Header);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,45 @@
import { Component } from '@angular/core';
import { Logo } from '../logo/logo';
import { EventsLink } from '../events-link/events-link';
import { UserGalleriesLink } from '../user-galleries-link/user-galleries-link';
import { ContentManagerPanelLink } from '../content-manager-panel-link/content-manager-panel-link';
import { AdminPanelLink } from '../admin-panel-link/admin-panel-link';
import { UserProfileLink } from '../user-profile-link/user-profile-link';
import { LoginLink } from '../login-link/login-link';
import { TagsLink } from '../tags-link/tags-link';
import { userService } from '../../services/userService/userService';
import { OnInit } from '@angular/core';
import { userModel } from '../../../models/userModel';
import { ServicesLink } from '../services-link/services-link';
@Component({
selector: 'custom-header',
imports: [
Logo,
EventsLink,
UserGalleriesLink,
ContentManagerPanelLink,
AdminPanelLink,
UserProfileLink,
LoginLink,
TagsLink,
ServicesLink,
],
templateUrl: './header.html',
styleUrl: './header.scss',
})
export class Header implements OnInit {
constructor(private userService: userService) {}
private currentUser: userModel = userModel.DefaultUser;
ngOnInit() {
this.userService.getUser().subscribe((user) => {
this.currentUser = user;
});
}
get user() {
return this.currentUser;
}
}

View File

@@ -0,0 +1,7 @@
<svg-button
label="login-link"
class="login-button"
routerLink="/login"
textAtRight="Login"
icon="assets/icons/door-open-svgrepo-com.svg"
></svg-button>

After

Width:  |  Height:  |  Size: 163 B

View File

@@ -0,0 +1,68 @@
.login-button {
// Variables para el lenguaje visual (SCSS)
$primary-white: #fefcf8; // Blanco ahuevado gentil
$border-grey: #e0ddd8; // Gris suave para bordes
$text-dark: #2a2926; // Texto principal
$standard-button-icon: #8d8d8d; // Texto principal
$standard-button-border: #b8b8b891; // Texto principal
$standard-button-hovered: #494949; // Texto principal
$text-muted: #706b63; // Texto secundario
svg-button {
button {
background: $primary-white;
border: 2px solid $standard-button-border;
color: $standard-button-icon;
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
min-width: 3.2rem;
height: 3.2rem;
margin: 0;
padding: 0;
flex-shrink: 1;
display: flex;
flex-wrap: nowrap;
align-items: center;
align-content: center;
justify-content: space-evenly;
padding: 5%;
label {
text-align: center;
flex-grow: 1;
}
&:hover {
color: $standard-button-hovered;
transform: scale(1.07);
box-shadow: 0 6px 16px rgba(42, 41, 38, 0.1);
}
&:disabled {
background: $primary-white;
color: $text-muted;
}
svg-loader {
box-sizing: border-box;
pointer-events: none;
display: block;
height: 80%;
width: 80%;
margin: 0;
padding: 0;
}
&:hover {
svg-loader {
fill: $primary-white;
}
label {
color: $primary-white;
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginLink } from './login-link';
describe('LoginLink', () => {
let component: LoginLink;
let fixture: ComponentFixture<LoginLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [LoginLink]
})
.compileComponents();
fixture = TestBed.createComponent(LoginLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { SvgButton } from '../../../utils/svg-button/svg-button';
@Component({
selector: 'login-link',
imports: [SvgButton],
templateUrl: './login-link.html',
styleUrl: './login-link.scss',
})
export class LoginLink {}

View File

@@ -0,0 +1,3 @@
<a routerLink="/">
<img [src]="logoSrc" alt="Logo" />
</a>

View File

@@ -0,0 +1,6 @@
a {
img {
width: 100%;
height: auto;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Logo } from './logo';
describe('Logo', () => {
let component: Logo;
let fixture: ComponentFixture<Logo>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Logo]
})
.compileComponents();
fixture = TestBed.createComponent(Logo);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { config } from '../../../models/config';
@Component({
selector: 'logo',
imports: [],
templateUrl: './logo.html',
styleUrl: './logo.scss',
})
export class Logo {
protected logoSrc = config.get().logoSrc;
}

View File

@@ -0,0 +1,6 @@
<svg-button
label="Servicios"
routerLink="/services"
textAtRight="Servicios"
icon="assets/icons/book-section-svgrepo-com.svg"
></svg-button>

After

Width:  |  Height:  |  Size: 149 B

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ServicesLink } from './services-link';
describe('ServicesLink', () => {
let component: ServicesLink;
let fixture: ComponentFixture<ServicesLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ServicesLink]
})
.compileComponents();
fixture = TestBed.createComponent(ServicesLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { SvgButton } from '../../../utils/svg-button/svg-button';
@Component({
selector: 'services-link',
imports: [SvgButton],
templateUrl: './services-link.html',
styleUrl: './services-link.scss',
})
export class ServicesLink {}

View File

@@ -0,0 +1,6 @@
<svg-button
label="tags-link"
routerLink="/tags"
textAtRight="Etiquetas"
icon="assets/icons/tags-svgrepo-com.svg"
></svg-button>

After

Width:  |  Height:  |  Size: 137 B

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TagsLink } from './tags-link';
describe('TagsLink', () => {
let component: TagsLink;
let fixture: ComponentFixture<TagsLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TagsLink]
})
.compileComponents();
fixture = TestBed.createComponent(TagsLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { SvgButton } from '../../../utils/svg-button/svg-button';
@Component({
selector: 'tags-link',
imports: [SvgButton],
templateUrl: './tags-link.html',
styleUrl: './tags-link.scss',
})
export class TagsLink {}

View File

@@ -0,0 +1,3 @@
<div class="user-galleries-link">
<a href="/galeria">Galería</a>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserGalleriesLink } from './user-galleries-link';
describe('UserGalleriesLink', () => {
let component: UserGalleriesLink;
let fixture: ComponentFixture<UserGalleriesLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserGalleriesLink]
})
.compileComponents();
fixture = TestBed.createComponent(UserGalleriesLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'user-galleries-link',
imports: [],
templateUrl: './user-galleries-link.html',
styleUrl: './user-galleries-link.scss'
})
export class UserGalleriesLink {
}

View File

@@ -0,0 +1,3 @@
<div class="user-profile-link">
<a href="/perfil">Perfil</a>
</div>

View File

@@ -0,0 +1,79 @@
@use "../../../styles/variables" as *;
.user-profile-link {
a {
display: inline-flex;
align-items: center;
padding: 0.75rem 1.5rem;
text-decoration: none;
color: $text-dark;
font-size: 0.95rem;
font-weight: 500;
letter-spacing: 0.5px;
border-radius: 8px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
// Hover effect
&:hover {
color: $primary-accent;
background: rgba($primary-accent, 0.08);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba($primary-accent, 0.15);
}
// Active state
&:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba($primary-accent, 0.2);
}
// Focus state for accessibility
&:focus {
outline: 2px solid $primary-accent;
outline-offset: 2px;
}
// Subtle animation on hover
&::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba($primary-accent, 0.1),
transparent
);
transition: left 0.5s ease;
}
&:hover::before {
left: 100%;
}
}
}
// Responsive adjustments
@media (max-width: 768px) {
.user-profile-link {
a {
padding: 0.6rem 1.2rem;
font-size: 0.9rem;
}
}
}
@media (max-width: 480px) {
.user-profile-link {
a {
padding: 0.5rem 1rem;
font-size: 0.85rem;
letter-spacing: 0.25px;
}
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserProfileLink } from './user-profile-link';
describe('UserProfileLink', () => {
let component: UserProfileLink;
let fixture: ComponentFixture<UserProfileLink>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserProfileLink]
})
.compileComponents();
fixture = TestBed.createComponent(UserProfileLink);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'user-profile-link',
imports: [],
templateUrl: './user-profile-link.html',
styleUrl: './user-profile-link.scss'
})
export class UserProfileLink {
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { Theme } from './theme';
describe('Theme', () => {
let service: Theme;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(Theme);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class Theme {
private isDarkTheme: boolean = false;
toggleTheme() {
this.isDarkTheme = !this.isDarkTheme;
this.applyTheme();
}
isDark() {
return this.isDarkTheme;
}
private applyTheme() {
const theme = this.isDarkTheme ? 'dark' : 'light';
document.body.classList.remove('light-theme', 'dark-theme');
document.body.classList.add(`${theme}-theme`);
}
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { userService } from './userService';
describe('userService', () => {
let service: userService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(userService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { userModel } from '../../../models/userModel';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class userService {
private currentUser: userModel = userModel.DefaultUser;
private userSubject = new BehaviorSubject<userModel>(this.currentUser);
setUser(user: userModel) {
this.currentUser = user;
this.userSubject.next(user);
}
getUser() {
return this.userSubject.asObservable();
}
}

View File

@@ -0,0 +1 @@
<p>admin-view works!</p>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminView } from './admin-view';
describe('AdminView', () => {
let component: AdminView;
let fixture: ComponentFixture<AdminView>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AdminView]
})
.compileComponents();
fixture = TestBed.createComponent(AdminView);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'admin-view',
imports: [],
templateUrl: './admin-view.html',
styleUrl: './admin-view.scss'
})
export class AdminView {
}

View File

@@ -0,0 +1 @@
<p>content-manager-view works!</p>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentManagerView } from './content-manager-view';
describe('ContentManagerView', () => {
let component: ContentManagerView;
let fixture: ComponentFixture<ContentManagerView>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ContentManagerView]
})
.compileComponents();
fixture = TestBed.createComponent(ContentManagerView);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'content-manager-view',
imports: [],
templateUrl: './content-manager-view.html',
styleUrl: './content-manager-view.scss'
})
export class ContentManagerView {
}

View File

@@ -0,0 +1 @@
<p>events-view works!</p>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EventsView } from './events-view';
describe('EventsView', () => {
let component: EventsView;
let fixture: ComponentFixture<EventsView>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [EventsView]
})
.compileComponents();
fixture = TestBed.createComponent(EventsView);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'events-view',
imports: [],
templateUrl: './events-view.html',
styleUrl: './events-view.scss'
})
export class EventsView {
}

View File

@@ -0,0 +1,7 @@
<ul>
@if (gallery.photos) { @for (item of gallery.photos; track $index) {
<li>
<img [src]="item.lowResUrl" [alt]="item.title" />
</li>
} }
</ul>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeView } from './home-view';
describe('HomeView', () => {
let component: HomeView;
let fixture: ComponentFixture<HomeView>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HomeView]
})
.compileComponents();
fixture = TestBed.createComponent(HomeView);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,14 @@
import { Component, OnInit } from '@angular/core';
import { homeGallery } from '../../../models/gallery/homeGallery';
@Component({
selector: 'home-view',
imports: [],
templateUrl: './home-view.html',
styleUrl: './home-view.scss',
})
export class HomeView implements OnInit {
public gallery: homeGallery = new homeGallery();
ngOnInit() {}
}

View File

@@ -0,0 +1 @@
<p>login-view works!</p>

Some files were not shown because too many files have changed in this diff Show More