improve: readme and configs

This commit is contained in:
2026-04-27 17:42:27 +02:00
parent 38d4f7b2a6
commit 0d7b8a59a5
8 changed files with 74 additions and 114 deletions
-56
View File
@@ -1,56 +0,0 @@
# Repository Guidelines
## Project Structure & Module Organization
This repository is an Angular 21 SSR application. Main app code lives in `src/`,
with standalone components under `src/app/` such as `home/`, `footer/`, and
`imprint/`. Shared constants are kept in `src/global.ts`. Component tests sit
next to their source files as `*.spec.ts`. Automation and project maintenance
scripts live in `scripts/`. Generated build output goes to `dist/` and should
not be edited manually.
## Build, Test, and Development Commands
- `npm run dev`: generate static assets, then start the Angular dev server.
- `npm run build`: generate assets, create a production build, then copy static
root files.
- `npm run test`: run unit tests with Karma/Jasmine.
- `npm run lint`: run the base ESLint config and the type-aware TypeScript
config.
- `npm run format:check`: verify Prettier formatting without changing files.
- `npm run check`: full CI-style verification (`build`, `lint`, formatting,
version, and text checks).
- `npm run fix`: apply the local autofix workflow, including version placeholder
reset, lint fixes, text cleanup, and Prettier.
## Coding Style & Naming Conventions
Follow `.editorconfig`: UTF-8, spaces, 2-space indentation, final newline, and
trimmed trailing whitespace. Use Prettier for formatting and ESLint for code
quality. Keep Angular file naming consistent: `feature.component.ts`,
`feature.component.html`, and `feature.component.spec.ts`. Prefer PascalCase for
classes and interfaces, camelCase for members, and keep scripts in CommonJS
format as `*.cjs`.
## Testing Guidelines
The project uses Jasmine with Karma via `ng test`. Place tests beside the
implementation file and keep names aligned with the component or module under
test. Run `npm run test` for unit tests and `npm run check` before opening a PR.
No explicit coverage gate is configured, so contributors should add focused
tests for changed behavior.
## Commit & Pull Request Guidelines
Recent history mixes short imperative messages (`Update src/global.ts`) with
lightweight conventional commits (`feat: pre-render routes and restore scroll`).
Prefer concise, imperative commit subjects and include a scope or prefix when it
adds clarity. PRs should summarize the user-visible change, mention any config
or script updates, link related issues, and include screenshots for UI changes.
## Configuration Tips
Use the placeholder version workflow intentionally: `version:check` expects
`YYDDDhhmm+GIT_HASH`, while build pipelines may resolve it through the scripts
in `scripts/version.cjs`. Keep `package.json` and `package-lock.json` in sync,
and avoid committing manual edits to generated files in `dist/`.
+25 -25
View File
@@ -4,11 +4,13 @@
![grafik](https://github.com/user-attachments/assets/65f1e491-62ab-4b16-a39c-5f04377ce5cb) ![grafik](https://github.com/user-attachments/assets/65f1e491-62ab-4b16-a39c-5f04377ce5cb)
## 👂 Languages/Framework/Packages: ## 👂 Languages / Framework / Packages
- Angular v21 - Angular v21 (with SSR)
- TypeScript - TypeScript
- SCSS - SCSS
- Angular Material
- FontAwesome
## 💻 Development ## 💻 Development
@@ -21,18 +23,12 @@ npm run dev
### Building ### Building
```bash ```bash
npm run buildDevelopment npm run build
```
or for Production Build
```bash
npm run buildProduction
``` ```
This will compile your project and store the build artifacts in the `dist/` This will compile your project and store the build artifacts in the `dist/`
directory. By default, the production build optimizes your application for directory. The production build optimizes your application for performance and
performance and speed. speed.
### Start compiled Project ### Start compiled Project
@@ -40,28 +36,32 @@ performance and speed.
npm run start npm run start
``` ```
## Running unit tests ## 🔍 Code Quality
### Lint & Format check
```bash
npm run check
```
### Auto-fix lint & format issues
```bash
npm run fix
```
## 🧪 Running Unit Tests
To execute unit tests with the [Karma](https://karma-runner.github.io) test To execute unit tests with the [Karma](https://karma-runner.github.io) test
runner, use the following command: runner, use the following command:
```bash ```bash
nom run test npm run test
``` ```
## Update Packages/Libraries
```bash
npm run updatePackageVersions
```
## 📋 Credits:
~ made by [**FrauJulian**](https://fraujulian.xyz/).
## 🤝 Enjoy? ## 🤝 Enjoy?
Give it a star ⭐ on ~ made by [**FrauJulian**](https://fraujulian.xyz/). Give it a star ⭐ on
[github](https://github.com/FrauJulian/discord-audio-stream)! [GitHub](https://github.com/FrauJulian/Personal-Portfolio-Website)!
### Greetings from Austria! ⛰️ ### Greetings from Austria! ⛰️
+2
View File
@@ -50,6 +50,8 @@ const config = [
/* Base */ /* Base */
'no-debugger': 'warn', 'no-debugger': 'warn',
'no-var': 'error',
'prefer-const': ['error', { destructuring: 'all' }],
/* TypeScript */ /* TypeScript */
'unused-imports/no-unused-imports': 'warn', 'unused-imports/no-unused-imports': 'warn',
+10 -5
View File
@@ -14,11 +14,16 @@ const typeAwareLayer = {
'@typescript-eslint': require('@typescript-eslint/eslint-plugin'), '@typescript-eslint': require('@typescript-eslint/eslint-plugin'),
}, },
rules: { rules: {
'@typescript-eslint/no-floating-promises': 'warn', '@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': ['warn', { checksVoidReturn: false }], '@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }],
'@typescript-eslint/no-unsafe-assignment': 'warn', '@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-member-access': 'warn', '@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-argument': 'warn', '@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
'@typescript-eslint/prefer-optional-chain': 'warn',
}, },
}; };
+21 -21
View File
@@ -20,7 +20,7 @@ function writeJson(location, value) {
} }
function getSelectedMode() { function getSelectedMode() {
let selectedModes = process.argv.slice(2).filter((value) => MODES.has(value)); const selectedModes = process.argv.slice(2).filter((value) => MODES.has(value));
if (selectedModes.length !== 1) { if (selectedModes.length !== 1) {
throw new Error('Use exactly one mode: --set, --ensure, --check or --place.'); throw new Error('Use exactly one mode: --set, --ensure, --check or --place.');
@@ -30,7 +30,7 @@ function getSelectedMode() {
} }
function getVersionParts(version) { function getVersionParts(version) {
let parts = String(version).split('.'); const parts = String(version).split('.');
if (parts.length < 3) { if (parts.length < 3) {
throw new Error(`Version "${version}" does not follow the expected major.minor.build format.`); throw new Error(`Version "${version}" does not follow the expected major.minor.build format.`);
@@ -40,12 +40,12 @@ function getVersionParts(version) {
} }
function getVersionPrefix(version) { function getVersionPrefix(version) {
let [major, minor] = getVersionParts(version); const [major, minor] = getVersionParts(version);
return `${major}.${minor}.`; return `${major}.${minor}.`;
} }
function getBuildPart(version) { function getBuildPart(version) {
let [, , buildPart] = getVersionParts(version); const [, , buildPart] = getVersionParts(version);
return buildPart; return buildPart;
} }
@@ -54,7 +54,7 @@ function hasPlaceholderVersion(version) {
} }
function hasResolvedVersion(version) { function hasResolvedVersion(version) {
let buildPart = getBuildPart(version); const buildPart = getBuildPart(version);
return buildPart !== VERSION_PLACEHOLDER && RESOLVED_BUILD_PATTERN.test(buildPart); return buildPart !== VERSION_PLACEHOLDER && RESOLVED_BUILD_PATTERN.test(buildPart);
} }
@@ -63,7 +63,7 @@ function getExplicitVersion() {
} }
function getGitHash() { function getGitHash() {
let explicitHash = process.env.BUILD_GIT_HASH?.trim() || process.env.GITHUB_SHA?.trim(); const explicitHash = process.env.BUILD_GIT_HASH?.trim() || process.env.GITHUB_SHA?.trim();
if (explicitHash) { if (explicitHash) {
return explicitHash.slice(0, 7); return explicitHash.slice(0, 7);
@@ -81,18 +81,18 @@ function getGitHash() {
} }
function getBuildNumber() { function getBuildNumber() {
let now = new Date(); const now = new Date();
let year = String(now.getFullYear()).slice(-2); const year = String(now.getFullYear()).slice(-2);
let startOfYear = new Date(now.getFullYear(), 0, 1); const startOfYear = new Date(now.getFullYear(), 0, 1);
let dayOfYear = Math.floor((now - startOfYear) / (1000 * 60 * 60 * 24)) + 1; const dayOfYear = Math.floor((now - startOfYear) / (1000 * 60 * 60 * 24)) + 1;
let hours = String(now.getHours()).padStart(2, '0'); const hours = String(now.getHours()).padStart(2, '0');
let minutes = String(now.getMinutes()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0');
return `${year}${String(dayOfYear).padStart(3, '0')}${hours}${minutes}`; return `${year}${String(dayOfYear).padStart(3, '0')}${hours}${minutes}`;
} }
function resolveVersion(currentVersion) { function resolveVersion(currentVersion) {
let explicitVersion = getExplicitVersion(); const explicitVersion = getExplicitVersion();
if (explicitVersion) { if (explicitVersion) {
return explicitVersion; return explicitVersion;
@@ -102,7 +102,7 @@ function resolveVersion(currentVersion) {
} }
function isAlreadyEnsured(currentVersion) { function isAlreadyEnsured(currentVersion) {
let explicitVersion = getExplicitVersion(); const explicitVersion = getExplicitVersion();
if (explicitVersion) { if (explicitVersion) {
return currentVersion === explicitVersion; return currentVersion === explicitVersion;
@@ -112,7 +112,7 @@ function isAlreadyEnsured(currentVersion) {
} }
function writeResolvedVersion(resolvedVersion) { function writeResolvedVersion(resolvedVersion) {
let packageJson = readJson(PACKAGE_JSON_PATH); const packageJson = readJson(PACKAGE_JSON_PATH);
packageJson.version = resolvedVersion; packageJson.version = resolvedVersion;
writeJson(PACKAGE_JSON_PATH, packageJson); writeJson(PACKAGE_JSON_PATH, packageJson);
@@ -120,7 +120,7 @@ function writeResolvedVersion(resolvedVersion) {
return; return;
} }
let packageLock = readJson(PACKAGE_LOCK_PATH); const packageLock = readJson(PACKAGE_LOCK_PATH);
packageLock.version = resolvedVersion; packageLock.version = resolvedVersion;
if (packageLock.packages && packageLock.packages['']) { if (packageLock.packages && packageLock.packages['']) {
@@ -161,7 +161,7 @@ function runEnsure(currentVersion) {
} }
function runSet(currentVersion) { function runSet(currentVersion) {
let resolvedVersion = resolveVersion(currentVersion); const resolvedVersion = resolveVersion(currentVersion);
writeResolvedVersion(resolvedVersion); writeResolvedVersion(resolvedVersion);
console.log(`Version set to: ${resolvedVersion}`); console.log(`Version set to: ${resolvedVersion}`);
} }
@@ -172,10 +172,10 @@ function runSetPlace() {
} }
try { try {
let selectedMode = getSelectedMode(); const selectedMode = getSelectedMode();
let packageJson = readJson(PACKAGE_JSON_PATH); const packageJson = readJson(PACKAGE_JSON_PATH);
let packageVersion = String(packageJson.version); const packageVersion = String(packageJson.version);
let currentVersion = String(packageJson.currentVersion); const currentVersion = String(packageJson.currentVersion);
switch (selectedMode) { switch (selectedMode) {
case '--check': case '--check':
+10 -5
View File
@@ -95,10 +95,12 @@
<div class="story-grid"> <div class="story-grid">
<div class="story-copy"> <div class="story-copy">
<p> <p>
My name is {{ global.firstname }}, though most people call me Julie. Im{{ age }}and based in Austria. A large part of my day happens on the move — usually on trains, going between meetings, offices, and time with my family. My name is {{ global.firstname }}, though most people call me Julie. Im{{ age }}and based in Austria. A large part of my day
happens on the move — usually on trains, going between meetings, offices, and time with my family.
</p> </p>
<p> <p>
I work with modern web technologies and on business-critical systems. I dont care much for unnecessary complexity — I focus on clear, stable solutions that actually hold up in day-to-day use and deliver real value. I work with modern web technologies and on business-critical systems. I dont care much for unnecessary complexity — I focus on
clear, stable solutions that actually hold up in day-to-day use and deliver real value.
</p> </p>
</div> </div>
@@ -111,13 +113,16 @@
@if (isLongBioMounted) { @if (isLongBioMounted) {
<div class="detail-panel" [class.detail-panel-enter]="isLongBioShown" [class.detail-panel-leave]="!isLongBioShown"> <div class="detail-panel" [class.detail-panel-enter]="isLongBioShown" [class.detail-panel-leave]="!isLongBioShown">
<p> <p>
What really interests me is modern code — well-structured, maintainable, and built with performance in mind. No unnecessary bloat, just clean, readable solutions that reliably work under real-world conditions… in theory 😁 What really interests me is modern code — well-structured, maintainable, and built with performance in mind. No unnecessary
bloat, just clean, readable solutions that reliably work under real-world conditions… in theory 😁
</p> </p>
<p> <p>
Outside of software, my main hobby is scuba diving. The silence underwater and the focus on the present moment keep pulling me back into Austrias dark, cold lakes. Outside of software, my main hobby is scuba diving. The silence underwater and the focus on the present moment keep pulling me
back into Austrias dark, cold lakes.
</p> </p>
<p> <p>
Right now, I mainly work for SobIT GmbH in Vienna, alongside freelance projects for companies, organizations, and private clients. No gimmicks — just software that does what its supposed to do, built properly. Right now, I mainly work for SobIT GmbH in Vienna, alongside freelance projects for companies, organizations, and private
clients. No gimmicks — just software that does what its supposed to do, built properly.
</p> </p>
<button class="inline-link inline-link-button" type="button" (click)="scrollToContactLinks()">Get in touch</button> <button class="inline-link inline-link-button" type="button" (click)="scrollToContactLinks()">Get in touch</button>
</div> </div>
+2 -1
View File
@@ -5,7 +5,8 @@
<p class="eyebrow">Legal</p> <p class="eyebrow">Legal</p>
<h1>Imprint & Privacy</h1> <h1>Imprint & Privacy</h1>
<p class="hero-intro legal-intro"> <p class="hero-intro legal-intro">
Legal information for this website under Austrian law, including privacy information for websites operated by {{ global.firstname }} {{ global.lastname }} Legal information for this website under Austrian law, including privacy information for websites operated by
{{ global.firstname }} {{ global.lastname }}
(Lechner Systems). (Lechner Systems).
</p> </p>
</div> </div>
+4 -1
View File
@@ -3,7 +3,10 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="description" content="Full-stack developer building reliable, high-performance systems and clean, maintainable code. Focused on practical solutions that actually hold up in production."> <meta
name="description"
content="Full-stack developer building reliable, high-performance systems and clean, maintainable code. Focused on practical solutions that actually hold up in production."
/>
<base href="/" /> <base href="/" />
<link rel="icon" type="image/webp" sizes="128x128" href="assets/optimized/portrait/me-128.webp" /> <link rel="icon" type="image/webp" sizes="128x128" href="assets/optimized/portrait/me-128.webp" />