Add legend component with interactive items (#3047)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-09-13 11:59:56 +02:00
1 parent bd5c010595
commit be30919bb2
22 files changed
+727 -75

No files matched your search

+4 -4
View File
@@ -16,7 +16,7 @@ interface Props {
title: string
/** dir="rtl" + the .rtl.css variant of tabler.css */
rtl?: boolean
/** the Tabler logo above the card (+ balancing spacer below it) */
/** the Tabler logo at the bottom of the frame */
showLogo?: boolean
/** caps the [data-screenshot-target] width at columns * 320px */
columns?: number
@@ -111,11 +111,13 @@ const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file)
}
.screenshot-logo {
position: absolute;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
height: 8rem;
padding: 0 5rem;
flex: 1;
}
/* fake mouse pointer, to make the static screenshot read as a live interaction */
@@ -135,8 +137,6 @@ const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file)
<body>
<div class="page page-center align-items-center">
<div class="screenshot d-flex flex-column justify-content-center align-items-center px-12" id="screenshot">
{showLogo && <div class="screenshot-logo" />}
<div class:list={['screenshot-wrapper', className]} style={targetStyle} data-screenshot-target>
<slot />
</div>
+35
View File
@@ -0,0 +1,35 @@
---
// Legend component on its own, no card and no chart: a LegendList of button
// items — colored dot, source name, its share in tabular numerals — wrapping
// over a few rows in a narrow container. The fake cursor rests on the active
// item so the tinted hover background is part of the picture, and the last
// items show the `off` state of a hidden series.
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import Legend from '@ui/Legend.astro'
import LegendList from '@ui/LegendList.astro'
const sources = [
{ name: 'Organic search', color: 'blue', value: '31%' },
{ name: 'Direct', color: 'azure', value: '22%' },
{ name: 'Paid search', color: 'indigo', value: '14%' },
{ name: 'Social media', color: 'purple', value: '11%', active: true },
{ name: 'Referral', color: 'pink', value: '8%' },
{ name: 'Newsletter', color: 'orange', value: '6%' },
{ name: 'Partners', color: 'teal', value: '4%' },
{ name: 'Email', color: 'green', value: '3%', off: true },
{ name: 'Other', color: 'lime', value: '1%', off: true },
]
---
<ScreenshotLayout title="Legend list" columns={2}>
<LegendList class="justify-content-center">
{
sources.map((item) => (
<Legend button color={item.color} value={item.value} active={item.active} off={item.off} class="position-relative">
{item.name}
{item.active && <span class="cursor" />}
</Legend>
))
}
</LegendList>
</ScreenshotLayout>
+45
View File
@@ -0,0 +1,45 @@
---
// Legend component: a request-volume card whose header carries an interactive
// legend. Each item is a button — colored dot, series name, total in tabular
// numerals — and the fake cursor rests on one of them so the tinted hover
// background is part of the picture. `legend-requests` is a three-series stacked bar
// chart in charts.json with the ApexCharts legend left off, since the card's
// own legend replaces it.
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
import CardTitle from '@ui/CardTitle.astro'
import CardBody from '@ui/CardBody.astro'
import Legend from '@ui/Legend.astro'
import LegendList from '@ui/LegendList.astro'
import Chart from '@components/demo/Chart.astro'
// Series order and colors follow the `legend-requests` entry in charts.json.
const series = [
{ name: 'Allowed', color: 'blue', value: '339.0k' },
{ name: 'Challenged', color: 'azure', value: '815' },
{ name: 'Logged', color: 'green', value: '12.4k', active: true },
{ name: 'Rate limited', color: 'red', value: '-', off: true },
]
---
<ScreenshotLayout title="Legend" columns={2.6} pageLibs={['apexcharts']}>
<Card>
<CardHeader>
<CardTitle>Requests</CardTitle>
<LegendList class="ms-auto">
{
series.map((item) => (
<Legend button color={item.color} value={item.value} active={item.active} off={item.off} class="position-relative">
{item.name}
{item.active && <span class="cursor" />}
</Legend>
))
}
</LegendList>
</CardHeader>
<CardBody>
<Chart chartId="legend-requests" height={14} label="Requests per day, split by firewall action" />
</CardBody>
</Card>
</ScreenshotLayout>