Skip to content

Commit aa29bd2

Browse files
author
Joshua Stübner
committed
feat(ui-generator): add sparkline component
1 parent 60ca332 commit aa29bd2

File tree

3 files changed

+186
-1
lines changed

3 files changed

+186
-1
lines changed

apps/ui-generator/src/modules/components/components/ComponentsOverview.astro

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import SectionTitle from './SectionTitle.astro';
44
import type { SmarterSection } from './sections';
55
import PageHeader from '../../common/components/PageHeader.astro';
66
import SecondaryNav from '../../common/components/SecondaryNav.astro';
7+
import SparkLine from '../../customComponents/SparkLine/SparkLine.astro';
8+
import SparkLineSvelte from '../../customComponents/SparkLine/SparkLine.svelte';
79
810
interface Props {
911
sections: SmarterSection[];
@@ -14,7 +16,10 @@ const { sections } = Astro.props;
1416
const entries = sections.map((section) => ({
1517
title: section.title,
1618
url: `#${section.sectionId}`,
17-
}));
19+
})).concat({
20+
title: "Custom components",
21+
url: '#custom-components',
22+
})
1823
---
1924

2025

@@ -50,4 +55,41 @@ const entries = sections.map((section) => ({
5055
</ul>
5156
</section>
5257
))}
58+
<hr>
59+
<section class="comp-section nc-region" id="custom-components">
60+
<SectionTitle title="Custom Components" sectionId="#custom-components" />
61+
<ul class="nc-list-reset nc-grid -far">
62+
<li>
63+
<div class="nc-card nc-flow">
64+
<h3>Sparkline</h3>
65+
<div class="nc-stack -near">
66+
<p>This is an inline Sparkline:<SparkLine data={[5, 10, 8, 12, 7, 14, 10, 15, 9, 18, 12, 20]} label="Example SparkLine" appearance="gradient" /> </p>
67+
</div>
68+
69+
<div class="nc-stack -near">
70+
<p>This is an large Sparkline:</p>
71+
<SparkLine data={[5, 10, 8, 12, 7, 14, 10, 15, 9, 18, 12, 20]} label="Example SparkLine" appearance="gradient" style="width: min(400px, 100%); height: auto;" />
72+
</div>
73+
74+
<div class="nc-stack -near">
75+
<p>This is an large Sparkline as line only:</p>
76+
<SparkLine data={[5, 10, 8, 12, 7, 14, 10, 15, 9, 18, 12, 20]} label="Example SparkLine" appearance="line" style="width: min(400px, 100%); height: auto;" />
77+
</div>
78+
79+
<div class="nc-stack -near">
80+
<p>This is an inline Sparkline in svelte:
81+
<SparkLineSvelte
82+
data={[5, 10, 8, 12, 7, 14, 10, 15, 9, 18, 12, 20]}
83+
label="Example SparkLine"
84+
appearance="gradient"
85+
client:load="svelte"
86+
/>
87+
</p>
88+
</div>
89+
</div>
90+
</li>
91+
</ul>
92+
</section>
5393
</div>
94+
95+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
3+
interface Props {
4+
data: number[];
5+
strokeWidth?: number;
6+
label: string;
7+
appearance?: 'gradient' | 'line';
8+
class?: string;
9+
style?: string;
10+
}
11+
12+
const {
13+
data,
14+
strokeWidth = 2,
15+
label = "",
16+
appearance = "gradient",
17+
class: className = "",
18+
style = ""
19+
} = Astro.props;
20+
21+
22+
// x max = amount of values - 1
23+
const viewBoxX = data.length - 1;
24+
// y max = highest value + stroke width
25+
const viewBoxY = Math.max(...data) + strokeWidth;
26+
27+
const path = data.map((value, index) => {
28+
return `${index === 0 ? 'M' : 'L'} ${index} ${viewBoxY - value}`;
29+
}).join(' ');
30+
31+
const gradientPath = `${path} L ${viewBoxX} ${viewBoxY} L 0 ${viewBoxY} Z`;
32+
---
33+
34+
35+
<svg
36+
width="50px"
37+
height="200px"
38+
preserveAspectRatio="none"
39+
viewBox=`0 0 ${viewBoxX} ${viewBoxY}`
40+
style={style ?? ""}
41+
aria-label={label ?? ""}
42+
role="img"
43+
class:list={["nc-sparkline", className]}
44+
>
45+
{ appearance !== 'line' ? (
46+
<>
47+
<defs>
48+
<linearGradient id="sparkline-gradient" x1="0" y1="0" x2="0" y2="1">
49+
<stop offset="0%" stop-color="var(--gradient-color)" stop-opacity="1" />
50+
<stop offset="100%" stop-color="var(--gradient-color)" stop-opacity="0" />
51+
</linearGradient>
52+
</defs>
53+
54+
<path d={gradientPath} fill="url(#sparkline-gradient)" stroke="transparent" />
55+
</>
56+
) : null }
57+
58+
<path d={path} fill="transparent" vector-effect="non-scaling-stroke" stroke="var(--line-color)" stroke-width={strokeWidth} />
59+
</svg>
60+
61+
<style>
62+
.nc-sparkline {
63+
display: inline-block;
64+
aspect-ratio: 4 / 1;
65+
width: auto;
66+
height: 1em;
67+
vertical-align: middle;
68+
69+
--line-color: var(--color-brand-primary-base);
70+
--gradient-color: var(--color-brand-primary-surface);
71+
}
72+
73+
</style>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<script lang="ts">
2+
interface SparklineProps {
3+
data: number[];
4+
strokeWidth?: number;
5+
label: string;
6+
appearance?: 'gradient' | 'line';
7+
class?: string;
8+
style?: string;
9+
}
10+
11+
let {
12+
data,
13+
strokeWidth = 2,
14+
label = "",
15+
appearance = "gradient",
16+
class: className = "",
17+
style = ""
18+
}: SparklineProps = $props();
19+
20+
// x max = amount of values - 1
21+
const viewBoxX = data.length - 1;
22+
// y max = highest value + stroke width
23+
const viewBoxY = Math.max(...data) + strokeWidth;
24+
25+
const path = data.map((value, index) => {
26+
return `${index === 0 ? 'M' : 'L'} ${index} ${viewBoxY - value}`;
27+
}).join(' ');
28+
29+
const gradientPath = `${path} L ${viewBoxX} ${viewBoxY} L 0 ${viewBoxY} Z`;
30+
</script>
31+
32+
33+
<svg
34+
width="50px"
35+
height="200px"
36+
preserveAspectRatio="none"
37+
viewBox={`0 0 ${viewBoxX} ${viewBoxY}`}
38+
style={style ?? ""}
39+
aria-label={label ?? ""}
40+
role="img"
41+
class={["nc-sparkline", className].filter(Boolean).join(' ')}
42+
>
43+
{#if appearance !== 'line'}
44+
<defs>
45+
<linearGradient id="sparkline-gradient" x1="0" y1="0" x2="0" y2="1">
46+
<stop offset="0%" stop-color="var(--gradient-color)" stop-opacity="1" />
47+
<stop offset="100%" stop-color="var(--gradient-color)" stop-opacity="0" />
48+
</linearGradient>
49+
</defs>
50+
51+
<path d={gradientPath} fill="url(#sparkline-gradient)" stroke="transparent" />
52+
{/if}
53+
54+
55+
<path d={path} fill="transparent" vector-effect="non-scaling-stroke" stroke="var(--line-color)" stroke-width={strokeWidth} />
56+
</svg>
57+
58+
<style>
59+
.nc-sparkline {
60+
display: inline-block;
61+
aspect-ratio: 4 / 1;
62+
width: auto;
63+
height: 1em;
64+
vertical-align: middle;
65+
66+
--line-color: var(--color-brand-primary-base);
67+
--gradient-color: var(--color-brand-primary-surface);
68+
}
69+
70+
</style>

0 commit comments

Comments
 (0)