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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pnpm-debug.log*
# environment variables
.env
.env.production
data/studio-commissions.json

# macOS-specific files
.DS_Store
Expand Down
65 changes: 54 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ This repository powers a content-first website with:
- a markdown-driven blog (`/blog` and `/blog/[slug]`)
- a private studio gate and session dashboard (`/studio`, `/studio/[session]`)

The project uses Astro for routing/rendering, Svelte for interactive UI, and Tailwind CSS v4 for styling.
The project uses Astro for routing/rendering, Svelte for interactive UI, and
Tailwind CSS v4 for styling.

## Tech Stack

Expand Down Expand Up @@ -87,7 +88,8 @@ draft: false

Notes:

- `draft: true` posts are hidden from `/blog` and redirected away on detail pages.
- `draft: true` posts are hidden from `/blog` and redirected away on detail
pages.
- The slug is derived from the markdown filename.

## Environment Variables
Expand All @@ -97,28 +99,67 @@ Create a local env file before using the commissions form integration:
```bash
cat > .env <<'EOF'
VITE_TOKEN=your_telegram_bot_token
PUBLIC_STUDIO_API_BASE_URL=https://api.gxbs.dev
PUBLIC_STUDIO_USE_MOCK_DATA=true
STUDIO_COMMISSIONS_FILE=/absolute/path/to/studio-commissions.json
STUDIO_ADMIN_USERNAME=owner
STUDIO_ADMIN_PASSWORD=change_me
STUDIO_AUTH_SECRET=replace_with_a_long_random_secret
STUDIO_KOFI_URL=https://ko-fi.com/gabs
STUDIO_GITHUB_SPONSORS_URL=https://github.com/sponsors/gabs
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxx
STUDIO_EMAIL_FROM="gxbs Studio <studio@your-domain.com>"
STUDIO_EMAIL_REPLY_TO=hello@your-domain.com
EOF
```

The commissions form (`src/components/Commissions.svelte`) sends submissions to Telegram using this token.

If you do not set `VITE_TOKEN`, the partnerships form submission will fail.
The commissions form (`src/components/Commissions.svelte`) sends submissions to
Telegram using this token. `PUBLIC_STUDIO_API_BASE_URL` controls where the
Studio client fetches production project data from.
`PUBLIC_STUDIO_USE_MOCK_DATA` only applies during local development; set it to
`false` to exercise the live API path. `STUDIO_COMMISSIONS_FILE` optionally
overrides the server-side JSON persistence file used by Studio admin APIs.
`STUDIO_ADMIN_USERNAME` and `STUDIO_ADMIN_PASSWORD` define admin credentials.
`STUDIO_AUTH_SECRET` signs the admin session cookie and should be a long random
secret. `STUDIO_KOFI_URL` sets the default client payment page used by the admin
payment-link action. `STUDIO_GITHUB_SPONSORS_URL` is optional fallback for
sponsor-style payments. `RESEND_API_KEY` enables transactional Studio emails via
Resend. `STUDIO_EMAIL_FROM` controls the sender identity (must be verified in
Resend). `STUDIO_EMAIL_REPLY_TO` is optional and sets the reply-to mailbox.

If you do not set `VITE_TOKEN`, the partnerships form submission will fail. If
Ko-fi/GitHub payment URLs are not set, Studio defaults to
`https://ko-fi.com/gabs`.

## Studio Routes

- `src/pages/studio/index.astro`: access gate view
- `src/pages/studio/[session].astro`: session-based dashboard route (`prerender = false`)
- `src/pages/studio/[session].astro`: session-based dashboard route
(`prerender = false`)
- `src/pages/studio/admin.astro`: authenticated admin dashboard route
- `src/pages/studio/admin/login.astro`: admin sign-in route

Current behavior in `src/components/studio/StudioDashboard.svelte`:

- `DEV_MODE` is set to `true`, so mock data is used.
- Set `DEV_MODE` to `false` to fetch real data from `https://api.gxbs.dev/api/studio/${uuid}`.
- Client mode fetches from `PUBLIC_STUDIO_API_BASE_URL` (defaults to
`https://api.gxbs.dev`).
- Local mock data can be enabled in development with
`PUBLIC_STUDIO_USE_MOCK_DATA`.
- In `mode="admin"`, approved commissions can generate Ko-fi payment links and
mark invoices paid.
- Admin commission records are persisted server-side via
`src/pages/api/studio/commissions*.ts`.
- Studio admin route and admin APIs are protected by a signed cookie in
`src/middleware.ts`.
- Lifecycle emails are sent on review/approve/deny/payment updates using Resend
and templates from `src/utils/studioEmailTemplates.ts`.

## Styling and Assets

- Global styles: `src/styles/global.css`
- Typography plugin enabled for rich markdown rendering
- Custom `PPEditorialNew` & `PPNeueMontreal` font files are loaded from `public/fonts/`
- Custom `PPEditorialNew` & `PPNeueMontreal` font files are loaded from
`public/fonts/`

## Build and Deployment

Expand All @@ -128,12 +169,14 @@ Build for production:
pnpm build
```

This project uses the Astro Node adapter in standalone mode (`astro.config.mjs`), suitable for Node hosting platforms.
This project uses the Astro Node adapter in standalone mode
(`astro.config.mjs`), suitable for Node hosting platforms.

Typical deployment flow:

1. Install dependencies
2. Run `pnpm build`
3. Run the generated Node server output from `dist/`

If your platform supports Astro directly, follow its Astro Node adapter deployment docs and point it to this repository.
If your platform supports Astro directly, follow its Astro Node adapter
deployment docs and point it to this repository.
22 changes: 11 additions & 11 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// @ts-check
import { defineConfig } from 'astro/config';
import { EventEmitter } from 'node:events';
import node from '@astrojs/node';
import { defineConfig } from "astro/config";
import { EventEmitter } from "node:events";
import node from "@astrojs/node";

import svelte from '@astrojs/svelte';
import svelte from "@astrojs/svelte";

import tailwindcss from '@tailwindcss/vite';
import tailwindcss from "@tailwindcss/vite";

EventEmitter.defaultMaxListeners = 30;

// https://astro.build/config
export default defineConfig({
site: 'https://gxbs.dev',
output: 'server',
adapter: node({ mode: 'standalone' }),
site: "https://gxbs.dev",
output: "server",
adapter: node({ mode: "standalone" }),
integrations: [svelte()],

vite: {
plugins: [tailwindcss()]
}
});
plugins: [tailwindcss()],
},
});
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"astro": "^6.3.1",
"gray-matter": "^4.0.3",
"marked": "^18.0.2",
"pocketbase": "^0.27.0",
"sharp": "^0.34.4",
"svelte": "^5.55.4",
"tailwindcss": "^4.2.4",
Expand All @@ -30,4 +31,4 @@
"devDependencies": {
"@types/node": "^25.6.0"
}
}
}
Loading