diff --git a/flightscore/src/components/icon-card.ts b/flightscore/src/components/icon-card.ts new file mode 100644 index 0000000..61142c5 --- /dev/null +++ b/flightscore/src/components/icon-card.ts @@ -0,0 +1,79 @@ +// components/icon-card.ts +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +@customElement('icon-card') +export class IconCard extends LitElement { + static styles = css` + :host { + display: block; + } + + .card { + background: var(--color-bg-nav); + border: 1px solid var(--color-border); + border-radius: 0.75rem; + padding: 1.75rem; + display: flex; + flex-direction: column; + gap: 0.75rem; + transition: border-color 0.25s ease; + } + + .card:hover { + border-color: color-mix( + in srgb, + var(--color-accent) 40%, + transparent + ); + } + + .icon { + width: 2.25rem; + height: 2.25rem; + display: grid; + place-items: center; + border-radius: 0.5rem; + background: color-mix( + in srgb, + var(--color-accent) 10%, + transparent + ); + color: var(--color-accent); + } + + ::slotted(svg) { + width: 1.15rem; + height: 1.15rem; + } + + h3 { + margin: 0; + font-size: 1rem; + font-weight: 650; + color: var(--color-text); + } + + p { + margin: 0; + font-size: 0.875rem; + line-height: 1.6; + color: color-mix(in srgb, var(--color-text) 55%, transparent); + } + `; + + @property() heading = ''; + @property() description = ''; + + render() { + return html` +
+
+ +
+

${this.heading}

+

${this.description}

+
+ `; + } +} \ No newline at end of file diff --git a/flightscore/src/components/stat-card.ts b/flightscore/src/components/stat-card.ts new file mode 100644 index 0000000..84dbd7f --- /dev/null +++ b/flightscore/src/components/stat-card.ts @@ -0,0 +1,56 @@ +// components/stat-card.ts +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +@customElement('stat-card') +export class StatCard extends LitElement { + static styles = css` + :host { + display: block; + } + + .card { + background: var(--color-bg-nav); + border: 1px solid var(--color-border); + border-radius: 0.75rem; + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.25rem; + transition: border-color 0.25s ease; + } + + .card:hover { + border-color: color-mix( + in srgb, + var(--color-accent) 40%, + transparent + ); + } + + .value { + font-size: 2rem; + font-weight: 800; + letter-spacing: -0.03em; + color: var(--color-accent); + } + + .label { + font-size: 0.85rem; + color: color-mix(in srgb, var(--color-text) 55%, transparent); + font-weight: 500; + } + `; + + @property() value = ''; + @property() label = ''; + + render() { + return html` +
+ ${this.value} + ${this.label} +
+ `; + } +} \ No newline at end of file diff --git a/flightscore/src/components/ui-badge.ts b/flightscore/src/components/ui-badge.ts new file mode 100644 index 0000000..4bcbdd6 --- /dev/null +++ b/flightscore/src/components/ui-badge.ts @@ -0,0 +1,79 @@ +// components/ui-badge.ts +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +export type BadgeVariant = 'accent' | 'success' | 'warning' | 'muted' | 'error'; + +@customElement('ui-badge') +export class UiBadge extends LitElement { + static styles = css` + :host { + display: inline-flex; + } + + .badge { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.3rem 0.75rem; + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.03em; + text-transform: uppercase; + border-radius: 2rem; + border: 1px solid transparent; + white-space: nowrap; + } + + .badge.accent { + color: var(--color-accent); + background: color-mix(in srgb, var(--color-accent) 10%, transparent); + border-color: color-mix( + in srgb, + var(--color-accent) 25%, + transparent + ); + } + + .badge.success { + color: #30a46c; + background: color-mix(in srgb, #30a46c 10%, transparent); + border-color: color-mix(in srgb, #30a46c 25%, transparent); + } + + .badge.warning { + color: #e79d13; + background: color-mix(in srgb, #e79d13 10%, transparent); + border-color: color-mix(in srgb, #e79d13 25%, transparent); + } + + .badge.muted { + color: color-mix(in srgb, var(--color-text) 45%, transparent); + background: color-mix(in srgb, var(--color-text) 6%, transparent); + border-color: var(--color-border); + } + + .badge.error { + color: #e5484d; + background: color-mix(in srgb, #e5484d 10%, transparent); + border-color: color-mix(in srgb, #e5484d 25%, transparent); + } + + + ::slotted(svg) { + width: 0.85rem; + height: 0.85rem; + flex-shrink: 0; + } + `; + + @property() variant: BadgeVariant = 'accent'; + + render() { + return html` + + + + `; + } +} \ No newline at end of file diff --git a/flightscore/src/components/ui-button-secondary.ts b/flightscore/src/components/ui-button-secondary.ts new file mode 100644 index 0000000..c398b41 --- /dev/null +++ b/flightscore/src/components/ui-button-secondary.ts @@ -0,0 +1,72 @@ +// components/ui-button-secondary.ts +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +@customElement('ui-button-secondary') +export class UiButtonSecondary extends LitElement { + static styles = css` + :host { + display: inline-flex; + } + + :host([full]) { + display: flex; + } + + :host([full]) button { + width: 100%; + } + + button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.45rem; + padding: 0.65rem 1.25rem; + font-size: 0.95rem; + font-weight: 600; + color: var(--color-text); + background: transparent; + border: 1px solid var(--color-border); + border-radius: 0.5rem; + cursor: pointer; + transition: + border-color 0.25s ease, + color 0.25s ease, + background 0.25s ease, + transform 0.15s ease; + } + + button:hover:not(:disabled) { + border-color: var(--color-accent); + color: var(--color-accent); + background: color-mix(in srgb, var(--color-accent) 6%, transparent); + } + + button:active:not(:disabled) { + transform: scale(0.98); + } + + button:disabled { + opacity: 0.55; + cursor: not-allowed; + } + + ::slotted(svg) { + width: 1rem; + height: 1rem; + flex-shrink: 0; + } + `; + + @property({ type: Boolean }) disabled = false; + @property({ type: Boolean, reflect: true }) full = false; + + render() { + return html` + + `; + } +} \ No newline at end of file diff --git a/flightscore/src/pages/home-page.ts b/flightscore/src/pages/home-page.ts index afc691d..592f851 100644 --- a/flightscore/src/pages/home-page.ts +++ b/flightscore/src/pages/home-page.ts @@ -1,7 +1,11 @@ +// pages/home/home-page.ts (updated) import { LitElement, html, css } from 'lit'; import { customElement } from 'lit/decorators.js'; -import '../components/ui-card'; import '../components/ui-button'; +import '../components/ui-button-secondary'; +import '../components/ui-badge'; +import '../components/stat-card'; +import '../components/icon-card'; import '../components/ui-link'; @customElement('home-page') @@ -45,29 +49,8 @@ export class HomePage extends LitElement { background: var(--color-border); } - .hero-badge { - display: inline-flex; - align-items: center; - gap: 0.4rem; - padding: 0.35rem 0.85rem; - font-size: 0.78rem; - font-weight: 600; - letter-spacing: 0.03em; - text-transform: uppercase; - color: var(--color-accent); - background: color-mix(in srgb, var(--color-accent) 10%, transparent); - border: 1px solid color-mix(in srgb, var(--color-accent) 25%, transparent); - border-radius: 2rem; - margin-bottom: 1.5rem; - } - - .hero-badge svg { - width: 0.85rem; - height: 0.85rem; - } - .hero h1 { - margin: 0; + margin: 1.5rem 0 0; font-size: clamp(2.2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; @@ -102,30 +85,6 @@ export class HomePage extends LitElement { justify-content: center; } - .btn-secondary { - display: inline-flex; - align-items: center; - gap: 0.4rem; - padding: 0.65rem 1.25rem; - font-size: 0.95rem; - font-weight: 600; - color: var(--color-text); - background: transparent; - border: 1px solid var(--color-border); - border-radius: 0.5rem; - cursor: pointer; - transition: - border-color 0.25s ease, - color 0.25s ease, - background 0.25s ease; - } - - .btn-secondary:hover { - border-color: var(--color-accent); - color: var(--color-accent); - background: color-mix(in srgb, var(--color-accent) 6%, transparent); - } - section { padding: 4rem 1.5rem; max-width: 1100px; @@ -168,84 +127,12 @@ export class HomePage extends LitElement { gap: 1rem; } - .stat-card { - background: var(--color-bg-nav); - border: 1px solid var(--color-border); - border-radius: 0.75rem; - padding: 1.5rem; - display: flex; - flex-direction: column; - gap: 0.25rem; - transition: border-color 0.25s ease; - } - - .stat-card:hover { - border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); - } - - .stat-value { - font-size: 2rem; - font-weight: 800; - letter-spacing: -0.03em; - color: var(--color-accent); - } - - .stat-label { - font-size: 0.85rem; - color: color-mix(in srgb, var(--color-text) 55%, transparent); - font-weight: 500; - } - .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; } - .feature-card { - background: var(--color-bg-nav); - border: 1px solid var(--color-border); - border-radius: 0.75rem; - padding: 1.75rem; - display: flex; - flex-direction: column; - gap: 0.75rem; - transition: border-color 0.25s ease; - } - - .feature-card:hover { - border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); - } - - .feature-icon { - width: 2.25rem; - height: 2.25rem; - display: grid; - place-items: center; - border-radius: 0.5rem; - background: color-mix(in srgb, var(--color-accent) 10%, transparent); - color: var(--color-accent); - } - - .feature-icon svg { - width: 1.15rem; - height: 1.15rem; - } - - .feature-card h3 { - margin: 0; - font-size: 1rem; - font-weight: 650; - color: var(--color-text); - } - - .feature-card p { - margin: 0; - font-size: 0.875rem; - line-height: 1.6; - color: color-mix(in srgb, var(--color-text) 55%, transparent); - } - .competitions-list { display: flex; flex-direction: column; @@ -265,7 +152,11 @@ export class HomePage extends LitElement { } .comp-row:hover { - border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); + border-color: color-mix( + in srgb, + var(--color-accent) 40%, + transparent + ); } .comp-date { @@ -274,7 +165,11 @@ export class HomePage extends LitElement { align-items: center; min-width: 3.5rem; padding: 0.5rem 0.65rem; - background: color-mix(in srgb, var(--color-accent) 10%, transparent); + background: color-mix( + in srgb, + var(--color-accent) 10%, + transparent + ); border-radius: 0.5rem; flex-shrink: 0; } @@ -322,35 +217,6 @@ export class HomePage extends LitElement { flex-shrink: 0; } - .comp-badge { - font-size: 0.72rem; - font-weight: 600; - letter-spacing: 0.03em; - text-transform: uppercase; - padding: 0.3rem 0.7rem; - border-radius: 2rem; - flex-shrink: 0; - } - - .comp-badge.upcoming { - color: var(--color-accent); - background: color-mix(in srgb, var(--color-accent) 10%, transparent); - border: 1px solid - color-mix(in srgb, var(--color-accent) 25%, transparent); - } - - .comp-badge.live { - color: #30a46c; - background: color-mix(in srgb, #30a46c 10%, transparent); - border: 1px solid color-mix(in srgb, #30a46c 25%, transparent); - } - - .comp-badge.ended { - color: color-mix(in srgb, var(--color-text) 45%, transparent); - background: color-mix(in srgb, var(--color-text) 6%, transparent); - border: 1px solid var(--color-border); - } - @media (max-width: 600px) { .hero { padding: 3.5rem 1.25rem 3rem; @@ -364,10 +230,6 @@ export class HomePage extends LitElement { flex-wrap: wrap; gap: 0.75rem; } - - .comp-badge { - margin-left: auto; - } } `; @@ -384,29 +246,28 @@ export class HomePage extends LitElement { render() { return html`
-
- + + Live Scoring Platform -
+

Precision scoring for balloon competitions

- Track tasks, manage participants, and deliver real-time results - for hot air balloon competitions worldwide. + Track tasks, manage participants, and deliver real-time + results for hot air balloon competitions worldwide.

this.navigate('/competitions')}> Browse competitions - +
@@ -417,22 +278,13 @@ export class HomePage extends LitElement { FlightScore powers balloon competitions across the globe.

-
- 42 - Competitions scored -
-
- 318 - Registered pilots -
-
- 1,240 - Tasks completed -
-
- 12 - Countries -
+ + + +
@@ -443,92 +295,68 @@ export class HomePage extends LitElement { Everything organizers, judges, and pilots need in one place.

-
-
- - - - -
-

Real-Time Scoring

-

- Scores update live as judges submit results. Pilots and - spectators always see the latest standings. -

-
-
-
- - - - - - - -
-

Task Management

-

- Define and manage competition tasks with support for all - standard ballooning task types. -

-
-
-
- - - - - - -
-

Pilot Profiles

-

- Every pilot gets a profile with competition history, - rankings, and performance statistics. -

-
-
-
- - - - - - -
-

Live Leaderboard

-

- Public leaderboards let spectators follow the action - from anywhere in the world. -

-
-
-
- - - - -
-

GPS Integration

-

- Import GPS tracks and calculate distances to targets - automatically for precise scoring. -

-
-
-
- - - - - -
-

Result Export

-

- Export final standings and detailed score sheets as PDF - or CSV for official records. -

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -548,9 +376,9 @@ export class HomePage extends LitElement { Mar
- European Balloon Challenge 2026 + + European Balloon Challenge 2026 + @@ -559,7 +387,7 @@ export class HomePage extends LitElement { Salzburg, Austria
- Upcoming + Upcoming
- Live + Live
Feb
- Albuquerque Winter Fiesta + + Albuquerque Winter Fiesta + @@ -603,7 +431,7 @@ export class HomePage extends LitElement { New Mexico, USA
- Ended + Ended
Jan
- Swiss Alpine Balloon Trophy + + Swiss Alpine Balloon Trophy + @@ -626,7 +454,7 @@ export class HomePage extends LitElement { Chateau-d'Oex, Switzerland
- Ended + Canceled