🔱 VALHALLA: Added standalone God Mode app (independent container)

This commit is contained in:
cawcenter
2025-12-14 17:55:01 -05:00
parent c51dbc716e
commit c6a7ff286d
8 changed files with 938 additions and 0 deletions

42
god-mode/Dockerfile Normal file
View File

@@ -0,0 +1,42 @@
# God Mode (Valhalla) Dockerfile
# Optimized for reliable builds with full dependencies
# 1. Base Image
FROM node:20-alpine AS base
WORKDIR /app
# Install libc6-compat for sharp/performance
RUN apk add --no-cache libc6-compat
# 2. Dependencies
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
# Use npm install for robustness (npm ci can fail if lockfile is out of sync)
RUN npm install --legacy-peer-deps
# 3. Builder
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# 4. Runner
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=4321
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 astro
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
COPY package.json ./
USER astro
EXPOSE 4321
CMD ["node", "./dist/server/entry.mjs"]

23
god-mode/astro.config.mjs Normal file
View File

@@ -0,0 +1,23 @@
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';
// https://astro.build/config
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone'
}),
integrations: [
react(),
tailwind({
applyBaseStyles: false,
}),
],
vite: {
ssr: {
noExternal: ['path-to-regexp']
}
}
});

99
god-mode/package.json Normal file
View File

@@ -0,0 +1,99 @@
{
"name": "spark-god-mode",
"type": "module",
"version": "1.0.0",
"scripts": {
"dev": "astro dev",
"start": "node ./dist/server/entry.mjs",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/node": "^8.2.6",
"@astrojs/partytown": "^2.1.4",
"@astrojs/react": "^3.2.0",
"@astrojs/sitemap": "^3.6.0",
"@astrojs/tailwind": "^5.1.0",
"@bull-board/api": "^6.15.0",
"@bull-board/express": "^6.15.0",
"@craftjs/core": "^0.2.12",
"@craftjs/utils": "^0.2.5",
"@directus/sdk": "^17.0.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@hookform/resolvers": "^5.2.2",
"@nanostores/react": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@tanstack/react-query": "^5.90.12",
"@tanstack/react-table": "^8.21.3",
"@tanstack/react-virtual": "^3.13.13",
"@tiptap/extension-placeholder": "^3.13.0",
"@tiptap/react": "^3.13.0",
"@tiptap/starter-kit": "^3.13.0",
"@tremor/react": "^3.18.7",
"@turf/turf": "^7.3.1",
"@types/leaflet": "^1.9.21",
"@types/lodash-es": "^4.17.12",
"@types/papaparse": "^5.5.2",
"@types/react-syntax-highlighter": "^15.5.13",
"@vite-pwa/astro": "^1.2.0",
"astro": "^4.7.0",
"astro-imagetools": "^0.9.0",
"bullmq": "^5.66.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"framer-motion": "^12.23.26",
"html-to-image": "^1.11.13",
"immer": "^11.0.1",
"ioredis": "^5.8.2",
"leaflet": "^1.9.4",
"lodash-es": "^4.17.21",
"lucide-react": "^0.346.0",
"lzutf8": "^0.6.3",
"nanoid": "^5.0.5",
"nanostores": "^1.1.0",
"papaparse": "^5.5.3",
"pdfmake": "^0.2.20",
"pg": "^8.16.3",
"react": "^18.3.1",
"react-contenteditable": "^3.3.7",
"react-diff-viewer-continued": "^3.4.0",
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.8",
"react-flow-renderer": "^10.3.17",
"react-hook-form": "^7.68.0",
"react-leaflet": "^4.2.1",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^16.1.0",
"reactflow": "^11.11.4",
"recharts": "^3.5.1",
"remark-gfm": "^4.0.1",
"sonner": "^2.0.7",
"tailwind-merge": "^2.6.0",
"tailwindcss": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.25.76",
"zustand": "^5.0.9"
},
"devDependencies": {
"@types/node": "^20.11.0",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"rollup-plugin-visualizer": "^6.0.5",
"sharp": "^0.33.3",
"typescript": "^5.4.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-inspect": "^11.3.3"
}
}

View File

@@ -0,0 +1,187 @@
/**
* 🔱 GOD MODE BACKDOOR - Direct PostgreSQL Access
* Standalone Version (Valhalla)
*/
import type { APIRoute } from 'astro';
import pg from 'pg'; // Default import for some environments
const { Pool } = pg;
import Redis from 'ioredis';
// Database connection
// Coolify provides DATABASE_URL in format: postgres://user:pass@host:5432/db
const pool = new Pool({
connectionString: process.env.DATABASE_URL || process.env.DB_CONNECTION_STRING,
max: 3,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
ssl: process.env.DATABASE_URL?.includes('sslmode=require') ? { rejectUnauthorized: false } : undefined
});
// Redis connection
const REDIS_URL = process.env.REDIS_URL || 'redis://redis:6379';
// Service URLs
const DIRECTUS_URL = process.env.PUBLIC_DIRECTUS_URL || 'http://directus:8055';
// Token validation
function validateGodToken(request: Request): boolean {
const token = request.headers.get('X-God-Token') ||
request.headers.get('Authorization')?.replace('Bearer ', '') ||
new URL(request.url).searchParams.get('token');
const godToken = process.env.GOD_MODE_TOKEN;
if (!godToken) {
// In standalone mode, we force a token for security
console.warn('⚠️ GOD_MODE_TOKEN not set in env!');
return false;
}
return token === godToken;
}
function json(data: object, status = 200) {
return new Response(JSON.stringify(data, null, 2), {
status,
headers: { 'Content-Type': 'application/json' }
});
}
// GET Handler
export const GET: APIRoute = async ({ request, url }) => {
// Quick health check (no auth needed for load balancers)
if (url.pathname.endsWith('/healthz')) {
return new Response('OK', { status: 200 });
}
if (!validateGodToken(request)) {
return json({ error: 'Unauthorized - Invalid God Mode Token' }, 401);
}
const action = url.pathname.split('/').pop();
try {
switch (action) {
case 'health': return await getHealth();
case 'services': return await getServices();
case 'db-status': return await getDbStatus();
case 'tables': return await getTables();
case 'logs': return await getLogs();
default: return json({
message: '🔱 Valhalla Active',
timestamp: new Date().toISOString()
});
}
} catch (error: any) {
return json({ error: error.message, stack: error.stack }, 500);
}
};
// POST Handler
export const POST: APIRoute = async ({ request, url }) => {
if (!validateGodToken(request)) {
return json({ error: 'Unauthorized' }, 401);
}
const action = url.pathname.split('/').pop();
if (action === 'sql') {
try {
const body = await request.json();
if (!body.query) return json({ error: 'Missing query' }, 400);
const result = await pool.query(body.query);
return json({
success: true,
rowCount: result.rowCount,
rows: result.rows,
fields: result.fields?.map(f => f.name)
});
} catch (error: any) {
return json({ error: error.message }, 500);
}
}
return json({ error: 'Method not allowed' }, 405);
};
// --- Helpers ---
async function getServices() {
const services: any = { timestamp: new Date().toISOString() };
// DB Check
try {
const start = Date.now();
await pool.query('SELECT 1');
services.postgresql = { status: '✅ RUNNING', latency: Date.now() - start };
} catch (e: any) {
services.postgresql = { status: '❌ DOWN', error: e.message };
}
// Redis Check
try {
const redis = new Redis(REDIS_URL, { maxRetriesPerRequest: 1, connectTimeout: 2000 });
const start = Date.now();
await redis.ping();
services.redis = { status: '✅ RUNNING', latency: Date.now() - start };
redis.disconnect();
} catch (e: any) {
services.redis = { status: '❌ DOWN', error: e.message };
}
// Directus Check
try {
const start = Date.now();
const res = await fetch(`${DIRECTUS_URL}/server/health`, { signal: AbortSignal.timeout(5000) });
services.directus = {
status: res.ok ? '✅ RUNNING' : `⚠️ HTTP ${res.status}`,
latency: Date.now() - start
};
} catch (e: any) {
services.directus = { status: '❌ DOWN', error: e.message };
}
return json(services);
}
async function getHealth() {
// Full system health (similar to getServices but more detail)
return getServices();
}
async function getDbStatus() {
try {
const res = await pool.query(`
SELECT current_database() as db, version(),
(SELECT count(*) FROM pg_stat_activity) as connections
`);
return json({ status: 'connected', ...res.rows[0] });
} catch (e: any) {
return json({ status: 'error', error: e.message });
}
}
async function getTables() {
try {
const res = await pool.query(`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name
`);
return json({ total: res.rows.length, tables: res.rows });
} catch (e: any) {
return json({ error: e.message });
}
}
async function getLogs() {
try {
const res = await pool.query('SELECT * FROM work_log ORDER BY timestamp DESC LIMIT 50');
return json({ logs: res.rows });
} catch (e: any) {
return json({ error: e.message });
}
}

View File

@@ -0,0 +1,367 @@
---
/**
* 🔱 GOD PANEL - System Diagnostics Dashboard
*
* This page is COMPLETELY STANDALONE:
* - No middleware
* - No Directus dependency
* - No redirects
* - Works even when everything else is broken
*/
export const prerender = false;
---
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔱 🔱 Valhalla - Spark God Mode</title>
<meta name="robots" content="noindex, nofollow">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
god: {
gold: '#FFD700',
dark: '#0a0a0a',
card: '#111111',
border: '#333333'
}
}
}
}
}
</script>
<style>
@keyframes pulse-gold {
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.4); }
50% { box-shadow: 0 0 20px 10px rgba(255, 215, 0, 0.1); }
}
.pulse-gold { animation: pulse-gold 2s infinite; }
.status-healthy { color: #22c55e; }
.status-unhealthy { color: #ef4444; }
.status-warning { color: #eab308; }
pre { white-space: pre-wrap; word-wrap: break-word; }
</style>
</head>
<body class="bg-god-dark text-white min-h-screen">
<div id="god-panel"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import ReactDOM from 'https://esm.sh/react-dom@18/client';
const { useState, useEffect, useCallback } = React;
const h = React.createElement;
// API Helper
const api = {
async get(endpoint) {
const token = localStorage.getItem('godToken') || '';
const res = await fetch(`/api/god/${endpoint}`, {
headers: { 'X-God-Token': token }
});
return res.json();
},
async post(endpoint, data) {
const token = localStorage.getItem('godToken') || '';
const res = await fetch(`/api/god/${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-God-Token': token
},
body: JSON.stringify(data)
});
return res.json();
}
};
// Status Badge Component
function StatusBadge({ status }) {
const isHealthy = status?.includes('✅') || status === 'healthy' || status === 'connected';
const isWarning = status?.includes('⚠️');
const className = isHealthy ? 'status-healthy' : isWarning ? 'status-warning' : 'status-unhealthy';
return h('span', { className: `font-bold ${className}` }, status || 'Unknown');
}
// Service Card Component
function ServiceCard({ name, data, icon }) {
const status = data?.status || 'Unknown';
const isHealthy = status?.includes('✅') || status?.includes('healthy');
return h('div', {
className: `bg-god-card border border-god-border rounded-xl p-4 ${isHealthy ? '' : 'border-red-500/50'}`
}, [
h('div', { className: 'flex items-center justify-between mb-2' }, [
h('div', { className: 'flex items-center gap-2' }, [
h('span', { className: 'text-2xl' }, icon),
h('span', { className: 'font-semibold text-lg' }, name)
]),
h(StatusBadge, { status })
]),
data?.latency_ms && h('div', { className: 'text-sm text-gray-400' },
`Latency: ${data.latency_ms}ms`
),
data?.error && h('div', { className: 'text-sm text-red-400 mt-1' },
`Error: ${data.error}`
)
]);
}
// SQL Console Component
function SQLConsole() {
const [query, setQuery] = useState('SELECT * FROM sites LIMIT 5;');
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const execute = async () => {
setLoading(true);
try {
const data = await api.post('sql', { query });
setResult(data);
} catch (err) {
setResult({ error: err.message });
}
setLoading(false);
};
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3 flex items-center gap-2' }, [
'🗄️ SQL Console'
]),
h('textarea', {
className: 'w-full bg-black border border-god-border rounded-lg p-3 font-mono text-sm text-green-400 mb-3',
rows: 4,
value: query,
onChange: e => setQuery(e.target.value),
placeholder: 'Enter SQL query...'
}),
h('button', {
className: 'bg-god-gold text-black font-bold px-4 py-2 rounded-lg hover:bg-yellow-400 disabled:opacity-50',
onClick: execute,
disabled: loading
}, loading ? 'Executing...' : 'Execute SQL'),
result && h('div', { className: 'mt-4' }, [
result.error ?
h('div', { className: 'text-red-400 font-mono text-sm' }, `Error: ${result.error}`) :
h('div', {}, [
h('div', { className: 'text-sm text-gray-400 mb-2' },
`${result.rowCount || 0} rows returned`
),
h('pre', {
className: 'bg-black rounded-lg p-3 overflow-auto max-h-64 text-xs font-mono text-gray-300'
}, JSON.stringify(result.rows, null, 2))
])
])
]);
}
// Tables List Component
function TablesList({ tables }) {
if (!tables?.tables) return null;
const customTables = tables.tables.filter(t => !t.name.startsWith('directus_'));
const systemTables = tables.tables.filter(t => t.name.startsWith('directus_'));
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3' },
`📊 Database Tables (${tables.total})`
),
h('div', { className: 'grid grid-cols-2 gap-4' }, [
h('div', {}, [
h('h4', { className: 'text-sm font-semibold text-god-gold mb-2' },
`Custom Tables (${customTables.length})`
),
h('div', { className: 'space-y-1 max-h-48 overflow-auto' },
customTables.map(t =>
h('div', {
key: t.name,
className: 'text-xs font-mono flex justify-between bg-black/50 px-2 py-1 rounded'
}, [
h('span', {}, t.name),
h('span', { className: 'text-gray-500' }, `${t.rows} rows`)
])
)
)
]),
h('div', {}, [
h('h4', { className: 'text-sm font-semibold text-gray-400 mb-2' },
`Directus System (${systemTables.length})`
),
h('div', { className: 'text-xs text-gray-500' },
systemTables.length + ' system tables'
)
])
])
]);
}
// Quick Actions Component
function QuickActions() {
const actions = [
{ label: 'Check Sites', query: 'SELECT id, name, url, status FROM sites LIMIT 10' },
{ label: 'Count Articles', query: 'SELECT COUNT(*) as count FROM generated_articles' },
{ label: 'Active Connections', query: 'SELECT count(*) FROM pg_stat_activity' },
{ label: 'DB Size', query: "SELECT pg_size_pretty(pg_database_size(current_database())) as size" },
];
const [result, setResult] = useState(null);
const run = async (query) => {
const data = await api.post('sql', { query });
setResult(data);
};
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3' }, '⚡ Quick Actions'),
h('div', { className: 'flex flex-wrap gap-2' },
actions.map(a =>
h('button', {
key: a.label,
className: 'bg-god-border hover:bg-god-gold hover:text-black px-3 py-1 rounded text-sm transition-colors',
onClick: () => run(a.query)
}, a.label)
)
),
result && h('pre', {
className: 'mt-3 bg-black rounded-lg p-3 text-xs font-mono text-gray-300 overflow-auto max-h-32'
}, JSON.stringify(result.rows || result, null, 2))
]);
}
// Main God Panel Component
function GodPanel() {
const [services, setServices] = useState(null);
const [health, setHealth] = useState(null);
const [tables, setTables] = useState(null);
const [loading, setLoading] = useState(true);
const [autoRefresh, setAutoRefresh] = useState(false);
const [lastUpdate, setLastUpdate] = useState(null);
const refresh = useCallback(async () => {
try {
const [svc, hlth, tbl] = await Promise.all([
api.get('services'),
api.get('health'),
api.get('tables')
]);
setServices(svc);
setHealth(hlth);
setTables(tbl);
setLastUpdate(new Date().toLocaleTimeString());
} catch (err) {
console.error('Refresh failed:', err);
}
setLoading(false);
}, []);
useEffect(() => {
refresh();
if (autoRefresh) {
const interval = setInterval(refresh, 5000);
return () => clearInterval(interval);
}
}, [refresh, autoRefresh]);
return h('div', { className: 'max-w-6xl mx-auto p-6' }, [
// Header
h('div', { className: 'flex items-center justify-between mb-8' }, [
h('div', {}, [
h('h1', { className: 'text-3xl font-bold flex items-center gap-3' }, [
h('span', { className: 'text-god-gold pulse-gold inline-block' }, '🔱'),
'God Panel'
]),
h('p', { className: 'text-gray-400 mt-1' },
'System Diagnostics & Emergency Access'
)
]),
h('div', { className: 'flex items-center gap-4' }, [
h('label', { className: 'flex items-center gap-2 text-sm' }, [
h('input', {
type: 'checkbox',
checked: autoRefresh,
onChange: e => setAutoRefresh(e.target.checked),
className: 'rounded'
}),
'Auto-refresh (5s)'
]),
h('button', {
className: 'bg-god-gold text-black font-bold px-4 py-2 rounded-lg hover:bg-yellow-400',
onClick: refresh
}, '🔄 Refresh'),
lastUpdate && h('span', { className: 'text-xs text-gray-500' },
`Last: ${lastUpdate}`
)
])
]),
// Summary Banner
services?.summary && h('div', {
className: `rounded-xl p-4 mb-6 text-center font-bold text-lg ${
services.summary.includes('✅') ? 'bg-green-900/30 border border-green-500/50' :
'bg-red-900/30 border border-red-500/50'
}`
}, services.summary),
// Service Grid
h('div', { className: 'grid grid-cols-2 md:grid-cols-4 gap-4 mb-6' }, [
h(ServiceCard, { name: 'Frontend', data: services?.frontend, icon: '🌐' }),
h(ServiceCard, { name: 'PostgreSQL', data: services?.postgresql, icon: '🐘' }),
h(ServiceCard, { name: 'Redis', data: services?.redis, icon: '🔴' }),
h(ServiceCard, { name: 'Directus', data: services?.directus, icon: '📦' }),
]),
// Memory & Performance
health && h('div', { className: 'grid grid-cols-3 gap-4 mb-6' }, [
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.uptime_seconds ? Math.round(health.uptime_seconds / 60) + 'm' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Uptime')
]),
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.memory?.heap_used_mb ? health.memory.heap_used_mb + 'MB' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Memory Used')
]),
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.total_latency_ms ? health.total_latency_ms + 'ms' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Health Check')
])
]),
// Main Content Grid
h('div', { className: 'grid md:grid-cols-2 gap-6' }, [
h(SQLConsole, {}),
h('div', { className: 'space-y-6' }, [
h(QuickActions, {}),
h(TablesList, { tables })
])
]),
// Raw Health Data
health && h('details', { className: 'mt-6' }, [
h('summary', { className: 'cursor-pointer text-gray-400 hover:text-white' },
'📋 Raw Health Data'
),
h('pre', {
className: 'mt-2 bg-god-card border border-god-border rounded-xl p-4 text-xs font-mono overflow-auto max-h-64'
}, JSON.stringify(health, null, 2))
])
]);
}
// Render
const root = ReactDOM.createRoot(document.getElementById('god-panel'));
root.render(h(GodPanel));
</script>
</body>
</html>

View File

@@ -0,0 +1,116 @@
/** @type {import('tailwindcss').Config} */
import defaultTheme from 'tailwindcss/defaultTheme'
export default {
darkMode: ['class'],
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {
colors: {
// === THE TITANIUM PRO SYSTEM ===
// The Void (Base Layer - Pure Black)
void: '#000000',
// Surface Staircase (Hard-Edge Layers)
titanium: '#121212', // Level 1: Main panels
graphite: '#1C1C1E', // Level 2: Inputs/Secondary
jet: '#27272A', // Level 3: Popups/Modals
// Edge System (Borders & Separators)
edge: {
subtle: 'rgba(255, 255, 255, 0.10)', // Standard borders
normal: 'rgba(255, 255, 255, 0.15)', // Card borders
bright: 'rgba(255, 255, 255, 0.30)', // Active borders
gold: '#D4AF37', // Selected state
},
// The Luxury (Gold Accent System)
gold: {
100: '#FEF3C7', // Lightest
200: '#FDE68A',
300: '#FDE047', // Glowing text/data
400: '#EAB308', // Button highlight
500: '#D4AF37', // Antique Brass (primary)
600: '#B49428', // Button dark
700: '#A16207',
800: '#854D0E',
900: '#422006', // Deep shadow
},
// The Tech (Electric Blue - for live indicators)
electric: {
400: '#38BDF8',
500: '#0EA5E9',
},
// Text System (High Contrast Only)
silver: '#D1D5DB', // text-silver (darkest allowed)
// shadcn/ui compatibility
border: 'rgba(255, 255, 255, 0.15)',
input: 'rgba(255, 255, 255, 0.10)',
ring: '#D4AF37',
background: '#000000',
foreground: '#FFFFFF',
primary: {
DEFAULT: '#D4AF37',
foreground: '#000000',
},
secondary: {
DEFAULT: '#1C1C1E',
foreground: '#FFFFFF',
},
destructive: {
DEFAULT: '#EF4444',
foreground: '#FFFFFF',
},
muted: {
DEFAULT: '#121212',
foreground: '#D1D5DB',
},
accent: {
DEFAULT: '#27272A',
foreground: '#FFFFFF',
},
popover: {
DEFAULT: '#27272A',
foreground: '#FFFFFF',
},
card: {
DEFAULT: '#121212',
foreground: '#FFFFFF',
},
},
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
mono: ['JetBrains Mono', 'Consolas', ...defaultTheme.fontFamily.mono],
},
backgroundImage: {
'gold-gradient': 'linear-gradient(to bottom, #EAB308, #CA8A04)',
'gold-gradient-r': 'linear-gradient(to right, #EAB308, #CA8A04)',
'metal-shine': 'linear-gradient(45deg, transparent 25%, rgba(255,255,255,0.05) 50%, transparent 75%)',
'dot-grid': 'radial-gradient(rgba(255,255,255,0.1) 1px, transparent 1px)',
},
boxShadow: {
'glow-gold': '0 0 20px -5px rgba(212, 175, 55, 0.3)',
'glow-blue': '0 0 20px -5px rgba(56, 189, 248, 0.3)',
'hard': '0 4px 0 0 #1c1c1e', // Block shadow for cards
'hard-gold': '0 4px 0 0 rgba(212, 175, 55, 0.3)',
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(--radius) - 4px)',
},
backgroundSize: {
'dot-size': '20px 20px',
},
},
},
plugins: [require('tailwindcss-animate')],
}

14
god-mode/tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"moduleResolution": "node",
"jsx": "react-jsx",
"jsxImportSource": "react",
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
}
}