feat: initial Greasy Sprocket website — Astro static + Go feedback service

- Astro 5.x static site with content collections for extensions
- Pages: index, [slug] (per-extension), coffee (Ko-fi), feedback form
- Go binary gs-feedback: SQLite storage + Discord webhook notification
- Nginx config: static serving + POST proxy to Go backend
- Deploy script: build + rsync to VPS
- ThockBoard landing page with features and sound pack listing
This commit is contained in:
Jose Juan Moñino
2026-07-09 23:53:01 +02:00
commit c5958f283f
23 changed files with 4601 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
---
import Base from '../layouts/Base.astro';
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const extensions = await getCollection('extensions');
return extensions.map((ext) => ({
params: { slug: ext.slug },
props: { ext },
}));
}
const { ext } = Astro.props;
const { Content } = await ext.render();
---
<Base title={`${ext.data.name} — Greasy Sprocket`} description={ext.data.tagline}>
<section class="ext-hero">
<div class="container">
<div class="info">
<span class="badge">100% Free</span>
<h1>{ext.data.name}</h1>
<p>{ext.data.tagline}</p>
<div style="display:flex;gap:12px">
{ext.data.chromeStoreUrl && (
<a href={ext.data.chromeStoreUrl} class="btn btn-primary" target="_blank" rel="noopener">
Add to Chrome
</a>
)}
{ext.data.downloadUrl && (
<a href={ext.data.downloadUrl} class="btn btn-outline">
Download ZIP
</a>
)}
</div>
</div>
{ext.data.screenshot && (
<div class="screenshot">
<img src={ext.data.screenshot} alt={`${ext.data.name} screenshot`} />
</div>
)}
</div>
</section>
<section class="section">
<div class="container">
<div class="feature-list">
{ext.data.features?.map((feature: string) => (
<div class="feature-item">
<h4>✅ {feature}</h4>
</div>
))}
</div>
<div style="margin-top:32px">
<Content />
</div>
</div>
</section>
</Base>