feat: imprint

This commit is contained in:
2026-04-27 17:06:08 +02:00
parent 87fe28cbfc
commit 026af41c4d
7 changed files with 193 additions and 178 deletions
+2 -2
View File
@@ -150,8 +150,8 @@
[ngSrc]="project.icon" [ngSrc]="project.icon"
[attr.srcset]="project.iconSrcset ?? null" [attr.srcset]="project.iconSrcset ?? null"
[attr.sizes]="project.iconSizes ?? null" [attr.sizes]="project.iconSizes ?? null"
width="216" [width]="project.iconWidth ?? 216"
height="216" [height]="project.iconHeight ?? 216"
disableOptimizedSrcset disableOptimizedSrcset
[alt]="project.title + ' icon'" [alt]="project.title + ' icon'"
/> />
+144 -66
View File
@@ -1,83 +1,161 @@
<main class="page-shell imprint-page"> <main class="page-shell imprint-page">
<section class="panel legal-hero"> <section class="hero-section panel legal-hero">
<a class="back-link" routerLink=""> <div class="hero-copy">
<fa-icon [icon]="faArrowLeft"></fa-icon> <div class="hero-copy-main">
<span>Back to portfolio</span> <p class="eyebrow">Legal</p>
</a> <h1>Imprint & Privacy</h1>
<p class="hero-intro legal-intro">
Legal information for this website under Austrian law, including privacy information for websites operated by Julian Lechner
(Lechner Systems).
</p>
</div>
<p class="eyebrow">Legal</p> <div class="hero-actions">
<h1>Imprint & Privacy</h1> <a class="back-link" routerLink="">
<p class="legal-intro"> <fa-icon [icon]="faArrowLeft"></fa-icon>
Legal disclosure for this website under Austrian law, in particular Section 5 ECG (E-Commerce Act) and Section 25 Austrian Media Act. <span>Back to portfolio</span>
</p> </a>
</div>
</div>
<div class="hero-visual">
<div class="portrait-highlight legal-contact-box">
<p class="hero-contact-title">Provider</p>
<p class="legal-provider-name">{{ global.firstname }} {{ global.lastname }} / Lechner Systems</p>
<p>{{ displayStreet }} {{ global.address.houseNumber }}</p>
<p>{{ global.address.zip }} {{ displayCity }}</p>
<p>{{ global.address.country }}</p>
<hr />
<p class="hero-contact-title">Direct Contact</p>
<p>
Phone:
<a class="inline-link" href="tel:{{ global.hrefContactPhone }}">{{ global.contactPhone }}</a>
</p>
<p>
Contact:
<a class="inline-link" [href]="contactSafeMail">{{ global.contactMail }}</a>
</p>
<p>
Abuse:
<a class="inline-link" [href]="abuseSafeMail">{{ global.abuseMail }}</a>
</p>
</div>
</div>
</section> </section>
<section class="legal-grid"> <section class="story-section panel legal-section">
<article class="panel legal-card"> <div class="section-heading">
<p class="eyebrow">Provider</p> <p class="eyebrow">Scope</p>
<p class="legal-provider-name">{{ global.firstname }} {{ global.lastname }}</p> <h2>Scope Of These Notices</h2>
<p class="legal-row">{{ global.address.street }} {{ global.address.houseNumber }}</p> </div>
<p class="legal-row">{{ global.address.zip }} {{ global.address.city }}</p>
<p class="legal-row">{{ global.address.country }}</p>
</article>
<article class="panel legal-card"> <div class="story-grid">
<p class="eyebrow">Contact</p> <div class="story-copy">
<p class="legal-row"> <p>
Phone: These notices apply to this website and, unless a more specific notice is published there, to other websites operated by Julian
<a href="tel:{{ global.hrefContactPhone }}">{{ global.contactPhone }}</a> Lechner under the name Lechner Systems.
</p> </p>
<p class="legal-row"> </div>
E-mail:
<a [href]="contactSafeMail">{{ global.contactMail }}</a> <div class="story-detail">
</p> <p>
<p class="legal-row"> This website provides information about projects, technical services, contact options, and professional work in software
Abuse: engineering, IT, and related digital services.
<a [href]="abuseSafeMail">{{ global.abuseMail }}</a> </p>
</p> </div>
</article> </div>
</section> </section>
<section class="panel legal-copy"> <section class="story-section panel legal-section">
<div class="legal-block"> <div class="section-heading compact">
<h2>Scope of Website</h2> <p class="eyebrow">Privacy</p>
<p>This website is a personal portfolio and a contact point for software engineering and related digital services.</p> <h2>Privacy And Data Processing</h2>
</div> </div>
<div class="legal-block"> <div class="story-grid">
<h2>Media Disclosure (Section 25 Austrian Media Act)</h2> <div class="story-copy">
<p> <p>
Media owner and publisher: {{ global.firstname }} {{ global.lastname }}. Editorial policy: Information about projects, technical The controller for data processing within the meaning of the GDPR is {{ global.firstname }} {{ global.lastname }}, reachable at
services, and professional activities in software development. <a class="inline-link" [href]="contactSafeMail">{{ global.contactMail }}</a> and by phone at
</p> <a class="inline-link" href="tel:{{ global.hrefContactPhone }}">{{ global.contactPhone }}</a>.
</p>
<p>
As currently implemented in this web project, this website does not use its own tracking, analytics cookies, marketing cookies, or
long-term personal usage profiling.
</p>
<p>
For informational website access, technically necessary connection and server data may be processed for operation, IT security,
abuse prevention, and troubleshooting.
</p>
</div>
<div class="story-detail">
<p>
If you contact me by email or phone, the data you provide is processed to handle your request and maintain communication.
Applicable legal bases may include Article 6(1)(b), 6(1)(c), and 6(1)(f) GDPR, depending on context.
</p>
<p>
Personal data is disclosed only where legally required, needed for the establishment, exercise, or defence of legal claims, or
explicitly initiated by you.
</p>
<p>
Data is stored only as long as required for communication, request handling, and legal retention duties.
</p>
</div>
</div>
</section>
<section class="story-section panel legal-section">
<div class="section-heading compact">
<p class="eyebrow">Rights</p>
<h2>Data Subject Rights And Complaints</h2>
</div> </div>
<div class="legal-block"> <div class="story-grid">
<h2>Liability for Content and External Links</h2> <div class="story-copy">
<p> <p>
Great care is taken when creating and maintaining this website. However, no liability is accepted for external websites linked from Subject to statutory requirements, data subjects have the right of access, rectification, erasure, restriction of processing, data
this page. The respective operators are solely responsible for linked content. portability, and objection.
</p> </p>
</div>
<div class="story-detail">
<p>
Complaints can be submitted to the Austrian Data Protection Authority: Barichgasse 40-42, 1030 Vienna, email
<a class="inline-link" href="mailto:dsb@dsb.gv.at">dsb@dsb.gv.at</a>, website
<a class="inline-link" href="https://dsb.gv.at/">dsb.gv.at</a>.
</p>
</div>
</div>
</section>
<section class="story-section panel legal-section">
<div class="section-heading compact">
<p class="eyebrow">Copyright</p>
<h2>Copyright, External Links, And Applicable Law</h2>
</div> </div>
<div class="legal-block"> <div class="story-grid">
<h2>Copyright</h2> <div class="story-copy">
<p> <p>
All content on this website (including text, images, and layout) is protected by copyright law. Any use beyond statutory exceptions All content on this website, including texts, images, graphics, photographs, layouts, source code, and other works, is protected
requires prior written permission. by copyright unless stated otherwise. All rights remain reserved.
</p> </p>
</div> <p>
Any use beyond statutory exceptions requires prior written consent of the respective rights holder.
</p>
</div>
<div class="legal-block"> <div class="story-detail">
<h2>Privacy (GDPR / DSGVO)</h2> <p>
<p> This website may contain links to third-party websites. Their operators are solely responsible for those contents, and no liability
This website can generally be used without submitting personal data. If you contact me by e-mail, your data is processed only to is accepted for external links to the extent permitted by law.
handle your request and is not shared without a valid legal basis. </p>
</p> <p>
<p> Austrian law applies exclusively, excluding conflict-of-law rules that would refer to another legal system, unless mandatory
You may exercise your data subject rights (access, rectification, erasure, restriction, objection) via the contact details listed consumer protection provisions require otherwise.
above. </p>
</p> </div>
</div> </div>
</section> </section>
</main> </main>
+12
View File
@@ -20,6 +20,8 @@ export class ImprintComponent implements OnInit {
private readonly sanitizer = inject(DomSanitizer); private readonly sanitizer = inject(DomSanitizer);
protected readonly global: Global = global; protected readonly global: Global = global;
protected readonly displayStreet: string = this.normalizeText(global.address.street);
protected readonly displayCity: string = this.normalizeText(global.address.city);
protected contactSafeMail!: SafeUrl; protected contactSafeMail!: SafeUrl;
protected abuseSafeMail!: SafeUrl; protected abuseSafeMail!: SafeUrl;
@@ -30,4 +32,14 @@ export class ImprintComponent implements OnInit {
this.contactSafeMail = this.sanitizer.bypassSecurityTrustUrl(`mailto:${global.contactMail}`); this.contactSafeMail = this.sanitizer.bypassSecurityTrustUrl(`mailto:${global.contactMail}`);
this.abuseSafeMail = this.sanitizer.bypassSecurityTrustUrl(`mailto:${this.global.abuseMail}`); this.abuseSafeMail = this.sanitizer.bypassSecurityTrustUrl(`mailto:${this.global.abuseMail}`);
} }
private normalizeText(value: string): string {
return value
.replaceAll('ß', 'ß')
.replaceAll('ö', 'ö')
.replaceAll('Ä', 'Ä')
.replaceAll('ä', 'ä')
.replaceAll('Ü', 'Ü')
.replaceAll('ü', 'ü');
}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 KiB

+6
View File
@@ -6,6 +6,8 @@ export interface PortfolioProject {
icon?: string; icon?: string;
iconSrcset?: string; iconSrcset?: string;
iconSizes?: string; iconSizes?: string;
iconWidth?: number;
iconHeight?: number;
CircleIcon?: boolean; CircleIcon?: boolean;
} }
@@ -163,6 +165,8 @@ export const global: Global = {
iconSrcset: iconSrcset:
'assets/optimized/logos/synhost-64.webp 64w, assets/optimized/logos/synhost-128.webp 128w, assets/optimized/logos/synhost.webp 216w', 'assets/optimized/logos/synhost-64.webp 64w, assets/optimized/logos/synhost-128.webp 128w, assets/optimized/logos/synhost.webp 216w',
iconSizes: '(max-width: 700px) 64px, 108px', iconSizes: '(max-width: 700px) 64px, 108px',
iconWidth: 108,
iconHeight: 64,
CircleIcon: false, CircleIcon: false,
}, },
{ {
@@ -199,6 +203,8 @@ export const global: Global = {
iconSrcset: iconSrcset:
'assets/optimized/portrait/me-64.webp 64w, assets/optimized/portrait/me-128.webp 128w, assets/optimized/portrait/me.webp 216w', 'assets/optimized/portrait/me-64.webp 64w, assets/optimized/portrait/me-128.webp 128w, assets/optimized/portrait/me.webp 216w',
iconSizes: '(max-width: 700px) 64px, 108px', iconSizes: '(max-width: 700px) 64px, 108px',
iconWidth: 320,
iconHeight: 385,
CircleIcon: true, CircleIcon: true,
}, },
{ {
+7 -47
View File
@@ -15,54 +15,14 @@
<body> <body>
<app-root></app-root> <app-root></app-root>
<script src='https://storage.ko-fi.com/cdn/scripts/overlay-widget.js'></script>
<script> <script>
(() => { kofiWidgetOverlay.draw('fraujulian', {
const widgetTitle = 'Ko-fi donation chat'; 'type': 'floating-chat',
let hasLoadedWidget = false; 'floating-chat.donateButton.text': 'Coffee',
'floating-chat.donateButton.background-color': '#ff5f5f',
const titleKofiFrames = () => { 'floating-chat.donateButton.text-color': '#fff'
document.querySelectorAll('iframe[id^="kofi-wo-container"]').forEach((frame) => { });
frame.setAttribute('title', widgetTitle);
});
};
const drawWidget = () => {
window.kofiWidgetOverlay.draw('fraujulian', {
type: 'floating-chat',
'floating-chat.donateButton.text': 'Tip me',
'floating-chat.donateButton.background-color': '#ff5f5f',
'floating-chat.donateButton.text-color': '#fff',
});
window.setTimeout(titleKofiFrames, 300);
};
const loadWidget = () => {
if (hasLoadedWidget) {
return;
}
hasLoadedWidget = true;
const script = document.createElement('script');
script.src = 'https://storage.ko-fi.com/cdn/scripts/overlay-widget.js';
script.async = true;
script.onload = drawWidget;
document.body.appendChild(script);
};
window.addEventListener(
'load',
() => {
const observer = new MutationObserver(titleKofiFrames);
observer.observe(document.body, { childList: true, subtree: true });
window.addEventListener('pointerdown', loadWidget, { once: true, passive: true });
window.addEventListener('touchstart', loadWidget, { once: true, passive: true });
window.addEventListener('scroll', loadWidget, { once: true, passive: true });
window.addEventListener('keydown', loadWidget, { once: true });
},
{ once: true },
);
})();
</script> </script>
</body> </body>
</html> </html>
+22 -63
View File
@@ -191,9 +191,7 @@ hr {
.legal-intro, .legal-intro,
.project-description, .project-description,
.story-copy p, .story-copy p,
.detail-panel p, .detail-panel p {
.legal-copy p,
.legal-card p {
color: var(--text-muted); color: var(--text-muted);
line-height: 1.75; line-height: 1.75;
} }
@@ -473,8 +471,7 @@ hr {
.story-section, .story-section,
.contact-strip, .contact-strip,
.legal-hero, .legal-hero {
.legal-copy {
margin-top: var(--space-5); margin-top: var(--space-5);
padding: clamp(1.5rem, 3vw, 2.5rem); padding: clamp(1.5rem, 3vw, 2.5rem);
} }
@@ -513,14 +510,12 @@ hr {
} }
.story-copy p:first-child, .story-copy p:first-child,
.detail-panel p:first-child, .detail-panel p:first-child {
.legal-copy p:first-child {
margin-top: 0; margin-top: 0;
} }
.story-copy p:last-child, .story-copy p:last-child,
.detail-panel p:last-child, .detail-panel p:last-child {
.legal-copy p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@@ -791,7 +786,7 @@ hr {
.project-icon { .project-icon {
width: clamp(84px, 12vw, 108px); width: clamp(84px, 12vw, 108px);
min-width: clamp(84px, 12vw, 108px); min-width: clamp(84px, 12vw, 108px);
height: clamp(84px, 12vw, 108px); height: auto;
object-fit: contain; object-fit: contain;
object-position: center; object-position: center;
box-shadow: none; box-shadow: none;
@@ -806,19 +801,8 @@ hr {
gap: var(--space-5); gap: var(--space-5);
} }
.imprint-page a {
color: #5ca8ff;
text-decoration: underline;
text-decoration-thickness: 1.5px;
text-underline-offset: 2px;
}
.imprint-page a:hover {
color: #8bc2ff;
}
.legal-hero .back-link { .legal-hero .back-link {
margin-bottom: var(--space-5); margin-bottom: 0;
} }
.legal-hero h1 { .legal-hero h1 {
@@ -833,54 +817,30 @@ hr {
line-height: 1.8; line-height: 1.8;
} }
.legal-grid { .legal-section {
display: grid; margin-top: var(--space-5);
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-4);
}
.legal-card {
padding: clamp(1.4rem, 3vw, 2rem);
} }
.legal-provider-name { .legal-provider-name {
margin: 0 0 0.6rem; margin: 0;
font-size: clamp(1.35rem, 1.8vw, 1.7rem); font-size: 1.1rem;
font-weight: 650; font-weight: 700;
letter-spacing: -0.02em; letter-spacing: 0;
color: var(--text-primary); color: var(--text-primary);
} }
.legal-card p { .legal-contact-box {
margin: 0 0 0.45rem;
line-height: 1.5;
}
.legal-row:last-child {
margin-bottom: 0;
}
.legal-copy p {
margin: 0 0 var(--space-3);
}
.legal-copy {
display: grid; display: grid;
gap: var(--space-4); gap: 0.5rem;
padding: clamp(1.7rem, 3vw, 2.6rem); width: 100%;
justify-items: start;
text-align: left;
} }
.legal-block { .legal-contact-box p {
padding: var(--space-4); margin: 0;
border: 1px solid var(--border-soft); color: var(--text-muted);
border-radius: var(--radius-md); line-height: 1.6;
background: rgba(255, 255, 255, 0.03);
}
.legal-block h2 {
margin: 0 0 var(--space-3);
font-size: clamp(1.4rem, 2.5vw, 2rem);
letter-spacing: -0.03em;
} }
.site-footer { .site-footer {
@@ -922,7 +882,6 @@ hr {
@media (max-width: 900px) { @media (max-width: 900px) {
.hero-section, .hero-section,
.story-grid, .story-grid,
.legal-grid,
.project-entry, .project-entry,
.project-entry-reverse { .project-entry-reverse {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@@ -1017,7 +976,7 @@ hr {
.project-icon { .project-icon {
width: 64px; width: 64px;
min-width: 64px; min-width: 64px;
height: 64px; height: auto;
align-self: start; align-self: start;
} }