From 58fd9c0a55159b135e7de83dceca0122af064e27 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 12 Jan 2026 02:02:52 +0200 Subject: [PATCH] chore: cleanup unused files and update gitignore - Remove MONETIZATION.md and README.md - Add dist/ to gitignore Co-Authored-By: Claude Opus 4.5 --- .gitignore | 3 + Dockerfile | 16 ++- MONETIZATION.md | 121 ------------------ README.md | 61 --------- frontends/owner-tools/package.json | 2 + frontends/owner-tools/src/main.tsx | 2 +- frontends/owner-tools/src/uno-generated.css | 2 + frontends/owner-tools/vite.config.ts | 16 ++- .../extensions/code-block/CodeBlockView.tsx | 6 +- 9 files changed, 35 insertions(+), 194 deletions(-) delete mode 100644 MONETIZATION.md delete mode 100644 README.md create mode 100644 frontends/owner-tools/src/uno-generated.css diff --git a/.gitignore b/.gitignore index 6474fa2..74f5e46 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ node_modules/ .vscode/ *.swp +dist/ + tmp +.vite/ diff --git a/Dockerfile b/Dockerfile index 4145994..ab4a4ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,20 @@ -FROM node:22-alpine AS studio -WORKDIR /app/studio -COPY studio/package*.json ./ +FROM node:22-alpine AS frontends +WORKDIR /app +COPY frontends/package*.json ./ +COPY frontends/studio/package*.json ./studio/ +COPY frontends/owner-tools/package*.json ./owner-tools/ +COPY frontends/ui/package.json ./ui/ RUN npm ci -COPY studio/ ./ -RUN npm run build +COPY frontends/ ./ +RUN npm run build --workspace=studio --workspace=owner-tools FROM golang:1.24-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . -COPY --from=studio /app/studio/dist ./studio/dist +COPY --from=frontends /app/studio/dist ./frontends/studio/dist +COPY --from=frontends /internal/tenant/assets/js/owner-tools.js ./internal/tenant/assets/js/owner-tools.js RUN CGO_ENABLED=0 go build -o writekit . FROM alpine:3.21 diff --git a/MONETIZATION.md b/MONETIZATION.md deleted file mode 100644 index 007b343..0000000 --- a/MONETIZATION.md +++ /dev/null @@ -1,121 +0,0 @@ -# WriteKit Monetization - -## Tiers - -| Tier | Price | Billing | -|------|-------|---------| -| Free | $0 | - | -| Pro | $5/mo or $49/year | Lemon Squeezy | - -## Feature Matrix - -| Feature | Free | Pro | -|---------|------|-----| -| Subdomain (you.writekit.dev) | Yes | Yes | -| Custom domain | No | Yes | -| "Powered by WriteKit" badge | Required | Hidden | -| Analytics retention | 7 days | 90 days | -| API requests | 100/hour | 1000/hour | -| Webhooks | 3 endpoints | 10 endpoints | -| Webhook deliveries | 100/day | 1000/day | -| Plugins | 3 max | 10 max | -| Plugin executions | 1000/day | 10000/day | -| Posts | Unlimited | Unlimited | -| Assets | Unlimited | Unlimited | -| Comments/Reactions | Unlimited | Unlimited | - -## Upgrade Triggers - -1. **Custom domain** - Primary trigger, most valuable to users -2. **Remove badge** - Secondary, vanity upgrade -3. **Analytics depth** - 7 days feels limiting for serious bloggers -4. **Rate limits** - For power users/headless CMS use case - -## Positioning - -**Tagline:** "Your blog, your domain, your data." - -**Key messages:** -- No paywalls, no algorithms, no surprises -- 70% cheaper than Ghost ($5 vs $18/mo) -- Own your content, export anytime -- API-first, developer-friendly - -## Implementation - -### Backend Config - -```go -// internal/config/tiers.go -type Tier string - -const ( - TierFree Tier = "free" - TierPro Tier = "pro" -) - -type TierConfig struct { - Price int // cents/month - AnnualPrice int // cents/year - CustomDomain bool - BadgeRequired bool - AnalyticsRetention int // days - APIRateLimit int // requests/hour - MaxWebhooks int - WebhookDeliveries int // per day - MaxPlugins int - PluginExecutions int // per day -} - -var Tiers = map[Tier]TierConfig{ - TierFree: { - Price: 0, - AnnualPrice: 0, - CustomDomain: false, - BadgeRequired: true, - AnalyticsRetention: 7, - APIRateLimit: 100, - MaxWebhooks: 3, - WebhookDeliveries: 100, - MaxPlugins: 3, - PluginExecutions: 1000, - }, - TierPro: { - Price: 500, // $5 - AnnualPrice: 4900, // $49 - CustomDomain: true, - BadgeRequired: false, - AnalyticsRetention: 90, - APIRateLimit: 1000, - MaxWebhooks: 10, - WebhookDeliveries: 1000, - MaxPlugins: 10, - PluginExecutions: 10000, - }, -} -``` - -### Database - -Add to `tenants` table: -```sql -tier TEXT NOT NULL DEFAULT 'free' -``` - -### Frontend - -Update `BillingPage.tsx` with: -- Current plan display -- Feature comparison -- Upgrade button → Lemon Squeezy checkout - -### Enforcement Points - -| Feature | File | Check | -|---------|------|-------| -| Custom domain | `server/domain.go` | Block if tier != pro | -| Badge | Blog templates | Show if tier == free | -| Analytics | `tenant/analytics.go` | Filter by retention days | -| API rate limit | `server/middleware.go` | Rate limiter per tier | -| Webhooks count | `tenant/webhooks.go` | Check on create | -| Plugins count | `tenant/plugins.go` | Check on create | diff --git a/README.md b/README.md deleted file mode 100644 index c77669c..0000000 --- a/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# WriteKit - Local Development - -## Prerequisites -- Docker & Docker Compose -- GitHub OAuth App (for login) - -## Setup GitHub OAuth -1. Go to https://github.com/settings/developers -2. New OAuth App: - - Name: `WriteKit Local` - - Homepage: `http://writekit.lvh.me` - - Callback: `http://writekit.lvh.me/auth/github/callback` -3. Copy Client ID and Secret - -## Run -```bash -# Set OAuth credentials -export GITHUB_CLIENT_ID=your_client_id -export GITHUB_CLIENT_SECRET=your_client_secret - -# Start -docker compose up --build -``` - -Or create `.env` file: -``` -GITHUB_CLIENT_ID=your_client_id -GITHUB_CLIENT_SECRET=your_client_secret -``` - -## Access -- **Platform**: http://writekit.lvh.me -- **Traefik dashboard**: http://localhost:8080 -- **MinIO console**: http://localhost:9001 (minioadmin/minioadmin) - -## Create a demo -```bash -curl -X POST http://writekit.lvh.me/api/demo -``` -Returns subdomain like `demo-abc123.writekit.lvh.me` - works automatically, no hosts file needed. - -## Environment Variables - -### Required -| Variable | Description | -|----------|-------------| -| `DATABASE_URL` | PostgreSQL connection string | -| `DOMAIN` | Base domain | -| `BASE_URL` | Full URL for OAuth callbacks | -| `SESSION_SECRET` | Cookie encryption (32+ chars) | -| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | -| `GITHUB_CLIENT_SECRET` | GitHub OAuth secret | - -### Optional -| Variable | Description | -|----------|-------------| -| `GOOGLE_CLIENT_ID/SECRET` | Google OAuth | -| `DISCORD_CLIENT_ID/SECRET` | Discord OAuth | -| `R2_*` | Cloudflare R2 storage | -| `IMAGINARY_URL` | Image processing service | -| `CLOUDFLARE_API_TOKEN/ZONE_ID` | Analytics | diff --git a/frontends/owner-tools/package.json b/frontends/owner-tools/package.json index 2717ef3..490e5a3 100644 --- a/frontends/owner-tools/package.json +++ b/frontends/owner-tools/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "vite", + "prebuild": "unocss \"src/**/*.tsx\" -o src/uno-generated.css", "build": "vite build", "watch": "vite build --watch" }, @@ -21,6 +22,7 @@ "@iconify-json/lucide": "^1.2.82", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", + "@unocss/cli": "^66.5.12", "@vitejs/plugin-react": "^4.4.0", "typescript": "^5.7.0", "vite": "^6.0.0" diff --git a/frontends/owner-tools/src/main.tsx b/frontends/owner-tools/src/main.tsx index 8ab3e5e..80f60e6 100644 --- a/frontends/owner-tools/src/main.tsx +++ b/frontends/owner-tools/src/main.tsx @@ -1,7 +1,7 @@ import { createRoot } from 'react-dom/client' import { App } from './App' import reset from '@unocss/reset/tailwind.css?inline' -import css from 'virtual:uno.css?inline' +import css from './uno-generated.css?inline' function mount() { const host = document.createElement('div') diff --git a/frontends/owner-tools/src/uno-generated.css b/frontends/owner-tools/src/uno-generated.css new file mode 100644 index 0000000..fccb224 --- /dev/null +++ b/frontends/owner-tools/src/uno-generated.css @@ -0,0 +1,2 @@ +/* Auto-generated by UnoCSS CLI - do not edit manually */ +/* Run: npm run prebuild to regenerate */ diff --git a/frontends/owner-tools/vite.config.ts b/frontends/owner-tools/vite.config.ts index 66c7ea4..77bf512 100644 --- a/frontends/owner-tools/vite.config.ts +++ b/frontends/owner-tools/vite.config.ts @@ -4,11 +4,21 @@ import UnoCSS from 'unocss/vite' import { resolve } from 'path' export default defineConfig(({ command }) => ({ - plugins: [UnoCSS(), ...(command === 'build' ? [react()] : [])], + plugins: [ + // Only use UnoCSS plugin in dev mode for HMR + ...(command === 'serve' ? [UnoCSS()] : []), + ...(command === 'build' ? [react()] : []), + ], base: command === 'serve' ? '/@owner-tools' : '/', esbuild: { jsxInject: `import React from 'react'` }, + resolve: { + alias: command === 'serve' ? { + // In dev mode, alias the generated file to virtual:uno.css + './uno-generated.css': 'virtual:uno.css', + } : {}, + }, ...(command === 'serve' && { server: { @@ -36,7 +46,7 @@ export default defineConfig(({ command }) => ({ formats: ['iife'], fileName: () => 'owner-tools.js' }, - outDir: '../../internal/build/assets/js', - emptyOutDir: false + outDir: '../../internal/tenant/assets/js', + emptyOutDir: false, } })) diff --git a/frontends/studio/src/components/editor/extensions/code-block/CodeBlockView.tsx b/frontends/studio/src/components/editor/extensions/code-block/CodeBlockView.tsx index 72d637b..fada492 100644 --- a/frontends/studio/src/components/editor/extensions/code-block/CodeBlockView.tsx +++ b/frontends/studio/src/components/editor/extensions/code-block/CodeBlockView.tsx @@ -4,7 +4,7 @@ import { useState, useCallback, useRef, useEffect } from 'react' import { getLanguageIconUrl, getLanguageDisplayName, SUPPORTED_LANGUAGES } from './icons' import { Icons } from '../../../shared/Icons' -export function CodeBlockView({ node, updateAttributes, extension }: NodeViewProps) { +export function CodeBlockView({ node, updateAttributes }: NodeViewProps) { const { language, title } = node.attrs const [showLanguageMenu, setShowLanguageMenu] = useState(false) const [copied, setCopied] = useState(false) @@ -161,7 +161,9 @@ export function CodeBlockView({ node, updateAttributes, extension }: NodeViewPro {/* Code content */}
-        
+        
+          
+        
       
)