Added a competition page
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
@customElement('competition-page')
|
||||
export class CompetitionPage extends LitElement {
|
||||
render() {
|
||||
return html`
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
<h1>Welcome to the Competitions</h1>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
// pages/competition-page.ts
|
||||
import { LitElement, html, css, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import type { Tab } from "../../components/ui-tab-bar.js";
|
||||
import "../../components/ui-tab-bar.js";
|
||||
|
||||
type TabModule = { default: () => unknown };
|
||||
|
||||
const TAB_LOADERS: Record<string, () => Promise<TabModule>> = {
|
||||
details: () => import("./tabs/competition-details.js"),
|
||||
results: () => import("./tabs/competition-results.js"),
|
||||
tasks: () => import("./tabs/competition-tasks.js"),
|
||||
noticeboard: () => import("./tabs/competition-noticeboard.js"),
|
||||
pilots: () => import("./tabs/competition-pilots.js"),
|
||||
officials: () => import("./tabs/competition-officials.js"),
|
||||
};
|
||||
|
||||
@customElement("competition-page")
|
||||
export class CompetitionPage extends LitElement {
|
||||
@state() private activeTab = "details";
|
||||
@state() private loadedTabs = new Set<string>();
|
||||
@state() private loadingTab = "";
|
||||
|
||||
private tabs: Tab[] = [
|
||||
{ id: "details", label: "Event Details", icon: "calendar" },
|
||||
{ id: "results", label: "Results", icon: "trophy" },
|
||||
{ id: "tasks", label: "Task Data", icon: "target" },
|
||||
{ id: "noticeboard", label: "Noticeboard", icon: "clipboard" },
|
||||
{ id: "pilots", label: "Pilots", icon: "users" },
|
||||
{ id: "officials", label: "Officials", icon: "user" },
|
||||
];
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1e3a5f 0%, #2563eb 100%);
|
||||
color: white;
|
||||
padding: 3rem 1.5rem 2rem;
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.breadcrumb a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.breadcrumb span {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.hero-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.hero-meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.hero-meta-item svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4rem;
|
||||
color: color-mix(in srgb, var(--color-text) 45%, transparent);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border: 2px solid var(--color-border);
|
||||
border-top-color: var(--color-accent);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.loadTab(this.activeTab);
|
||||
}
|
||||
|
||||
private async loadTab(id: string) {
|
||||
if (this.loadedTabs.has(id)) return;
|
||||
|
||||
const loader = TAB_LOADERS[id];
|
||||
if (!loader) return;
|
||||
|
||||
this.loadingTab = id;
|
||||
try {
|
||||
await loader();
|
||||
this.loadedTabs = new Set([...this.loadedTabs, id]);
|
||||
} catch (e) {
|
||||
console.error(`Failed to load tab "${id}":`, e);
|
||||
} finally {
|
||||
this.loadingTab = "";
|
||||
}
|
||||
}
|
||||
|
||||
private handleTabChange(e: CustomEvent<{ tab: string }>) {
|
||||
this.activeTab = e.detail.tab;
|
||||
this.loadTab(e.detail.tab);
|
||||
}
|
||||
|
||||
private renderTabContent() {
|
||||
if (this.loadingTab === this.activeTab) {
|
||||
return html`
|
||||
<div class="loading">
|
||||
<div class="spinner"></div>
|
||||
Loading…
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
switch (this.activeTab) {
|
||||
case "details":
|
||||
return html`<competition-details></competition-details>`;
|
||||
case "results":
|
||||
return html`<competition-results></competition-results>`;
|
||||
case "tasks":
|
||||
return html`<competition-tasks></competition-tasks>`;
|
||||
case "noticeboard":
|
||||
return html`<competition-noticeboard></competition-noticeboard>`;
|
||||
case "pilots":
|
||||
return html`<competition-pilots></competition-pilots>`;
|
||||
case "officials":
|
||||
return html`<competition-officials></competition-officials>`;
|
||||
default:
|
||||
return nothing;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="hero">
|
||||
<div class="hero-inner">
|
||||
<div class="breadcrumb">
|
||||
<a href="/">Home</a>
|
||||
<span>/</span>
|
||||
<a href="/competitions">Competitions</a>
|
||||
<span>/</span>
|
||||
<span
|
||||
>22. Schweizermeisterschaften Heissluftballon / Swiss
|
||||
Cup</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<h1>
|
||||
22. Schweizermeisterschaften Heissluftballon / Swiss Cup
|
||||
</h1>
|
||||
|
||||
<div class="hero-meta">
|
||||
<div class="hero-meta-item">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1 1 15 0Z"
|
||||
/>
|
||||
</svg>
|
||||
Langenthal / BE, Switzerland
|
||||
</div>
|
||||
<div class="hero-meta-item">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5"
|
||||
/>
|
||||
</svg>
|
||||
13 – 17 May 2026
|
||||
</div>
|
||||
<ui-badge variant="accent">CAT2</ui-badge>
|
||||
<ui-badge variant="success">Upcoming</ui-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ui-tab-bar
|
||||
.tabs=${this.tabs}
|
||||
.active=${this.activeTab}
|
||||
@tab-change=${this.handleTabChange}
|
||||
></ui-tab-bar>
|
||||
|
||||
<div class="tab-content">${this.renderTabContent()}</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
// tabs/competition-details.ts
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-details")
|
||||
export class CompetitionDetails extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 380px;
|
||||
gap: 1.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.main-card {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-date {
|
||||
padding: 1rem 1.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
color: color-mix(in srgb, var(--color-text) 65%, transparent);
|
||||
}
|
||||
|
||||
.card-body a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card-body a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-card-header {
|
||||
padding: 1rem 1.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.sidebar-card-header svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.sidebar-card-body {
|
||||
padding: 1.25rem 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: color-mix(in srgb, var(--color-text) 65%, transparent);
|
||||
}
|
||||
|
||||
.detail-row svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-accent);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-row a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.detail-row a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="layout">
|
||||
<div>
|
||||
<div class="main-card">
|
||||
<div class="card-date">13 May 2026 – 17 May 2026</div>
|
||||
<div class="card-body">
|
||||
<span>Schweizermeisterschaften 2026</span>
|
||||
<span>Open Swiss Nationals & Swiss Cup</span>
|
||||
<span
|
||||
>Location: Berufsfachschule BZL Langenthal</span
|
||||
>
|
||||
<span
|
||||
>Official announcement can be found in the
|
||||
<a href="#">ENB</a></span
|
||||
>
|
||||
<span
|
||||
>Registration via
|
||||
<a
|
||||
href="https://www.smhl.ch/de/registration"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>https://www.smhl.ch/de/registration</a
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-row">
|
||||
<stat-card value="32" label="Registered Pilots"></stat-card>
|
||||
<stat-card value="12" label="Tasks Planned"></stat-card>
|
||||
<stat-card value="5" label="Days"></stat-card>
|
||||
<stat-card value="CAT2" label="FAI Category"></stat-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-card">
|
||||
<div class="sidebar-card-header">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.049.58.025 1.193-.14 1.743"/></svg>
|
||||
Competition Details
|
||||
</div>
|
||||
<div class="sidebar-card-body">
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/></svg>
|
||||
Director: Claude Weber
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5a17.92 17.92 0 0 1-8.716-2.247m0 0A8.966 8.966 0 0 1 3 12c0-1.264.26-2.467.73-3.56"/></svg>
|
||||
FAI sanctioned – CAT2 / CIA Sporting event
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25A2.25 2.25 0 0 1 5.25 3h13.5A2.25 2.25 0 0 1 21 5.25Z"/></svg>
|
||||
Combined Logger/Marker Event
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-card">
|
||||
<div class="sidebar-card-header">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"/></svg>
|
||||
Contact Details
|
||||
</div>
|
||||
<div class="sidebar-card-body">
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/></svg>
|
||||
Werner BEYELER
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/></svg>
|
||||
<a href="#" target="_blank" rel="noopener">Website</a>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"/></svg>
|
||||
<a href="mailto:bewerner@bluewin.ch">bewerner@bluewin.ch</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionDetails;
|
||||
@@ -0,0 +1,42 @@
|
||||
// tabs/competition-noticeboard.ts
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-noticeboard")
|
||||
export class CompetitionNoticeboard extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
color: color-mix(in srgb, var(--color-text) 55%, transparent);
|
||||
}
|
||||
|
||||
.placeholder p:first-child {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder p:last-child {
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<p>Noticeboard</p>
|
||||
<p>Content will appear here once the competition is underway.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionNoticeboard;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-officials")
|
||||
export class CompetitionOfficials extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
color: color-mix(in srgb, var(--color-text) 55%, transparent);
|
||||
}
|
||||
|
||||
.placeholder p:first-child {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder p:last-child {
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<p>Officials</p>
|
||||
<p>Content will appear here once the competition is underway.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionOfficials;
|
||||
@@ -0,0 +1,42 @@
|
||||
// tabs/competition-pilots.ts
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-pilots")
|
||||
export class CompetitionPilots extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
color: color-mix(in srgb, var(--color-text) 55%, transparent);
|
||||
}
|
||||
|
||||
.placeholder p:first-child {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder p:last-child {
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<p>Pilots</p>
|
||||
<p>Content will appear here once the competition is underway.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionPilots;
|
||||
@@ -0,0 +1,42 @@
|
||||
// tabs/competition-results.ts
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-results")
|
||||
export class CompetitionResults extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
color: color-mix(in srgb, var(--color-text) 55%, transparent);
|
||||
}
|
||||
|
||||
.placeholder p:first-child {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder p:last-child {
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<p>Results</p>
|
||||
<p>Content will appear here once the competition is underway.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionResults;
|
||||
@@ -0,0 +1,42 @@
|
||||
// tabs/competition-tasks.ts
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
@customElement("competition-tasks")
|
||||
export class CompetitionTasks extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--color-bg-nav);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
color: color-mix(in srgb, var(--color-text) 55%, transparent);
|
||||
}
|
||||
|
||||
.placeholder p:first-child {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.placeholder p:last-child {
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<p>Task Data</p>
|
||||
<p>Content will appear here once the competition is underway.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompetitionTasks;
|
||||
@@ -254,7 +254,7 @@ export class HomePage extends LitElement {
|
||||
</svg>
|
||||
Live Scoring Platform
|
||||
</ui-badge>
|
||||
<h1>Precision scoring for <span>balloon competitions</span></h1>
|
||||
<h1>Transparent scoring for <span>balloon competitions</span></h1>
|
||||
<p class="hero-sub">
|
||||
Track tasks, manage participants, and deliver real-time
|
||||
results for hot air balloon competitions worldwide.
|
||||
@@ -292,12 +292,12 @@ export class HomePage extends LitElement {
|
||||
<p class="section-label">Features</p>
|
||||
<h2 class="section-title">Built for balloon events</h2>
|
||||
<p class="section-desc">
|
||||
Everything organizers, judges, and pilots need in one place.
|
||||
Everything organizers, officials, juries and pilots need in one place.
|
||||
</p>
|
||||
<div class="features-grid">
|
||||
<icon-card
|
||||
heading="Real-Time Scoring"
|
||||
description="Scores update live as judges submit results. Pilots and spectators always see the latest standings."
|
||||
description="Scores update live as scorers submit results. Pilots and spectators always see the latest standings."
|
||||
>
|
||||
<svg slot="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
|
||||
Reference in New Issue
Block a user