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
1 change: 1 addition & 0 deletions .github/workflows/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
app_build_command: "npm run build"
env: # Put a node version on the following line
NODE_VERSION: 22
PUBLIC_RYBBIT_SITE_ID: ${{ secrets.PUBLIC_RYBBIT_SITE_ID }}

close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
Expand Down
14 changes: 14 additions & 0 deletions swa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ Mostly you will start with a `favicon.svg` file, and use a tool like [RealFavico

To figure out which icons are needed for your specific use case, you can refer to [this comprehensive guide on favicons](https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs) and [RealFaviconGenerator - FAQ](https://realfavicongenerator.net/faq).

## Web Analytics

This page is using [Rybbit](https://rybbit.io/) for web analytics. To set it up, you need to sign up for an account at Rybbit and create a new site to get your unique Site ID.

To include your Rybbit Site ID in the Astro project, you should set it as an environment variable `PUBLIC_RYBBIT_SITE_ID` in your deployment platform. For local development, you can create a `.env` file in the `swa/` directory with the following content:

```plaintext
PUBLIC_RYBBIT_SITE_ID=your_site_id_here
```

_This variable is rendered into the astro page at buildtime._

You can find more information about using environment variables in Astro in the [Astro documentation](https://docs.astro.build/en/guides/environment-variables/).

## 🧞 Commands

All commands are run from the `swa` directory, from a terminal:
Expand Down
22 changes: 22 additions & 0 deletions swa/src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { text } = Astro.props;

<footer>
<p>{text}</p>
<a href="/privacy">Privacy Statement</a>
</footer>

<style>
Expand All @@ -17,4 +18,25 @@ const { text } = Astro.props;
color: rgb(var(--accent-light));
font-size: 0.9rem;
}

/* Unvisited (unclicked) link */
a:link {
color: rgb(var(--accent-light));
text-decoration: none;
}

/* Visited (opened/clicked) link */
a:visited {
text-decoration:line-through;
color: rgb(var(--accent-light));
}

/* Hover state */
a:hover {
text-decoration: underline;
font-weight: bold;
}

/* Active state (while clicking) */
a:active {}
</style>
9 changes: 9 additions & 0 deletions swa/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
/// <reference types="astro/client" />

interface ImportMetaEnv {
readonly PUBLIC_RYBBIT_SITE_ID: number
// more env variables...
}

interface ImportMeta {
readonly env: ImportMetaEnv
}
10 changes: 10 additions & 0 deletions swa/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface Props {
}

const { title, description, keywords } = Astro.props;

const rybbitSiteId = import.meta.env.PUBLIC_RYBBIT_SITE_ID || "";

---

<!doctype html>
Expand All @@ -29,6 +32,13 @@ const { title, description, keywords } = Astro.props;
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<meta name="generator" content={Astro.generator} />

<script
is:inline
src="https://app.rybbit.io/api/script.js"
data-site-id={rybbitSiteId}
defer
></script>
</head>
<body>
<slot />
Expand Down
84 changes: 84 additions & 0 deletions swa/src/layouts/LegalPage.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
import BaseLayout from '@layouts/BaseLayout.astro';
import "@styles/base.css";
// 1. The frontmatter prop gives access to frontmatter and other data
const { frontmatter } = Astro.props;
---
<BaseLayout
title={frontmatter.title}
description={frontmatter.description}
keywords={frontmatter.categories ? frontmatter.categories.join(", ") : ""}
>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">

<main class="container">
<header class="title">
<h1>{frontmatter.title}</h1>
<div class="meta">
<span>
Last Updated: {new Date(frontmatter.lastModified)
.toLocaleDateString('en-US', { year: 'numeric', month: 'long' })}
</span>
</div>
</header>
<article class="content">
<slot /> <!-- Markdown content is injected here -->
</article>
</main>
</BaseLayout>

<style>
main.container {
max-width: 1000px;
margin: 2rem auto;
padding: 2rem;
background-color: rgb(var(--contrast-dark));
border-radius: 1.25rem;
box-shadow: 0 4px 24px 0 rgb(var(--contrast-light));
}
header.title {
margin-bottom: 1.5rem;
text-align: center;
}
.meta {
color: rgb(var(--accent-light));
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.meta > span:first-child {
flex-basis: 100%;
}
.tags {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
justify-content: center;
}
.tag {
padding: 0.375rem 0.75rem;
background-color: rgb(var(--accent-light));
color: rgb(var(--contrast));
border-radius: 0.375rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: capitalize;
white-space: nowrap;
}
article.content {
padding: 1.6rem;
margin-bottom: 2rem;
background-color: rgb(var(--contrast));
border-radius: 1.25rem;
overflow-wrap: break-word;
font-size: 0.9rem;
/* explicitly remove box-shadow to overwrite pico.css */
box-shadow: none !important;
}
article.content>h2 {
--pico-font-size: 0.6rem !important;
font-size: 0.6rem !important;
}
</style>
88 changes: 88 additions & 0 deletions swa/src/pages/privacy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
layout: '@layouts/LegalPage.astro'
title: 'Privacy Policy'
draft: false
lastModified: 2025-12
description: 'Our commitment to protecting your data and privacy.'
categories: ['legal', 'privacy']
---


## Overview

We take your privacy seriously. This policy explains what data we collect, why we collect it, and how we use it.

We may update this Privacy Policy periodically to reflect changes in our practices or for legal reasons. We will post the updated policy on this page with a revised date. If you want to make sure that you are up-to-date with the latest changes, we advise you to frequently visit this page.

## Consent

By using our website, you hereby consent to our Privacy Policy and agree to its terms.

## What We Collect

We gather only minimal data necessary to operate our website effectively and enhance your experience. We collect this information based on our legitimate interests to improve our services and maintain site functionality.
We will not sell your personal information to any third parties, but we may be required to share it by law.

### Website Analytics

We use the privacy-focused analytics service Rybbit to gain insights into how visitors interact with our website. This allows us to enhance the user experience and identify the most valuable features.

**Data collected:**

- Pages you have visited
- Time spent on pages
- Your approximate location (country/region level)
- Device type and browser information

Rybbit.com does not use cookies. This data is collected through a small tracking script.

**Why:** To understand usage patterns and improve our website.
**Retention:** Analytics data is retained for 6 months to help us identify trends over time without storing long-term personal data.

### Backend Monitoring

For certain backend APIs, we use Azure Services to troubleshoot technical issues and understand which features people use.

**Data collected:**

- API request information (what was requested, when, and how long it took)
- Error details in case of failures
- Performance metrics

**Why:** To keep our services running smoothly and identify problems quickly.
**Retention:** Monitoring data that may contain client details is retained for 30 days.

## What We Don't Collect

- **No cookies** — Our website does not use cookies.
- **No personal identification** — We don't collect your name, email, or personal information unless you explicitly provide it. _We do process your IP address to determine your approximate location — we don't store your IP address._
- **No tracking across other websites** — Our analytics are limited to this website only. We do not follow you around the web.

## Links to Other Websites

Our website contains links that lead to other websites. If you click on these links, we cannot be held responsible for your data and privacy protection. Visiting those websites is not governed by this privacy policy agreement. Make
sure to read the privacy policy of any website you visit from ours.

## Third-Party Services

Our data processors:

- **Rybbit.com** — Web analytics. See their [privacy policy](https://rybbit.com/privacy).
- **Microsoft Azure** — Hosting and application monitoring. See their [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) and [understand privacy at Azure](https://azure.microsoft.com/en-us/explore/trusted-cloud/privacy/).

## Your Data Rights

Under the General Data Protection Regulation (GDPR), you have the rights to:

- Know what data we collect about you
- Correct any inaccurate data
- Request access to your data
- Request deletion of your data (where legally possible)
- Restrict processing of your data
- Request your data in a portable format
- Decline our processing of your data for specific purposes (where applicable)
- File a complaint with your local data protection authority if you believe we violate your rights

## Contact Us

If you have any questions about this Privacy Policy, please contact us at <[email protected]>.