diff --git a/src/assets/svg/icon-download.svg b/src/assets/svg/icon-download.svg
new file mode 100644
index 0000000..5dbdaf4
--- /dev/null
+++ b/src/assets/svg/icon-download.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/js/components/table/sortable-table.js b/src/js/components/table/sortable-table.js
new file mode 100644
index 0000000..df358e7
--- /dev/null
+++ b/src/js/components/table/sortable-table.js
@@ -0,0 +1,111 @@
+function getRowsContainer(root) {
+ if (root.tagName === "TABLE") {
+ return root.querySelector("tbody") || root;
+ }
+ const selector = root.getAttribute("data-sort-rows");
+ if (selector) return root.querySelector(selector);
+ return (
+ root.querySelector(".iati-file-card-table__cards") ||
+ root.querySelector(".iati-file-card-table__rows") ||
+ root
+ );
+}
+
+function getHeaders(root) {
+ return Array.from(root.querySelectorAll("[aria-sort]"));
+}
+
+function getRows(rowsContainer) {
+ return Array.from(rowsContainer.children).filter(
+ (el) =>
+ el.tagName !== "THEAD" &&
+ !el.classList.contains("iati-file-card-table__header"),
+ );
+}
+
+function getCellText(row, columnIndex) {
+ const cells = row.querySelectorAll(
+ "td, .iati-file-card__cell, .iati-table__cell",
+ );
+ const cell = cells[columnIndex];
+ return cell ? cell.textContent.trim() : "";
+}
+
+function compareValues(a, b, type) {
+ if (type === "number") {
+ const numA = parseFloat(a.replace(/[^0-9.\-]/g, "")) || 0;
+ const numB = parseFloat(b.replace(/[^0-9.\-]/g, "")) || 0;
+ return numA - numB;
+ }
+ return a.localeCompare(b, undefined, { numeric: true });
+}
+
+function sortRows(root, header) {
+ const headers = getHeaders(root);
+ const explicit = header.getAttribute("data-column-index");
+ const columnIndex =
+ explicit !== null ? parseInt(explicit, 10) : headers.indexOf(header);
+ if (columnIndex < 0 || Number.isNaN(columnIndex)) return;
+
+ const current = header.getAttribute("aria-sort");
+ const next = current === "ascending" ? "descending" : "ascending";
+
+ headers.forEach((h) => h.setAttribute("aria-sort", "none"));
+ header.setAttribute("aria-sort", next);
+
+ const type = header.getAttribute("data-sort-type") || "string";
+ const rowsContainer = getRowsContainer(root);
+ const rows = getRows(rowsContainer);
+
+ rows.sort((rowA, rowB) => {
+ const cmp = compareValues(
+ getCellText(rowA, columnIndex),
+ getCellText(rowB, columnIndex),
+ type,
+ );
+ return next === "ascending" ? cmp : -cmp;
+ });
+
+ rows.forEach((row) => rowsContainer.appendChild(row));
+}
+
+function attachSortHandlers(root) {
+ if (root.dataset.sortableInitialised) return;
+ root.dataset.sortableInitialised = "true";
+
+ getHeaders(root).forEach((header) => {
+ if (!header.querySelector("button")) {
+ const original = header.innerHTML;
+ header.innerHTML = `${original} `;
+ }
+ const button = header.querySelector("button");
+ button.addEventListener("click", () => sortRows(root, header));
+ });
+}
+
+function initialiseSortableTables() {
+ document.querySelectorAll("[data-sortable]").forEach(attachSortHandlers);
+}
+
+function setupMutationObserver() {
+ let debounceTimer;
+ const observer = new MutationObserver(() => {
+ clearTimeout(debounceTimer);
+ debounceTimer = setTimeout(initialiseSortableTables, 50);
+ });
+
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
+}
+
+if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", () => {
+ initialiseSortableTables();
+ setupMutationObserver();
+ });
+} else {
+ initialiseSortableTables();
+ setupMutationObserver();
+}
diff --git a/src/js/main.js b/src/js/main.js
index 3ebd999..2399d8d 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -2,3 +2,4 @@ import "../scss/components/select/multi-select.ts";
import "./components/data-card/data-card.js";
import "./components/header/header.js";
import "./components/jump-menu/jump-menu.js";
+import "./components/table/sortable-table.js";
diff --git a/src/scss/components/_index.scss b/src/scss/components/_index.scss
index 6f5fbdc..9a3b472 100644
--- a/src/scss/components/_index.scss
+++ b/src/scss/components/_index.scss
@@ -5,6 +5,7 @@
@forward "card/card";
@forward "country-switcher/country-switcher";
@forward "data-card/data-card";
+@forward "file-card/file-card";
@forward "figures/figures";
@forward "form/form";
@forward "piped-list/piped-list";
diff --git a/src/scss/components/file-card/_file-card.scss b/src/scss/components/file-card/_file-card.scss
new file mode 100644
index 0000000..c5658c7
--- /dev/null
+++ b/src/scss/components/file-card/_file-card.scss
@@ -0,0 +1,169 @@
+@use "../../tokens/color" as *;
+@use "../../tokens/font" as *;
+@use "../../tokens/spacing" as *;
+
+.iati-file-card-table {
+ overflow-x: auto;
+ min-width: 100%;
+ background: $color-blue-10;
+
+ // Table header that appears visually like a table head
+ &__header {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ min-width: 800px;
+ gap: 0;
+ border: 1px solid $color-teal-60;
+ border-bottom: 1px solid $color-teal-60;
+ background-color: $color-teal-30;
+
+ .iati-file-card-table__header-cell {
+ padding: 0.5rem 1rem;
+ text-transform: uppercase;
+ color: $color-grey-90;
+ font-weight: 800;
+ font-size: 0.75rem;
+ border-right: 1px solid $color-teal-60;
+ text-align: center;
+ min-width: 20ch;
+
+ &:last-child {
+ border-right: none;
+ }
+ }
+ }
+
+ // Container for all file cards
+ &__cards {
+ display: flex;
+ flex-direction: column;
+ gap: $padding-block;
+ margin-top: $padding-block;
+ min-width: 800px;
+ }
+}
+
+.iati-file-card {
+ border: 1px solid $color-teal-60;
+ border-top: 3px solid $color-teal-60;
+ background: white;
+ font-size: 0.75rem;
+ color: $color-teal-90;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ min-width: 800px;
+ width: 100%;
+ text-align: center;
+
+ // First row with 5 cells
+ &__main-row {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ min-width: 800px;
+ gap: 0;
+ align-items: center;
+ font-weight: 800;
+
+ .iati-file-card__cell {
+ padding: 0.5rem 0;
+ border-right: 1px solid $color-teal-60;
+
+ &:first-child {
+ text-transform: uppercase;
+ }
+
+ &:last-child {
+ border-right: none;
+ }
+ }
+ }
+
+ // Second row with 5 cells
+ &__details-row {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ min-width: 800px;
+ gap: 0;
+ align-items: stretch;
+ padding-top: 0;
+ border-top: 1px solid $color-teal-60;
+
+ .iati-file-card__cell {
+ padding: 0.5rem 1rem;
+ border-right: 1px solid $color-teal-60;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ min-height: 100%;
+
+ .iati-button {
+ max-width: 125px;
+ width: auto;
+ }
+
+ .iati-file-card__chart-container {
+ .iati-data-card__sparkline {
+ // width: 100px !important;
+ height: 30px !important;
+ max-width: 100%;
+ }
+
+ .iati-file-card_chart-caption {
+ font-size: 11px;
+ font-weight: 700;
+ text-transform: uppercase;
+ line-height: 14px;
+ }
+ }
+
+ &:last-child {
+ border-right: none;
+ }
+ }
+ }
+
+ // Third row: labeled info cells
+ &__footer-row {
+ min-width: 800px;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 0;
+ border-top: 1px solid $color-teal-60;
+ text-align: center;
+
+ .iati-file-card__cell {
+ padding: 0.75rem 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.25rem;
+ }
+ }
+
+ &__info-label {
+ text-transform: uppercase;
+ font-weight: 800;
+ font-size: 0.75rem;
+ color: $color-teal-90;
+ }
+}
+
+.iati-file-card__status {
+ font-weight: 700;
+
+ &--success {
+ color: $color-green-70;
+ }
+
+ &--error {
+ color: $color-orange-70;
+ }
+
+ &--critical {
+ color: $color-purple-70;
+ }
+}
diff --git a/src/scss/components/file-card/file-card.stories.ts b/src/scss/components/file-card/file-card.stories.ts
new file mode 100644
index 0000000..7c9a01d
--- /dev/null
+++ b/src/scss/components/file-card/file-card.stories.ts
@@ -0,0 +1,292 @@
+import type { Meta, StoryObj } from "@storybook/web-components";
+import { html } from "lit";
+
+const meta: Meta = {
+ title: "Components/File Card",
+ parameters: {
+ docs: {
+ description: {
+ component:
+ "A card-based layout for displaying file information that maintains the visual structure of a table header while presenting data in an accessible card format.",
+ },
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => html`
+
+
+
+
+
+
+
+ Africalia-Activities
+
+
11
+
0
+
223.1 kb
+
2.03
+
+
+
+ Package details
+
+
+ Activity count
+
+
+ Org count
+
+
+ Total size
+
+
+ IATI version
+
+
+
+
+
+
+
+
+ Alcis-Am
+
+
1
+
0
+
14.89 kb
+
+
+
+
+ Package details
+
+
+ Activity count
+
+
+ Org count
+
+
+ Total size
+
+
+ IATI version
+
+
+
+
+
+
+
+
+ Africalia-Org
+
+
1
+
0
+
14.89 kb
+
2.03
+
+
+
+ Package details
+
+
+ Activity count
+
+
+ Org count
+
+
+ Total size
+
+
+ IATI version
+
+
+
+
+
+
+ `,
+};
+
+export const SingleCard: Story = {
+ render: () => html`
+
+
+
+
+
+
+
+ Example-Package
+
+
25
+
3
+
542.7 kb
+
2.03
+
+
+
+ Package details
+
+
+ Activity count
+
+
+ Org count
+
+
+ Total size
+
+
+ IATI version
+
+
+
+
+
+
+ `,
+};
diff --git a/src/scss/components/icon/_icon.scss b/src/scss/components/icon/_icon.scss
index 3749efe..f37dfc3 100644
--- a/src/scss/components/icon/_icon.scss
+++ b/src/scss/components/icon/_icon.scss
@@ -27,6 +27,10 @@
background-image: url("@assets/svg/icon-chevron-left.svg");
}
+ &--download {
+ background-image: url("@assets/svg/icon-download.svg");
+ }
+
&--youtube {
background-image: url("@assets/svg/youtube-logo.svg");
aspect-ratio: 1.2 / 1;
diff --git a/src/scss/components/section/_section.scss b/src/scss/components/section/_section.scss
index 0c1d403..a144888 100644
--- a/src/scss/components/section/_section.scss
+++ b/src/scss/components/section/_section.scss
@@ -26,4 +26,10 @@
background-color: $color-teal-10;
}
}
+ &--fill-darker {
+ .iati-section__content {
+ padding-inline: 1rem;
+ background-color: $color-teal-20;
+ }
+ }
}
diff --git a/src/scss/components/section/section.stories.ts b/src/scss/components/section/section.stories.ts
index 72f126f..d008a48 100644
--- a/src/scss/components/section/section.stories.ts
+++ b/src/scss/components/section/section.stories.ts
@@ -16,8 +16,14 @@ export default meta;
type Story = StoryObj;
const Template = {
- render: ({ title, content, fill, headingId }) => html`
-
+ render: ({ title, content, fill, fillDarker, headingId }) => html`
+
${title}
@@ -75,3 +81,20 @@ export const Fill: Story = {
`,
},
};
+
+export const FillDarker: Story = {
+ ...Template,
+ args: {
+ title: "Section",
+ fillDarker: true,
+ content: html`
+
+ This section has a darker background using color-teal-20. Lorem ipsum
+ dolor sit amet, consectetur adipiscing elit. Pellentesque non augue
+ diam. Morbi nibh arcu, pulvinar sit amet erat ut, gravida imperdiet
+ erat.
+
+ ${Table.render?.call({})}
+ `,
+ },
+};
diff --git a/src/scss/components/table/_table.scss b/src/scss/components/table/_table.scss
index 8659033..b966044 100644
--- a/src/scss/components/table/_table.scss
+++ b/src/scss/components/table/_table.scss
@@ -23,6 +23,11 @@
td {
background-color: #fff;
}
+ &--plain {
+ th {
+ background-color: transparent;
+ }
+ }
td,
th {
border-right: 1px solid $color-teal-60;
@@ -48,3 +53,39 @@
text-transform: uppercase;
}
}
+
+.iati-table,
+.iati-file-card-table__header {
+ [aria-sort] {
+ cursor: pointer;
+ }
+
+ [aria-sort] button {
+ background: none;
+ border: 0;
+ padding: 0;
+ color: inherit;
+ font: inherit;
+ text-align: inherit;
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25em;
+ }
+
+ [aria-sort] button::before {
+ content: "▴▾";
+ opacity: 0.4;
+ font-size: 0.8em;
+ }
+
+ [aria-sort="ascending"] button::before {
+ content: "▴";
+ opacity: 1;
+ }
+
+ [aria-sort="descending"] button::before {
+ content: "▾";
+ opacity: 1;
+ }
+}
diff --git a/src/scss/components/table/table.stories.ts b/src/scss/components/table/table.stories.ts
index 5e25e17..939e1e7 100644
--- a/src/scss/components/table/table.stories.ts
+++ b/src/scss/components/table/table.stories.ts
@@ -97,3 +97,41 @@ export const Scrolling: Story = {
`,
};
+
+export const Sortable: Story = {
+ render: () => html`
+
+
+
+
+ Name
+ Files
+ Size (kB)
+
+
+
+
+ Africalia
+ 11
+ 223.1
+
+
+ Alcis
+ 1
+ 14.89
+
+
+ BRAC
+ 27
+ 891.4
+
+
+ CAFOD
+ 3
+ 52.6
+
+
+
+
+ `,
+};
diff --git a/src/scss/layout/_index.scss b/src/scss/layout/_index.scss
index 38f1754..4c7e06d 100644
--- a/src/scss/layout/_index.scss
+++ b/src/scss/layout/_index.scss
@@ -1,3 +1,4 @@
@forward "page/page";
@forward "masonry/masonry";
@forward "landing-page/landing-page";
+@forward "publishers-page/publishers-page";
diff --git a/src/scss/layout/publishers-page/_publishers-page.scss b/src/scss/layout/publishers-page/_publishers-page.scss
new file mode 100644
index 0000000..2237170
--- /dev/null
+++ b/src/scss/layout/publishers-page/_publishers-page.scss
@@ -0,0 +1,208 @@
+@use "../../base/mixins";
+@use "../../tokens/screens" as *;
+@use "../../tokens/color" as *;
+
+.iati-publishers-page {
+ @include mixins.page-width-container();
+ background-color: white;
+ flex: 1;
+ padding-block: 1rem;
+}
+
+.iati-publishers-page__before-content {
+ margin-block-end: 1rem;
+ @media (min-width: $screen-md) {
+ margin-block-end: 2rem;
+ }
+ & > * + * {
+ margin-block-start: 1rem;
+ }
+}
+
+.iati-publishers-page__intro-row {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ border-bottom: 1px solid black;
+ padding-bottom: 1rem;
+ @media (min-width: $screen-lg) {
+ position: relative;
+ flex-direction: row;
+ align-items: flex-end;
+ gap: 2rem;
+ }
+}
+
+.iati-publishers-page__intro-text {
+ margin: 0;
+ color: $color-teal-90;
+ line-height: 25px;
+ @media (min-width: $screen-lg) {
+ width: 75%;
+ padding-right: 2rem;
+ }
+}
+
+.iati-publishers-page__intro-button {
+ @media (min-width: $screen-lg) {
+ position: absolute;
+ bottom: 1rem;
+ right: 0;
+ }
+
+ .iati-button {
+ white-space: nowrap;
+ }
+}
+
+.iati-publishers-page__content {
+ display: flex;
+ flex-direction: column-reverse;
+ gap: 1rem;
+ @media (min-width: $screen-md) {
+ flex-direction: row;
+ gap: 2rem;
+ }
+}
+
+.iati-publishers-page__article {
+ flex: 1;
+ min-width: 0;
+ & > * + * {
+ margin-top: 1rem;
+ @media (min-width: $screen-md) {
+ margin-top: 2rem;
+ }
+ }
+ > :first-child {
+ margin-top: 0;
+ }
+}
+
+.iati-publishers-page__side {
+ min-inline-size: 15rem;
+ flex-grow: 0;
+}
+
+.iati-publishers-page__side--sticky > * {
+ position: sticky;
+ top: 1rem;
+ margin-top: 20px;
+}
+
+.iati-publishers-page__after-content {
+ margin-block-start: 1rem;
+ @media (min-width: $screen-md) {
+ margin-block-start: 2rem;
+ }
+ & > * + * {
+ margin-block-start: 1rem;
+ @media (min-width: $screen-md) {
+ margin-top: 2rem;
+ }
+ }
+}
+
+.iati-publishers-page {
+ .iati-section__subheading {
+ font-size: 1.0625rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ }
+
+ .iati-section__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 1rem;
+
+ .iati-section__subheading {
+ flex: 1;
+ }
+ }
+
+ .iati-table {
+ table,
+ tbody,
+ thead,
+ tfoot {
+ border-color: $color-grey-20;
+ }
+ td,
+ th {
+ border-right-color: $color-grey-20;
+ }
+ tr {
+ border-bottom-color: $color-grey-20;
+ }
+ th {
+ background-color: $color-teal-30;
+ }
+ &--plain th {
+ background-color: transparent;
+ }
+ }
+
+ .iati-subsection_intro {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+
+ @media (min-width: $screen-lg) {
+ position: relative;
+ flex-direction: row;
+ align-items: flex-end;
+ gap: 2rem;
+ }
+
+ p {
+ margin: 0;
+
+ @media (min-width: $screen-lg) {
+ width: 75%;
+ }
+ }
+
+ .iati-button {
+ align-self: flex-start;
+
+ @media (min-width: $screen-lg) {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ }
+ }
+ }
+
+ .iati-publishers-page__data-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 1rem;
+ margin-top: 1rem;
+
+ .iati-data-card {
+ max-width: 350px;
+ }
+
+ .iati-data-card--body {
+ justify-content: space-between;
+ flex: 1;
+
+ .iati-data-card__graph {
+ width: unset;
+ margin: 0;
+ }
+
+ .iati-button {
+ font-size: 14px;
+ }
+ }
+ }
+ .iati-button {
+ gap: 0.5rem;
+
+ .iati-icon--download {
+ height: 1.5rem;
+ }
+ }
+}
diff --git a/src/scss/layout/publishers-page/publishers-page.stories.ts b/src/scss/layout/publishers-page/publishers-page.stories.ts
new file mode 100644
index 0000000..73f7009
--- /dev/null
+++ b/src/scss/layout/publishers-page/publishers-page.stories.ts
@@ -0,0 +1,1118 @@
+import type { Meta, StoryObj } from "@storybook/web-components";
+import { html } from "lit";
+
+import { TwoLevel as Breadcrumb } from "../../components/breadcrumb/breadcrumb.stories";
+import { Footer } from "../../components/footer/footer.stories";
+import { Header } from "../../components/header/header.stories";
+import { Default as JumpMenu } from "../../components/jump-menu/jump-menu.stories";
+
+const meta: Meta = {
+ title: "Layout/Publishers Page",
+ parameters: {
+ layout: "fullscreen",
+ backgrounds: {
+ default: "grey",
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const PublishersPage: Story = {
+ render: (args, context) => html`
+ ${Header.render?.call({ ...args })}
+
+
+ ${Breadcrumb.render(
+ {
+ currentPageTitle: "Publisher Page",
+ previousPageTitles: ["Home", "Reporting Orgs"],
+ },
+ context,
+ )}
+
+
+
+
+
Reporting Org: Publisher Page
+
+
+ A text area next to their name for info and notes about their
+ own data, publishers provide information about their
+ organisation and the development or humanitarian activities they
+ are involved in. This includes details about the organisation
+ itself, as well as specific information about each activity,
+ like financial data, contextual information, and results.
+
+
+
+
+
+
+
+
+
+
+ On the registry
+
+
+
+ Reporting org on registry
+
+
+ BE-BCE_KBO-0474198059
+
+
+ Reporting org(s) in data
+
+
+ BE-BCE_KBO-0474198059
+
+
+
+
+ Hierarchies
+
+
+ 1 2
+
+
+ Licenses
+
+
+
+ Files failing scheme validation
+
+
0
+
+
+
+
+
+
+ Organisation files
+
+
1
+
+
+
Total file size
+
29.8kb
+
+
+
+
+ Unique activities
+
+
19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Description below chart showing changes over time
+
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
+ Funding breakdown by source
+
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
Most common sectors
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
Activities by country
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
Budget trends by year
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
Transaction patterns
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+
+
+
+
+ Results reporting by quarter
+
+
+
+ Download data (.JSON)
+
+
+
+
+
+
+
+ Exploring Data
+
+
+
Files
+
+
+ This is a list of all the files the Reporting Organisation has
+ uploaded. Up to 50 words here explaining that the package name
+ might not accurately describe the data. You can access all
+ file information via an API.
+
+
+
+ Download API
+
+
+
+
+
+
+
+
+
+ Africalia-Activities
+
+
11
+
0
+
223.1 kb
+
+
+
+
+
+
+ Download API
+
+
+
Activity count
+
Org count
+
Total size
+
IATI version
+
+
+
+
+
+
+
Alcis-Am
+
1
+
0
+
14.89 kb
+
+
+
+
+
+
+ Download API
+
+
+ Download from Reporting Org.
+
+
+
+
+
+
+ A short chart
description here
+
+
+
+
+
+
+
+ A short chart
description here
+
+
+
+
+
+
+
+ chart description might go over more than 1 or
2
+ lines
+
+
+
+
+
+
+
+ chart
description
+
+
+
+
+
+
+
+
+
+
Africalia-Org
+
1
+
0
+
14.89 kb
+
2.03
+
+
+
+
+
+ Download API
+
+
+
Activity count
+
Org count
+
Total size
+
IATI version
+
+
+
+
+
+
+
+
+
+
+ Organisation Identifiers
+
+
+
+
+
+
+ Org Type
+
+ Total
+
+ Self Refs
+
+ Excluding Self Refs
+
+
+
+ Org Elements
+
+
+ Refs
+
+
+ Non-Empty Refs
+
+
+ Org Elements
+
+
+ Refs
+
+
+ Non-Empty Refs
+
+
+ Valid Refs
+
+
+ Provided
+
+
+
+
+
+ Accountable
+ 19
+ 19
+ 19
+ 19
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+ Extending
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+ Funding
+ 27
+ 27
+ 27
+ 8
+ 19
+ 19
+ 19
+ 19
+ 100
+
+
+ Implementing
+ 37
+ 12
+ 12
+ 11
+ 26
+ 1
+ 1
+ 1
+ 4
+
+
+ Provider
+ 181
+ 181
+ 181
+ 122
+ 59
+ 59
+ 59
+ 54
+ 92
+
+
+ Receiver
+ 159
+ 40
+ 40
+ 29
+ 130
+ 11
+ 11
+ 10
+ 8
+
+
+
+
+
+
+
+
+
Financial
+
+
Budgets
+
+ The below figures are calculated based on the data contained
+ within the <budget> element for each reported activity.
+ Original and revised elements are based on the value declared in
+ the budget/@type attribute. Where budgets fall across two
+ calendar years, the month of the <period-end> date is used
+ to determine annual groupings, with budgets for periods ending
+ January–June added to the previous calendar year.
+
+
+
+
+
+ Year
+
+ Count (all)
+
+
+ Sum (all)
+
+
+ Count (Original)
+
+
+ Sum (Original)
+
+
+ Count (Revised)
+
+
+ Sum (Revised)
+
+
+
+
+
+ 2021
+ 4
+ 1,250,000
+ 3
+ 900,000
+ 1
+ 350,000
+
+
+ 2022
+ 6
+ 1,820,500
+ 5
+ 1,500,500
+ 1
+ 320,000
+
+
+ 2023
+ 7
+ 2,140,750
+ 5
+ 1,640,750
+ 2
+ 500,000
+
+
+ 2024
+ 5
+ 1,675,000
+ 4
+ 1,275,000
+ 1
+ 400,000
+
+
+
+
+
+
+
+
+ ${JumpMenu.render(
+ {
+ items: [
+ { text: "Headlines", link: "#headlines" },
+ { text: "Publisher Data", link: "#publisherData" },
+ { text: "Codelist values", link: "#codelistValues" },
+ {
+ text: "Elements and attributes",
+ link: "#elementsAttributes",
+ },
+ { text: "Organisation identifiers", link: "#orgIdentifiers" },
+ { text: "Financial", link: "#financial" },
+ ],
+ },
+ context,
+ )}
+
+
+
+ ${Footer.render?.call({ ...args })}
+ `,
+};