mirror of
https://github.com/f/awesome-chatgpt-prompts.git
synced 2026-02-12 15:52:47 +00:00
feat(docker): add whitelabel branding support for custom images
This commit is contained in:
62
DOCKER.md
62
DOCKER.md
@@ -16,6 +16,68 @@ docker run -d \
|
||||
|
||||
Open http://localhost in your browser.
|
||||
|
||||
## Whitelabel / Custom Branding
|
||||
|
||||
Build your own branded image with custom name, logo, and colors:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg BRAND_NAME="My Prompt Library" \
|
||||
--build-arg BRAND_DESCRIPTION="Our team's AI prompts" \
|
||||
--build-arg BRAND_COLOR="#ff6600" \
|
||||
--build-arg AUTH_PROVIDERS="github,google" \
|
||||
--build-arg LOCALES="en,es,fr" \
|
||||
-f docker/Dockerfile \
|
||||
-t my-prompts .
|
||||
|
||||
docker run -p 80:80 -v prompts-data:/data my-prompts
|
||||
```
|
||||
|
||||
### Build Arguments
|
||||
|
||||
| Argument | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `BRAND_NAME` | App name shown in UI | `My Prompt Library` |
|
||||
| `BRAND_DESCRIPTION` | App description | `Collect, organize, and share AI prompts` |
|
||||
| `BRAND_LOGO` | Logo path (in public/) | `/logo.svg` |
|
||||
| `BRAND_LOGO_DARK` | Dark mode logo | Same as `BRAND_LOGO` |
|
||||
| `BRAND_FAVICON` | Favicon path | `/logo.svg` |
|
||||
| `BRAND_COLOR` | Primary color (hex) | `#6366f1` |
|
||||
| `THEME_RADIUS` | Border radius: `none\|sm\|md\|lg` | `sm` |
|
||||
| `THEME_VARIANT` | UI style: `default\|flat\|brutal` | `default` |
|
||||
| `THEME_DENSITY` | Spacing: `compact\|default\|comfortable` | `default` |
|
||||
| `AUTH_PROVIDERS` | Auth providers (comma-separated) | `credentials` |
|
||||
| `ALLOW_REGISTRATION` | Allow public signup | `true` |
|
||||
| `LOCALES` | Supported locales (comma-separated) | `en` |
|
||||
| `DEFAULT_LOCALE` | Default locale | `en` |
|
||||
| `FEATURE_PRIVATE_PROMPTS` | Enable private prompts | `true` |
|
||||
| `FEATURE_CHANGE_REQUESTS` | Enable versioning | `true` |
|
||||
| `FEATURE_CATEGORIES` | Enable categories | `true` |
|
||||
| `FEATURE_TAGS` | Enable tags | `true` |
|
||||
| `FEATURE_COMMENTS` | Enable comments | `true` |
|
||||
| `FEATURE_AI_SEARCH` | Enable AI search | `false` |
|
||||
| `FEATURE_AI_GENERATION` | Enable AI generation | `false` |
|
||||
| `FEATURE_MCP` | Enable MCP features | `false` |
|
||||
|
||||
### Adding Custom Logo
|
||||
|
||||
1. Create your logo file (SVG recommended)
|
||||
2. Mount it when running:
|
||||
|
||||
```bash
|
||||
docker run -p 80:80 \
|
||||
-v ./my-logo.svg:/app/public/logo.svg \
|
||||
-v prompts-data:/data \
|
||||
my-prompts
|
||||
```
|
||||
|
||||
Or include it in your own Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
FROM ghcr.io/f/prompts.chat
|
||||
COPY my-logo.svg /app/public/logo.svg
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
@@ -2,12 +2,40 @@
|
||||
# Contains Node.js + PostgreSQL for single-container deployment
|
||||
#
|
||||
# Usage:
|
||||
# docker run -p 80:80 ghcr.io/f/prompts.chat
|
||||
# docker run -p 80:80 -e AUTH_SECRET=xxx ghcr.io/f/prompts.chat
|
||||
# docker run -p 80:80 --name my-prompts ghcr.io/f/prompts.chat
|
||||
# docker build -t my-prompts .
|
||||
# docker build --build-arg BRAND_NAME="My App" --build-arg BRAND_COLOR="#ff0000" -t my-prompts .
|
||||
# docker run -p 80:80 my-prompts
|
||||
#
|
||||
# Build Arguments (all optional):
|
||||
# BRAND_NAME, BRAND_DESCRIPTION, BRAND_LOGO, BRAND_COLOR
|
||||
# AUTH_PROVIDERS (comma-separated: github,google,credentials)
|
||||
# LOCALES (comma-separated: en,es,fr)
|
||||
|
||||
FROM node:24-bookworm-slim AS builder
|
||||
|
||||
# Build arguments for whitelabel branding
|
||||
ARG BRAND_NAME="My Prompt Library"
|
||||
ARG BRAND_DESCRIPTION="Collect, organize, and share AI prompts"
|
||||
ARG BRAND_LOGO="/logo.svg"
|
||||
ARG BRAND_LOGO_DARK=""
|
||||
ARG BRAND_FAVICON="/logo.svg"
|
||||
ARG BRAND_COLOR="#6366f1"
|
||||
ARG THEME_RADIUS="sm"
|
||||
ARG THEME_VARIANT="default"
|
||||
ARG THEME_DENSITY="default"
|
||||
ARG AUTH_PROVIDERS="credentials"
|
||||
ARG ALLOW_REGISTRATION="true"
|
||||
ARG LOCALES="en"
|
||||
ARG DEFAULT_LOCALE="en"
|
||||
ARG FEATURE_PRIVATE_PROMPTS="true"
|
||||
ARG FEATURE_CHANGE_REQUESTS="true"
|
||||
ARG FEATURE_CATEGORIES="true"
|
||||
ARG FEATURE_TAGS="true"
|
||||
ARG FEATURE_COMMENTS="true"
|
||||
ARG FEATURE_AI_SEARCH="false"
|
||||
ARG FEATURE_AI_GENERATION="false"
|
||||
ARG FEATURE_MCP="false"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files first for better caching
|
||||
@@ -23,6 +51,31 @@ COPY . .
|
||||
# Remove unnecessary files
|
||||
RUN rm -rf .github .claude packages .git
|
||||
|
||||
# Run docker-setup.js to generate prompts.config.ts with branding
|
||||
ENV BRAND_NAME=${BRAND_NAME}
|
||||
ENV BRAND_DESCRIPTION=${BRAND_DESCRIPTION}
|
||||
ENV BRAND_LOGO=${BRAND_LOGO}
|
||||
ENV BRAND_LOGO_DARK=${BRAND_LOGO_DARK}
|
||||
ENV BRAND_FAVICON=${BRAND_FAVICON}
|
||||
ENV BRAND_COLOR=${BRAND_COLOR}
|
||||
ENV THEME_RADIUS=${THEME_RADIUS}
|
||||
ENV THEME_VARIANT=${THEME_VARIANT}
|
||||
ENV THEME_DENSITY=${THEME_DENSITY}
|
||||
ENV AUTH_PROVIDERS=${AUTH_PROVIDERS}
|
||||
ENV ALLOW_REGISTRATION=${ALLOW_REGISTRATION}
|
||||
ENV LOCALES=${LOCALES}
|
||||
ENV DEFAULT_LOCALE=${DEFAULT_LOCALE}
|
||||
ENV FEATURE_PRIVATE_PROMPTS=${FEATURE_PRIVATE_PROMPTS}
|
||||
ENV FEATURE_CHANGE_REQUESTS=${FEATURE_CHANGE_REQUESTS}
|
||||
ENV FEATURE_CATEGORIES=${FEATURE_CATEGORIES}
|
||||
ENV FEATURE_TAGS=${FEATURE_TAGS}
|
||||
ENV FEATURE_COMMENTS=${FEATURE_COMMENTS}
|
||||
ENV FEATURE_AI_SEARCH=${FEATURE_AI_SEARCH}
|
||||
ENV FEATURE_AI_GENERATION=${FEATURE_AI_GENERATION}
|
||||
ENV FEATURE_MCP=${FEATURE_MCP}
|
||||
|
||||
RUN node scripts/docker-setup.js
|
||||
|
||||
# Generate Prisma client and build
|
||||
# DATABASE_URL is needed at build time for Prisma, but not used
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# prompts.chat App-Only Dockerfile
|
||||
# For use with docker-compose (separate database container)
|
||||
#
|
||||
# Build with branding:
|
||||
# docker build --build-arg BRAND_NAME="My App" -f docker/Dockerfile.app -t my-prompts .
|
||||
|
||||
FROM node:24-alpine AS base
|
||||
|
||||
@@ -17,6 +20,19 @@ RUN npm ci
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
|
||||
# Build arguments for whitelabel branding
|
||||
ARG BRAND_NAME="My Prompt Library"
|
||||
ARG BRAND_DESCRIPTION="Collect, organize, and share AI prompts"
|
||||
ARG BRAND_LOGO="/logo.svg"
|
||||
ARG BRAND_LOGO_DARK=""
|
||||
ARG BRAND_FAVICON="/logo.svg"
|
||||
ARG BRAND_COLOR="#6366f1"
|
||||
ARG THEME_RADIUS="sm"
|
||||
ARG THEME_VARIANT="default"
|
||||
ARG AUTH_PROVIDERS="credentials"
|
||||
ARG LOCALES="en"
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
@@ -24,6 +40,20 @@ COPY . .
|
||||
# Remove unnecessary files
|
||||
RUN rm -rf .github .claude packages docker .git
|
||||
|
||||
# Run docker-setup.js to generate prompts.config.ts with branding
|
||||
ENV BRAND_NAME=${BRAND_NAME} \
|
||||
BRAND_DESCRIPTION=${BRAND_DESCRIPTION} \
|
||||
BRAND_LOGO=${BRAND_LOGO} \
|
||||
BRAND_LOGO_DARK=${BRAND_LOGO_DARK} \
|
||||
BRAND_FAVICON=${BRAND_FAVICON} \
|
||||
BRAND_COLOR=${BRAND_COLOR} \
|
||||
THEME_RADIUS=${THEME_RADIUS} \
|
||||
THEME_VARIANT=${THEME_VARIANT} \
|
||||
AUTH_PROVIDERS=${AUTH_PROVIDERS} \
|
||||
LOCALES=${LOCALES}
|
||||
|
||||
RUN node scripts/docker-setup.js
|
||||
|
||||
# DATABASE_URL is needed at build time for Prisma, but not used
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
|
||||
|
||||
172
scripts/docker-setup.js
Normal file
172
scripts/docker-setup.js
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
|
||||
/**
|
||||
* Non-interactive setup script for Docker builds.
|
||||
* Generates prompts.config.ts from environment variables.
|
||||
*
|
||||
* Usage: BRAND_NAME="My App" node scripts/docker-setup.js
|
||||
*
|
||||
* Environment Variables:
|
||||
* BRAND_NAME - App name (default: "My Prompt Library")
|
||||
* BRAND_DESCRIPTION - App description
|
||||
* BRAND_LOGO - Logo path (default: "/logo.svg")
|
||||
* BRAND_LOGO_DARK - Dark mode logo path
|
||||
* BRAND_FAVICON - Favicon path
|
||||
* BRAND_COLOR - Primary color hex (default: "#6366f1")
|
||||
* THEME_RADIUS - Border radius: none|sm|md|lg (default: "sm")
|
||||
* THEME_VARIANT - UI variant: default|flat|brutal (default: "default")
|
||||
* THEME_DENSITY - Spacing: compact|default|comfortable (default: "default")
|
||||
* AUTH_PROVIDERS - Comma-separated: github,google,credentials (default: "credentials")
|
||||
* ALLOW_REGISTRATION - Allow public registration: true|false (default: "true")
|
||||
* LOCALES - Comma-separated locales (default: "en")
|
||||
* DEFAULT_LOCALE - Default locale (default: "en")
|
||||
* FEATURE_PRIVATE_PROMPTS - Enable private prompts (default: "true")
|
||||
* FEATURE_CHANGE_REQUESTS - Enable change requests (default: "true")
|
||||
* FEATURE_CATEGORIES - Enable categories (default: "true")
|
||||
* FEATURE_TAGS - Enable tags (default: "true")
|
||||
* FEATURE_COMMENTS - Enable comments (default: "true")
|
||||
* FEATURE_AI_SEARCH - Enable AI search (default: "false")
|
||||
* FEATURE_AI_GENERATION - Enable AI generation (default: "false")
|
||||
* FEATURE_MCP - Enable MCP (default: "false")
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const CONFIG_FILE = path.join(__dirname, '..', 'prompts.config.ts');
|
||||
|
||||
function env(key, defaultValue) {
|
||||
return process.env[key] || defaultValue;
|
||||
}
|
||||
|
||||
function envBool(key, defaultValue) {
|
||||
const val = process.env[key];
|
||||
if (val === undefined) return defaultValue;
|
||||
return val.toLowerCase() === 'true' || val === '1';
|
||||
}
|
||||
|
||||
function envArray(key, defaultValue) {
|
||||
const val = process.env[key];
|
||||
if (!val) return defaultValue;
|
||||
return val.split(',').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
function generateConfig(config) {
|
||||
return `import { defineConfig } from "@/lib/config";
|
||||
|
||||
// Docker build configuration - generated by docker-setup.js
|
||||
const useCloneBranding = true;
|
||||
|
||||
export default defineConfig({
|
||||
// Branding - your organization's identity
|
||||
branding: {
|
||||
name: "${config.branding.name}",
|
||||
logo: "${config.branding.logo}",
|
||||
logoDark: "${config.branding.logoDark}",
|
||||
favicon: "${config.branding.favicon}",
|
||||
description: "${config.branding.description}",
|
||||
},
|
||||
|
||||
// Theme - design system configuration
|
||||
theme: {
|
||||
radius: "${config.theme.radius}",
|
||||
variant: "${config.theme.variant}",
|
||||
density: "${config.theme.density}",
|
||||
colors: {
|
||||
primary: "${config.theme.primaryColor}",
|
||||
},
|
||||
},
|
||||
|
||||
// Authentication plugins
|
||||
auth: {
|
||||
providers: [${config.auth.providers.map(p => `"${p}"`).join(', ')}],
|
||||
allowRegistration: ${config.auth.allowRegistration},
|
||||
},
|
||||
|
||||
// Internationalization
|
||||
i18n: {
|
||||
locales: [${config.i18n.locales.map(l => `"${l}"`).join(', ')}],
|
||||
defaultLocale: "${config.i18n.defaultLocale}",
|
||||
},
|
||||
|
||||
// Features
|
||||
features: {
|
||||
privatePrompts: ${config.features.privatePrompts},
|
||||
changeRequests: ${config.features.changeRequests},
|
||||
categories: ${config.features.categories},
|
||||
tags: ${config.features.tags},
|
||||
comments: ${config.features.comments},
|
||||
aiSearch: ${config.features.aiSearch},
|
||||
aiGeneration: ${config.features.aiGeneration},
|
||||
mcp: ${config.features.mcp},
|
||||
},
|
||||
|
||||
// Homepage customization (clone branding mode)
|
||||
homepage: {
|
||||
useCloneBranding,
|
||||
achievements: {
|
||||
enabled: false,
|
||||
},
|
||||
sponsors: {
|
||||
enabled: false,
|
||||
items: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
`;
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log('🔧 Docker Setup: Generating prompts.config.ts...');
|
||||
|
||||
const config = {
|
||||
branding: {
|
||||
name: env('BRAND_NAME', 'My Prompt Library'),
|
||||
description: env('BRAND_DESCRIPTION', 'Collect, organize, and share AI prompts'),
|
||||
logo: env('BRAND_LOGO', '/logo.svg'),
|
||||
logoDark: env('BRAND_LOGO_DARK', env('BRAND_LOGO', '/logo.svg')),
|
||||
favicon: env('BRAND_FAVICON', '/logo.svg'),
|
||||
},
|
||||
theme: {
|
||||
primaryColor: env('BRAND_COLOR', '#6366f1'),
|
||||
radius: env('THEME_RADIUS', 'sm'),
|
||||
variant: env('THEME_VARIANT', 'default'),
|
||||
density: env('THEME_DENSITY', 'default'),
|
||||
},
|
||||
auth: {
|
||||
providers: envArray('AUTH_PROVIDERS', ['credentials']),
|
||||
allowRegistration: envBool('ALLOW_REGISTRATION', true),
|
||||
},
|
||||
i18n: {
|
||||
locales: envArray('LOCALES', ['en']),
|
||||
defaultLocale: env('DEFAULT_LOCALE', 'en'),
|
||||
},
|
||||
features: {
|
||||
privatePrompts: envBool('FEATURE_PRIVATE_PROMPTS', true),
|
||||
changeRequests: envBool('FEATURE_CHANGE_REQUESTS', true),
|
||||
categories: envBool('FEATURE_CATEGORIES', true),
|
||||
tags: envBool('FEATURE_TAGS', true),
|
||||
comments: envBool('FEATURE_COMMENTS', true),
|
||||
aiSearch: envBool('FEATURE_AI_SEARCH', false),
|
||||
aiGeneration: envBool('FEATURE_AI_GENERATION', false),
|
||||
mcp: envBool('FEATURE_MCP', false),
|
||||
},
|
||||
};
|
||||
|
||||
// Log configuration
|
||||
console.log('');
|
||||
console.log(' Brand: ', config.branding.name);
|
||||
console.log(' Color: ', config.theme.primaryColor);
|
||||
console.log(' Auth: ', config.auth.providers.join(', '));
|
||||
console.log(' Locales: ', config.i18n.locales.join(', '));
|
||||
console.log('');
|
||||
|
||||
// Generate and write config
|
||||
const content = generateConfig(config);
|
||||
fs.writeFileSync(CONFIG_FILE, content);
|
||||
|
||||
console.log('✅ Generated prompts.config.ts');
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user