fixed some bugs

This commit is contained in:
CodingPhoenixx
2026-02-13 16:42:35 +01:00
parent 6b9d59ae2d
commit 479d7f1381
5 changed files with 623 additions and 26 deletions
+6
View File
@@ -66,6 +66,12 @@ export class AppRoot extends LitElement {
return document.createElement('cc-home-page'); return document.createElement('cc-home-page');
} }
}, },
{
path: '/dev', view: async () => {
await import('./pages/dev-page.js');
return document.createElement('dev-page');
}
}
]); ]);
this.router.onRouteChange = (path: string) => { this.router.onRouteChange = (path: string) => {
+18 -17
View File
@@ -2,7 +2,7 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
export type BadgeVariant = 'accent' | 'success' | 'warning' | 'muted' | 'error'; export type BadgeVariant = 'accent' | 'success' | 'warning' | 'error' | 'muted';
@customElement('ui-badge') @customElement('ui-badge')
export class UiBadge extends LitElement { export class UiBadge extends LitElement {
@@ -25,14 +25,21 @@ export class UiBadge extends LitElement {
white-space: nowrap; white-space: nowrap;
} }
.icon {
display: inline-flex;
align-items: center;
}
.icon ::slotted(svg) {
width: 0.85rem;
height: 0.85rem;
flex-shrink: 0;
}
.badge.accent { .badge.accent {
color: var(--color-accent); color: var(--color-accent);
background: color-mix(in srgb, var(--color-accent) 10%, transparent); background: color-mix(in srgb, var(--color-accent) 10%, transparent);
border-color: color-mix( border-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
in srgb,
var(--color-accent) 25%,
transparent
);
} }
.badge.success { .badge.success {
@@ -47,23 +54,16 @@ export class UiBadge extends LitElement {
border-color: color-mix(in srgb, #e79d13 25%, 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 { .badge.error {
color: #e5484d; color: #e5484d;
background: color-mix(in srgb, #e5484d 10%, transparent); background: color-mix(in srgb, #e5484d 10%, transparent);
border-color: color-mix(in srgb, #e5484d 25%, transparent); border-color: color-mix(in srgb, #e5484d 25%, transparent);
} }
.badge.muted {
::slotted(svg) { color: color-mix(in srgb, var(--color-text) 45%, transparent);
width: 0.85rem; background: color-mix(in srgb, var(--color-text) 6%, transparent);
height: 0.85rem; border-color: var(--color-border);
flex-shrink: 0;
} }
`; `;
@@ -72,6 +72,7 @@ export class UiBadge extends LitElement {
render() { render() {
return html` return html`
<span class="badge ${this.variant}"> <span class="badge ${this.variant}">
<span class="icon"><slot name="icon"></slot></span>
<slot></slot> <slot></slot>
</span> </span>
`; `;
@@ -52,7 +52,12 @@ export class UiButtonSecondary extends LitElement {
cursor: not-allowed; cursor: not-allowed;
} }
::slotted(svg) { .icon {
display: inline-flex;
align-items: center;
}
.icon ::slotted(svg) {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
flex-shrink: 0; flex-shrink: 0;
@@ -65,6 +70,7 @@ export class UiButtonSecondary extends LitElement {
render() { render() {
return html` return html`
<button ?disabled=${this.disabled}> <button ?disabled=${this.disabled}>
<span class="icon"><slot name="icon"></slot></span>
<slot></slot> <slot></slot>
</button> </button>
`; `;
+8 -1
View File
@@ -1,3 +1,4 @@
// components/ui-button.ts
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
@@ -52,7 +53,12 @@ export class UiButton extends LitElement {
cursor: not-allowed; cursor: not-allowed;
} }
::slotted(svg) { .icon {
display: inline-flex;
align-items: center;
}
.icon ::slotted(svg) {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
flex-shrink: 0; flex-shrink: 0;
@@ -65,6 +71,7 @@ export class UiButton extends LitElement {
render() { render() {
return html` return html`
<button ?disabled=${this.disabled}> <button ?disabled=${this.disabled}>
<span class="icon"><slot name="icon"></slot></span>
<slot></slot> <slot></slot>
</button> </button>
`; `;
+577
View File
@@ -0,0 +1,577 @@
import { LitElement, html, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import '../components/ui-button';
import '../components/ui-button-secondary';
import '../components/ui-badge';
import '../components/ui-card';
import '../components/card-backdrop';
import '../components/card-header';
import '../components/auth-card';
import '../components/stat-card';
import '../components/icon-card';
import '../components/form-input';
import '../components/horizontal-divider';
import '../components/notify-bar';
import '../components/ui-link';
@customElement('dev-page')
export class DevPage extends LitElement {
static styles = css`
:host {
flex: 1;
display: flex;
flex-direction: column;
background: var(--color-bg);
}
.container {
max-width: 1100px;
width: 100%;
margin: 0 auto;
padding: 2.5rem 1.5rem 4rem;
display: flex;
flex-direction: column;
gap: 3rem;
}
.page-header {
display: flex;
flex-direction: column;
gap: 0.35rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid var(--color-border);
}
.page-header h1 {
margin: 0;
font-size: 2rem;
font-weight: 800;
letter-spacing: -0.03em;
color: var(--color-text);
}
.page-header p {
margin: 0;
font-size: 0.95rem;
color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.section {
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.section-head {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.section-head h2 {
margin: 0;
font-size: 1.25rem;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--color-text);
}
.section-head p {
margin: 0;
font-size: 0.85rem;
color: color-mix(in srgb, var(--color-text) 50%, transparent);
}
.component-group {
background: var(--color-bg-nav);
border: 1px solid var(--color-border);
border-radius: 0.75rem;
overflow: hidden;
}
.component-label {
padding: 0.6rem 1.25rem;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: color-mix(in srgb, var(--color-text) 45%, transparent);
background: color-mix(in srgb, var(--color-text) 4%, transparent);
border-bottom: 1px solid var(--color-border);
}
.component-preview {
padding: 1.5rem 1.25rem;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
}
.component-preview.col {
flex-direction: column;
align-items: stretch;
}
.component-preview.grid-2 {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.component-preview.grid-4 {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.component-preview + .component-label {
border-top: 1px solid var(--color-border);
}
.spacer {
width: 1px;
height: 1.5rem;
background: var(--color-border);
margin: 0 0.25rem;
}
.input-row {
max-width: 360px;
width: 100%;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.card-demo {
display: flex;
justify-content: center;
padding: 2rem;
background:
radial-gradient(
ellipse at 30% 20%,
color-mix(in srgb, var(--color-accent) 8%, transparent) 0%,
transparent 50%
),
var(--color-bg);
border-radius: 0 0 0.75rem 0.75rem;
}
.toggle-row {
display: flex;
align-items: center;
gap: 0.5rem;
}
.toggle-label {
font-size: 0.85rem;
color: color-mix(in srgb, var(--color-text) 60%, transparent);
}
`;
@state() inputValue = '';
@state() notifyVisible = true;
render() {
return html`
<div class="container">
<div class="page-header">
<h1>Component Library</h1>
<p>
All available UI components with variants and states
</p>
</div>
<div class="section">
<div class="section-head">
<h2>Buttons</h2>
<p>Primary and secondary action buttons</p>
</div>
<div class="component-group">
<div class="component-label">Primary</div>
<div class="component-preview">
<ui-button>Default</ui-button>
<ui-button>
<svg
slot="icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
With Icon
</ui-button>
<ui-button disabled>Disabled</ui-button>
</div>
<div class="component-label">Primary Full Width</div>
<div class="component-preview col">
<ui-button full>Full Width Button</ui-button>
</div>
<div class="component-label">Secondary</div>
<div class="component-preview">
<ui-button-secondary>Default</ui-button-secondary>
<ui-button-secondary>
<svg
slot="icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="19" y1="12" x2="5" y2="12" />
<polyline points="12 19 5 12 12 5" />
</svg>
With Icon
</ui-button-secondary>
<ui-button-secondary disabled>
Disabled
</ui-button-secondary>
</div>
<div class="component-label">Secondary Full Width</div>
<div class="component-preview col">
<ui-button-secondary full>
Full Width Secondary
</ui-button-secondary>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Badges</h2>
<p>Status and category indicators</p>
</div>
<div class="component-group">
<div class="component-label">Variants</div>
<div class="component-preview">
<ui-badge variant="accent">Accent</ui-badge>
<ui-badge variant="success">Success</ui-badge>
<ui-badge variant="warning">Warning</ui-badge>
<ui-badge variant="error">Error</ui-badge>
<ui-badge variant="muted">Muted</ui-badge>
</div>
<div class="component-label">With Icon</div>
<div class="component-preview">
<ui-badge variant="accent">
<svg
slot="icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 2L2 7l10 5 10-5-10-5z" />
<path d="M2 17l10 5 10-5" />
<path d="M2 12l10 5 10-5" />
</svg>
Platform
</ui-badge>
<ui-badge variant="success">
<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" />
<path d="M8 12l2.5 2.5L16 9" />
</svg>
Live
</ui-badge>
<ui-badge variant="error">
<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" />
<line x1="15" y1="9" x2="9" y2="15" />
<line x1="9" y1="9" x2="15" y2="15" />
</svg>
Offline
</ui-badge>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Notification Bars</h2>
<p>Inline feedback messages</p>
</div>
<div class="component-group">
<div class="component-label">Types</div>
<div class="component-preview col">
<notify-bar
type="success"
message="Competition successfully created."
></notify-bar>
<notify-bar
type="warning"
message="GPS data incomplete. Some scores may be inaccurate."
></notify-bar>
<notify-bar
type="error"
message="Login failed. Please check your credentials."
></notify-bar>
</div>
<div class="component-label">Non-Dismissible</div>
<div class="component-preview col">
<notify-bar
type="success"
message="This notification cannot be dismissed."
.dismissible=${false}
></notify-bar>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Links</h2>
<p>Navigation links with underline animation</p>
</div>
<div class="component-group">
<div class="component-label">States</div>
<div class="component-preview">
<ui-link href="#">Default Link</ui-link>
<div class="spacer"></div>
<ui-link href="#" active>Active Link</ui-link>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Form Inputs</h2>
<p>Text input fields with labels</p>
</div>
<div class="component-group">
<div class="component-label">Types</div>
<div class="component-preview col">
<div class="input-row">
<form-input
label="Text"
placeholder="Enter some text"
.value=${this.inputValue}
@value-changed=${(e: CustomEvent) =>
(this.inputValue = e.detail.value)}
></form-input>
<form-input
label="Email"
type="email"
placeholder="you@example.com"
></form-input>
<form-input
label="Password"
type="password"
placeholder="Enter your password"
></form-input>
</div>
</div>
<div class="component-label">Live Value</div>
<div class="component-preview">
<span style="font-size:0.85rem;color:color-mix(in srgb,var(--color-text) 60%,transparent)">
Current value: "${this.inputValue}"
</span>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Stat Cards</h2>
<p>Metric display cards</p>
</div>
<div class="component-group">
<div class="component-label">Grid</div>
<div class="component-preview grid-4">
<stat-card
value="42"
label="Competitions"
></stat-card>
<stat-card
value="318"
label="Pilots"
></stat-card>
<stat-card
value="1,240"
label="Tasks"
></stat-card>
<stat-card
value="12"
label="Countries"
></stat-card>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Icon Cards</h2>
<p>Feature highlight cards</p>
</div>
<div class="component-group">
<div class="component-label">Grid</div>
<div class="component-preview grid-2">
<icon-card
heading="Real-Time Scoring"
description="Scores update live as judges submit results."
>
<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" />
<polyline points="12 6 12 12 16 14" />
</svg>
</icon-card>
<icon-card
heading="GPS Integration"
description="Import GPS tracks and calculate distances automatically."
>
<svg
slot="icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
</icon-card>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Cards</h2>
<p>Container cards and layout primitives</p>
</div>
<div class="component-group">
<div class="component-label">ui-card (default)</div>
<div class="card-demo">
<ui-card>
<card-header
heading="Card Title"
subheading="A subtitle goes here"
></card-header>
<p
style="margin:0;font-size:0.9rem;color:color-mix(in srgb,var(--color-text) 60%,transparent)"
>
This is the default card layout with a header
component inside.
</p>
<horizontal-divider></horizontal-divider>
<ui-button full>Action</ui-button>
</ui-card>
</div>
<div class="component-label">ui-card (centered)</div>
<div class="card-demo">
<ui-card centered>
<p
style="margin:0;font-size:3rem;font-weight:800;letter-spacing:-0.03em;color:var(--color-accent)"
>
404
</p>
<card-header
heading="Centered Content"
subheading="Used for error pages and similar layouts"
></card-header>
<horizontal-divider></horizontal-divider>
<ui-button>Action</ui-button>
</ui-card>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Divider</h2>
<p>Visual separator for content sections</p>
</div>
<div class="component-group">
<div class="component-label">horizontal-divider</div>
<div class="component-preview col">
<p
style="margin:0;font-size:0.85rem;color:color-mix(in srgb,var(--color-text) 60%,transparent)"
>
Content above
</p>
<horizontal-divider></horizontal-divider>
<p
style="margin:0;font-size:0.85rem;color:color-mix(in srgb,var(--color-text) 60%,transparent)"
>
Content below
</p>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h2>Composed: Auth Card</h2>
<p>Pre-composed card for authentication flows</p>
</div>
<div class="component-group">
<div class="component-label">Login Example</div>
<div class="card-demo">
<ui-card>
<card-header
heading="Welcome back"
subheading="Sign in to your FlightScore account"
></card-header>
<form-input
label="Email"
type="email"
placeholder="you@example.com"
></form-input>
<form-input
label="Password"
type="password"
placeholder="Enter your password"
></form-input>
<notify-bar
type="error"
message="Invalid email or password."
></notify-bar>
<ui-button full>Sign in</ui-button>
<horizontal-divider></horizontal-divider>
<p
style="margin:0;text-align:center;font-size:0.875rem;color:color-mix(in srgb,var(--color-text) 60%,transparent)"
>
No account?
<ui-link href="#">Create one</ui-link>
</p>
</ui-card>
</div>
</div>
</div>
</div>
`;
}
}