Extracted the button into own component

This commit is contained in:
CodingPhoenixx
2026-02-12 15:00:47 +01:00
parent 49bf7522b9
commit 7a69e4a4ea
5 changed files with 114 additions and 37 deletions
+4 -3
View File
@@ -1,6 +1,7 @@
import { LitElement, html, css, unsafeCSS } from 'lit'; import { LitElement, html, css, unsafeCSS } from 'lit';
import { customElement } from 'lit/decorators.js'; import { customElement } from 'lit/decorators.js';
import styles from './footer-bar.css?inline'; import styles from './footer-bar.css?inline';
import './ui-link';
@customElement('footer-bar') @customElement('footer-bar')
export class FooterBar extends LitElement { export class FooterBar extends LitElement {
@@ -12,9 +13,9 @@ export class FooterBar extends LitElement {
return html` return html`
<footer> <footer>
<div class="center"> <div class="center">
<a href="/privacy" @click=${(e: Event) => e.preventDefault()}>Privacy</a> <ui-link href="/privacy">Privacy</ui-link>
<a href="/imprint" @click=${(e: Event) => e.preventDefault()}>Imprint</a> <ui-link href="/imprint">Imprint</ui-link>
<a href="/contact" @click=${(e: Event) => e.preventDefault()}>Contact</a> <ui-link href="/contact">Contact</ui-link>
</div> </div>
<div class="right"> <div class="right">
<span>© ${year} Jan Meinl</span> <span>© ${year} Jan Meinl</span>
+26 -31
View File
@@ -1,52 +1,47 @@
import { LitElement, html, css, unsafeCSS } from 'lit'; import { LitElement, html, css, unsafeCSS } from 'lit';
import { customElement, state } from 'lit/decorators.js'; import { customElement, state } from 'lit/decorators.js';
import styles from './nav-bar.css?inline'; import styles from './nav-bar.css?inline';
import './ui-link';
@customElement('nav-bar') @customElement('nav-bar')
export class NavBar extends LitElement { export class NavBar extends LitElement {
static styles = css`${unsafeCSS(styles)}`; static styles = css`${unsafeCSS(styles)}`;
@state() theme: 'light' | 'dark' = @state() theme: 'light' | 'dark' =
(localStorage.getItem('theme') as 'light' | 'dark') || (localStorage.getItem('theme') as 'light' | 'dark') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches (window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' ? 'dark'
: 'light'); : 'light');
firstUpdated() { firstUpdated() {
document.documentElement.setAttribute('data-theme', this.theme); document.documentElement.setAttribute('data-theme', this.theme);
} }
toggleTheme() { toggleTheme() {
this.theme = this.theme === 'light' ? 'dark' : 'light'; this.theme = this.theme === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', this.theme); document.documentElement.setAttribute('data-theme', this.theme);
localStorage.setItem('theme', this.theme); localStorage.setItem('theme', this.theme);
} }
navigate(path: string) { navigate(path: string) {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('nav', { detail: { path }, bubbles: true, composed: true }) new CustomEvent('nav', { detail: { path }, bubbles: true, composed: true })
); );
} }
render() { render() {
return html` return html`
<nav> <nav>
<div class="brand"><img src="/logo.svg" alt="Flight Score Logo" /> FlightScore</div> <div class="brand"><img src="/logo.svg" alt="Flight Score Logo" /> FlightScore</div>
<div class="links"> <div class="links">
<a href="/" @click=${(e: Event) => (e.preventDefault(), this.navigate('/'))}> <ui-link href="/">Home</ui-link>
Home <ui-link href="/competitions">Competitions</ui-link>
</a>
<a
href="/competitions"
@click=${(e: Event) => (e.preventDefault(), this.navigate('/competitions'))}
>
Competitions
</a>
<button @click=${this.toggleTheme}> <button @click=${this.toggleTheme}>
${this.theme === 'light' ? '🌙 Dark' : '☀️ Light'} ${this.theme === 'light' ? '🌙 Dark' : '☀️ Light'}
</button> </button>
</div> </div>
</nav> </nav>
`; `;
} }
} }
+28
View File
@@ -0,0 +1,28 @@
a {
position: relative;
color: var(--color-text);
font-weight: 500;
text-decoration: none;
transition: color 0.25s ease;
display: inline-block;
}
a::after {
content: '';
position: absolute;
left: 0;
bottom: -2px;
width: 0%;
height: 2px;
background: var(--color-accent);
transition: width 0.3s ease;
}
a:hover::after,
a.active::after {
width: 100%;
}
a.active {
color: var(--color-accent);
}
+34
View File
@@ -0,0 +1,34 @@
import { LitElement, html, css, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import styles from './ui-link.css?inline';
@customElement('ui-link')
export class UiLink extends LitElement {
static styles = css`${unsafeCSS(styles)}`;
@property() href = '/';
@property({ type: Boolean }) active = false;
navigate(e: Event) {
e.preventDefault();
this.dispatchEvent(
new CustomEvent('nav', {
detail: { path: this.href },
bubbles: true,
composed: true,
})
);
}
render() {
return html`
<a
href=${this.href}
class=${this.active ? 'active' : ''}
@click=${this.navigate}
>
<slot></slot>
</a>
`;
}
}
+22 -3
View File
@@ -1,12 +1,31 @@
import { LitElement, html } from 'lit'; import { LitElement, html, css } from 'lit';
import { customElement } from 'lit/decorators.js'; import { customElement } from 'lit/decorators.js';
@customElement('not-found-page') @customElement('not-found-page')
export class NotFoundPage extends LitElement { export class NotFoundPage extends LitElement {
static styles = css`
div {
padding-top: 4rem;
* {
width: fit-content;
margin: auto auto;
padding-bottom: 1rem;
}
}
`;
navigate(path: string) {
this.dispatchEvent(
new CustomEvent('nav', { detail: { path }, bubbles: true, composed: true })
);
}
render() { render() {
return html` return html`
<h1>404 Not Found</h1> <div>
<p>How did you get here?</p> <h1>404 Not Found</h1>
<p><ui-link href="/">Here</ui-link>you can get back.</p>
</div>
`; `;
} }
} }