pages and imprint

This commit is contained in:
Vincent van der Wal
2026-08-01 08:42:54 +02:00
parent 6b2db975b3
commit 315d4e2bdc
10 changed files with 426 additions and 11 deletions
@@ -131,6 +131,36 @@
{/each}
</nav>
<!-- About / legal links (hidden when collapsed; the pages stay reachable
via any expanded sidebar and the signup page footer) -->
{#if !collapsed}
<div class="px-4 py-3 text-[11px] leading-relaxed text-sidebar-foreground/60">
<a
class="hover:text-sidebar-foreground hover:underline"
href={resolve('/about')}
onclick={onMobileClose}>About</a
>
<span aria-hidden="true"> · </span>
<a
class="hover:text-sidebar-foreground hover:underline"
href={resolve('/legal/imprint')}
onclick={onMobileClose}>Imprint</a
>
<span aria-hidden="true"> · </span>
<a
class="hover:text-sidebar-foreground hover:underline"
href={resolve('/legal/privacy')}
onclick={onMobileClose}>Privacy</a
>
<span aria-hidden="true"> · </span>
<a
class="hover:text-sidebar-foreground hover:underline"
href={resolve('/legal/terms')}
onclick={onMobileClose}>Terms</a
>
</div>
{/if}
<!-- Collapse toggle (desktop sidebar only; the mobile drawer omits onToggle) -->
{#if onToggle}
<div class="border-t border-sidebar-border px-2 py-3">
+77
View File
@@ -0,0 +1,77 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
title: string;
/** Optional muted line under the title (e.g. "Last updated ..."). */
subtitle?: string;
children: Snippet;
}
let { title, subtitle, children }: Props = $props();
</script>
<svelte:head>
<title>{title} · Drizz.li</title>
</svelte:head>
<article class="mx-auto max-w-3xl py-2 lg:py-4">
<h1 class="text-2xl font-bold tracking-tight lg:text-3xl">{title}</h1>
{#if subtitle}
<p class="mt-1.5 text-sm text-muted-foreground">{subtitle}</p>
{/if}
<div class="prose-body mt-6">
{@render children()}
</div>
</article>
<style>
/* Lightweight typography for long-form pages (about / legal), themed with the
app tokens so it reads correctly in light and dark. */
.prose-body {
line-height: 1.65;
font-size: 0.95rem;
}
.prose-body :global(h2) {
margin: 2rem 0 0.6rem;
font-size: 1.15rem;
font-weight: 700;
letter-spacing: -0.01em;
}
.prose-body :global(h3) {
margin: 1.4rem 0 0.4rem;
font-size: 1rem;
font-weight: 600;
}
.prose-body :global(p) {
margin: 0.6rem 0;
}
.prose-body :global(ul) {
margin: 0.6rem 0;
padding-left: 1.4rem;
}
.prose-body :global(li) {
margin: 0.25rem 0;
}
.prose-body :global(a) {
color: var(--primary);
text-decoration: underline;
text-underline-offset: 2px;
}
.prose-body :global(strong) {
font-weight: 600;
}
.prose-body :global(address) {
font-style: normal;
margin: 0.6rem 0;
padding: 0.8rem 1rem;
border: 1px solid var(--border);
border-radius: 0.625rem;
background: var(--card);
}
.prose-body :global(hr) {
margin: 2rem 0;
border: 0;
border-top: 1px solid var(--border);
}
</style>
+4 -3
View File
@@ -52,9 +52,10 @@
</svg>
</div>
<h2 class="text-xl font-bold tracking-tight">{feature} is a premium feature</h2>
<h2 class="text-xl font-bold tracking-tight">{feature} is a supporter extra</h2>
<p class="mx-auto mt-1.5 max-w-sm text-sm text-muted-foreground">
Support this open-source weather project and unlock the extras from {price}.
Drizz.li is free and open source. Chip in from {price} to keep it running - as a thank-you, supporters
unlock the extras.
</p>
<ul class="mx-auto mt-5 grid max-w-sm gap-2 text-left">
@@ -81,7 +82,7 @@
rel="noopener"
class="inline-flex h-10 w-full items-center justify-center rounded-lg bg-primary px-5 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90 sm:w-auto"
>
Subscribe
Become a supporter
</a>
<button
type="button"
+2 -2
View File
@@ -16,8 +16,8 @@
? 'border-amber-400/50 bg-amber-400/10 text-amber-700 hover:bg-amber-400/20 dark:text-amber-300'
: 'border-border/70 text-muted-foreground hover:bg-muted hover:text-foreground'}"
onclick={() => (open = true)}
title={$isPremium ? 'Premium active' : 'Unlock premium'}
aria-label={$isPremium ? 'Premium active' : 'Unlock premium'}
title={$isPremium ? 'Supporter extras active' : 'Support Drizz.li'}
aria-label={$isPremium ? 'Supporter extras active' : 'Support Drizz.li'}
>
{#if $isPremium}
<!-- star -->
+3 -3
View File
@@ -60,9 +60,9 @@
<Dialog.Root bind:open>
<Dialog.Content class="sm:max-w-md">
<Dialog.Header>
<Dialog.Title>Drizz.li Premium</Dialog.Title>
<Dialog.Title>Drizz.li Supporter</Dialog.Title>
<Dialog.Description>
Paste the access key from your subscription email to unlock premium pages.
Paste the access key from your supporter email to unlock the extras.
</Dialog.Description>
</Dialog.Header>
@@ -131,7 +131,7 @@
rel="noopener"
class="font-semibold text-primary underline-offset-2 hover:underline"
>
Subscribe from {price}
Support the project from {price}
</a>
</p>
{/if}
+3 -3
View File
@@ -13,7 +13,7 @@ const stripTrailingSlash = (url: string): string => url.replace(/\/+$/, '');
/** Base URL of the self-hosted verify API (drizzli-paywall). */
export const PAYWALL_API_BASE = stripTrailingSlash(
env.VITE_PAYWALL_API_BASE ?? 'https://paywall.drizz.li'
env.VITE_PAYWALL_API_BASE ?? 'https://support.drizz.li'
);
/** Where prospective subscribers go to sign up (the paywall repo's signup form). */
@@ -60,8 +60,8 @@ export function getPremiumPrice(): string {
return currency === 'CHF' ? `${symbol} 3 / month` : `${symbol}3 / month`;
}
/** Short, human list of what premium unlocks (shown on the locked panel). */
/** Short, human list of what supporting unlocks (shown on the locked panel). */
export const PREMIUM_PERKS = [
'Historical weather & climate-normal comparisons',
'New premium features as they land'
'New supporter extras as they land'
];
+41
View File
@@ -0,0 +1,41 @@
<script lang="ts">
import ProsePage from '$lib/components/prose-page.svelte';
</script>
<ProsePage title="About Drizz.li" subtitle="A small, open-source weather site.">
<p>
Drizz.li is an independent weather site. It shows multi-model forecasts, model comparisons,
14-day outlooks, weather maps and historical weather - without accounts, ads or trackers.
</p>
<h2>How it works</h2>
<p>
All weather data comes from the excellent open-data APIs of
<a href="https://open-meteo.com" target="_blank" rel="noopener">Open-Meteo</a>, which aggregates
national weather services (DWD, NOAA, Météo-France, MeteoSwiss and more). Drizz.li is a static
site: forecasts are fetched directly by your browser and rendered on your device.
</p>
<p>
The site is open source. Anyone can read the code, report issues or contribute improvements.
</p>
<h2>Supporting the project</h2>
<p>
Drizz.li is free to use. If you find it useful, you can support it with a small monthly
contribution (from €3 / month) - it helps cover the domain, hosting and development time. As a
thank-you, supporters unlock the extras: historical weather with climate-normal comparisons, and
new supporter features as they land.
</p>
<p>
Contributions are handled by a simple bank transfer - no payment processor, no stored card
details. The details of how that works are in the
<a href="/legal/terms/">supporter terms</a> and the
<a href="/legal/privacy/">privacy policy</a>.
</p>
<h2>Contact</h2>
<p>
Questions, feedback or bug reports:
<a href="mailto:drizzli@vincentvanderwal.nl">drizzli@vincentvanderwal.nl</a>
</p>
</ProsePage>
+36
View File
@@ -0,0 +1,36 @@
<script lang="ts">
import ProsePage from '$lib/components/prose-page.svelte';
</script>
<!-- TODO(vincent): replace the [bracketed] placeholders with your real postal
address and country before deploying. An imprint without a serviceable
address does not satisfy the imprint/contact requirements. -->
<ProsePage title="Imprint" subtitle="Legal notice / provider identification.">
<h2>Service provider</h2>
<address>
Vincent van der Wal<br />
[Street and number]<br />
[Postal code, City]<br />
[Country]
</address>
<p>
Email: <a href="mailto:drizzli@vincentvanderwal.nl">drizzli@vincentvanderwal.nl</a>
</p>
<p>
Drizz.li is operated as a personal, independent project. Responsible for the content of this
website: Vincent van der Wal (address above).
</p>
<h2>Disclaimer</h2>
<p>
Weather data shown on this site is provided for general information only. Forecasts are
inherently uncertain; do not rely on them where life, health or property is at stake - consult
official warnings from your national weather service instead.
</p>
<p>
Weather and geodata are retrieved from
<a href="https://open-meteo.com" target="_blank" rel="noopener">Open-Meteo</a>, which is not
affiliated with this site. External links are provided in good faith; their content is the
responsibility of the respective operators.
</p>
</ProsePage>
+146
View File
@@ -0,0 +1,146 @@
<script lang="ts">
import ProsePage from '$lib/components/prose-page.svelte';
</script>
<!-- TODO(vincent): fill in the [bracketed] placeholders (address, hosting
provider, supervisory authority) before deploying. -->
<ProsePage title="Privacy policy" subtitle="Last updated: 1 August 2026">
<p>
Drizz.li is built to need as little of your data as possible: there are no user accounts, no
cookies, no advertising and no analytics or tracking scripts. This page explains what little
processing does happen - when you browse the site, and when you support the project with a
contribution.
</p>
<h2>1. Controller</h2>
<address>
Vincent van der Wal<br />
[Street and number], [Postal code, City], [Country]<br />
Email: <a href="mailto:drizzli@vincentvanderwal.nl">drizzli@vincentvanderwal.nl</a>
</address>
<p>
This policy covers the websites drizz.li (the weather app) and support.drizz.li (the supporter
signup page).
</p>
<h2>2. Browsing the site</h2>
<h3>Weather data requests</h3>
<p>
Drizz.li is a static site: when you open a forecast, your browser fetches the weather data
directly from the open-data APIs of
<a href="https://open-meteo.com" target="_blank" rel="noopener">Open-Meteo</a>
(api.open-meteo.com, geocoding-api.open-meteo.com, archive-api.open-meteo.com, ensemble-api.open-meteo.com,
and map tiles from maps.open-meteo.com / map-tiles.open-meteo.com / map-assets.open-meteo.com). Like
any web request, this transmits your IP address and the requested location or search term to Open-Meteo.
We do not receive or store any of this. See
<a href="https://open-meteo.com/en/terms" target="_blank" rel="noopener"
>Open-Meteo's terms and privacy information</a
>. Legal basis: our legitimate interest in delivering the content you request (Art. 6(1)(f)
GDPR).
</p>
<h3>Hosting</h3>
<p>
The static site is served by [hosting provider, location]. The hosting infrastructure may keep
short-lived technical server logs (IP address, requested URL, timestamp) for security and
operations. Legal basis: legitimate interest in a secure, reliable service (Art. 6(1)(f) GDPR).
</p>
<h3>Settings on your device (local storage)</h3>
<p>
Your preferences - theme, measurement units, last searched location, and (for supporters) your
access key and its last verification result - are stored only in your browser's local storage.
They never leave your device except as described below for key verification, and you can clear
them at any time via your browser.
</p>
<h2>3. Supporting the project (contributions)</h2>
<p>
Supporter contributions unlock the supporter extras, so legally they are a paid agreement, not a
pure gift - and this is what we process to handle them:
</p>
<h3>Signup form</h3>
<ul>
<li>
<strong>Email address</strong> (required) - to send you the transfer details and, after your contribution
arrives, your access key.
</li>
<li><strong>Name</strong> (optional) - to help match your bank transfer.</li>
<li>
<strong>Currency and amount</strong> - shown based on your browser's locale/timezone, detected on
your device (no geolocation request is made).
</li>
<li>
<strong>IP address and technical anti-bot signals</strong> - kept with the signup request to prevent
abuse and spam of the form.
</li>
<li>
<strong>Payment reference</strong> (e.g. DRZ-XXXXXX) - generated per request to match your transfer
to your signup.
</li>
</ul>
<p>
The transfer details (bank account and reference) are sent to you by email rather than shown on
the page. Legal bases: performance of the agreement (Art. 6(1)(b) GDPR) and, for the anti-abuse
measures, legitimate interest (Art. 6(1)(f) GDPR).
</p>
<h3>Bank transfer</h3>
<p>
Contributions are paid by ordinary bank transfer. Your bank and ours process the transfer data
under their own responsibility; on our bank statement we see the usual transfer details (your
name, account number, amount, reference). We use them only to match your contribution and are
required to retain accounting records under statutory bookkeeping and tax law (Art. 6(1)(c)
GDPR).
</p>
<h3>Access key and verification</h3>
<p>
After your transfer is matched (manually, usually within 24 hours), you receive an access key by
email. When you paste it into Drizz.li, your browser sends the key to our verification endpoint
(support.drizz.li) to check whether it is active; the response contains only the validity, tier
and expiry. The subscriber list (key, email, expiry) is stored on our server for as long as your
access is active.
</p>
<h3>Email</h3>
<p>
Transactional emails (transfer details, access key, renewals) are sent through our email
provider, Strato (Strato AG, Germany), acting as a processor. We send no newsletters or
marketing email.
</p>
<h2>4. Retention</h2>
<ul>
<li>Signup requests that are never paid are deleted after 6 months at the latest.</li>
<li>
Supporter records (key, email, expiry) are kept while your access is active and deleted within
12 months after it expires, unless you ask us to delete them sooner.
</li>
<li>
Accounting records (bank statements showing your transfer) are kept for the statutory
retention period (up to 10 years, depending on jurisdiction).
</li>
</ul>
<h2>5. Recipients</h2>
<p>
We do not sell or share personal data with third parties for their own purposes. Recipients are
limited to: Open-Meteo (weather requests made directly by your browser), our hosting provider,
our email provider (Strato), and the banks involved in your transfer.
</p>
<h2>6. Your rights</h2>
<p>
Under the GDPR you have the right to access, rectification, erasure, restriction of processing,
data portability, and to object to processing based on legitimate interest. Where processing is
based on consent, you may withdraw it at any time. To exercise any of these rights, email
<a href="mailto:drizzli@vincentvanderwal.nl">drizzli@vincentvanderwal.nl</a>. You also have the
right to lodge a complaint with a supervisory authority, in particular in the EU member state of
your residence, or with [competent supervisory authority of the controller].
</p>
<p>
For visitors from Switzerland: the corresponding rights under the Swiss Federal Act on Data
Protection (FADP) apply equivalently.
</p>
<h2>7. Changes</h2>
<p>
We may update this policy when the service changes; the date above reflects the latest revision.
</p>
</ProsePage>
+84
View File
@@ -0,0 +1,84 @@
<script lang="ts">
import ProsePage from '$lib/components/prose-page.svelte';
</script>
<!-- TODO(vincent): confirm the governing-law country in section 8. -->
<ProsePage title="Supporter terms" subtitle="Last updated: 1 August 2026">
<p>
Drizz.li is free to use. These terms cover the optional supporter contribution: a small payment
that helps keep the project running and, as a thank-you, unlocks the supporter extras. Although
we call it a contribution, features are unlocked in return - so legally it is a paid agreement
between you and the provider named in the
<a href="/legal/imprint/">imprint</a>, and consumer protection rules apply to it.
</p>
<h2>1. What you get</h2>
<p>
A supporter contribution unlocks the supporter extras for the paid period: currently historical
weather with climate-normal comparisons, plus new supporter features as they land. The free
parts of Drizz.li stay free for everyone.
</p>
<h2>2. How it works</h2>
<ul>
<li>
You request the transfer details on the signup page; we email them to you together with a
personal payment reference.
</li>
<li>
You transfer the amount (from €3 / $3 / CHF 3 per month) by ordinary bank transfer, including
the reference.
</li>
<li>
Transfers are matched manually. Once your contribution arrives - usually within 24 hours, at
most a few days - you receive a personal access key by email.
</li>
<li>
You paste the key into Drizz.li once; it is stored on your device and verified automatically.
</li>
</ul>
<h2>3. No auto-renewal</h2>
<p>
Contributions are one-off and prepaid: nothing renews automatically and we never charge you.
When your period ends, the extras simply lock again; contributing again with the same email
extends your existing key.
</p>
<h2>4. Withdrawal and refunds</h2>
<p>
If you are a consumer in the EU/EEA, you have a statutory 14-day right of withdrawal. Beyond
that, we keep it simple: if you are unhappy for any reason within 14 days of receiving your
access key, email
<a href="mailto:drizzli@vincentvanderwal.nl">drizzli@vincentvanderwal.nl</a> and we will refund your
contribution in full.
</p>
<h2>5. Fair use</h2>
<p>
The access key is personal. Please don't publish or share it; keys that are clearly abused (e.g.
shared publicly) may be revoked. If your key is revoked without cause, you are entitled to a
pro-rata refund.
</p>
<h2>6. Service and availability</h2>
<p>
Drizz.li is a personal open-source project, provided as-is. We work to keep it available and
accurate, but we cannot guarantee uninterrupted availability or the correctness of forecasts -
weather data is informational only (see the disclaimer in the imprint). If the supporter extras
become permanently unavailable during a period you paid for, we will refund the remaining period
on request.
</p>
<h2>7. Data</h2>
<p>
How we handle your data (email, payment reference, bank transfer details) is described in the
<a href="/legal/privacy/">privacy policy</a>.
</p>
<h2>8. Governing law</h2>
<p>
These terms are governed by the law of [Switzerland], without prejudice to mandatory consumer
protection provisions of your country of residence.
</p>
</ProsePage>