Skip to main content

#!/usr/bin/env python3 """ CODITECT Website Builder Script

Build websites from templates for CODITECT product sites, documentation portals, and landing pages.

Usage: python3 scripts/build-website.py docs --name docs --source ./docs --output ./docs-site python3 scripts/build-website.py product --name dms python3 scripts/build-website.py --help

Author: CODITECT Team Created: December 31, 2025 """

import argparse import json import os import shutil import subprocess import sys from pathlib import Path from datetime import datetime

CODITECT color scheme

COLORS = { 'primary': { '50': '#f0f9ff', '100': '#e0f2fe', '200': '#bae6fd', '300': '#7dd3fc', '400': '#38bdf8', '500': '#0ea5e9', '600': '#0284c7', '700': '#0369a1', '800': '#075985', '900': '#0c4a6e', } }

Template configurations

TEMPLATES = { 'docs': { 'dependencies': [ 'react', 'react-dom', 'react-router-dom', '@mdx-js/react', '@mdx-js/rollup', ], 'dev_dependencies': [ 'tailwindcss', 'postcss', 'autoprefixer', '@vitejs/plugin-react', 'vite', ], 'structure': [ 'src/components', 'src/pages', 'src/lib', 'content/getting-started', 'content/guides', 'content/reference', 'content/api', 'public', ] }, 'product': { 'dependencies': [ 'react', 'react-dom', 'react-router-dom', ], 'dev_dependencies': [ 'tailwindcss', 'postcss', 'autoprefixer', '@vitejs/plugin-react', 'vite', ], 'structure': [ 'src/components', 'src/pages', 'src/data', 'public/images', ] }, 'static': { 'dependencies': [ 'react', 'react-dom', 'react-router-dom', ], 'dev_dependencies': [ 'tailwindcss', 'postcss', 'autoprefixer', '@vitejs/plugin-react', 'vite', ], 'structure': [ 'src/components/templates', 'src/pages', 'public', ] } }

def print_status(message: str, status: str = 'info'): """Print colored status message.""" colors = { 'info': '\033[94m', 'success': '\033[92m', 'warning': '\033[93m', 'error': '\033[91m', 'reset': '\033[0m' } symbols = { 'info': 'ℹ️', 'success': '✅', 'warning': '⚠️', 'error': '❌' } print(f"{colors.get(status, '')}{symbols.get(status, '')} {message}{colors['reset']}")

def run_command(cmd: list, cwd: str = None, capture: bool = False) -> subprocess.CompletedProcess: """Run shell command with error handling.""" try: result = subprocess.run( cmd, cwd=cwd, capture_output=capture, text=True, check=True ) return result except subprocess.CalledProcessError as e: print_status(f"Command failed: {' '.join(cmd)}", 'error') if e.stderr: print(e.stderr) raise

def create_project_structure(output_dir: Path, template: str): """Create project directory structure.""" print_status(f"Creating project structure for {template} template...")

for directory in TEMPLATES[template]['structure']:
dir_path = output_dir / directory
dir_path.mkdir(parents=True, exist_ok=True)
print(f" Created: {directory}/")

def create_package_json(output_dir: Path, name: str, template: str): """Create package.json file.""" config = TEMPLATES[template]

package = {
"name": f"coditect-{name}-site",
"private": True,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {dep: "latest" for dep in config['dependencies']},
"devDependencies": {dep: "latest" for dep in config['dev_dependencies']}
}

with open(output_dir / 'package.json', 'w') as f:
json.dump(package, f, indent=2)

print_status("Created package.json", 'success')

def create_tailwind_config(output_dir: Path): """Create Tailwind CSS configuration.""" config = f"""/** @type {{import('tailwindcss').Config}} / export default {{ content: ['./index.html', './src/**/.{{js,ts,jsx,tsx}}'], darkMode: 'class', theme: {{ extend: {{ colors: {{ primary: {json.dumps(COLORS['primary'], indent=8)}, }}, }}, }}, plugins: [], }} """ with open(output_dir / 'tailwind.config.js', 'w') as f: f.write(config)

print_status("Created tailwind.config.js", 'success')

def create_postcss_config(output_dir: Path): """Create PostCSS configuration.""" config = """export default { plugins: { tailwindcss: {}, autoprefixer: {}, }, } """ with open(output_dir / 'postcss.config.js', 'w') as f: f.write(config)

print_status("Created postcss.config.js", 'success')

def create_vite_config(output_dir: Path): """Create Vite configuration.""" config = """import { defineConfig } from 'vite' import react from '@vitejs/plugin-react'

export default defineConfig({ plugins: [react()], build: { outDir: 'dist', sourcemap: true, }, server: { port: 3000, }, }) """ with open(output_dir / 'vite.config.ts', 'w') as f: f.write(config)

print_status("Created vite.config.ts", 'success')

def create_index_html(output_dir: Path, name: str): """Create index.html file.""" html = f"""

CODITECT {name.upper()}
""" with open(output_dir / 'index.html', 'w') as f: f.write(html)
print_status("Created index.html", 'success')

def create_main_tsx(output_dir: Path): """Create main.tsx entry point.""" content = """import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> </React.StrictMode>, ) """ src_dir = output_dir / 'src' src_dir.mkdir(exist_ok=True)

with open(src_dir / 'main.tsx', 'w') as f:
f.write(content)

print_status("Created src/main.tsx", 'success')

def create_app_tsx(output_dir: Path, name: str, template: str): """Create App.tsx component.""" if template == 'docs': content = f"""import {{ BrowserRouter, Routes, Route }} from 'react-router-dom' import DocsHome from './pages/DocsHome' import DocPage from './pages/DocPage'

export default function App() {{ return ( <Route path="/" element={{}} /> <Route path="/*" element={{}} /> ) }} """ elif template == 'product': content = f"""import {{ BrowserRouter, Routes, Route }} from 'react-router-dom' import Landing from './pages/Landing' import Features from './pages/Features' import Pricing from './pages/Pricing'

export default function App() {{ return ( <Route path="/" element={{}} /> <Route path="/features" element={{}} /> <Route path="/pricing" element={{}} /> ) }} """ else: content = """export default function App() { return (

CODITECT Site

) } """

with open(output_dir / 'src' / 'App.tsx', 'w') as f:
f.write(content)

print_status("Created src/App.tsx", 'success')

def create_index_css(output_dir: Path): """Create index.css with Tailwind directives.""" css = """@tailwind base; @tailwind components; @tailwind utilities;

@layer base { html { font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } }

@layer components { .btn-primary { @apply bg-primary-600 hover:bg-primary-700 text-white font-medium py-2 px-4 rounded-lg transition-colors; }

.btn-secondary { @apply bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white font-medium py-2 px-4 rounded-lg transition-colors; } } """ with open(output_dir / 'src' / 'index.css', 'w') as f: f.write(css)

print_status("Created src/index.css", 'success')

def create_dockerfile(output_dir: Path): """Create Dockerfile for deployment.""" dockerfile = """FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build

FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 8080 CMD ["nginx", "-g", "daemon off;"] """ with open(output_dir / 'Dockerfile', 'w') as f: f.write(dockerfile)

print_status("Created Dockerfile", 'success')

def create_nginx_conf(output_dir: Path): """Create nginx configuration.""" conf = """server { listen 8080; server_name _; root /usr/share/nginx/html; index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location ~* \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

} """ with open(output_dir / 'nginx.conf', 'w') as f: f.write(conf)

print_status("Created nginx.conf", 'success')

def create_cloudbuild_yaml(output_dir: Path, name: str): """Create Cloud Build configuration.""" config = f"""steps:

  • name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/{name}-coditect:$COMMIT_SHA', '.']

  • name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/$PROJECT_ID/{name}-coditect:$COMMIT_SHA']

  • name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args:

    • 'run'
    • 'deploy'
    • '{name}-coditect'
    • '--image'
    • 'gcr.io/$PROJECT_ID/{name}-coditect:$COMMIT_SHA'
    • '--region'
    • 'us-central1'
    • '--allow-unauthenticated'

images:

  • 'gcr.io/$PROJECT_ID/{name}-coditect:$COMMIT_SHA' """ with open(output_dir / 'cloudbuild.yaml', 'w') as f: f.write(config)

    print_status("Created cloudbuild.yaml", 'success')

def copy_content(source: Path, output_dir: Path): """Copy content from source directory.""" if source.exists(): content_dir = output_dir / 'content' if content_dir.exists(): shutil.rmtree(content_dir) shutil.copytree(source, content_dir) print_status(f"Copied content from {source}", 'success') else: print_status(f"Source directory not found: {source}", 'warning')

def install_dependencies(output_dir: Path): """Install npm dependencies.""" print_status("Installing dependencies...") run_command(['npm', 'install'], cwd=str(output_dir)) print_status("Dependencies installed", 'success')

def build_site(output_dir: Path): """Build the site.""" print_status("Building site...") run_command(['npm', 'run', 'build'], cwd=str(output_dir)) print_status("Build complete", 'success')

def main(): parser = argparse.ArgumentParser( description='CODITECT Website Builder', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: python3 build-website.py docs --name docs --source ./docs python3 build-website.py product --name dms python3 build-website.py static --name landing """ )

parser.add_argument('type', choices=['docs', 'product', 'static'],
help='Type of site to build')
parser.add_argument('--name', required=True,
help='Site name (e.g., docs, dms, workflow)')
parser.add_argument('--source', type=Path, default=Path('./docs'),
help='Source content directory')
parser.add_argument('--output', type=Path,
help='Output directory (default: ./{name}-site)')
parser.add_argument('--no-install', action='store_true',
help='Skip npm install')
parser.add_argument('--no-build', action='store_true',
help='Skip build step')

args = parser.parse_args()

# Set default output directory
if args.output is None:
args.output = Path(f'./{args.name}-site')

print("\n" + "=" * 60)
print(f" CODITECT Website Builder")
print(f" Type: {args.type} | Name: {args.name}")
print("=" * 60 + "\n")

start_time = datetime.now()

# Create project
args.output.mkdir(parents=True, exist_ok=True)

create_project_structure(args.output, args.type)
create_package_json(args.output, args.name, args.type)
create_tailwind_config(args.output)
create_postcss_config(args.output)
create_vite_config(args.output)
create_index_html(args.output, args.name)
create_main_tsx(args.output)
create_app_tsx(args.output, args.name, args.type)
create_index_css(args.output)
create_dockerfile(args.output)
create_nginx_conf(args.output)
create_cloudbuild_yaml(args.output, args.name)

# Copy content for docs type
if args.type == 'docs' and args.source:
copy_content(args.source, args.output)

# Install and build
if not args.no_install:
install_dependencies(args.output)

if not args.no_build and not args.no_install:
build_site(args.output)

# Summary
elapsed = (datetime.now() - start_time).total_seconds()

print("\n" + "=" * 60)
print(f" ✅ Site created successfully!")
print("=" * 60)
print(f"\n📁 Output: {args.output}")
print(f"⏱️ Time: {elapsed:.1f}s")
print(f"\n🚀 Next steps:")
print(f" 1. cd {args.output}")
print(f" 2. npm run dev # Preview locally")
print(f" 3. /deploy-site {args.name}.coditect.ai --source ./dist")
print()

if name == 'main': main()