Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions .github/workflows/build_container_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,42 @@ on:
branches:
- main
workflow_dispatch:

env:
DOCKER_HUB_ORGANIZATION: ${{ vars.DOCKER_HUB_ORGANIZATION }}
DOCKER_HUB_REPOSITORY: ogcr-app

jobs:
build:
runs-on: ubuntu-latest
env:
# Publishing needs the Docker Hub organisation and credentials, which only the upstream
# repository has. Without them (e.g. on a fork) the image is still built, so the
# Dockerfile is checked on every push, but not pushed or signed.
CAN_PUBLISH: ${{ vars.DOCKER_HUB_ORGANIZATION != '' && secrets.DOCKER_HUB_USERNAME != '' && secrets.DOCKER_HUB_TOKEN != '' }}
steps:

- uses: actions/checkout@v4
- name: Build the Docker image with latest tag
- name: Build the Docker image
run: docker build . --tag ogcr-app:$GITHUB_SHA

- name: Publish the Docker image with latest tag
if: env.CAN_PUBLISH == 'true'
run: |
echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin docker.io
docker build . --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:$GITHUB_SHA --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:main --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:latest
for tag in $GITHUB_SHA main latest; do
docker tag ogcr-app:$GITHUB_SHA docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:$tag
done
docker push docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }} --all-tags
echo docker ogcr-app with latest tag done

- uses: sigstore/cosign-installer@main
if: env.CAN_PUBLISH == 'true'
- name: Write signing key to disk (only needed for `cosign sign --key`)
if: env.CAN_PUBLISH == 'true'
run: echo "${{ secrets.COSIGN_PRIVATE_KEY }}" > cosign.key
- name: Sign container image with annotations from our environment
if: env.CAN_PUBLISH == 'true'
env:
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
Expand All @@ -35,7 +49,3 @@ jobs:
-a "workflow=${{ github.workflow }}" \
-a "ref=${{ github.sha }}" \
docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:main




26 changes: 24 additions & 2 deletions src/lib/components/Kpi.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* status signal. `accentBar={false}` gives the quiet icon-led tile used in a
* dense row — which is what the registry summary uses, since a tone would
* imply a judgement we have no data to make.
*
* `href` turns the label and value into links to the page behind the figure.
*/
import type { Snippet } from 'svelte';

Expand All @@ -25,6 +27,7 @@
icon,
tone = 'positive',
accentBar = true,
href,
class: className = '',
...rest
}: {
Expand All @@ -34,6 +37,7 @@
icon?: Snippet;
tone?: Tone;
accentBar?: boolean;
href?: string;
class?: string;
[key: string]: unknown;
} = $props();
Expand All @@ -48,10 +52,18 @@
{#if icon}
<span class="ogcr-kpi__icon" aria-hidden="true">{@render icon()}</span>
{/if}
<span class="ogcr-kpi__label">{label}</span>
{#if href}
<a {href} class="ogcr-kpi__label ogcr-kpi__link">{label}</a>
{:else}
<span class="ogcr-kpi__label">{label}</span>
{/if}
</span>
</header>
<div class="ogcr-kpi__value">{value}</div>
{#if href}
<a {href} class="ogcr-kpi__value ogcr-kpi__link" tabindex="-1">{value}</a>
{:else}
<div class="ogcr-kpi__value">{value}</div>
{/if}
{#if secondaryText}
<p class="ogcr-kpi__secondary">{secondaryText}</p>
{/if}
Expand Down Expand Up @@ -135,6 +147,16 @@
font-variant-numeric: tabular-nums;
}

/* The value link duplicates the label link, so it is taken out of the tab
order (tabindex="-1") to avoid two stops for one destination. */
.ogcr-kpi__link {
text-decoration: none;
}
.ogcr-kpi__link:hover,
.ogcr-kpi__link:focus-visible {
text-decoration: underline;
}

.ogcr-kpi__secondary {
margin: 0;
font-family: var(--font-family-default);
Expand Down
2 changes: 1 addition & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
chain: 'Chain',
my: 'My',
operators: 'Operators',
'dynamic-entities': 'Entities',
schema: 'Schema',
create: 'Create',
user: 'My Account',
login: 'Login',
Expand Down
12 changes: 6 additions & 6 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,22 @@
const tools = $derived(
[
{
href: '/dynamic-entities',
href: '/schema',
icon: Database,
title: 'Entities',
description: 'Lookup, link, main and on-chain tables, with their endpoints and roles.'
title: 'Schema',
description: 'View schema and endpoints.'
},
{
href: data.apiManagerUrl,
icon: Wrench,
title: 'API Manager',
description: 'Manage OBP entities, roles and consumers.'
description: 'Manage schema and access.'
},
{
href: data.mcpUrl,
icon: Bot,
title: 'MCP Server',
description: 'Connect an AI assistant to OBP.'
description: 'Connect AI tools to the API.'
}
].filter((tool): tool is typeof tool & { href: string } => tool.href !== null)
);
Expand Down Expand Up @@ -116,7 +116,7 @@
{#if tools.length > 0}
<section aria-labelledby="obp-tools" class="mt-16 flex w-full justify-center px-8 pb-12">
<div class="w-full max-w-5xl">
<h2 id="obp-tools" class="mb-6 text-center h3">OBP tools</h2>
<h2 id="obp-tools" class="mb-6 text-center h3">Environment</h2>
<nav aria-labelledby="obp-tools" class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{#each tools as { href, icon: Icon, title, description } (title)}
<Card {href} {title} subtitle={description}>
Expand Down
81 changes: 15 additions & 66 deletions src/routes/registry/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,6 @@

let { data }: { data: PageData } = $props();

/**
* Hero image slot. Set this to the asset path once the final image is
* supplied (drop the file in static/ and point at it, e.g. '/registry-hero.jpg').
* Left null so the layout is demo-ready without shipping a broken <img> or
* hot-linking an external URL.
*/
const HERO_IMAGE: string | null = null;
const HERO_ALT =
'Farmland under cultivation, representative of the carbon farming activities listed in the registry';

const activityCount = $derived(data.activityCount);

// Issuance, holding and retirement figures have no source in the DCR schema
Expand All @@ -36,40 +26,28 @@
</svelte:head>

<div class="mx-auto max-w-6xl px-6 py-8">
<div class="grid grid-cols-1 gap-8 lg:grid-cols-2 lg:items-center">
<div>
<img src="/ogcr_logo.svg" alt="" class="mb-6 h-12" />
<h1 class="text-h1 mb-4">OGCR — Open Geospatial Carbon Registry</h1>
<p class="text-body mb-4 text-surface-600-400">
The OGCR registry lists carbon removal and carbon farming activities certified under the EU
Carbon Removals and Carbon Farming framework (CRCF). Each activity records the land it
covers, the practices applied, the operator responsible and the monitoring period over which
its results are measured.
</p>
<p class="text-body mb-8 text-surface-600-400">
Certification is carried out by accredited bodies and recorded against the activity, so a
buyer can trace a unit back to the parcel, the practice and the verification behind it.
</p>
<a href="/registry/activities" class="btn preset-filled-primary-500">Browse Activities</a>
</div>

<div class="ogcr-hero">
{#if HERO_IMAGE}
<img src={HERO_IMAGE} alt={HERO_ALT} class="ogcr-hero__img" />
{:else}
<!-- Placeholder until the final asset is supplied; see HERO_IMAGE above. -->
<div class="ogcr-hero__placeholder">
<span class="text-body-s">Hero image</span>
</div>
{/if}
</div>
<div class="max-w-3xl">
<img src="/ogcr_logo.svg" alt="" class="mb-6 h-12" />
<h1 class="text-h1 mb-4">OGCR — Open Geospatial Carbon Registry</h1>
<p class="text-body mb-4 text-surface-600-400">
The OGCR registry lists carbon removal and carbon farming activities certified under the EU
Carbon Removals and Carbon Farming framework (CRCF). Each activity records the land it
covers, the practices applied, the operator responsible and the monitoring period over which
its results are measured.
</p>
<p class="text-body mb-8 text-surface-600-400">
Certification is carried out by accredited bodies and recorded against the activity, so a
buyer can trace a unit back to the parcel, the practice and the verification behind it.
</p>
<a href="/registry/activities" class="btn preset-filled-primary-500">Browse Activities</a>
</div>

<section aria-labelledby="registry-summary" class="mt-12">
<h2 id="registry-summary" class="sr-only">Registry summary</h2>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Kpi
label="Activities"
href="/registry/activities"
value={activityCount ?? '—'}
secondaryText={activityCount === null ? 'Unavailable right now' : undefined}
accentBar={false}
Expand All @@ -95,32 +73,3 @@
{/if}
</section>
</div>

<style>
.ogcr-hero {
width: 100%;
}

.ogcr-hero__img,
.ogcr-hero__placeholder {
width: 100%;
aspect-ratio: 3 / 2;
border-radius: var(--radius-xl);
object-fit: cover;
}

.ogcr-hero__placeholder {
display: flex;
align-items: center;
justify-content: center;
background: var(--surface-neutral);
border: 1px dashed var(--border-medium);
color: var(--text-secondary);
}

:global([data-mode='dark']) .ogcr-hero__placeholder {
background: var(--color-surface-900);
border-color: var(--color-surface-700);
color: var(--color-surface-400);
}
</style>
Loading
Loading