Skip to content

Commit 6bc873a

Browse files
committed
Merge branch 'main' into jump-menu
2 parents eb02a3a + d71ba9b commit 6bc873a

File tree

20 files changed

+564
-8
lines changed

20 files changed

+564
-8
lines changed

package-lock.json

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"vite": "^5.4.4"
5353
},
5454
"dependencies": {
55+
"chart.js": "^4.5.0",
5556
"normalize-scss": "^8.0.0"
5657
},
5758
"commitlint": {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {
2+
CategoryScale,
3+
Chart as ChartJS,
4+
Filler,
5+
LineController,
6+
LineElement,
7+
LinearScale,
8+
PointElement,
9+
} from "chart.js";
10+
11+
// Register Chart.js components
12+
ChartJS.register(
13+
CategoryScale,
14+
LinearScale,
15+
PointElement,
16+
LineElement,
17+
LineController,
18+
Filler,
19+
);
20+
21+
// Initialise sparklines when DOM is ready
22+
function initialiseSparklines() {
23+
const sparklines = document.querySelectorAll(".iati-data-card__sparkline");
24+
25+
sparklines.forEach((canvas) => {
26+
const dataAttr = canvas.getAttribute("data-sparkline");
27+
28+
if (dataAttr) {
29+
try {
30+
const data = JSON.parse(dataAttr);
31+
const ctx = canvas.getContext("2d");
32+
33+
new ChartJS(ctx, {
34+
type: "line",
35+
data: {
36+
labels: data.labels,
37+
datasets: [
38+
{
39+
data: data.values,
40+
borderColor: "#155366",
41+
borderWidth: 2,
42+
fill: true,
43+
backgroundColor: "#E6F9FE",
44+
pointRadius: 0,
45+
},
46+
],
47+
},
48+
options: {
49+
responsive: true,
50+
maintainAspectRatio: false,
51+
plugins: {
52+
legend: {
53+
display: false,
54+
},
55+
},
56+
elements: {
57+
point: {
58+
radius: 0,
59+
},
60+
},
61+
scales: {
62+
y: {
63+
display: false,
64+
},
65+
x: {
66+
display: false,
67+
},
68+
},
69+
},
70+
});
71+
} catch (e) {
72+
console.error("Failed to create sparkline:", e);
73+
}
74+
}
75+
});
76+
}
77+
78+
// MutationObserver for Storybook dynamic content
79+
function setupMutationObserver() {
80+
const observer = new MutationObserver(() => {
81+
setTimeout(initialiseSparklines, 50);
82+
});
83+
84+
observer.observe(document.body, {
85+
childList: true,
86+
subtree: true,
87+
});
88+
}
89+
90+
// Initialise when DOM is ready
91+
if (document.readyState === "loading") {
92+
document.addEventListener("DOMContentLoaded", () => {
93+
initialiseSparklines();
94+
setupMutationObserver();
95+
});
96+
} else {
97+
initialiseSparklines();
98+
setupMutationObserver();
99+
}
100+
101+
export { initialiseSparklines };

src/js/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
import "./components/data-card/data-card.js";
12
import "./components/header/header.js";
23
import "./components/jump-menu/jump-menu.js";

src/scss/components/_index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
@forward "callout/callout";
55
@forward "card/card";
66
@forward "country-switcher/country-switcher";
7+
@forward "data-card/data-card";
78
@forward "figures/figures";
89
@forward "piped-list/piped-list";
910
@forward "icon/icon";

src/scss/components/button/_button.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@
4646
background-color: $color-green-50;
4747
}
4848
}
49+
50+
&--compact {
51+
padding-top: 0.5rem;
52+
padding-bottom: 0.5rem;
53+
}
4954
}

src/scss/components/button/button.stories.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,27 @@ export const WithIcon: Story = {
5050
</button>
5151
`,
5252
};
53+
54+
export const Compact: Story = {
55+
render: () =>
56+
html`<button class="iati-button iati-button--compact">Button</button>`,
57+
};
58+
59+
export const CompactLight: Story = {
60+
parameters: {
61+
backgrounds: {
62+
default: "dark",
63+
},
64+
},
65+
render: () =>
66+
html`<button class="iati-button iati-button--light iati-button--compact">
67+
Button
68+
</button>`,
69+
};
70+
71+
export const CompactSubmit: Story = {
72+
render: () =>
73+
html`<button class="iati-button iati-button--submit iati-button--compact">
74+
Submit
75+
</button>`,
76+
};

src/scss/components/country-switcher/_country-switcher.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,16 @@
3737
background-color: currentColor;
3838
clip-path: polygon(15% 0, 0 0, 50% 100%, 100% 0, 85% 0, 50% 70%);
3939
}
40+
41+
&--compact {
42+
.iati-country-switcher__control {
43+
padding-top: 0.5rem;
44+
padding-bottom: 0.5rem;
45+
}
46+
&::after {
47+
right: 0.6875rem;
48+
width: 0.625rem;
49+
height: 0.3125rem;
50+
}
51+
}
4052
}

src/scss/components/country-switcher/country-switcher.stories.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,22 @@ export const CountrySwitcher: Story = {
2626
</div>
2727
`,
2828
};
29+
30+
export const Compact: Story = {
31+
render: () => html`
32+
<div class="iati-country-switcher iati-country-switcher--compact">
33+
<label
34+
for="iati-country-switcher-compact"
35+
class="iati-country-switcher__label"
36+
>Choose your language</label
37+
>
38+
<select
39+
id="iati-country-switcher-compact"
40+
class="iati-country-switcher__control"
41+
>
42+
<option>English</option>
43+
<option>French</option>
44+
</select>
45+
</div>
46+
`,
47+
};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
@use "../../tokens/color" as *;
2+
@use "../../tokens/font" as *;
3+
@use "../../tokens/spacing" as *;
4+
@use "../../base/mixins";
5+
6+
.iati-data-card {
7+
color: $color-teal-90;
8+
background-color: $color-teal-20;
9+
padding: 1.25rem;
10+
padding-top: $padding-block;
11+
display: flex;
12+
flex-direction: column;
13+
gap: 0.75rem;
14+
max-width: 297px;
15+
text-align: center;
16+
17+
& :first-child {
18+
margin-top: 0;
19+
}
20+
21+
& :last-child {
22+
margin-bottom: 0;
23+
}
24+
25+
&__title {
26+
margin: 0;
27+
font-family: $font-stack-heading;
28+
font-weight: $font-weight-body-xstrong;
29+
font-size: 1.625rem;
30+
}
31+
32+
&__tagline {
33+
margin: 0;
34+
font-size: 0.9rem;
35+
font-weight: $font-weight-body-xstrong;
36+
line-height: 1.4;
37+
}
38+
39+
&__stats {
40+
display: flex;
41+
gap: 0.5rem;
42+
margin: 0.5rem 0;
43+
flex-wrap: wrap;
44+
justify-content: center;
45+
}
46+
47+
&__stat {
48+
display: flex;
49+
flex-direction: column;
50+
background-color: $color-teal-10;
51+
padding: 0.75rem;
52+
gap: 0.5rem;
53+
min-width: 0;
54+
55+
&:not(:only-child) {
56+
max-width: calc(50% - 0.25rem);
57+
}
58+
59+
&-label {
60+
font-size: 0.75rem;
61+
text-transform: uppercase;
62+
font-weight: $font-weight-body-xstrong;
63+
letter-spacing: 0.5px;
64+
}
65+
66+
&-value {
67+
font-family: $font-stack-heading;
68+
font-weight: $font-weight-heading;
69+
font-size: 1.5rem;
70+
color: $color-teal-90;
71+
margin: 0;
72+
}
73+
}
74+
75+
&__graph {
76+
border-radius: 4px;
77+
display: flex;
78+
align-items: center;
79+
justify-content: center;
80+
width: 90%;
81+
height: 53.5px;
82+
margin: auto;
83+
}
84+
85+
&__caption {
86+
font-size: 0.75rem;
87+
font-weight: $font-weight-body-xxstrong;
88+
text-transform: uppercase;
89+
}
90+
91+
&__button {
92+
margin-top: 1rem;
93+
}
94+
}

0 commit comments

Comments
 (0)