chore: init pogoo-web deploy repo (static site + compose)

This commit is contained in:
Kantin Petit 2026-08-08 16:48:08 +02:00
commit 65fa14cb32
15 changed files with 210 additions and 0 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
* text=auto eol=lf
*.png binary
*.ico binary

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.env

26
README.md Normal file
View file

@ -0,0 +1,26 @@
# pogoo-web — repo `git.pogoo.app/kantin/pogoo-web`
Self-contained deploy repo for **pogoo.app** (main house site). Portainer-git friendly.
```
pogoo-web/
├── docker-compose.yml # context: ./site
└── site/ # index.html, Dockerfile, nginx.conf, favicons
```
## Deploy (Portainer-git, auto)
1. Push this repo to Forgejo: `git.pogoo.app/kantin/pogoo-web`.
2. Portainer → Stacks → Add → **Git repository**
- URL: `https://git.pogoo.app/kantin/pogoo-web.git`
- Compose path: `docker-compose.yml`
- Auth: Forgejo deploy token (read)
- **Automatic updates + webhook: ON**
3. Forgejo repo → Settings → Webhooks → paste the Portainer webhook URL.
4. `git push` → webhook → Portainer rebuilds + redeploys. TLS via Traefik (edge).
## Prereqs
- Edge stack up (Traefik + Portainer), `edge` network exists.
- DNS: `pogoo.app` + `www.pogoo.app` → server IP.
## Update the site
Edit `site/index.html` (or assets) → commit → push. Done.

22
docker-compose.yml Normal file
View file

@ -0,0 +1,22 @@
# pogoo.app — main house site. Self-contained repo for Portainer-git auto-deploy.
# Build context is INSIDE the repo (./site) so Portainer's checkout builds correctly.
name: pogoo-web
services:
web:
build:
context: ./site
image: pogoo/web:latest
restart: unless-stopped
networks: [edge]
labels:
- "traefik.enable=true"
- "traefik.http.routers.pogoo.rule=Host(`pogoo.app`) || Host(`www.pogoo.app`)"
- "traefik.http.routers.pogoo.entrypoints=websecure"
- "traefik.http.routers.pogoo.tls.certresolver=le"
- "traefik.http.routers.pogoo.middlewares=www-redirect@file,security-headers@file"
- "traefik.http.services.pogoo.loadbalancer.server.port=80"
networks:
edge:
external: true

3
site/.dockerignore Normal file
View file

@ -0,0 +1,3 @@
Dockerfile
.dockerignore
atlas/

6
site/Dockerfile Normal file
View file

@ -0,0 +1,6 @@
# Immutable static image for pogoo.app (main house site).
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY . /usr/share/nginx/html
# atlas/ lives here in the repo but is served on its own subdomain image; harmless if present.
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost/ >/dev/null || exit 1

BIN
site/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
site/favicon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

BIN
site/favicon-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
site/favicon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
site/favicon-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
site/favicon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
site/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

133
site/index.html Normal file
View file

@ -0,0 +1,133 @@
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Pogoo — A house of good tools</title>
<meta name="description" content="Pogoo builds things. A house of good tools — we design, build and ship durable digital products, all from the same spine."/>
<link rel="icon" href="favicon.ico" sizes="any"/>
<link rel="icon" href="favicon-32.png" type="image/png" sizes="32x32"/>
<link rel="apple-touch-icon" href="apple-touch-icon.png"/>
<meta property="og:title" content="Pogoo — A house of good tools"/>
<meta property="og:description" content="Perceive. Build. Ship."/>
<link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Instrument+Sans:wght@400;500;600&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet"/>
<style>
:root{
--ember:#E9762E;--ember-bright:#F0834A;--ink:#1A1714;
--clay:#C24A38;--sage:#7E8B5B;--stone:#4E7C8C;--plum:#7A5A78;--gold:#D9A441;
--sand-50:#FAF7F2;--sand-100:#F2ECE3;--sand-200:#E0D6C8;--clay-600:#6B6357;--ink-800:#2A251F;--ink-900:#1A1714;--ink-950:#14110E;
--bg:var(--sand-50);--surface:#fff;--surface-2:var(--sand-100);--border:var(--sand-200);
--text:var(--ink-900);--muted:var(--clay-600);--accent:var(--ember);--on-accent:var(--ink-900);
--fd:'Space Grotesk','Segoe UI',system-ui,sans-serif;--fb:'Instrument Sans','Inter',system-ui,sans-serif;--fm:'Space Mono',ui-monospace,monospace;
}
:root[data-theme="dark"]{--bg:var(--ink-950);--surface:var(--ink-900);--surface-2:var(--ink-800);--border:#332C24;--text:#F5F0E8;--muted:#A69D8D;--accent:var(--ember-bright);--on-accent:var(--ink-950)}
@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:var(--ink-950);--surface:var(--ink-900);--surface-2:var(--ink-800);--border:#332C24;--text:#F5F0E8;--muted:#A69D8D;--accent:var(--ember-bright);--on-accent:var(--ink-950)}}
*{box-sizing:border-box;margin:0}
body{background:var(--bg);color:var(--text);font-family:var(--fb);line-height:1.6;-webkit-font-smoothing:antialiased}
.wrap{max-width:1120px;margin:0 auto;padding:0 26px}
h1,h2,h3,.d{font-family:var(--fd);letter-spacing:-.03em;text-wrap:balance}
.mono{font-family:var(--fm)}
nav{position:sticky;top:0;z-index:20;backdrop-filter:blur(12px);background:color-mix(in srgb,var(--bg) 80%,transparent);border-bottom:1px solid var(--border)}
nav .wrap{display:flex;align-items:center;justify-content:space-between;height:70px}
.brand{display:flex;align-items:center;gap:10px;font-family:var(--fd);font-weight:600;font-size:21px;letter-spacing:-.03em}
.brand svg{width:30px;height:30px}
.nlinks{display:flex;gap:26px;align-items:center;font-size:15px}
.nlinks a{color:var(--muted);text-decoration:none}.nlinks a:hover{color:var(--text)}
.tbtn{font-family:var(--fm);font-size:12px;background:var(--surface);border:1px solid var(--border);color:var(--muted);padding:7px 12px;border-radius:99px;cursor:pointer}
.hero{padding:110px 0 80px;display:grid;grid-template-columns:1.25fr .75fr;gap:40px;align-items:center}
.hero h1{font-size:clamp(3rem,8vw,6rem);font-weight:700;line-height:.97}
.hero .sub{margin-top:24px;font-size:clamp(1.1rem,2vw,1.35rem);color:var(--muted);max-width:34ch}
.cta{margin-top:34px;display:flex;gap:16px;align-items:center;flex-wrap:wrap}
.btn{background:var(--accent);color:var(--on-accent);font-family:var(--fd);font-weight:600;padding:14px 24px;border-radius:14px;text-decoration:none;box-shadow:0 6px 20px rgba(233,118,46,.28);transition:transform .14s}
.btn:hover{transform:translateY(-1px)}
.ghost{font-family:var(--fm);color:var(--muted);text-decoration:none;font-size:14px}.ghost:hover{color:var(--accent)}
.heroart{display:flex;justify-content:center}.heroart svg{width:min(320px,66vw)}
#hr{stroke-dasharray:220;stroke-dashoffset:220;animation:draw 1.1s cubic-bezier(.16,1,.3,1) .2s forwards}
#hd{transform-box:fill-box;transform-origin:center;opacity:0;animation:pop .55s cubic-bezier(.34,1.56,.64,1) 1s forwards}
@keyframes draw{to{stroke-dashoffset:0}}@keyframes pop{0%{opacity:0;transform:translateY(-16px) scale(.3)}60%{opacity:1;transform:translateY(3px) scale(1.18)}100%{transform:none;opacity:1}}
@media(prefers-reduced-motion:reduce){#hr,#hd{animation:none;stroke-dashoffset:0;opacity:1}}
section{padding:64px 0}
.eyebrow{font-family:var(--fm);font-size:12px;text-transform:uppercase;letter-spacing:.14em;color:var(--muted)}
h2{font-size:clamp(1.7rem,3.6vw,2.4rem);font-weight:700;margin:8px 0 0}
.grid{margin-top:30px;display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:18px}
.card{position:relative;display:block;background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:26px;overflow:hidden;text-decoration:none;color:inherit;transition:transform .22s,box-shadow .22s}
.card:hover{transform:translateY(-3px);box-shadow:0 12px 32px rgba(26,23,20,.12)}
.card::after{content:"";position:absolute;top:0;right:0;width:36px;height:36px;background:var(--ca,var(--accent));clip-path:polygon(100% 0,0 0,100% 100%)}
.card .tag{font-family:var(--fm);font-size:12px;color:var(--ca,var(--accent))}
.card h3{font-family:var(--fd);font-weight:600;font-size:22px;margin:8px 0 6px}
.card p{color:var(--muted);font-size:14px}
.card .go{margin-top:14px;font-family:var(--fm);font-size:12px;color:var(--muted)}
.steps{margin-top:30px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:18px}
.step{border-top:2px solid var(--accent);padding-top:16px}
.step b{font-family:var(--fd);font-size:1.15rem;display:block}
.step p{color:var(--muted);font-size:14px;margin-top:6px}
.manifesto{background:var(--ink-950);color:var(--sand-50);border-radius:28px;padding:64px 48px;margin-top:20px;position:relative;overflow:hidden}
.manifesto h2{font-size:clamp(2rem,5vw,3.4rem);max-width:18ch;position:relative;z-index:1}
.manifesto p{color:#C9BCA9;max-width:52ch;margin-top:18px;position:relative;z-index:1}
.manifesto .bgpat{position:absolute;inset:0;opacity:.5}
footer{background:var(--ink-950);color:var(--sand-50);padding:56px 0}
footer .wrap{display:flex;justify-content:space-between;flex-wrap:wrap;gap:24px}
footer .col{display:flex;flex-direction:column;gap:8px;font-size:14px}
footer .col b{font-family:var(--fd)}footer a{color:#A69D8D;text-decoration:none}footer a:hover{color:var(--ember-bright)}
footer small{font-family:var(--fm);color:#7A7266}
@media(max-width:820px){.hero{grid-template-columns:1fr}.steps{grid-template-columns:1fr}.nlinks a:not(.pill){display:none}}
</style>
</head>
<body>
<nav><div class="wrap">
<span class="brand"><svg viewBox="0 0 100 100"><defs><mask id="n"><rect width="100" height="100" fill="#fff"/><rect x="45" y="-8" width="12" height="42" rx="6" transform="rotate(45 50 50)" fill="#000"/></mask></defs><g fill="var(--accent)"><path fill-rule="evenodd" d="M50 11a39 39 0 1 0 0 78 39 39 0 0 0 0-78Zm0 21a18 18 0 1 1 0 36 18 18 0 0 1 0-36Z" mask="url(#n)"/><circle cx="50" cy="50" r="8.5"/></g></svg> pogoo</span>
<span class="nlinks"><a href="#products">Products</a><a href="#build">How we build</a><a href="#lab">Lab</a><a href="#" class="pill"><button class="tbtn" id="tt">◐ theme</button></a></span>
</div></nav>
<header class="hero wrap">
<div>
<div class="eyebrow">A house of good tools · pogoo.app</div>
<h1>Pogoo builds things.</h1>
<p class="sub">We design, build and ship durable digital products — one at a time, all from the same spine.</p>
<div class="cta"><a class="btn" href="#products">See the products</a><a class="ghost" href="#build">$ how we build </a></div>
</div>
<div class="heroart"><svg viewBox="0 0 100 100"><circle id="hr" cx="50" cy="50" r="28" fill="none" stroke="var(--accent)" stroke-width="20"/><circle id="hd" cx="50" cy="50" r="8.5" fill="var(--accent)"/></svg></div>
</header>
<section id="products" class="wrap">
<div class="eyebrow">The house · products</div>
<h2>One house, many tools.</h2>
<div class="grid">
<a class="card" style="--ca:var(--stone)" href="https://atlas.pogoo.app"><span class="tag">pogoo · atlas</span><h3>Atlas</h3><p>Know where everything is. A living map of your infrastructure and services.</p><div class="go">atlas.pogoo.app →</div></a>
<a class="card" style="--ca:var(--sage)" href="https://relay.pogoo.app"><span class="tag">pogoo · relay</span><h3>Relay</h3><p>Move data between your tools without glue code. Connect, transform, ship.</p><div class="go">relay.pogoo.app →</div></a>
<a class="card" style="--ca:var(--clay)" href="https://mesa.pogoo.app"><span class="tag">pogoo · mesa</span><h3>Mesa</h3><p>A calm workspace for docs and decisions. Flat, fast, yours.</p><div class="go">mesa.pogoo.app →</div></a>
<a class="card" style="--ca:var(--plum)" href="https://lab.pogoo.app"><span class="tag">pogoo · lab</span><h3>Lab</h3><p>Experiments in progress. Freer voice, same house.</p><div class="go">lab.pogoo.app →</div></a>
</div>
</section>
<section id="build" class="wrap">
<div class="eyebrow">Method</div>
<h2>Perceive. Build. Ship.</h2>
<div class="steps">
<div class="step"><b>Perceive</b><p>Like the parietal eye — sense the real need before writing a line. No solution in search of a problem.</p></div>
<div class="step"><b>Build</b><p>One spine, shared tokens, shared craft. Each product inherits the system, then earns its own colour.</p></div>
<div class="step"><b>Ship</b><p>Durable over flashy. We release things meant to still be here in a decade.</p></div>
</div>
</section>
<section class="wrap" id="lab">
<div class="manifesto">
<svg class="bgpat" width="100%" height="100%" preserveAspectRatio="xMidYMid slice"><defs><pattern id="sc" width="80" height="70" patternUnits="userSpaceOnUse"><g fill="none" stroke="#E9762E" stroke-width="2" opacity=".4"><path d="M40 5 a35 35 0 0 1 35 35 a35 35 0 0 1 -70 0 a35 35 0 0 1 35 -35Z"/><circle cx="40" cy="40" r="6" fill="#E9762E" stroke="none"/></g></pattern></defs><rect width="100%" height="100%" fill="url(#sc)"/></svg>
<h2>A scale on its own still holds. Together, theyre armour.</h2>
<p>Every Pogoo product is a scale of the same body. Youll recognise the house before you see the logo — the type, the grid, the warmth. Thats the point.</p>
</div>
</section>
<footer><div class="wrap">
<div class="col"><span class="brand" style="color:var(--sand-50)"><svg viewBox="0 0 100 100"><defs><mask id="f"><rect width="100" height="100" fill="#fff"/><rect x="45" y="-8" width="12" height="42" rx="6" transform="rotate(45 50 50)" fill="#000"/></mask></defs><g fill="#F0834A"><path fill-rule="evenodd" d="M50 11a39 39 0 1 0 0 78 39 39 0 0 0 0-78Zm0 21a18 18 0 1 1 0 36 18 18 0 0 1 0-36Z" mask="url(#f)"/><circle cx="50" cy="50" r="8.5"/></g></svg> pogoo</span><small>Perceive · Build · Ship</small></div>
<div class="col"><b>Products</b><a href="https://atlas.pogoo.app">Atlas</a><a href="https://relay.pogoo.app">Relay</a><a href="https://mesa.pogoo.app">Mesa</a></div>
<div class="col"><b>Company</b><a href="#">About</a><a href="#lab">Lab</a><a href="#">Docs</a></div>
<div class="col"><b>Elsewhere</b><a href="#">@pogoo</a><a href="#">GitHub</a><small>© pogoo.app</small></div>
</div></footer>
<script>
document.getElementById('tt').addEventListener('click',function(e){e.preventDefault();var r=document.documentElement,c=r.getAttribute('data-theme')||(matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light');r.setAttribute('data-theme',c==='dark'?'light':'dark');});
</script>
</body>
</html>

16
site/nginx.conf Normal file
View file

@ -0,0 +1,16 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# long cache for hashed/static assets
location ~* \.(?:png|ico|svg|woff2?|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ /index.html;
}
# TLS + security headers are handled by Traefik at the edge.
}