first content

add: Cards for Generators on startpage. test site, navbar
This commit is contained in:
danielvici123
2025-11-16 18:17:15 +01:00
parent ab780e788c
commit 05e3fa1dcb
32 changed files with 299 additions and 81 deletions

3
.prettierignore Normal file
View File

@@ -0,0 +1,3 @@
# Ignore artifacts:
build
coverage

1
.prettierrc Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -14,9 +14,7 @@
"builder": "@angular/build:application", "builder": "@angular/build:application",
"options": { "options": {
"browser": "src/main.ts", "browser": "src/main.ts",
"polyfills": [ "polyfills": ["zone.js"],
"zone.js"
],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"assets": [ "assets": [
{ {
@@ -24,9 +22,7 @@
"input": "public" "input": "public"
} }
], ],
"styles": [ "styles": ["src/styles.css"]
"src/styles.css"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
@@ -70,10 +66,7 @@
"test": { "test": {
"builder": "@angular/build:karma", "builder": "@angular/build:karma",
"options": { "options": {
"polyfills": [ "polyfills": ["zone.js", "zone.js/testing"],
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"assets": [ "assets": [
{ {
@@ -81,9 +74,7 @@
"input": "public" "input": "public"
} }
], ],
"styles": [ "styles": ["src/styles.css"]
"src/styles.css"
]
} }
} }
} }

16
package-lock.json generated
View File

@@ -16,6 +16,7 @@
"@angular/router": "^20.3.0", "@angular/router": "^20.3.0",
"@tailwindcss/postcss": "^4.1.17", "@tailwindcss/postcss": "^4.1.17",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"prettier": "^3.6.2",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tailwindcss": "^4.1.17", "tailwindcss": "^4.1.17",
"tslib": "^2.3.0", "tslib": "^2.3.0",
@@ -8392,6 +8393,21 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/proc-log": { "node_modules/proc-log": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz",

View File

@@ -30,6 +30,7 @@
"@angular/router": "^20.3.0", "@angular/router": "^20.3.0",
"@tailwindcss/postcss": "^4.1.17", "@tailwindcss/postcss": "^4.1.17",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"prettier": "^3.6.2",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tailwindcss": "^4.1.17", "tailwindcss": "^4.1.17",
"tslib": "^2.3.0", "tslib": "^2.3.0",

View File

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

View File

@@ -1,6 +1,6 @@
<app-navbar class="fixed top-0 left-0 w-screen h-16 z-[999]"></app-navbar> <app-navbar class="fixed top-0 left-0 w-screen h-16 z-[999]"></app-navbar>
<main class="pt-16 bg-black-eerie min-h-screen"> <div class="p-8 pt-24 h-screen text-white bg-black-eerie mx-auto flex justify-center-safe" >
<!-- pt-16 bg-black-eerie h-screen flex justify-center-safe mx-auto " -->
<router-outlet></router-outlet> <router-outlet></router-outlet>
</main> </div>

View File

@@ -1,13 +1,18 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { Startpage } from './sites/startpage/startpage'; import { Startpage } from './sites/startpage/startpage';
import {TestIt} from './sites/test-it/test-it';
export const routes: Routes = [ export const routes: Routes = [
{
path:'test',
component: TestIt,
},
{ {
path: '', path: '',
component: Startpage, component: Startpage,
},
{
path: '**',
redirectTo: '',
} }
]; ];

View File

@@ -1,12 +1,12 @@
import { Component, signal } from '@angular/core'; import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
import {Navbar} from './components/navbar/navbar'; import { Navbar } from './components/navbar/navbar';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
imports: [RouterOutlet, Navbar], imports: [RouterOutlet, Navbar],
templateUrl: './app.html', templateUrl: './app.html',
styleUrl: './app.css' styleUrl: './app.css',
}) })
export class App { export class App {
protected readonly title = signal('tools-website'); protected readonly title = signal('tools-website');

View File

@@ -0,0 +1,15 @@
@if (enabled()) {
<div
class="h-full
hover:cursor-pointer flex flex-col p-6 rounded-lg border border-gray-700 bg-zinc-800 transition-colors duration-200 hover:border-blue-500"
[routerLink]="destination()">
<app-custom-title
[text]="title()"
[textSizeInPx]="titleSizeInPx()"
[textColor]="titleColor()"
fontWeight="bold"
class="mb-2"
></app-custom-title>
<span [ngStyle]="{'color': descriptionColor()}">{{ description() }}</span>
</div>
}

View File

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

View File

@@ -0,0 +1,28 @@
import { Component, input } from '@angular/core';
import { CustomTitle } from '../custom-title/custom-title';
import {RouterLink} from '@angular/router';
import {NgStyle} from '@angular/common';
@Component({
selector: 'app-custom-card',
imports: [CustomTitle, RouterLink, NgStyle],
templateUrl: './custom-card.html',
styleUrl: './custom-card.css',
})
export class CustomCard {
title = input.required<string>();
titleSizeInPx = input<number>(20);
titleColor = input<string>();
description = input.required<string>();
descriptionColor = input<string>();
destination = input.required<string>();
enabled = input.required<boolean>();
ngOnInit() {
console.log(this.destination());
}
}

View File

@@ -0,0 +1,6 @@
<a
[ngStyle]="{
'font-size': textSizeInPx() + 'px',
color: textColor(),
'font-weight': fontWeight()}"
>{{ text() }}</a>

View File

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

View File

@@ -0,0 +1,15 @@
import { Component, input } from '@angular/core';
import {NgClass, NgStyle} from '@angular/common';
@Component({
selector: 'app-custom-title',
imports: [NgStyle, NgClass],
templateUrl: './custom-title.html',
styleUrl: './custom-title.css',
})
export class CustomTitle {
text = input.required<string>();
textSizeInPx = input<number>(16);
textColor = input<string>();
fontWeight = input<string>("normal");
}

View File

@@ -1,11 +1,17 @@
<nav class="h-16 bg-blue-marian"> <nav class="h-16 bg-blue-marian">
<div class="flex justify-between items-center px-4 bg-blue-marian text-white container mx-auto h-full"> <div
class="flex justify-between items-center px-4 bg-blue-marian text-white container mx-auto h-full"
>
<div class="flex items-center h-full"> <div class="flex items-center h-full">
<span class="font-bold text-xl">Home</span> <a class="font-bold text-xl" routerLink="/">Home</a>
</div> </div>
<div class="flex flex-row space-x-4 gap-6"> <div class="flex flex-row space-x-4 gap-6">
<a class="hover:text-blue-200" routerLink="/coming-soon" routerLinkActive="active-link">Coming Soon</a> <a class="hover:text-blue-200" routerLink="/coming-soon" routerLinkActive="active-link"
<a class="hover:text-blue-200" routerLink="/changelog" routerLinkActive="active-link">Changelog</a> >Coming Soon</a
>
<a class="hover:text-blue-200" routerLink="/changelog" routerLinkActive="active-link"
>Changelog</a
>
<a class="hover:text-blue-200" routerLink="/about" routerLinkActive="active-link">About</a> <a class="hover:text-blue-200" routerLink="/about" routerLinkActive="active-link">About</a>
</div> </div>
</div> </div>

View File

@@ -8,9 +8,8 @@ describe('Navbar', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [Navbar] imports: [Navbar],
}) }).compileComponents();
.compileComponents();
fixture = TestBed.createComponent(Navbar); fixture = TestBed.createComponent(Navbar);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -1,17 +1,11 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {RouterLink, RouterLinkActive} from '@angular/router'; import { RouterLink, RouterLinkActive } from '@angular/router';
import {NgOptimizedImage} from '@angular/common'; import { NgOptimizedImage } from '@angular/common';
@Component({ @Component({
selector: 'app-navbar', selector: 'app-navbar',
imports: [ imports: [RouterLinkActive, RouterLink],
RouterLinkActive,
RouterLink,
NgOptimizedImage
],
templateUrl: './navbar.html', templateUrl: './navbar.html',
styleUrl: './navbar.css', styleUrl: './navbar.css',
}) })
export class Navbar { export class Navbar {}
}

View File

@@ -1,7 +1,32 @@
<div class="text-white"> <div class="text-white">
<div class="mb-6">
<h1 class="text-center">Moin Welt</h1> <app-custom-title
<p>TailwindCSS geht</p> [textSizeInPx]="24"
text="Tools"
textColor="white"
class="font-bold"
></app-custom-title>
</div>
<div class="gap-6 ml-4 max-w-7xl mx-auto space-y-12">
@for (feature of features; track $index) {
@if (feature.enabled) {
<div>
<div class="mb-4">
<app-custom-title
[textSizeInPx]="20"
[text]="feature.name"
textColor="oklch(70.7% 0.165 254.624)"
fontWeight="bold"
></app-custom-title>
</div>
<div class="ml-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@for (tool of feature.tools; track $index) {
<app-custom-card [title]="tool.name" [description]="tool.description" descriptionColor="oklch(70.4% 0.04 256.788)"
[destination]="tool.link" [enabled]="tool.enabled"></app-custom-card>
}
</div>
</div>
}
}
</div>
</div> </div>

View File

@@ -8,9 +8,8 @@ describe('Startpage', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [Startpage] imports: [Startpage],
}) }).compileComponents();
.compileComponents();
fixture = TestBed.createComponent(Startpage); fixture = TestBed.createComponent(Startpage);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -1,14 +1,43 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {NgOptimizedImage} from '@angular/common'; import { NgOptimizedImage } from '@angular/common';
import { CustomTitle } from '../../components/custom-title/custom-title';
import { CustomCard } from '../../components/custom-card/custom-card';
import {ReactiveFormsModule} from '@angular/forms';
@Component({ @Component({
selector: 'app-startpage', selector: 'app-startpage',
imports: [
NgOptimizedImage
],
templateUrl: './startpage.html', templateUrl: './startpage.html',
styleUrl: './startpage.css', styleUrl: './startpage.css',
imports: [CustomTitle, CustomCard, ReactiveFormsModule],
}) })
export class Startpage { export class Startpage {
features = [{
name: 'Generators',
enabled: true,
tools: [{
name: 'Password Generator',
description: 'Create secure passwords with custom options',
link: '/generator/password',
enabled: true,
}, {
name: 'QR Code Generator',
description: 'Generate and download QR codes for any text or URL',
link: '/generator/qr',
enabled: true,
}]}, {
name: 'Tests',
enabled: true,
tools: [{
name: 'Test 1',
description: 'This is a just test description.',
link: '/test',
enabled: true,
},{
name: 'Test 2',
description: 'This is a just test description.',
link: '/test',
enabled: false,
}]
}];
} }

View File

View File

@@ -0,0 +1,9 @@
<div class="flex flex-col justify-center items-center">
<h1 class="text-7xl text-white m-10">Yeah. This Site works...</h1>
<div class="flex justify-center">
<button
class="text-xl w-fit bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600 transition-colors hover:cursor-pointer"
routerLink="/"
>Home</button>
</div>
</div>

View File

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

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import {RouterLink} from '@angular/router';
@Component({
selector: 'app-test-it',
imports: [
RouterLink
],
templateUrl: './test-it.html',
styleUrl: './test-it.css',
})
export class TestIt {
}

View File

@@ -1,13 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<title>ToolsWebsite</title> <title>ToolsWebsite</title>
<base href="/"> <base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="app/assets/logo.ico"> <link rel="icon" type="image/x-icon" href="app/assets/logo.ico" />
</head> </head>
<body> <body>
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>

View File

@@ -2,5 +2,4 @@ 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';
bootstrapApplication(App, appConfig) bootstrapApplication(App, appConfig).catch((err) => console.error(err));
.catch((err) => console.error(err));

View File

@@ -1,8 +1,8 @@
/* 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 */
@import "tailwindcss"; @import 'tailwindcss';
@theme { @theme {
--color-blue-marian: #1E3A8A; --color-blue-marian: #1e3a8a;
--color-black-eerie: #18181B; --color-black-eerie: #18181b;
--color-black-charcoal: #374151; --color-black-charcoal: #374151;
} }

View File

@@ -6,10 +6,6 @@
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": []
}, },
"include": [ "include": ["src/**/*.ts"],
"src/**/*.ts" "exclude": ["src/**/*.spec.ts"]
],
"exclude": [
"src/**/*.spec.ts"
]
} }

View File

@@ -4,11 +4,7 @@
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/spec", "outDir": "./out-tsc/spec",
"types": [ "types": ["jasmine"]
"jasmine"
]
}, },
"include": [ "include": ["src/**/*.ts"]
"src/**/*.ts"
]
} }