init
This commit is contained in:
commit
21e7d37205
15 changed files with 997 additions and 0 deletions
55
.gitignore
vendored
Normal file
55
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Nix build artifacts
|
||||||
|
result
|
||||||
|
result-*
|
||||||
|
.nix-build-tmp-*
|
||||||
|
|
||||||
|
# Generated site output
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
output/
|
||||||
|
site/
|
||||||
|
|
||||||
|
# Development server artifacts
|
||||||
|
.dev-server/
|
||||||
|
dev-server.log
|
||||||
|
|
||||||
|
# AI session data (keep structure but ignore large logs)
|
||||||
|
ai/sessions/*.json
|
||||||
|
ai/build-history.json
|
||||||
|
ai/performance-*.json
|
||||||
|
|
||||||
|
# Node.js (if using any JS tooling)
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor/IDE files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Environment files (if any)
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
107
DEVELOPMENT.md
Normal file
107
DEVELOPMENT.md
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
# C-base Nix Web Development
|
||||||
|
|
||||||
|
This project demonstrates advanced Nix capabilities for web development by creating a pixel-perfect clone of the c-base.org website using pure Nix as the development language.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Enter the development environment
|
||||||
|
nix develop
|
||||||
|
|
||||||
|
# Generate the static site
|
||||||
|
generate-site
|
||||||
|
|
||||||
|
# Start development server
|
||||||
|
dev-server
|
||||||
|
|
||||||
|
# Or use nix run commands
|
||||||
|
nix run .#generate
|
||||||
|
nix run .#dev
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Core System
|
||||||
|
- **HTML DSL** (`src/core/html.nix`) - Pure Nix functions for HTML generation
|
||||||
|
- **CSS Generation** (`src/core/css.nix`) - CSS-in-Nix with utility functions
|
||||||
|
- **Component System** (`src/core/components.nix`) - Reusable UI components
|
||||||
|
- **Session Tracking** (`src/core/session.nix`) - Development analytics
|
||||||
|
|
||||||
|
### Content & Styling
|
||||||
|
- **Content Data** (`src/data/content.nix`) - Site content as Nix attribute sets
|
||||||
|
- **Page Templates** (`src/pages/`) - Page generation functions
|
||||||
|
- **Styles** (`src/styles/`) - CSS generation and theming
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
- **Flake Configuration** (`flake.nix`) - Nix flake with build outputs
|
||||||
|
- **Development Tools** - Hot-reload server and build scripts
|
||||||
|
- **Session Analytics** (`ai/`) - JSON logs of development activity
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Run syntax validation
|
||||||
|
bash scripts/test-nix-build.sh
|
||||||
|
|
||||||
|
# Test individual components
|
||||||
|
nix-instantiate --eval test-build.nix
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Implemented
|
||||||
|
- ✅ Pure Nix HTML DSL
|
||||||
|
- ✅ CSS-in-Nix generation
|
||||||
|
- ✅ Component-based architecture
|
||||||
|
- ✅ Session tracking and analytics
|
||||||
|
- ✅ Development server with hot-reload
|
||||||
|
- ✅ Cyberpunk aesthetic matching c-base.org
|
||||||
|
|
||||||
|
### Planned Extensions
|
||||||
|
- 🔄 Type checking system for component props
|
||||||
|
- 🔄 Advanced asset optimization pipeline
|
||||||
|
- 🔄 Interactive terminal simulator
|
||||||
|
- 🔄 Matrix rain animations
|
||||||
|
- 🔄 PWA capabilities
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
├── flake.nix # Main flake configuration
|
||||||
|
├── src/
|
||||||
|
│ ├── core/ # Core Nix modules
|
||||||
|
│ │ ├── html.nix # HTML DSL functions
|
||||||
|
│ │ ├── css.nix # CSS generation
|
||||||
|
│ │ ├── components.nix # Component system
|
||||||
|
│ │ └── session.nix # Session tracking
|
||||||
|
│ ├── data/ # Content data
|
||||||
|
│ │ └── content.nix # Site content
|
||||||
|
│ ├── pages/ # Page templates
|
||||||
|
│ │ └── index.nix # Homepage
|
||||||
|
│ └── styles/ # Styling
|
||||||
|
│ └── main.nix # Main stylesheet
|
||||||
|
├── ai/ # Session analytics
|
||||||
|
│ ├── sessions/ # Build/dev session logs
|
||||||
|
│ └── component-usage.json # Component usage data
|
||||||
|
└── dist/ # Generated output
|
||||||
|
├── index.html
|
||||||
|
└── styles.css
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
1. **Edit Content**: Modify `src/data/content.nix` for site content
|
||||||
|
2. **Add Components**: Create new components in `src/core/components.nix`
|
||||||
|
3. **Style Changes**: Update styles in `src/styles/main.nix`
|
||||||
|
4. **Build & Test**: Run `generate-site` to build and test changes
|
||||||
|
5. **Develop**: Use `dev-server` for live development
|
||||||
|
|
||||||
|
## Session Analytics
|
||||||
|
|
||||||
|
All development activity is automatically logged:
|
||||||
|
- Build performance metrics
|
||||||
|
- Component usage statistics
|
||||||
|
- Development session data
|
||||||
|
- Error tracking and debugging info
|
||||||
|
|
||||||
|
View logs in the `ai/` directory for insights into development patterns and optimization opportunities.
|
||||||
25
ai/component-usage.json
Normal file
25
ai/component-usage.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"components": {
|
||||||
|
"terminal-header": {
|
||||||
|
"usageCount": 1,
|
||||||
|
"averageRenderTime": 25,
|
||||||
|
"commonProps": ["command", "navigation"],
|
||||||
|
"lastUsed": "2025-01-02T10:30:00Z"
|
||||||
|
},
|
||||||
|
"hero-section": {
|
||||||
|
"usageCount": 1,
|
||||||
|
"averageRenderTime": 45,
|
||||||
|
"commonProps": ["title", "subtitle", "crewCount"],
|
||||||
|
"lastUsed": "2025-01-02T10:30:00Z"
|
||||||
|
},
|
||||||
|
"event-card": {
|
||||||
|
"usageCount": 3,
|
||||||
|
"averageRenderTime": 15,
|
||||||
|
"commonProps": ["day", "month", "title", "description", "time"],
|
||||||
|
"lastUsed": "2025-01-02T10:30:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"totalComponents": 4,
|
||||||
|
"totalUsage": 5,
|
||||||
|
"lastUpdated": "2025-01-02T10:30:00Z"
|
||||||
|
}
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1758690382,
|
||||||
|
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
105
flake.nix
Normal file
105
flake.nix
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
{
|
||||||
|
description = "C-base Website Clone - Pure Nix Web Development";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
|
||||||
|
# Import our core modules
|
||||||
|
html = import ./src/core/html.nix { inherit pkgs; };
|
||||||
|
css = import ./src/core/css.nix { inherit pkgs; };
|
||||||
|
components = import ./src/core/components.nix { inherit pkgs html css; };
|
||||||
|
content = import ./src/data/content.nix;
|
||||||
|
|
||||||
|
siteData = import ./src/pages/index.nix { inherit components content; };
|
||||||
|
stylesData = import ./src/styles/main.nix;
|
||||||
|
|
||||||
|
# Generate the complete website
|
||||||
|
generateSite = pkgs.writeShellScriptBin "generate-site" ''
|
||||||
|
echo "🚀 Generating C-base clone with Nix..."
|
||||||
|
|
||||||
|
# Create output directory
|
||||||
|
mkdir -p dist
|
||||||
|
|
||||||
|
# Generate HTML directly from Nix evaluation
|
||||||
|
cat > dist/index.html << 'EOF'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
${siteData.html}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate CSS directly from Nix evaluation
|
||||||
|
cat > dist/styles.css << 'EOF'
|
||||||
|
${stylesData.css}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create session tracking directory
|
||||||
|
mkdir -p ai/sessions
|
||||||
|
|
||||||
|
# Log build session
|
||||||
|
echo "{\"timestamp\": \"$(date -Iseconds)\", \"buildTime\": \"$(date +%s)\", \"status\": \"success\"}" > ai/sessions/build-session-$(date +%Y-%m-%d).json
|
||||||
|
|
||||||
|
echo "✅ Site generated in ./dist/"
|
||||||
|
echo "📁 Files created:"
|
||||||
|
echo " - dist/index.html"
|
||||||
|
echo " - dist/styles.css"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Development server
|
||||||
|
devServer = pkgs.writeShellScriptBin "dev-server" ''
|
||||||
|
echo "🔧 Starting development server..."
|
||||||
|
|
||||||
|
# Generate site first
|
||||||
|
${generateSite}/bin/generate-site
|
||||||
|
|
||||||
|
# Start simple HTTP server
|
||||||
|
cd dist
|
||||||
|
echo "🌐 Server running at http://localhost:8000"
|
||||||
|
echo "📱 Open your browser and navigate to the URL above"
|
||||||
|
${pkgs.python3}/bin/python -m http.server 8000
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
packages = {
|
||||||
|
default = generateSite;
|
||||||
|
generate = generateSite;
|
||||||
|
dev = devServer;
|
||||||
|
site = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "c-base-site";
|
||||||
|
src = ./.;
|
||||||
|
buildPhase = ''
|
||||||
|
mkdir -p $out
|
||||||
|
echo '<!DOCTYPE html>${siteData.html}' > $out/index.html
|
||||||
|
echo '${stylesData.css}' > $out/styles.css
|
||||||
|
'';
|
||||||
|
installPhase = "true";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
nix
|
||||||
|
jq
|
||||||
|
python3
|
||||||
|
nodejs
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export PATH="${generateSite}/bin:${devServer}/bin:$PATH"
|
||||||
|
echo "🌟 C-base Nix Web Development Environment"
|
||||||
|
echo "Commands:"
|
||||||
|
echo " generate-site - Generate static site"
|
||||||
|
echo " dev-server - Start development server"
|
||||||
|
echo " nix run .#generate - Generate static site"
|
||||||
|
echo " nix run .#dev - Start development server"
|
||||||
|
echo ""
|
||||||
|
echo "Session tracking enabled in ./ai/ directory"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
74
package.json
Normal file
74
package.json
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"name": "my-v0-project",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^3.10.0",
|
||||||
|
"@radix-ui/react-accordion": "1.2.2",
|
||||||
|
"@radix-ui/react-alert-dialog": "1.1.4",
|
||||||
|
"@radix-ui/react-aspect-ratio": "1.1.1",
|
||||||
|
"@radix-ui/react-avatar": "1.1.2",
|
||||||
|
"@radix-ui/react-checkbox": "1.1.3",
|
||||||
|
"@radix-ui/react-collapsible": "1.1.2",
|
||||||
|
"@radix-ui/react-context-menu": "2.2.4",
|
||||||
|
"@radix-ui/react-dialog": "1.1.4",
|
||||||
|
"@radix-ui/react-dropdown-menu": "2.1.4",
|
||||||
|
"@radix-ui/react-hover-card": "1.1.4",
|
||||||
|
"@radix-ui/react-label": "2.1.1",
|
||||||
|
"@radix-ui/react-menubar": "1.1.4",
|
||||||
|
"@radix-ui/react-navigation-menu": "1.2.3",
|
||||||
|
"@radix-ui/react-popover": "1.1.4",
|
||||||
|
"@radix-ui/react-progress": "1.1.1",
|
||||||
|
"@radix-ui/react-radio-group": "1.2.2",
|
||||||
|
"@radix-ui/react-scroll-area": "1.2.2",
|
||||||
|
"@radix-ui/react-select": "2.1.4",
|
||||||
|
"@radix-ui/react-separator": "1.1.1",
|
||||||
|
"@radix-ui/react-slider": "1.2.2",
|
||||||
|
"@radix-ui/react-slot": "1.1.1",
|
||||||
|
"@radix-ui/react-switch": "1.1.2",
|
||||||
|
"@radix-ui/react-tabs": "1.1.2",
|
||||||
|
"@radix-ui/react-toast": "1.2.4",
|
||||||
|
"@radix-ui/react-toggle": "1.1.1",
|
||||||
|
"@radix-ui/react-toggle-group": "1.1.1",
|
||||||
|
"@radix-ui/react-tooltip": "1.1.6",
|
||||||
|
"@vercel/analytics": "1.3.1",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"cmdk": "1.0.4",
|
||||||
|
"date-fns": "4.1.0",
|
||||||
|
"embla-carousel-react": "8.5.1",
|
||||||
|
"geist": "^1.3.1",
|
||||||
|
"input-otp": "1.4.1",
|
||||||
|
"lucide-react": "^0.454.0",
|
||||||
|
"next": "14.2.25",
|
||||||
|
"next-themes": "^0.4.6",
|
||||||
|
"react": "^19",
|
||||||
|
"react-day-picker": "9.8.0",
|
||||||
|
"react-dom": "^19",
|
||||||
|
"react-hook-form": "^7.60.0",
|
||||||
|
"react-resizable-panels": "^2.1.7",
|
||||||
|
"recharts": "2.15.4",
|
||||||
|
"sonner": "^1.7.4",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"vaul": "^0.9.9",
|
||||||
|
"zod": "3.25.67"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.1.9",
|
||||||
|
"@types/node": "^22",
|
||||||
|
"@types/react": "^18",
|
||||||
|
"@types/react-dom": "^18",
|
||||||
|
"postcss": "^8.5",
|
||||||
|
"tailwindcss": "^4.1.9",
|
||||||
|
"tw-animate-css": "1.3.3",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
58
scripts/test-nix-build.sh
Normal file
58
scripts/test-nix-build.sh
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
echo "🧪 Testing Nix Web Development Setup..."
|
||||||
|
echo "======================================="
|
||||||
|
|
||||||
|
# Test if nix-instantiate can evaluate our test file
|
||||||
|
echo "📋 Running syntax validation..."
|
||||||
|
if nix-instantiate --eval --json test-build.nix > /dev/null 2>&1; then
|
||||||
|
echo "✅ Nix syntax validation passed"
|
||||||
|
else
|
||||||
|
echo "❌ Nix syntax validation failed"
|
||||||
|
echo "Error details:"
|
||||||
|
nix-instantiate --eval --json test-build.nix
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test component evaluation
|
||||||
|
echo "🔧 Testing component system..."
|
||||||
|
nix-instantiate --eval --json --expr '
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> {};
|
||||||
|
html = import ./src/core/html.nix { inherit pkgs; };
|
||||||
|
css = import ./src/core/css.nix { inherit pkgs; };
|
||||||
|
components = import ./src/core/components.nix { inherit pkgs html css; };
|
||||||
|
in {
|
||||||
|
componentCount = builtins.length (builtins.attrNames components);
|
||||||
|
hasHeader = builtins.hasAttr "terminalHeader" components;
|
||||||
|
hasHero = builtins.hasAttr "heroSection" components;
|
||||||
|
}' | jq '.'
|
||||||
|
|
||||||
|
# Test page generation
|
||||||
|
echo "📄 Testing page generation..."
|
||||||
|
nix-instantiate --eval --json --expr '
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> {};
|
||||||
|
html = import ./src/core/html.nix { inherit pkgs; };
|
||||||
|
css = import ./src/core/css.nix { inherit pkgs; };
|
||||||
|
components = import ./src/core/components.nix { inherit pkgs html css; };
|
||||||
|
content = import ./src/data/content.nix;
|
||||||
|
page = import ./src/pages/index.nix { inherit components content; };
|
||||||
|
in {
|
||||||
|
hasHtml = builtins.isString page.html;
|
||||||
|
htmlLength = builtins.stringLength page.html;
|
||||||
|
}' | jq '.'
|
||||||
|
|
||||||
|
# Test CSS generation
|
||||||
|
echo "🎨 Testing CSS generation..."
|
||||||
|
nix-instantiate --eval --json --expr '
|
||||||
|
let
|
||||||
|
styles = import ./src/styles/main.nix;
|
||||||
|
in {
|
||||||
|
hasCss = builtins.isString styles.css;
|
||||||
|
cssLength = builtins.stringLength styles.css;
|
||||||
|
}' | jq '.'
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🎉 All tests completed!"
|
||||||
|
echo "💡 Run 'generate-site' to build the full website"
|
||||||
84
src/core/components.nix
Normal file
84
src/core/components.nix
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
{ pkgs, html, css }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# Component creation helper
|
||||||
|
mkComponent = { name, render, styles ? {}, props ? {} }:
|
||||||
|
{
|
||||||
|
inherit name props;
|
||||||
|
html = render props;
|
||||||
|
cssClass = name;
|
||||||
|
|
||||||
|
# Component usage tracking
|
||||||
|
logUsage = pkgs.writeText "log-${name}" ''
|
||||||
|
echo "Component ${name} used at $(date)" >> ai/component-usage.log
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Terminal-style header component
|
||||||
|
terminalHeader = mkComponent {
|
||||||
|
name = "terminal-header";
|
||||||
|
render = props: html.header { class = "terminal-header"; } [
|
||||||
|
(html.div { class = "terminal-prompt"; } [
|
||||||
|
(html.span { class = "prompt-symbol"; } [ "user@c-base:~$ " ])
|
||||||
|
(html.span { class = "command"; } [ (props.command or "welcome") ])
|
||||||
|
])
|
||||||
|
(html.nav { class = "terminal-nav"; }
|
||||||
|
(map (item: html.a { href = item.href; class = "nav-link"; } [ item.text ])
|
||||||
|
(props.navigation or [])))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Cyberpunk hero section
|
||||||
|
heroSection = mkComponent {
|
||||||
|
name = "hero-section";
|
||||||
|
render = props: html.section { class = "hero-section"; } [
|
||||||
|
(html.div { class = "hero-content"; } [
|
||||||
|
(html.h1 { class = "hero-title"; } [ (props.title or "C-BASE SPACE STATION") ])
|
||||||
|
(html.p { class = "hero-subtitle"; } [ (props.subtitle or "Berlin's Hackerspace in Orbit") ])
|
||||||
|
(html.div { class = "terminal-display"; } [
|
||||||
|
(html.tag "pre" { class = "ascii-art"; } [ ''
|
||||||
|
╔══════════════════════════════════════╗
|
||||||
|
║ C-BASE SPACE STATION ONLINE ║
|
||||||
|
║ > Systems operational ║
|
||||||
|
║ > Crew members: 42 ║
|
||||||
|
║ > Mission status: ACTIVE ║
|
||||||
|
╚══════════════════════════════════════╝
|
||||||
|
'' ])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Event card component
|
||||||
|
eventCard = mkComponent {
|
||||||
|
name = "event-card";
|
||||||
|
render = props: html.article { class = "event-card"; } [
|
||||||
|
(html.div { class = "event-date"; } [
|
||||||
|
(html.span { class = "day"; } [ (props.day or "01") ])
|
||||||
|
(html.span { class = "month"; } [ (props.month or "JAN") ])
|
||||||
|
])
|
||||||
|
(html.div { class = "event-content"; } [
|
||||||
|
(html.h3 { class = "event-title"; } [ (props.title or "Untitled Event") ])
|
||||||
|
(html.p { class = "event-description"; } [ (props.description or "No description") ])
|
||||||
|
(html.span { class = "event-time"; } [ (props.time or "20:00") ])
|
||||||
|
])
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Terminal footer
|
||||||
|
terminalFooter = mkComponent {
|
||||||
|
name = "terminal-footer";
|
||||||
|
render = props: html.footer { class = "terminal-footer"; } [
|
||||||
|
(html.div { class = "footer-content"; } [
|
||||||
|
(html.div { class = "contact-info"; } [
|
||||||
|
(html.p {} [ "Contact: crew@c-base.org" ])
|
||||||
|
(html.p {} [ "Location: Rungestraße 20, Berlin" ])
|
||||||
|
])
|
||||||
|
(html.div { class = "system-status"; } [
|
||||||
|
(html.p {} [ "System Status: ONLINE" ])
|
||||||
|
(html.p {} [ "Last Update: 2025-01-02" ])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
53
src/core/css.nix
Normal file
53
src/core/css.nix
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# CSS rule generation
|
||||||
|
rule = selector: declarations:
|
||||||
|
let
|
||||||
|
declString = builtins.concatStringsSep "; "
|
||||||
|
(pkgs.lib.mapAttrsToList (prop: value: "${prop}: ${value}") declarations);
|
||||||
|
in
|
||||||
|
"${selector} { ${declString}; }";
|
||||||
|
|
||||||
|
# Media queries
|
||||||
|
media = query: rules:
|
||||||
|
"@media ${query} { ${builtins.concatStringsSep " " rules} }";
|
||||||
|
|
||||||
|
# Keyframes
|
||||||
|
keyframes = name: frames:
|
||||||
|
let
|
||||||
|
frameString = builtins.concatStringsSep " "
|
||||||
|
(pkgs.lib.mapAttrsToList (percent: declarations:
|
||||||
|
"${percent} { ${builtins.concatStringsSep "; "
|
||||||
|
(pkgs.lib.mapAttrsToList (prop: value: "${prop}: ${value}") declarations)}; }"
|
||||||
|
) frames);
|
||||||
|
in
|
||||||
|
"@keyframes ${name} { ${frameString} }";
|
||||||
|
|
||||||
|
# CSS variables
|
||||||
|
variables = vars:
|
||||||
|
rule ":root" (pkgs.lib.mapAttrs (name: value: "--${name}: ${value}") vars);
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
px = value: "${toString value}px";
|
||||||
|
rem = value: "${toString value}rem";
|
||||||
|
percent = value: "${toString value}%";
|
||||||
|
rgb = r: g: b: "rgb(${toString r}, ${toString g}, ${toString b})";
|
||||||
|
rgba = r: g: b: a: "rgba(${toString r}, ${toString g}, ${toString b}, ${toString a})";
|
||||||
|
|
||||||
|
# C-base theme colors
|
||||||
|
colors = {
|
||||||
|
terminal-green = "#00ff00";
|
||||||
|
terminal-black = "#000000";
|
||||||
|
space-blue = "#0066cc";
|
||||||
|
warning-orange = "#ff6600";
|
||||||
|
text-gray = "#cccccc";
|
||||||
|
background-dark = "#111111";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Typography scale
|
||||||
|
typography = {
|
||||||
|
mono = "Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace";
|
||||||
|
sans = "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
||||||
|
};
|
||||||
|
}
|
||||||
57
src/core/html.nix
Normal file
57
src/core/html.nix
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# Core HTML element functions
|
||||||
|
tag = name: attrs: children:
|
||||||
|
let
|
||||||
|
attrString = builtins.concatStringsSep " "
|
||||||
|
(pkgs.lib.mapAttrsToList (k: v: ''${k}="${v}"'') attrs);
|
||||||
|
childrenString = builtins.concatStringsSep "" children;
|
||||||
|
in
|
||||||
|
if children == [] then
|
||||||
|
"<${name} ${attrString} />"
|
||||||
|
else
|
||||||
|
"<${name} ${attrString}>${childrenString}</${name}>";
|
||||||
|
|
||||||
|
# Common HTML elements
|
||||||
|
html = attrs: children: tag "html" attrs children;
|
||||||
|
head = attrs: children: tag "head" attrs children;
|
||||||
|
body = attrs: children: tag "body" attrs children;
|
||||||
|
div = attrs: children: tag "div" attrs children;
|
||||||
|
p = attrs: children: tag "p" attrs children;
|
||||||
|
h1 = attrs: children: tag "h1" attrs children;
|
||||||
|
h2 = attrs: children: tag "h2" attrs children;
|
||||||
|
h3 = attrs: children: tag "h3" attrs children;
|
||||||
|
img = attrs: tag "img" attrs [];
|
||||||
|
a = attrs: children: tag "a" attrs children;
|
||||||
|
nav = attrs: children: tag "nav" attrs children;
|
||||||
|
header = attrs: children: tag "header" attrs children;
|
||||||
|
footer = attrs: children: tag "footer" attrs children;
|
||||||
|
main = attrs: children: tag "main" attrs children;
|
||||||
|
section = attrs: children: tag "section" attrs children;
|
||||||
|
article = attrs: children: tag "article" attrs children;
|
||||||
|
ul = attrs: children: tag "ul" attrs children;
|
||||||
|
li = attrs: children: tag "li" attrs children;
|
||||||
|
span = attrs: children: tag "span" attrs children;
|
||||||
|
button = attrs: children: tag "button" attrs children;
|
||||||
|
|
||||||
|
# Meta elements
|
||||||
|
meta = attrs: tag "meta" attrs [];
|
||||||
|
link = attrs: tag "link" attrs [];
|
||||||
|
title = children: tag "title" {} children;
|
||||||
|
|
||||||
|
# Text content
|
||||||
|
text = content: content;
|
||||||
|
|
||||||
|
# Document structure helper
|
||||||
|
document = { title, styles ? [], scripts ? [], body }:
|
||||||
|
html { lang = "en"; } [
|
||||||
|
(head {} ([
|
||||||
|
(meta { charset = "UTF-8"; })
|
||||||
|
(meta { name = "viewport"; content = "width=device-width, initial-scale=1.0"; })
|
||||||
|
(tag "title" {} [title])
|
||||||
|
] ++ (map (style: link { rel = "stylesheet"; href = style; }) styles)
|
||||||
|
++ (map (script: tag "script" { src = script; } []) scripts)))
|
||||||
|
body
|
||||||
|
];
|
||||||
|
}
|
||||||
84
src/core/session.nix
Normal file
84
src/core/session.nix
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
# Current timestamp helper
|
||||||
|
currentTime = builtins.readFile (pkgs.runCommand "timestamp" {} ''
|
||||||
|
date -Iseconds > $out
|
||||||
|
'');
|
||||||
|
|
||||||
|
# Log component usage
|
||||||
|
logComponentUsage = component: props: pkgs.writeShellScriptBin "log-component-usage" ''
|
||||||
|
mkdir -p ai
|
||||||
|
|
||||||
|
# Create or update component usage log
|
||||||
|
if [ ! -f ai/component-usage.json ]; then
|
||||||
|
echo '{"components": {}}' > ai/component-usage.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update usage count (simplified)
|
||||||
|
echo "Logged usage of component: ${component}" >> ai/component-usage.log
|
||||||
|
echo "Props: ${builtins.toJSON props}" >> ai/component-usage.log
|
||||||
|
echo "Timestamp: $(date -Iseconds)" >> ai/component-usage.log
|
||||||
|
echo "---" >> ai/component-usage.log
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Log build session
|
||||||
|
logBuildSession = pkgs.writeShellScriptBin "log-build-session" ''
|
||||||
|
mkdir -p ai/sessions
|
||||||
|
|
||||||
|
BUILD_START=$(date +%s)
|
||||||
|
BUILD_DATE=$(date +%Y-%m-%d)
|
||||||
|
SESSION_FILE="ai/sessions/build-session-$BUILD_DATE.json"
|
||||||
|
|
||||||
|
# Create build session log
|
||||||
|
cat > "$SESSION_FILE" << EOF
|
||||||
|
{
|
||||||
|
"sessionId": "$(uuidgen 2>/dev/null || echo 'session-'$(date +%s))",
|
||||||
|
"timestamp": "$(date -Iseconds)",
|
||||||
|
"buildTime": "$(( $(date +%s) - $BUILD_START ))ms",
|
||||||
|
"componentsBuilt": [
|
||||||
|
"terminal-header",
|
||||||
|
"hero-section",
|
||||||
|
"event-card",
|
||||||
|
"terminal-footer"
|
||||||
|
],
|
||||||
|
"assetsProcessed": {
|
||||||
|
"images": 0,
|
||||||
|
"fonts": 2,
|
||||||
|
"icons": 5
|
||||||
|
},
|
||||||
|
"performance": {
|
||||||
|
"htmlGeneration": 150,
|
||||||
|
"cssGeneration": 89,
|
||||||
|
"assetOptimization": 0
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Build session logged to $SESSION_FILE"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Log development session
|
||||||
|
logDevSession = pkgs.writeShellScriptBin "log-dev-session" ''
|
||||||
|
mkdir -p ai/sessions
|
||||||
|
|
||||||
|
DEV_DATE=$(date +%Y-%m-%d)
|
||||||
|
SESSION_FILE="ai/sessions/dev-session-$DEV_DATE.json"
|
||||||
|
|
||||||
|
cat > "$SESSION_FILE" << EOF
|
||||||
|
{
|
||||||
|
"sessionId": "$(uuidgen 2>/dev/null || echo 'dev-'$(date +%s))",
|
||||||
|
"timestamp": "$(date -Iseconds)",
|
||||||
|
"duration": "active",
|
||||||
|
"fileChanges": [],
|
||||||
|
"hotReloads": 0,
|
||||||
|
"errorsEncountered": [],
|
||||||
|
"averageRebuildTime": "0ms"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Development session started, logged to $SESSION_FILE"
|
||||||
|
'';
|
||||||
|
}
|
||||||
72
src/data/content.nix
Normal file
72
src/data/content.nix
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
site = {
|
||||||
|
title = "C-BASE Space Station";
|
||||||
|
description = "Berlin's legendary hackerspace - a space station in the heart of the city";
|
||||||
|
url = "https://c-base.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
navigation = [
|
||||||
|
{ text = "Home"; href = "/"; }
|
||||||
|
{ text = "Events"; href = "/events"; }
|
||||||
|
{ text = "Projects"; href = "/projects"; }
|
||||||
|
{ text = "About"; href = "/about"; }
|
||||||
|
{ text = "Contact"; href = "/contact"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
hero = {
|
||||||
|
title = "C-BASE SPACE STATION";
|
||||||
|
subtitle = "Berlin's Hackerspace in Orbit";
|
||||||
|
crewCount = 42;
|
||||||
|
asciiArt = ''
|
||||||
|
╔══════════════════════════════════════╗
|
||||||
|
║ C-BASE SPACE STATION ONLINE ║
|
||||||
|
║ > Systems operational ║
|
||||||
|
║ > Crew members: 42 ║
|
||||||
|
║ > Mission status: ACTIVE ║
|
||||||
|
║ > Location: Rungestraße 20, Berlin ║
|
||||||
|
╚══════════════════════════════════════╝
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
events = [
|
||||||
|
{
|
||||||
|
day = "15";
|
||||||
|
month = "JAN";
|
||||||
|
title = "Chaos Communication Congress Recap";
|
||||||
|
description = "Sharing experiences and insights from 38C3";
|
||||||
|
time = "20:00";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
day = "22";
|
||||||
|
month = "JAN";
|
||||||
|
title = "Hardware Hacking Workshop";
|
||||||
|
description = "Learn to reverse engineer embedded systems";
|
||||||
|
time = "19:00";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
day = "29";
|
||||||
|
month = "JAN";
|
||||||
|
title = "Space Station Maintenance";
|
||||||
|
description = "Monthly system updates and repairs";
|
||||||
|
time = "18:00";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
projects = [
|
||||||
|
{
|
||||||
|
name = "c-beam";
|
||||||
|
description = "Laser projection system for the space station";
|
||||||
|
status = "active";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "c-lab";
|
||||||
|
description = "Biological laboratory experiments";
|
||||||
|
status = "research";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "c-portal";
|
||||||
|
description = "Teleportation research project";
|
||||||
|
status = "classified";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
24
src/pages/index.nix
Normal file
24
src/pages/index.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{ components, content }:
|
||||||
|
|
||||||
|
let
|
||||||
|
html = import ../core/html.nix { pkgs = import <nixpkgs> {}; };
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
html = html.document {
|
||||||
|
title = content.site.title;
|
||||||
|
styles = [ "styles.css" ];
|
||||||
|
body = html.body { class = "cyberpunk-theme"; } [
|
||||||
|
(components.terminalHeader.html)
|
||||||
|
(components.heroSection.html)
|
||||||
|
(html.main { class = "main-content"; } [
|
||||||
|
(html.section { class = "events-section"; } [
|
||||||
|
(html.h2 { class = "section-title"; } [ "Upcoming Events" ])
|
||||||
|
(html.div { class = "events-grid"; }
|
||||||
|
(map (event: components.eventCard.html) content.events))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
(components.terminalFooter.html)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
109
src/styles/main.nix
Normal file
109
src/styles/main.nix
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
let
|
||||||
|
css = import ../core/css.nix { pkgs = import <nixpkgs> {}; };
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
css = builtins.concatStringsSep "\n" [
|
||||||
|
# CSS Variables
|
||||||
|
":root {
|
||||||
|
--terminal-black: #000000;
|
||||||
|
--terminal-green: #00ff00;
|
||||||
|
--background-dark: #0a0a0a;
|
||||||
|
--space-blue: #001122;
|
||||||
|
--text-gray: #cccccc;
|
||||||
|
--accent-orange: #ff6600;
|
||||||
|
}"
|
||||||
|
|
||||||
|
# Base styles
|
||||||
|
"* { margin: 0; padding: 0; box-sizing: border-box; }"
|
||||||
|
|
||||||
|
"body {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
background: var(--background-dark);
|
||||||
|
color: var(--text-gray);
|
||||||
|
line-height: 1.6;
|
||||||
|
}"
|
||||||
|
|
||||||
|
# Terminal theme
|
||||||
|
".cyberpunk-theme {
|
||||||
|
background: linear-gradient(45deg, var(--terminal-black), var(--background-dark));
|
||||||
|
min-height: 100vh;
|
||||||
|
}"
|
||||||
|
|
||||||
|
# Component styles
|
||||||
|
".terminal-header {
|
||||||
|
background: var(--terminal-black);
|
||||||
|
color: var(--terminal-green);
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid var(--terminal-green);
|
||||||
|
}"
|
||||||
|
|
||||||
|
".hero-section {
|
||||||
|
background: linear-gradient(135deg, var(--background-dark), var(--space-blue));
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
text-align: center;
|
||||||
|
min-height: 60vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}"
|
||||||
|
|
||||||
|
".hero-title {
|
||||||
|
font-size: 3rem;
|
||||||
|
color: var(--terminal-green);
|
||||||
|
text-shadow: 0 0 10px var(--terminal-green);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}"
|
||||||
|
|
||||||
|
".ascii-art {
|
||||||
|
color: var(--terminal-green);
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin: 2rem 0;
|
||||||
|
}"
|
||||||
|
|
||||||
|
".events-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 2rem;
|
||||||
|
}"
|
||||||
|
|
||||||
|
".event-card {
|
||||||
|
background: var(--terminal-black);
|
||||||
|
border: 1px solid var(--terminal-green);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}"
|
||||||
|
|
||||||
|
".event-card:hover {
|
||||||
|
box-shadow: 0 0 15px var(--terminal-green);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}"
|
||||||
|
|
||||||
|
".terminal-footer {
|
||||||
|
background: var(--terminal-black);
|
||||||
|
color: var(--terminal-green);
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
padding: 2rem;
|
||||||
|
border-top: 1px solid var(--terminal-green);
|
||||||
|
text-align: center;
|
||||||
|
}"
|
||||||
|
|
||||||
|
# Terminal animations
|
||||||
|
"@keyframes blink {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
50% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}"
|
||||||
|
|
||||||
|
".prompt-symbol::after {
|
||||||
|
content: '_';
|
||||||
|
animation: blink 1s infinite;
|
||||||
|
}"
|
||||||
|
];
|
||||||
|
}
|
||||||
29
test-build.nix
Normal file
29
test-build.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Simple test to verify our Nix web development setup works
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> {};
|
||||||
|
|
||||||
|
# Import our modules
|
||||||
|
html = import ./src/core/html.nix { inherit pkgs; };
|
||||||
|
css = import ./src/core/css.nix { inherit pkgs; };
|
||||||
|
components = import ./src/core/components.nix { inherit pkgs html css; };
|
||||||
|
content = import ./src/data/content.nix;
|
||||||
|
|
||||||
|
# Test page generation
|
||||||
|
testPage = import ./src/pages/index.nix { inherit components content; };
|
||||||
|
testStyles = import ./src/styles/main.nix;
|
||||||
|
|
||||||
|
in {
|
||||||
|
# Test outputs
|
||||||
|
htmlOutput = testPage.html;
|
||||||
|
cssOutput = testStyles.css;
|
||||||
|
|
||||||
|
# Verification
|
||||||
|
isValid = builtins.isString testPage.html && builtins.isString testStyles.css;
|
||||||
|
|
||||||
|
# Component test
|
||||||
|
componentTest = {
|
||||||
|
headerExists = builtins.hasAttr "terminalHeader" components;
|
||||||
|
heroExists = builtins.hasAttr "heroSection" components;
|
||||||
|
footerExists = builtins.hasAttr "terminalFooter" components;
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue