diff --git a/flightscore/src/app-root.ts b/flightscore/src/app-root.ts
index ba94e44..d55fbf0 100644
--- a/flightscore/src/app-root.ts
+++ b/flightscore/src/app-root.ts
@@ -66,6 +66,12 @@ export class AppRoot extends LitElement {
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) => {
diff --git a/flightscore/src/components/ui-badge.ts b/flightscore/src/components/ui-badge.ts
index 4bcbdd6..a6ab879 100644
--- a/flightscore/src/components/ui-badge.ts
+++ b/flightscore/src/components/ui-badge.ts
@@ -2,11 +2,11 @@
import { LitElement, html, css } from 'lit';
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')
export class UiBadge extends LitElement {
- static styles = css`
+ static styles = css`
:host {
display: inline-flex;
}
@@ -25,14 +25,21 @@ export class UiBadge extends LitElement {
white-space: nowrap;
}
+ .icon {
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .icon ::slotted(svg) {
+ width: 0.85rem;
+ height: 0.85rem;
+ flex-shrink: 0;
+ }
+
.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
- );
+ border-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
}
.badge.success {
@@ -47,33 +54,27 @@ export class UiBadge extends LitElement {
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;
+ .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);
}
`;
- @property() variant: BadgeVariant = 'accent';
+ @property() variant: BadgeVariant = 'accent';
- render() {
- return html`
-
+ 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
index c398b41..894a442 100644
--- a/flightscore/src/components/ui-button-secondary.ts
+++ b/flightscore/src/components/ui-button-secondary.ts
@@ -52,7 +52,12 @@ export class UiButtonSecondary extends LitElement {
cursor: not-allowed;
}
- ::slotted(svg) {
+ .icon {
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .icon ::slotted(svg) {
width: 1rem;
height: 1rem;
flex-shrink: 0;
@@ -65,6 +70,7 @@ export class UiButtonSecondary extends LitElement {
render() {
return html`
`;
diff --git a/flightscore/src/components/ui-button.ts b/flightscore/src/components/ui-button.ts
index 276b954..bb6a255 100644
--- a/flightscore/src/components/ui-button.ts
+++ b/flightscore/src/components/ui-button.ts
@@ -1,3 +1,4 @@
+// components/ui-button.ts
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@@ -52,7 +53,12 @@ export class UiButton extends LitElement {
cursor: not-allowed;
}
- ::slotted(svg) {
+ .icon {
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .icon ::slotted(svg) {
width: 1rem;
height: 1rem;
flex-shrink: 0;
@@ -65,6 +71,7 @@ export class UiButton extends LitElement {
render() {
return html`
`;
diff --git a/flightscore/src/pages/dev-page.ts b/flightscore/src/pages/dev-page.ts
new file mode 100644
index 0000000..7fff3cf
--- /dev/null
+++ b/flightscore/src/pages/dev-page.ts
@@ -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`
+
+
+
+
+
+
Buttons
+
Primary and secondary action buttons
+
+
+
Primary
+
+ Default
+
+
+ With Icon
+
+ Disabled
+
+
Primary Full Width
+
+ Full Width Button
+
+
Secondary
+
+
Default
+
+
+ With Icon
+
+
+ Disabled
+
+
+
Secondary Full Width
+
+
+ Full Width Secondary
+
+
+
+
+
+
+
+
Badges
+
Status and category indicators
+
+
+
Variants
+
+ Accent
+ Success
+ Warning
+ Error
+ Muted
+
+
With Icon
+
+
+
+ Platform
+
+
+
+ Live
+
+
+
+ Offline
+
+
+
+
+
+
+
+
Notification Bars
+
Inline feedback messages
+
+
+
Types
+
+
+
+
+
+
Non-Dismissible
+
+
+
+
+
+
+
+
+
Links
+
Navigation links with underline animation
+
+
+
States
+
+
Default Link
+
+
Active Link
+
+
+
+
+
+
+
Form Inputs
+
Text input fields with labels
+
+
+
Types
+
+
+
+ (this.inputValue = e.detail.value)}
+ >
+
+
+
+
+
Live Value
+
+
+ Current value: "${this.inputValue}"
+
+
+
+
+
+
+
+
Stat Cards
+
Metric display cards
+
+
+
+
+
+
+
Icon Cards
+
Feature highlight cards
+
+
+
Grid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Cards
+
Container cards and layout primitives
+
+
+
ui-card (default)
+
+
+
+
+ This is the default card layout with a header
+ component inside.
+
+
+ Action
+
+
+
ui-card (centered)
+
+
+
+ 404
+
+
+
+ Action
+
+
+
+
+
+
+
+
Divider
+
Visual separator for content sections
+
+
+
horizontal-divider
+
+
+ Content above
+
+
+
+ Content below
+
+
+
+
+
+
+
+
Composed: Auth Card
+
Pre-composed card for authentication flows
+
+
+
Login Example
+
+
+
+
+
+
+ Sign in
+
+
+ No account?
+ Create one
+
+
+
+
+
+
+ `;
+ }
+}
\ No newline at end of file