From 67f7f4dd688054c40287f46197dce626e7c77059 Mon Sep 17 00:00:00 2001 From: CodingPhoenixx Date: Fri, 13 Feb 2026 18:03:57 +0100 Subject: [PATCH] fixed circle charts and added a component collection --- flightscore/src/components/_components | 185 +++++++++++++++++++++ flightscore/src/components/circle-chart.ts | 113 +++++++++++-- flightscore/src/pages/dev-page.ts | 18 +- 3 files changed, 289 insertions(+), 27 deletions(-) create mode 100644 flightscore/src/components/_components diff --git a/flightscore/src/components/_components b/flightscore/src/components/_components new file mode 100644 index 0000000..2e5299a --- /dev/null +++ b/flightscore/src/components/_components @@ -0,0 +1,185 @@ +# Component Library + +## ui-button + +| Attribute | Type | Description | +|------------|-----------|----------------------------| +| `disabled` | `boolean` | Disables the button | +| `full` | `boolean` | Full-width layout | + +| Slot | Description | +|-----------|---------------------| +| `default` | Button label text | +| `icon` | Leading SVG icon | + +--- + +## ui-button-secondary + +| Attribute | Type | Description | +|------------|-----------|----------------------------| +| `disabled` | `boolean` | Disables the button | +| `full` | `boolean` | Full-width layout | + +| Slot | Description | +|-----------|---------------------| +| `default` | Button label text | +| `icon` | Leading SVG icon | + +--- + +## ui-badge + +| Attribute | Type | Values | +|-----------|----------|------------------------------------------------------| +| `variant` | `string` | `accent` · `success` · `warning` · `error` · `muted` | + +| Slot | Description | +|-----------|-------------------| +| `default` | Badge label text | +| `icon` | Leading SVG icon | + +--- + +## notify-bar + +| Attribute | Type | Values / Description | +|---------------|-----------|-----------------------------------------| +| `type` | `string` | `success` · `warning` · `error` | +| `message` | `string` | Notification text | +| `dismissible` | `boolean` | Whether the bar can be dismissed (default `true`) | + +--- + +## ui-link + +| Attribute | Type | Description | +|-----------|-----------|--------------------------------| +| `href` | `string` | Navigation target | +| `active` | `boolean` | Renders in active/highlighted state | + +| Slot | Description | +|-----------|-------------| +| `default` | Link text | + +--- + +## form-input + +| Attribute | Type | Description | +|---------------|----------|------------------------------| +| `label` | `string` | Field label | +| `type` | `string` | `text` · `email` · `password` | +| `placeholder` | `string` | Placeholder text | +| `value` | `string` | Current input value | + +| Event | Detail | Description | +|-----------------|----------------|-------------------------| +| `value-changed` | `{ value: string }` | Fires on input change | + +--- + +## stat-card + +| Attribute | Type | Description | +|-----------|----------|----------------------| +| `value` | `string` | Displayed metric | +| `label` | `string` | Metric description | + +--- + +## icon-card + +| Attribute | Type | Description | +|---------------|----------|--------------------| +| `heading` | `string` | Card title | +| `description` | `string` | Card body text | + +| Slot | Description | +|--------|----------------| +| `icon` | Leading SVG icon | + +--- + +## ui-card + +| Attribute | Type | Description | +|------------|-----------|-----------------------------| +| `centered` | `boolean` | Centers all child content | + +| Slot | Description | +|-----------|----------------------| +| `default` | Arbitrary content | + +--- + +## card-header + +| Attribute | Type | Description | +|--------------|----------|---------------| +| `heading` | `string` | Title text | +| `subheading` | `string` | Subtitle text | + +--- + +## card-backdrop + +_No attributes or slots observed in usage._ + +--- + +## horizontal-divider + +_No attributes. Renders a visual separator line._ + +--- + +## loading-bar + +| Attribute | Type | Values / Description | +|-----------------|-----------|-----------------------------------------------| +| `label` | `string` | Text label next to the bar | +| `value` | `number` | Progress percentage (`0`–`100`) | +| `variant` | `string` | _(default)_ · `success` · `warning` · `error` | +| `size` | `string` | `sm` · `md` · `lg` | +| `indeterminate` | `boolean` | Infinite animation, no fixed value | +| `hideValue` | `boolean` | Hides the percentage label | + +--- + +## line-chart + +| Attribute | Type | Description | +|------------|-----------|------------------------------------| +| `heading` | `string` | Chart title | +| `subtitle` | `string` | Chart subtitle | +| `xLabel` | `string` | X-axis label | +| `yLabel` | `string` | Y-axis label | +| `showArea` | `boolean` | Fill area beneath lines | +| `series` | `Array` | Array of series objects (see below) | + +**Series object:** + +| Key | Type | Description | +|----------|----------|------------------------------------------| +| `label` | `string` | Legend label | +| `color` | `string` | CSS color value | +| `points` | `Array` | Array of `{ x: number, y: number }` | + +--- + +## circle-chart + +| Attribute | Type | Description | +|--------------|----------|--------------------------------------| +| `heading` | `string` | Chart title | +| `centerText` | `string` | Text rendered in the donut center | +| `segments` | `Array` | Array of segment objects (see below) | + +**Segment object:** + +| Key | Type | Description | +|---------|----------|--------------------| +| `label` | `string` | Legend label | +| `value` | `number` | Segment value | +| `color` | `string` | CSS color value | \ No newline at end of file diff --git a/flightscore/src/components/circle-chart.ts b/flightscore/src/components/circle-chart.ts index 527daa9..f478cab 100644 --- a/flightscore/src/components/circle-chart.ts +++ b/flightscore/src/components/circle-chart.ts @@ -1,10 +1,10 @@ import { LitElement, html, css, svg } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; export interface CircleSegment { label: string; value: number; - color?: string; + color: string; } @customElement('circle-chart') @@ -98,6 +98,46 @@ export class CircleChart extends LitElement { filter: brightness(1.15); } + .tooltip { + position: absolute; + pointer-events: none; + background: var(--color-bg-nav, #1a1a2e); + border: 1px solid var(--color-border, #333); + border-radius: 0.5rem; + padding: 0.35rem 0.65rem; + display: flex; + align-items: center; + gap: 0.4rem; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + transform: translate(-50%, -120%); + z-index: 10; + white-space: nowrap; + opacity: 0; + transition: opacity 0.15s ease; + } + + .tooltip.visible { + opacity: 1; + } + + .tooltip-dot { + width: 0.45rem; + height: 0.45rem; + border-radius: 50%; + flex-shrink: 0; + } + + .tooltip-label { + font-size: 0.75rem; + color: color-mix(in srgb, var(--color-text) 65%, transparent); + } + + .tooltip-value { + font-size: 0.75rem; + font-weight: 700; + color: var(--color-text); + } + .legend { display: flex; flex-direction: column; @@ -137,14 +177,33 @@ export class CircleChart extends LitElement { @property() centerText = 'Total'; @property({ type: Array }) segments: CircleSegment[] = []; - private defaultColors = [ - 'var(--color-accent)', - '#30a46c', - '#e79d13', - '#e5484d', - '#6e56cf', - '#0091ff', - ]; + @state() private _hoveredIndex = -1; + @state() private _tooltipX = 0; + @state() private _tooltipY = 0; + + private _onArcEnter(e: MouseEvent, index: number) { + this._hoveredIndex = index; + this._updateTooltipPos(e); + } + + private _onArcMove(e: MouseEvent) { + if (this._hoveredIndex < 0) return; + this._updateTooltipPos(e); + } + + private _onArcLeave() { + this._hoveredIndex = -1; + } + + private _updateTooltipPos(e: MouseEvent) { + const container = this.shadowRoot!.querySelector( + '.svg-container' + ) as HTMLElement; + if (!container) return; + const rect = container.getBoundingClientRect(); + this._tooltipX = e.clientX - rect.left; + this._tooltipY = e.clientY - rect.top; + } render() { const total = this.segments.reduce((s, d) => s + d.value, 0); @@ -160,8 +219,6 @@ export class CircleChart extends LitElement { const pct = total > 0 ? seg.value / total : 0; const dash = pct * usable; const gap = circumference - dash; - const color = - seg.color || this.defaultColors[i % this.defaultColors.length]; const currentOffset = offset; offset += dash + gapSize; @@ -169,14 +226,22 @@ export class CircleChart extends LitElement { this._onArcEnter(e, i)} + @mousemove=${(e: MouseEvent) => this._onArcMove(e)} + @mouseleave=${() => this._onArcLeave()} /> `; }); + const hovered = + this._hoveredIndex >= 0 + ? this.segments[this._hoveredIndex] + : null; + return html`
${this.heading @@ -189,17 +254,29 @@ export class CircleChart extends LitElement { ${total} ${this.centerText}
+
+ ${hovered + ? html` + + ${hovered.label} + ${hovered.value} + ` + : null} +
${this.segments.map( - (seg, i) => html` + (seg) => html`
${seg.label} ${seg.value} diff --git a/flightscore/src/pages/dev-page.ts b/flightscore/src/pages/dev-page.ts index 9dfb2ff..bc62bee 100644 --- a/flightscore/src/pages/dev-page.ts +++ b/flightscore/src/pages/dev-page.ts @@ -664,15 +664,15 @@ export class DevPage extends LitElement {
Example
+ heading="Pilots by Category" + centerText="Pilots" + .segments=${[ + { label: 'Sport', value: 124, color: 'var(--color-accent)' }, + { label: 'Serial', value: 89, color: '#30a46c' }, + { label: 'Open', value: 47, color: '#e79d13' }, + { label: 'Tandem', value: 18, color: '#e5484d' }, + ]} +>