Add static site for hatch.sh with blog post
- Create static site structure in site/ directory - Add landing page, blog index, and first blog post - Include Open Graph meta tags for social sharing - Add GitHub Actions workflow for GitHub Pages deployment - Include brand assets (OG image, favicon) - Add README with setup and DNS instructions Co-Authored-By: Paperclip <noreply@paperclip.ing>
43
.github/workflows/deploy-site.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
name: Deploy static site to GitHub Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'site/**'
|
||||||
|
- '.github/workflows/deploy-site.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v5
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
# Upload the site directory
|
||||||
|
path: 'site'
|
||||||
|
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
99
site/README.md
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# Hatch Static Site
|
||||||
|
|
||||||
|
This directory contains the static site for [hatch.sh](https://hatch.sh).
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
site/
|
||||||
|
├── index.html # Landing page
|
||||||
|
├── style.css # Global styles
|
||||||
|
├── blog/
|
||||||
|
│ ├── index.html # Blog index
|
||||||
|
│ └── why-we-are-building-hatch/
|
||||||
|
│ └── index.html # Blog post
|
||||||
|
└── brand/
|
||||||
|
├── og/
|
||||||
|
│ └── default.png # Open Graph image
|
||||||
|
└── favicon/
|
||||||
|
├── favicon.ico
|
||||||
|
└── favicon-*.png # Various sizes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
The site is automatically deployed to GitHub Pages via the `deploy-site.yml` workflow when changes are pushed to the `main` branch.
|
||||||
|
|
||||||
|
### GitHub Pages Setup
|
||||||
|
|
||||||
|
1. Go to repository Settings → Pages
|
||||||
|
2. Source: Deploy from a branch
|
||||||
|
3. Branch: `main`, folder: `/site`
|
||||||
|
4. Custom domain: `hatch.sh`
|
||||||
|
|
||||||
|
### DNS Configuration
|
||||||
|
|
||||||
|
To point `hatch.sh` to GitHub Pages:
|
||||||
|
|
||||||
|
1. Add these DNS records:
|
||||||
|
- Type: A, Name: @, Value: 185.199.108.153
|
||||||
|
- Type: A, Name: @, Value: 185.199.109.153
|
||||||
|
- Type: A, Name: @, Value: 185.199.110.153
|
||||||
|
- Type: A, Name: @, Value: 185.199.111.153
|
||||||
|
- Type: AAAA, Name: @, Value: 2606:50c0:8000::153
|
||||||
|
- Type: AAAA, Name: @, Value: 2606:50c0:8001::153
|
||||||
|
- Type: AAAA, Name: @, Value: 2606:50c0:8002::153
|
||||||
|
- Type: AAAA, Name: @, Value: 2606:50c0:8003::153
|
||||||
|
|
||||||
|
2. Enable HTTPS in GitHub Pages settings
|
||||||
|
|
||||||
|
### 301 Redirect from GitHub README
|
||||||
|
|
||||||
|
Add this to the README.md or as a GitHub Pages redirect:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- In site/index.html or a dedicated redirect page -->
|
||||||
|
<meta http-equiv="refresh" content="0; url=/blog/why-we-are-building-hatch/">
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use a JavaScript redirect for better SEO:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In a script tag or separate JS file
|
||||||
|
window.location.replace('/blog/why-we-are-building-hatch/');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
To preview the site locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd site
|
||||||
|
python3 -m http.server 8000
|
||||||
|
# Open http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with Node.js:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx serve site
|
||||||
|
```
|
||||||
|
|
||||||
|
## SEO Checklist
|
||||||
|
|
||||||
|
- [x] H1 = title
|
||||||
|
- [x] Meta description ≤ 160 chars
|
||||||
|
- [x] Primary keyword in first 200 words
|
||||||
|
- [x] OG image set
|
||||||
|
- [x] Internal link to repo
|
||||||
|
- [x] Canonical URL set
|
||||||
|
- [x] Semantic HTML
|
||||||
|
- [x] Mobile responsive
|
||||||
|
- [x] Fast loading (static HTML/CSS)
|
||||||
|
|
||||||
|
## Adding New Posts
|
||||||
|
|
||||||
|
1. Create a new directory under `blog/`
|
||||||
|
2. Create an `index.html` file with the post content
|
||||||
|
3. Update `blog/index.html` to include the new post
|
||||||
|
4. Follow the same HTML structure as existing posts
|
||||||
60
site/blog/index.html
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Blog — Hatch</title>
|
||||||
|
<meta name="description" content="Blog posts about Hatch, a self-hostable HTTP request inspector and mocker.">
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="Blog — Hatch">
|
||||||
|
<meta property="og:description" content="Blog posts about Hatch, a self-hostable HTTP request inspector and mocker.">
|
||||||
|
<meta property="og:image" content="https://hatch.sh/brand/og/default.png">
|
||||||
|
<meta property="og:url" content="https://hatch.sh/blog/">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="Blog — Hatch">
|
||||||
|
<meta name="twitter:description" content="Blog posts about Hatch, a self-hostable HTTP request inspector and mocker.">
|
||||||
|
<meta name="twitter:image" content="https://hatch.sh/brand/og/default.png">
|
||||||
|
|
||||||
|
<link rel="canonical" href="https://hatch.sh/blog/">
|
||||||
|
<link rel="icon" type="image/png" href="/brand/favicon/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<a href="/" class="logo">Hatch</a>
|
||||||
|
<nav>
|
||||||
|
<a href="https://github.com/elfoundation/hatch">GitHub</a>
|
||||||
|
<a href="/blog/">Blog</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="blog-index">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Blog</h1>
|
||||||
|
|
||||||
|
<article class="post-preview">
|
||||||
|
<header>
|
||||||
|
<h2><a href="/blog/why-we-are-building-hatch/">Why we are building Hatch</a></h2>
|
||||||
|
<time datetime="2026-06-23">June 23, 2026</time>
|
||||||
|
</header>
|
||||||
|
<p>Every team that integrates with a third-party API ends up needing a webhook inspector. The hosted tools work fine. They also send your payloads to someone else's server, which is a non-starter for the compliance-, privacy-, and "we'd rather not" set.</p>
|
||||||
|
<a href="/blog/why-we-are-building-hatch/" class="read-more">Read more →</a>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>© 2026 El Foundation. <a href="https://github.com/elfoundation/hatch">Hatch</a> is released under the <a href="https://github.com/elfoundation/hatch/blob/main/LICENSE">MIT License</a>.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
120
site/blog/why-we-are-building-hatch/index.html
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Why we are building Hatch — Hatch Blog</title>
|
||||||
|
<meta name="description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="Why we are building Hatch">
|
||||||
|
<meta property="og:description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
<meta property="og:image" content="https://hatch.sh/brand/og/default.png">
|
||||||
|
<meta property="og:url" content="https://hatch.sh/blog/why-we-are-building-hatch">
|
||||||
|
<meta property="og:type" content="article">
|
||||||
|
<meta property="article:published_time" content="2026-06-23">
|
||||||
|
<meta property="article:author" content="El Foundation">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="Why we are building Hatch">
|
||||||
|
<meta name="twitter:description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
<meta name="twitter:image" content="https://hatch.sh/brand/og/default.png">
|
||||||
|
|
||||||
|
<link rel="canonical" href="https://hatch.sh/blog/why-we-are-building-hatch">
|
||||||
|
<link rel="icon" type="image/png" href="/brand/favicon/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<a href="/" class="logo">Hatch</a>
|
||||||
|
<nav>
|
||||||
|
<a href="https://github.com/elfoundation/hatch">GitHub</a>
|
||||||
|
<a href="/blog/">Blog</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<article class="blog-post">
|
||||||
|
<div class="container">
|
||||||
|
<header class="post-header">
|
||||||
|
<h1>Why we are building Hatch</h1>
|
||||||
|
<time datetime="2026-06-23">June 23, 2026</time>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="post-content">
|
||||||
|
<p>Every team that integrates with a third-party API ends up needing a webhook inspector. The hosted tools — webhook.site, RequestBin (now Pipedream), Beeceptor, Hookdeck — work fine. They also send your payloads to someone else's server, which is a non-starter for the compliance-, privacy-, and "we'd rather not" set.</p>
|
||||||
|
|
||||||
|
<p>We are building Hatch for the set.</p>
|
||||||
|
|
||||||
|
<p>If you're looking for a <a href="https://github.com/elfoundation/hatch">requestbin alternative</a> that keeps your data on your own network, Hatch is the answer.</p>
|
||||||
|
|
||||||
|
<p>Hatch is a self-hostable HTTP request inspector and mocker. One Go binary. SQLite under the hood. <code>docker compose up</code>, and you have an inspection endpoint and a live feed in under 30 seconds. Your payloads never leave your box.</p>
|
||||||
|
|
||||||
|
<h2>Who this is for</h2>
|
||||||
|
|
||||||
|
<p>You are a backend or platform engineer. You integrate with one or more third-party APIs that send you webhooks. You have tried webhook.site or RequestBin; they are fine for an afternoon. You want the same UX, but you want the data on your own infrastructure, on your own laptop, on a $5 VPS, or in your CI. You do not want a hosted dashboard logging every payload to someone else's database. Hatch is for that job.</p>
|
||||||
|
|
||||||
|
<h2>What it does</h2>
|
||||||
|
|
||||||
|
<p>Three things, and nothing else:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><strong>Capture.</strong> Method, path, headers, query, body. Persists across restarts because the storage is SQLite on disk, not a hosted queue.</li>
|
||||||
|
<li><strong>Inspect.</strong> A live SSE feed of incoming requests. Click any captured request to see the headers, the body, the timing.</li>
|
||||||
|
<li><strong>Mock.</strong> Return a 200, a 500, or a custom JSON payload. For testing your own retry, backoff, and error-handling logic without spinning up a separate mock server.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>That is the whole v0.1.</p>
|
||||||
|
|
||||||
|
<h2>What it does not do</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>No auth, no teams, no SSO.</li>
|
||||||
|
<li>No search-across-history.</li>
|
||||||
|
<li>No multi-tenant cloud, no billing, no per-request fee.</li>
|
||||||
|
<li>No production webhook reliability primitives (retries, ordering, dedup). That is Hookdeck's lane.</li>
|
||||||
|
<li>No TCP/UDP tunneling. That is ngrok's lane.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Saying no is a feature. Every feature in v0.1 has to be something we can keep simple. A request inspector and a mocker are simple. Auth, teams, search, and cloud are not. So they are not in v0.1.</p>
|
||||||
|
|
||||||
|
<h2>Why a single binary, not a SaaS</h2>
|
||||||
|
|
||||||
|
<p>Three reasons, in order of importance:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><strong>Compliance and privacy.</strong> Some teams cannot legally send webhook payloads to a hosted SaaS. The current options for them are "build your own" (a week the first time, a day every time after) or "use a SaaS and accept the risk." Hatch is the third option — a self-hostable <a href="https://github.com/elfoundation/hatch">requestbin alternative</a> that keeps the data on your own network.</li>
|
||||||
|
<li><strong>Cost.</strong> A hosted inspector charges per request, per seat, or per retention day. Hatch is one Go binary on a $5 VPS. There is no per-request fee because there is no one to charge it. There is no free-tier cliff because there is no free tier.</li>
|
||||||
|
<li><strong>Speed of setup.</strong> <code>docker compose up</code> is faster than signing up for a SaaS, verifying your email, configuring your first bin, and pasting the URL into your webhook config. We have done the local-setup dance enough times to know.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>What is open and what is not</h2>
|
||||||
|
|
||||||
|
<p>The code is <a href="https://github.com/elfoundation/hatch">open source</a>. The license is MIT. The repo lives at <a href="https://github.com/elfoundation/hatch">github.com/elfoundation/hatch</a>. The README is the spec; the quickstart is one command; the issues tab is the roadmap.</p>
|
||||||
|
|
||||||
|
<p>We do not have a hosted cloud offering. We do not have a paid tier. We do not have a roadmap with a public date for either. When we do, the self-hosted build will keep working the same way it does today. We will not silently take a feature away from the OSS build to push it into a paid tier; that is a written promise, and the diff is the proof.</p>
|
||||||
|
|
||||||
|
<h2>How to try it</h2>
|
||||||
|
|
||||||
|
<pre><code>git clone https://github.com/elfoundation/hatch
|
||||||
|
cd hatch
|
||||||
|
docker compose up</code></pre>
|
||||||
|
|
||||||
|
<p>The README has the full quickstart, the API reference, and the limits of v0.1. If you find a bug, open an issue. If you want a feature that is not on the v0.1 list, open an issue anyway — we read every one, and "we do not do X yet" is a real answer.</p>
|
||||||
|
|
||||||
|
<p>Star the repo: <a href="https://github.com/elfoundation/hatch">github.com/elfoundation/hatch</a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>© 2026 El Foundation. <a href="https://github.com/elfoundation/hatch">Hatch</a> is released under the <a href="https://github.com/elfoundation/hatch/blob/main/LICENSE">MIT License</a>.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
site/brand/favicon/favicon-16.png
Normal file
|
After Width: | Height: | Size: 364 B |
BIN
site/brand/favicon/favicon-192.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
site/brand/favicon/favicon-32.png
Normal file
|
After Width: | Height: | Size: 691 B |
BIN
site/brand/favicon/favicon-48.png
Normal file
|
After Width: | Height: | Size: 786 B |
BIN
site/brand/favicon/favicon-512.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
site/brand/favicon/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
site/brand/og/default.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
87
site/index.html
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Hatch — Self-hostable HTTP request inspector + mocker</title>
|
||||||
|
<meta name="description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="Hatch — Self-hostable HTTP request inspector + mocker">
|
||||||
|
<meta property="og:description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
<meta property="og:image" content="/brand/og/default.png">
|
||||||
|
<meta property="og:url" content="https://hatch.sh">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="Hatch — Self-hostable HTTP request inspector + mocker">
|
||||||
|
<meta name="twitter:description" content="Hatch is a self-hostable HTTP request inspector and mocker. One Go binary, SQLite, no SaaS, no per-request fee. Open source, MIT.">
|
||||||
|
<meta name="twitter:image" content="/brand/og/default.png">
|
||||||
|
|
||||||
|
<link rel="canonical" href="https://hatch.sh">
|
||||||
|
<link rel="icon" type="image/png" href="/brand/favicon/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<a href="/" class="logo">Hatch</a>
|
||||||
|
<nav>
|
||||||
|
<a href="https://github.com/elfoundation/hatch">GitHub</a>
|
||||||
|
<a href="/blog/">Blog</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="hero">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Self-hostable HTTP request inspector + mocker</h1>
|
||||||
|
<p>One Go binary. SQLite under the hood. <code>docker compose up</code>, and you have an inspection endpoint and a live feed in under 30 seconds. Your payloads never leave your box.</p>
|
||||||
|
<div class="cta">
|
||||||
|
<a href="https://github.com/elfoundation/hatch" class="btn btn-primary">View on GitHub</a>
|
||||||
|
<a href="https://github.com/elfoundation/hatch#quick-start" class="btn btn-secondary">Quick Start</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="features">
|
||||||
|
<div class="container">
|
||||||
|
<h2>Three things, and nothing else</h2>
|
||||||
|
<div class="feature-grid">
|
||||||
|
<div class="feature">
|
||||||
|
<h3>Capture</h3>
|
||||||
|
<p>Method, path, headers, query, body. Persists across restarts because the storage is SQLite on disk, not a hosted queue.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<h3>Inspect</h3>
|
||||||
|
<p>A live SSE feed of incoming requests. Click any captured request to see the headers, the body, the timing.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<h3>Mock</h3>
|
||||||
|
<p>Return a 200, a 500, or a custom JSON payload. For testing your own retry, backoff, and error-handling logic.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="why">
|
||||||
|
<div class="container">
|
||||||
|
<h2>Why a single binary, not a SaaS</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Compliance and privacy.</strong> Some teams cannot legally send webhook payloads to a hosted SaaS. Hatch keeps the data on your own network.</li>
|
||||||
|
<li><strong>Cost.</strong> A hosted inspector charges per request, per seat, or per retention day. Hatch is one Go binary on a $5 VPS. There is no per-request fee because there is no one to charge it.</li>
|
||||||
|
<li><strong>Speed of setup.</strong> <code>docker compose up</code> is faster than signing up for a SaaS, verifying your email, configuring your first bin, and pasting the URL into your webhook config.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>© 2026 El Foundation. <a href="https://github.com/elfoundation/hatch">Hatch</a> is released under the <a href="https://github.com/elfoundation/hatch/blob/main/LICENSE">MIT License</a>.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
310
site/style.css
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/* Reset and base styles */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--color-primary: #2563eb;
|
||||||
|
--color-primary-dark: #1d4ed8;
|
||||||
|
--color-text: #1f2937;
|
||||||
|
--color-text-light: #6b7280;
|
||||||
|
--color-bg: #ffffff;
|
||||||
|
--color-bg-light: #f9fafb;
|
||||||
|
--color-border: #e5e7eb;
|
||||||
|
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
--font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.9em;
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Container */
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
header {
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 1rem 0;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
color: var(--color-text-light);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover {
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero section */
|
||||||
|
.hero {
|
||||||
|
padding: 4rem 0;
|
||||||
|
text-align: center;
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--color-text-light);
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: var(--color-primary-dark);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background-color: white;
|
||||||
|
color: var(--color-text);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Features section */
|
||||||
|
.features {
|
||||||
|
padding: 4rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features h2 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature {
|
||||||
|
padding: 1.5rem;
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature p {
|
||||||
|
color: var(--color-text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Why section */
|
||||||
|
.why {
|
||||||
|
padding: 4rem 0;
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.why ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.why li {
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blog post */
|
||||||
|
.blog-post {
|
||||||
|
padding: 3rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-header {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-header h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-header time {
|
||||||
|
color: var(--color-text-light);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 2rem 0 1rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content p {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content ul,
|
||||||
|
.post-content ol {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content li {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content strong {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
background-color: var(--color-bg-light);
|
||||||
|
padding: 2rem 0;
|
||||||
|
margin-top: 4rem;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--color-text-light);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||