Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub (part 2)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- package-lock.json +0 -0
- package.json +101 -0
- packages/create-open-lovable/index.js +94 -0
- packages/create-open-lovable/lib/installer.js +261 -0
- packages/create-open-lovable/lib/prompts.js +190 -0
- packages/create-open-lovable/package.json +36 -0
- packages/create-open-lovable/templates/e2b/.env.example +25 -0
- packages/create-open-lovable/templates/e2b/README.md +38 -0
- packages/create-open-lovable/templates/vercel/.env.example +28 -0
- packages/create-open-lovable/templates/vercel/README.md +52 -0
- pnpm-lock.yaml +0 -0
- postcss.config.mjs +8 -0
- public/compressor.json +16 -0
- public/file.svg +1 -0
- public/firecrawl-logo +0 -0
- public/firecrawl.svg +4 -0
- public/globe.svg +1 -0
- public/window.svg +1 -0
- requirements.txt +4 -0
- scripts/run.sh +50 -0
- scripts/run_latex.sh +44 -0
- scripts/run_latex_llm.sh +45 -0
- scripts/run_llm.sh +51 -0
- styles/additional-styles/custom-fonts.css +0 -0
- styles/additional-styles/theme.css +58 -0
- styles/additional-styles/utility-patterns.css +112 -0
- styles/chrome-bug.css +12 -0
- styles/colors.json +182 -0
- styles/components/.cursor/rules/component-styles.md +32 -0
- styles/components/button.css +72 -0
- styles/components/code.css +44 -0
- styles/components/index.css +10 -0
- styles/design-system/.cursor/rules/design-system.md +81 -0
- styles/design-system/animations.css +92 -0
- styles/design-system/base/body.css +132 -0
- styles/design-system/base/layout.css +212 -0
- styles/design-system/base/reset.css +132 -0
- styles/design-system/colors.css +135 -0
- styles/design-system/fonts.css +8 -0
- styles/design-system/typography.css +243 -0
- styles/design-system/utilities.css +235 -0
- styles/fire.css +103 -0
- styles/inside-border-fix.css +47 -0
- styles/main.css +282 -0
- tailwind.config.ts +406 -0
- tsconfig.json +27 -0
- types/conversation.ts +50 -0
- types/file-manifest.ts +77 -0
- types/sandbox.ts +31 -0
- utils/cn.ts +5 -0
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "open-lovable",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"private": true,
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "next dev --turbopack",
|
| 8 |
+
"build": "next build",
|
| 9 |
+
"start": "next start",
|
| 10 |
+
"lint": "next lint",
|
| 11 |
+
"test:api": "node tests/api-endpoints.test.js",
|
| 12 |
+
"test:code": "node tests/code-execution.test.js",
|
| 13 |
+
"test:all": "npm run test:integration && npm run test:api && npm run test:code"
|
| 14 |
+
},
|
| 15 |
+
"dependencies": {
|
| 16 |
+
"@ai-sdk/anthropic": "^2.0.1",
|
| 17 |
+
"@ai-sdk/google": "^2.0.4",
|
| 18 |
+
"@ai-sdk/groq": "^2.0.0",
|
| 19 |
+
"@ai-sdk/openai": "^2.0.4",
|
| 20 |
+
"@anthropic-ai/sdk": "^0.57.0",
|
| 21 |
+
"@e2b/code-interpreter": "^2.0.0",
|
| 22 |
+
"@mendable/firecrawl-js": "^4.3.3",
|
| 23 |
+
"@radix-ui/react-accordion": "^1.2.12",
|
| 24 |
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
| 25 |
+
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
| 26 |
+
"@radix-ui/react-avatar": "^1.1.10",
|
| 27 |
+
"@radix-ui/react-checkbox": "^1.3.3",
|
| 28 |
+
"@radix-ui/react-collapsible": "^1.1.12",
|
| 29 |
+
"@radix-ui/react-context-menu": "^2.2.16",
|
| 30 |
+
"@radix-ui/react-dialog": "^1.1.15",
|
| 31 |
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
| 32 |
+
"@radix-ui/react-hover-card": "^1.1.15",
|
| 33 |
+
"@radix-ui/react-label": "^2.1.7",
|
| 34 |
+
"@radix-ui/react-menubar": "^1.1.16",
|
| 35 |
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
| 36 |
+
"@radix-ui/react-popover": "^1.1.15",
|
| 37 |
+
"@radix-ui/react-progress": "^1.1.7",
|
| 38 |
+
"@radix-ui/react-radio-group": "^1.3.8",
|
| 39 |
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
| 40 |
+
"@radix-ui/react-select": "^2.2.6",
|
| 41 |
+
"@radix-ui/react-separator": "^1.1.7",
|
| 42 |
+
"@radix-ui/react-slider": "^1.3.6",
|
| 43 |
+
"@radix-ui/react-slot": "^1.2.3",
|
| 44 |
+
"@radix-ui/react-switch": "^1.2.5",
|
| 45 |
+
"@radix-ui/react-tabs": "^1.1.13",
|
| 46 |
+
"@radix-ui/react-toast": "^1.2.15",
|
| 47 |
+
"@radix-ui/react-toggle": "^1.1.10",
|
| 48 |
+
"@radix-ui/react-toggle-group": "^1.1.11",
|
| 49 |
+
"@radix-ui/react-tooltip": "^1.2.8",
|
| 50 |
+
"@tabler/icons-react": "^3.34.1",
|
| 51 |
+
"@tailwindcss/typography": "^0.5.16",
|
| 52 |
+
"@types/react-syntax-highlighter": "^15.5.13",
|
| 53 |
+
"@vercel/sandbox": "^0.0.17",
|
| 54 |
+
"ai": "^5.0.0",
|
| 55 |
+
"autoprefixer": "^10.4.21",
|
| 56 |
+
"axios": "^1.13.5",
|
| 57 |
+
"class-variance-authority": "^0.7.1",
|
| 58 |
+
"classnames": "^2.5.1",
|
| 59 |
+
"clsx": "^2.1.1",
|
| 60 |
+
"copy-to-clipboard": "^3.3.3",
|
| 61 |
+
"cors": "^2.8.5",
|
| 62 |
+
"dotenv": "^17.2.1",
|
| 63 |
+
"fast-xml-parser": "^5.3.6",
|
| 64 |
+
"framer-motion": "^12.23.12",
|
| 65 |
+
"groq-sdk": "^0.29.0",
|
| 66 |
+
"jotai": "^2.14.0",
|
| 67 |
+
"lodash-es": "^4.17.21",
|
| 68 |
+
"lucide-react": "^0.532.0",
|
| 69 |
+
"motion": "^12.23.12",
|
| 70 |
+
"nanoid": "^5.1.5",
|
| 71 |
+
"next": "15.4.3",
|
| 72 |
+
"next-themes": "^0.4.6",
|
| 73 |
+
"octokit": "^5.0.5",
|
| 74 |
+
"pixi.js": "^8.13.1",
|
| 75 |
+
"react": "19.1.0",
|
| 76 |
+
"react-dom": "19.1.0",
|
| 77 |
+
"react-hook-form": "^7.62.0",
|
| 78 |
+
"react-icons": "^5.5.0",
|
| 79 |
+
"react-syntax-highlighter": "^15.6.1",
|
| 80 |
+
"sonner": "^2.0.7",
|
| 81 |
+
"tailwind-gradient-mask-image": "^1.2.0",
|
| 82 |
+
"tailwind-merge": "^3.3.1",
|
| 83 |
+
"tailwindcss-animate": "^1.0.7",
|
| 84 |
+
"usehooks-ts": "^3.1.1",
|
| 85 |
+
"zod": "^3.25.76"
|
| 86 |
+
},
|
| 87 |
+
"devDependencies": {
|
| 88 |
+
"@eslint/eslintrc": "^3",
|
| 89 |
+
"@types/lodash-es": "^4.17.12",
|
| 90 |
+
"@types/node": "^20",
|
| 91 |
+
"@types/react": "^19",
|
| 92 |
+
"@types/react-dom": "^19",
|
| 93 |
+
"eslint": "^9",
|
| 94 |
+
"eslint-config-next": "15.4.3",
|
| 95 |
+
"postcss": "^8.5.6",
|
| 96 |
+
"postcss-import": "^16.1.1",
|
| 97 |
+
"postcss-nesting": "^13.0.2",
|
| 98 |
+
"tailwindcss": "^3.4.17",
|
| 99 |
+
"typescript": "^5"
|
| 100 |
+
}
|
| 101 |
+
}
|
packages/create-open-lovable/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
|
| 3 |
+
import { Command } from 'commander';
|
| 4 |
+
import inquirer from 'inquirer';
|
| 5 |
+
import chalk from 'chalk';
|
| 6 |
+
import ora from 'ora';
|
| 7 |
+
import path from 'path';
|
| 8 |
+
import { fileURLToPath } from 'url';
|
| 9 |
+
import { installer } from './lib/installer.js';
|
| 10 |
+
import { getPrompts } from './lib/prompts.js';
|
| 11 |
+
|
| 12 |
+
const __filename = fileURLToPath(import.meta.url);
|
| 13 |
+
const __dirname = path.dirname(__filename);
|
| 14 |
+
|
| 15 |
+
const program = new Command();
|
| 16 |
+
|
| 17 |
+
program
|
| 18 |
+
.name('create-open-lovable')
|
| 19 |
+
.description('Create a new Open Lovable project with your choice of sandbox provider')
|
| 20 |
+
.version('1.0.0')
|
| 21 |
+
.option('-s, --sandbox <provider>', 'Sandbox provider (e2b or vercel)')
|
| 22 |
+
.option('-n, --name <name>', 'Project name')
|
| 23 |
+
.option('-p, --path <path>', 'Installation path (defaults to current directory)')
|
| 24 |
+
.option('--skip-install', 'Skip npm install')
|
| 25 |
+
.option('--dry-run', 'Run without making changes')
|
| 26 |
+
.parse(process.argv);
|
| 27 |
+
|
| 28 |
+
const options = program.opts();
|
| 29 |
+
|
| 30 |
+
async function main() {
|
| 31 |
+
console.log(chalk.cyan('\n🚀 Welcome to Open Lovable Setup!\n'));
|
| 32 |
+
|
| 33 |
+
let config = {
|
| 34 |
+
sandbox: options.sandbox,
|
| 35 |
+
name: options.name || 'my-open-lovable',
|
| 36 |
+
path: options.path || process.cwd(),
|
| 37 |
+
skipInstall: options.skipInstall || false,
|
| 38 |
+
dryRun: options.dryRun || false
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
// Interactive mode if sandbox not specified
|
| 42 |
+
if (!config.sandbox) {
|
| 43 |
+
const prompts = getPrompts(config);
|
| 44 |
+
const answers = await inquirer.prompt(prompts);
|
| 45 |
+
config = { ...config, ...answers };
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
// Validate sandbox provider
|
| 49 |
+
if (!['e2b', 'vercel'].includes(config.sandbox)) {
|
| 50 |
+
console.error(chalk.red(`\n❌ Invalid sandbox provider: ${config.sandbox}`));
|
| 51 |
+
console.log(chalk.yellow('Valid options: e2b, vercel\n'));
|
| 52 |
+
process.exit(1);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
console.log(chalk.gray('\nConfiguration:'));
|
| 56 |
+
console.log(chalk.gray(` Project: ${config.name}`));
|
| 57 |
+
console.log(chalk.gray(` Sandbox: ${config.sandbox}`));
|
| 58 |
+
console.log(chalk.gray(` Path: ${path.resolve(config.path, config.name)}\n`));
|
| 59 |
+
|
| 60 |
+
if (config.dryRun) {
|
| 61 |
+
console.log(chalk.yellow('🔍 Dry run mode - no files will be created\n'));
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
const spinner = ora('Creating project...').start();
|
| 65 |
+
|
| 66 |
+
try {
|
| 67 |
+
await installer({
|
| 68 |
+
...config,
|
| 69 |
+
templatesDir: path.join(__dirname, 'templates')
|
| 70 |
+
});
|
| 71 |
+
|
| 72 |
+
spinner.succeed('Project created successfully!');
|
| 73 |
+
|
| 74 |
+
console.log(chalk.green('\n✅ Setup complete!\n'));
|
| 75 |
+
console.log(chalk.white('Next steps:'));
|
| 76 |
+
console.log(chalk.gray(` 1. cd ${config.name}`));
|
| 77 |
+
console.log(chalk.gray(` 2. Copy .env.example to .env and add your API keys`));
|
| 78 |
+
console.log(chalk.gray(` 3. npm run dev`));
|
| 79 |
+
console.log(chalk.gray('\nHappy coding! 🎉\n'));
|
| 80 |
+
|
| 81 |
+
} catch (error) {
|
| 82 |
+
spinner.fail('Setup failed');
|
| 83 |
+
console.error(chalk.red('\n❌ Error:'), error.message);
|
| 84 |
+
if (error.stack && process.env.DEBUG) {
|
| 85 |
+
console.error(chalk.gray(error.stack));
|
| 86 |
+
}
|
| 87 |
+
process.exit(1);
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
main().catch(error => {
|
| 92 |
+
console.error(chalk.red('Unexpected error:'), error);
|
| 93 |
+
process.exit(1);
|
| 94 |
+
});
|
packages/create-open-lovable/lib/installer.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fs from 'fs-extra';
|
| 2 |
+
import path from 'path';
|
| 3 |
+
import { execSync } from 'child_process';
|
| 4 |
+
import chalk from 'chalk';
|
| 5 |
+
import inquirer from 'inquirer';
|
| 6 |
+
import { getEnvPrompts } from './prompts.js';
|
| 7 |
+
|
| 8 |
+
export async function installer(config) {
|
| 9 |
+
const { name, sandbox, path: installPath, skipInstall, dryRun, templatesDir } = config;
|
| 10 |
+
const projectPath = path.join(installPath, name);
|
| 11 |
+
|
| 12 |
+
if (dryRun) {
|
| 13 |
+
console.log(chalk.blue('\n📋 Dry run - would perform these actions:'));
|
| 14 |
+
console.log(chalk.gray(` - Create directory: ${projectPath}`));
|
| 15 |
+
console.log(chalk.gray(` - Copy base template files`));
|
| 16 |
+
console.log(chalk.gray(` - Copy ${sandbox}-specific files`));
|
| 17 |
+
console.log(chalk.gray(` - Create .env file`));
|
| 18 |
+
if (!skipInstall) {
|
| 19 |
+
console.log(chalk.gray(` - Run npm install`));
|
| 20 |
+
}
|
| 21 |
+
return;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
// Check if directory exists
|
| 25 |
+
if (await fs.pathExists(projectPath)) {
|
| 26 |
+
const { overwrite } = await inquirer.prompt([{
|
| 27 |
+
type: 'confirm',
|
| 28 |
+
name: 'overwrite',
|
| 29 |
+
message: `Directory ${name} already exists. Overwrite?`,
|
| 30 |
+
default: false
|
| 31 |
+
}]);
|
| 32 |
+
|
| 33 |
+
if (!overwrite) {
|
| 34 |
+
throw new Error('Installation cancelled');
|
| 35 |
+
}
|
| 36 |
+
await fs.remove(projectPath);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
// Create project directory
|
| 40 |
+
await fs.ensureDir(projectPath);
|
| 41 |
+
|
| 42 |
+
// Copy base template (shared files)
|
| 43 |
+
const baseTemplatePath = path.join(templatesDir, 'base');
|
| 44 |
+
if (await fs.pathExists(baseTemplatePath)) {
|
| 45 |
+
await copyTemplate(baseTemplatePath, projectPath);
|
| 46 |
+
} else {
|
| 47 |
+
// If no base template exists yet, copy from the main project
|
| 48 |
+
await copyMainProject(path.dirname(templatesDir), projectPath, sandbox);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
// Copy provider-specific template
|
| 52 |
+
const providerTemplatePath = path.join(templatesDir, sandbox);
|
| 53 |
+
if (await fs.pathExists(providerTemplatePath)) {
|
| 54 |
+
await copyTemplate(providerTemplatePath, projectPath);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
// Configure environment variables
|
| 58 |
+
if (config.configureEnv) {
|
| 59 |
+
const envAnswers = await inquirer.prompt(getEnvPrompts(sandbox));
|
| 60 |
+
await createEnvFile(projectPath, sandbox, envAnswers);
|
| 61 |
+
} else {
|
| 62 |
+
// Create .env.example copy
|
| 63 |
+
await createEnvExample(projectPath, sandbox);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
// Update package.json with project name
|
| 67 |
+
await updatePackageJson(projectPath, name);
|
| 68 |
+
|
| 69 |
+
// Update configuration to use the selected sandbox provider
|
| 70 |
+
await updateAppConfig(projectPath, sandbox);
|
| 71 |
+
|
| 72 |
+
// Install dependencies
|
| 73 |
+
if (!skipInstall) {
|
| 74 |
+
console.log(chalk.cyan('\n📦 Installing dependencies...'));
|
| 75 |
+
execSync('npm install', {
|
| 76 |
+
cwd: projectPath,
|
| 77 |
+
stdio: 'inherit'
|
| 78 |
+
});
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
async function copyTemplate(src, dest) {
|
| 83 |
+
const files = await fs.readdir(src);
|
| 84 |
+
|
| 85 |
+
for (const file of files) {
|
| 86 |
+
const srcPath = path.join(src, file);
|
| 87 |
+
const destPath = path.join(dest, file);
|
| 88 |
+
|
| 89 |
+
const stat = await fs.stat(srcPath);
|
| 90 |
+
|
| 91 |
+
if (stat.isDirectory()) {
|
| 92 |
+
await fs.ensureDir(destPath);
|
| 93 |
+
await copyTemplate(srcPath, destPath);
|
| 94 |
+
} else {
|
| 95 |
+
await fs.copy(srcPath, destPath, { overwrite: true });
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
async function copyMainProject(mainProjectPath, projectPath, sandbox) {
|
| 101 |
+
// Copy essential directories and files from the main project
|
| 102 |
+
const itemsToCopy = [
|
| 103 |
+
'app',
|
| 104 |
+
'components',
|
| 105 |
+
'config',
|
| 106 |
+
'lib',
|
| 107 |
+
'types',
|
| 108 |
+
'public',
|
| 109 |
+
'styles',
|
| 110 |
+
'.eslintrc.json',
|
| 111 |
+
'.gitignore',
|
| 112 |
+
'next.config.js',
|
| 113 |
+
'package.json',
|
| 114 |
+
'tailwind.config.ts',
|
| 115 |
+
'tsconfig.json',
|
| 116 |
+
'postcss.config.mjs'
|
| 117 |
+
];
|
| 118 |
+
|
| 119 |
+
for (const item of itemsToCopy) {
|
| 120 |
+
const srcPath = path.join(mainProjectPath, '..', item);
|
| 121 |
+
const destPath = path.join(projectPath, item);
|
| 122 |
+
|
| 123 |
+
if (await fs.pathExists(srcPath)) {
|
| 124 |
+
await fs.copy(srcPath, destPath, {
|
| 125 |
+
overwrite: true,
|
| 126 |
+
filter: (src) => {
|
| 127 |
+
// Skip node_modules and .next
|
| 128 |
+
if (src.includes('node_modules') || src.includes('.next')) {
|
| 129 |
+
return false;
|
| 130 |
+
}
|
| 131 |
+
return true;
|
| 132 |
+
}
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
async function createEnvFile(projectPath, sandbox, answers) {
|
| 139 |
+
let envContent = '# Open Lovable Configuration\n\n';
|
| 140 |
+
|
| 141 |
+
// Sandbox provider
|
| 142 |
+
envContent += `# Sandbox Provider\n`;
|
| 143 |
+
envContent += `SANDBOX_PROVIDER=${sandbox}\n\n`;
|
| 144 |
+
|
| 145 |
+
// Required keys
|
| 146 |
+
envContent += `# REQUIRED - Web scraping for cloning websites\n`;
|
| 147 |
+
envContent += `FIRECRAWL_API_KEY=${answers.firecrawlApiKey || 'your_firecrawl_api_key_here'}\n\n`;
|
| 148 |
+
|
| 149 |
+
if (sandbox === 'e2b') {
|
| 150 |
+
envContent += `# REQUIRED - E2B Sandboxes\n`;
|
| 151 |
+
envContent += `E2B_API_KEY=${answers.e2bApiKey || 'your_e2b_api_key_here'}\n\n`;
|
| 152 |
+
} else if (sandbox === 'vercel') {
|
| 153 |
+
envContent += `# REQUIRED - Vercel Sandboxes\n`;
|
| 154 |
+
if (answers.vercelAuthMethod === 'oidc') {
|
| 155 |
+
envContent += `# Using OIDC authentication (automatic in Vercel environment)\n`;
|
| 156 |
+
} else {
|
| 157 |
+
envContent += `VERCEL_TEAM_ID=${answers.vercelTeamId || 'your_team_id'}\n`;
|
| 158 |
+
envContent += `VERCEL_PROJECT_ID=${answers.vercelProjectId || 'your_project_id'}\n`;
|
| 159 |
+
envContent += `VERCEL_TOKEN=${answers.vercelToken || 'your_access_token'}\n`;
|
| 160 |
+
}
|
| 161 |
+
envContent += '\n';
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Optional AI provider keys
|
| 165 |
+
envContent += `# OPTIONAL - AI Providers\n`;
|
| 166 |
+
|
| 167 |
+
if (answers.anthropicApiKey) {
|
| 168 |
+
envContent += `ANTHROPIC_API_KEY=${answers.anthropicApiKey}\n`;
|
| 169 |
+
} else {
|
| 170 |
+
envContent += `# ANTHROPIC_API_KEY=your_anthropic_api_key_here\n`;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
if (answers.openaiApiKey) {
|
| 174 |
+
envContent += `OPENAI_API_KEY=${answers.openaiApiKey}\n`;
|
| 175 |
+
} else {
|
| 176 |
+
envContent += `# OPENAI_API_KEY=your_openai_api_key_here\n`;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
if (answers.geminiApiKey) {
|
| 180 |
+
envContent += `GEMINI_API_KEY=${answers.geminiApiKey}\n`;
|
| 181 |
+
} else {
|
| 182 |
+
envContent += `# GEMINI_API_KEY=your_gemini_api_key_here\n`;
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
if (answers.groqApiKey) {
|
| 186 |
+
envContent += `GROQ_API_KEY=${answers.groqApiKey}\n`;
|
| 187 |
+
} else {
|
| 188 |
+
envContent += `# GROQ_API_KEY=your_groq_api_key_here\n`;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
await fs.writeFile(path.join(projectPath, '.env'), envContent);
|
| 192 |
+
await fs.writeFile(path.join(projectPath, '.env.example'), envContent.replace(/=.+/g, '=your_key_here'));
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
async function createEnvExample(projectPath, sandbox) {
|
| 196 |
+
let envContent = '# Open Lovable Configuration\n\n';
|
| 197 |
+
|
| 198 |
+
envContent += `# Sandbox Provider\n`;
|
| 199 |
+
envContent += `SANDBOX_PROVIDER=${sandbox}\n\n`;
|
| 200 |
+
|
| 201 |
+
envContent += `# REQUIRED - Web scraping for cloning websites\n`;
|
| 202 |
+
envContent += `# Get yours at https://firecrawl.dev\n`;
|
| 203 |
+
envContent += `FIRECRAWL_API_KEY=your_firecrawl_api_key_here\n\n`;
|
| 204 |
+
|
| 205 |
+
if (sandbox === 'e2b') {
|
| 206 |
+
envContent += `# REQUIRED - Sandboxes for code execution\n`;
|
| 207 |
+
envContent += `# Get yours at https://e2b.dev\n`;
|
| 208 |
+
envContent += `E2B_API_KEY=your_e2b_api_key_here\n\n`;
|
| 209 |
+
} else if (sandbox === 'vercel') {
|
| 210 |
+
envContent += `# REQUIRED - Vercel Sandboxes\n`;
|
| 211 |
+
envContent += `# Option 1: OIDC (automatic in Vercel environment)\n`;
|
| 212 |
+
envContent += `# Option 2: Personal Access Token\n`;
|
| 213 |
+
envContent += `VERCEL_TEAM_ID=your_team_id\n`;
|
| 214 |
+
envContent += `VERCEL_PROJECT_ID=your_project_id\n`;
|
| 215 |
+
envContent += `VERCEL_TOKEN=your_access_token\n\n`;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
envContent += `# OPTIONAL - AI Providers (need at least one)\n`;
|
| 219 |
+
envContent += `# Get yours at https://console.anthropic.com\n`;
|
| 220 |
+
envContent += `ANTHROPIC_API_KEY=your_anthropic_api_key_here\n\n`;
|
| 221 |
+
envContent += `# Get yours at https://platform.openai.com\n`;
|
| 222 |
+
envContent += `OPENAI_API_KEY=your_openai_api_key_here\n\n`;
|
| 223 |
+
envContent += `# Get yours at https://aistudio.google.com/app/apikey\n`;
|
| 224 |
+
envContent += `GEMINI_API_KEY=your_gemini_api_key_here\n\n`;
|
| 225 |
+
envContent += `# Get yours at https://console.groq.com\n`;
|
| 226 |
+
envContent += `GROQ_API_KEY=your_groq_api_key_here\n`;
|
| 227 |
+
|
| 228 |
+
await fs.writeFile(path.join(projectPath, '.env.example'), envContent);
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
async function updatePackageJson(projectPath, name) {
|
| 232 |
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
| 233 |
+
|
| 234 |
+
if (await fs.pathExists(packageJsonPath)) {
|
| 235 |
+
const packageJson = await fs.readJson(packageJsonPath);
|
| 236 |
+
packageJson.name = name;
|
| 237 |
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
async function updateAppConfig(projectPath, sandbox) {
|
| 242 |
+
const configPath = path.join(projectPath, 'config', 'app.config.ts');
|
| 243 |
+
|
| 244 |
+
if (await fs.pathExists(configPath)) {
|
| 245 |
+
let content = await fs.readFile(configPath, 'utf-8');
|
| 246 |
+
|
| 247 |
+
// Add sandbox provider configuration
|
| 248 |
+
const sandboxConfig = `
|
| 249 |
+
// Sandbox Provider Configuration
|
| 250 |
+
sandboxProvider: process.env.SANDBOX_PROVIDER || '${sandbox}',
|
| 251 |
+
`;
|
| 252 |
+
|
| 253 |
+
// Insert after the opening of appConfig
|
| 254 |
+
content = content.replace(
|
| 255 |
+
'export const appConfig = {',
|
| 256 |
+
`export const appConfig = {${sandboxConfig}`
|
| 257 |
+
);
|
| 258 |
+
|
| 259 |
+
await fs.writeFile(configPath, content);
|
| 260 |
+
}
|
| 261 |
+
}
|
packages/create-open-lovable/lib/prompts.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export function getPrompts(config) {
|
| 2 |
+
const prompts = [];
|
| 3 |
+
|
| 4 |
+
if (!config.name) {
|
| 5 |
+
prompts.push({
|
| 6 |
+
type: 'input',
|
| 7 |
+
name: 'name',
|
| 8 |
+
message: 'Project name:',
|
| 9 |
+
default: 'my-open-lovable',
|
| 10 |
+
validate: (input) => {
|
| 11 |
+
if (!input || input.trim() === '') {
|
| 12 |
+
return 'Project name is required';
|
| 13 |
+
}
|
| 14 |
+
if (!/^[a-z0-9-_]+$/i.test(input)) {
|
| 15 |
+
return 'Project name can only contain letters, numbers, hyphens, and underscores';
|
| 16 |
+
}
|
| 17 |
+
return true;
|
| 18 |
+
}
|
| 19 |
+
});
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
if (!config.sandbox) {
|
| 23 |
+
prompts.push({
|
| 24 |
+
type: 'list',
|
| 25 |
+
name: 'sandbox',
|
| 26 |
+
message: 'Choose your sandbox provider:',
|
| 27 |
+
choices: [
|
| 28 |
+
{
|
| 29 |
+
name: 'E2B - Full-featured development sandboxes',
|
| 30 |
+
value: 'e2b',
|
| 31 |
+
short: 'E2B'
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
name: 'Vercel - Lightweight ephemeral VMs',
|
| 35 |
+
value: 'vercel',
|
| 36 |
+
short: 'Vercel'
|
| 37 |
+
}
|
| 38 |
+
],
|
| 39 |
+
default: 'e2b'
|
| 40 |
+
});
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
prompts.push({
|
| 44 |
+
type: 'confirm',
|
| 45 |
+
name: 'configureEnv',
|
| 46 |
+
message: 'Would you like to configure API keys now?',
|
| 47 |
+
default: true
|
| 48 |
+
});
|
| 49 |
+
|
| 50 |
+
return prompts;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
export function getEnvPrompts(provider) {
|
| 54 |
+
const prompts = [];
|
| 55 |
+
|
| 56 |
+
// Always include Firecrawl API key
|
| 57 |
+
prompts.push({
|
| 58 |
+
type: 'input',
|
| 59 |
+
name: 'firecrawlApiKey',
|
| 60 |
+
message: 'Firecrawl API key (for web scraping):',
|
| 61 |
+
validate: (input) => {
|
| 62 |
+
if (!input || input.trim() === '') {
|
| 63 |
+
return 'Firecrawl API key is required for web scraping functionality';
|
| 64 |
+
}
|
| 65 |
+
return true;
|
| 66 |
+
}
|
| 67 |
+
});
|
| 68 |
+
|
| 69 |
+
if (provider === 'e2b') {
|
| 70 |
+
prompts.push({
|
| 71 |
+
type: 'input',
|
| 72 |
+
name: 'e2bApiKey',
|
| 73 |
+
message: 'E2B API key:',
|
| 74 |
+
validate: (input) => {
|
| 75 |
+
if (!input || input.trim() === '') {
|
| 76 |
+
return 'E2B API key is required';
|
| 77 |
+
}
|
| 78 |
+
return true;
|
| 79 |
+
}
|
| 80 |
+
});
|
| 81 |
+
} else if (provider === 'vercel') {
|
| 82 |
+
prompts.push({
|
| 83 |
+
type: 'list',
|
| 84 |
+
name: 'vercelAuthMethod',
|
| 85 |
+
message: 'Vercel authentication method:',
|
| 86 |
+
choices: [
|
| 87 |
+
{
|
| 88 |
+
name: 'OIDC Token (automatic in Vercel environment)',
|
| 89 |
+
value: 'oidc',
|
| 90 |
+
short: 'OIDC'
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
name: 'Personal Access Token',
|
| 94 |
+
value: 'pat',
|
| 95 |
+
short: 'PAT'
|
| 96 |
+
}
|
| 97 |
+
]
|
| 98 |
+
});
|
| 99 |
+
|
| 100 |
+
prompts.push({
|
| 101 |
+
type: 'input',
|
| 102 |
+
name: 'vercelTeamId',
|
| 103 |
+
message: 'Vercel Team ID:',
|
| 104 |
+
when: (answers) => answers.vercelAuthMethod === 'pat',
|
| 105 |
+
validate: (input) => {
|
| 106 |
+
if (!input || input.trim() === '') {
|
| 107 |
+
return 'Team ID is required for PAT authentication';
|
| 108 |
+
}
|
| 109 |
+
return true;
|
| 110 |
+
}
|
| 111 |
+
});
|
| 112 |
+
|
| 113 |
+
prompts.push({
|
| 114 |
+
type: 'input',
|
| 115 |
+
name: 'vercelProjectId',
|
| 116 |
+
message: 'Vercel Project ID:',
|
| 117 |
+
when: (answers) => answers.vercelAuthMethod === 'pat',
|
| 118 |
+
validate: (input) => {
|
| 119 |
+
if (!input || input.trim() === '') {
|
| 120 |
+
return 'Project ID is required for PAT authentication';
|
| 121 |
+
}
|
| 122 |
+
return true;
|
| 123 |
+
}
|
| 124 |
+
});
|
| 125 |
+
|
| 126 |
+
prompts.push({
|
| 127 |
+
type: 'input',
|
| 128 |
+
name: 'vercelToken',
|
| 129 |
+
message: 'Vercel Access Token:',
|
| 130 |
+
when: (answers) => answers.vercelAuthMethod === 'pat',
|
| 131 |
+
validate: (input) => {
|
| 132 |
+
if (!input || input.trim() === '') {
|
| 133 |
+
return 'Access token is required for PAT authentication';
|
| 134 |
+
}
|
| 135 |
+
return true;
|
| 136 |
+
}
|
| 137 |
+
});
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// Optional AI provider keys
|
| 141 |
+
prompts.push({
|
| 142 |
+
type: 'confirm',
|
| 143 |
+
name: 'addAiKeys',
|
| 144 |
+
message: 'Would you like to add AI provider API keys?',
|
| 145 |
+
default: true
|
| 146 |
+
});
|
| 147 |
+
|
| 148 |
+
prompts.push({
|
| 149 |
+
type: 'checkbox',
|
| 150 |
+
name: 'aiProviders',
|
| 151 |
+
message: 'Select AI providers to configure:',
|
| 152 |
+
when: (answers) => answers.addAiKeys,
|
| 153 |
+
choices: [
|
| 154 |
+
{ name: 'Anthropic (Claude)', value: 'anthropic' },
|
| 155 |
+
{ name: 'OpenAI (GPT)', value: 'openai' },
|
| 156 |
+
{ name: 'Google (Gemini)', value: 'gemini' },
|
| 157 |
+
{ name: 'Groq', value: 'groq' }
|
| 158 |
+
]
|
| 159 |
+
});
|
| 160 |
+
|
| 161 |
+
prompts.push({
|
| 162 |
+
type: 'input',
|
| 163 |
+
name: 'anthropicApiKey',
|
| 164 |
+
message: 'Anthropic API key:',
|
| 165 |
+
when: (answers) => answers.aiProviders && answers.aiProviders.includes('anthropic')
|
| 166 |
+
});
|
| 167 |
+
|
| 168 |
+
prompts.push({
|
| 169 |
+
type: 'input',
|
| 170 |
+
name: 'openaiApiKey',
|
| 171 |
+
message: 'OpenAI API key:',
|
| 172 |
+
when: (answers) => answers.aiProviders && answers.aiProviders.includes('openai')
|
| 173 |
+
});
|
| 174 |
+
|
| 175 |
+
prompts.push({
|
| 176 |
+
type: 'input',
|
| 177 |
+
name: 'geminiApiKey',
|
| 178 |
+
message: 'Gemini API key:',
|
| 179 |
+
when: (answers) => answers.aiProviders && answers.aiProviders.includes('gemini')
|
| 180 |
+
});
|
| 181 |
+
|
| 182 |
+
prompts.push({
|
| 183 |
+
type: 'input',
|
| 184 |
+
name: 'groqApiKey',
|
| 185 |
+
message: 'Groq API key:',
|
| 186 |
+
when: (answers) => answers.aiProviders && answers.aiProviders.includes('groq')
|
| 187 |
+
});
|
| 188 |
+
|
| 189 |
+
return prompts;
|
| 190 |
+
}
|
packages/create-open-lovable/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "create-open-lovable",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"description": "CLI to bootstrap Open Lovable with your choice of sandbox provider",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"main": "index.js",
|
| 7 |
+
"bin": {
|
| 8 |
+
"create-open-lovable": "./index.js"
|
| 9 |
+
},
|
| 10 |
+
"scripts": {
|
| 11 |
+
"test": "node index.js --dry-run"
|
| 12 |
+
},
|
| 13 |
+
"keywords": [
|
| 14 |
+
"lovable",
|
| 15 |
+
"sandbox",
|
| 16 |
+
"e2b",
|
| 17 |
+
"vercel",
|
| 18 |
+
"ai",
|
| 19 |
+
"code-generation"
|
| 20 |
+
],
|
| 21 |
+
"author": "",
|
| 22 |
+
"license": "MIT",
|
| 23 |
+
"dependencies": {
|
| 24 |
+
"chalk": "^5.3.0",
|
| 25 |
+
"commander": "^11.1.0",
|
| 26 |
+
"fs-extra": "^11.2.0",
|
| 27 |
+
"inquirer": "^9.2.12",
|
| 28 |
+
"ora": "^7.0.1"
|
| 29 |
+
},
|
| 30 |
+
"engines": {
|
| 31 |
+
"node": ">=16.0.0"
|
| 32 |
+
},
|
| 33 |
+
"publishConfig": {
|
| 34 |
+
"access": "public"
|
| 35 |
+
}
|
| 36 |
+
}
|
packages/create-open-lovable/templates/e2b/.env.example
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Lovable Configuration - E2B Provider
|
| 2 |
+
|
| 3 |
+
# Sandbox Provider
|
| 4 |
+
SANDBOX_PROVIDER=e2b
|
| 5 |
+
|
| 6 |
+
# REQUIRED - Sandboxes for code execution
|
| 7 |
+
# Get yours at https://e2b.dev
|
| 8 |
+
E2B_API_KEY=your_e2b_api_key_here
|
| 9 |
+
|
| 10 |
+
# REQUIRED - Web scraping for cloning websites
|
| 11 |
+
# Get yours at https://firecrawl.dev
|
| 12 |
+
FIRECRAWL_API_KEY=your_firecrawl_api_key_here
|
| 13 |
+
|
| 14 |
+
# OPTIONAL - AI Providers (need at least one)
|
| 15 |
+
# Get yours at https://console.anthropic.com
|
| 16 |
+
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
| 17 |
+
|
| 18 |
+
# Get yours at https://platform.openai.com
|
| 19 |
+
OPENAI_API_KEY=your_openai_api_key_here
|
| 20 |
+
|
| 21 |
+
# Get yours at https://aistudio.google.com/app/apikey
|
| 22 |
+
GEMINI_API_KEY=your_gemini_api_key_here
|
| 23 |
+
|
| 24 |
+
# Get yours at https://console.groq.com
|
| 25 |
+
GROQ_API_KEY=your_groq_api_key_here
|
packages/create-open-lovable/templates/e2b/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Lovable - E2B Sandbox
|
| 2 |
+
|
| 3 |
+
This project is configured to use E2B sandboxes for code execution.
|
| 4 |
+
|
| 5 |
+
## Setup
|
| 6 |
+
|
| 7 |
+
1. Get your E2B API key from [https://e2b.dev](https://e2b.dev)
|
| 8 |
+
2. Get your Firecrawl API key from [https://firecrawl.dev](https://firecrawl.dev)
|
| 9 |
+
3. Copy `.env.example` to `.env` and add your API keys
|
| 10 |
+
4. Run `npm install` to install dependencies
|
| 11 |
+
5. Run `npm run dev` to start the development server
|
| 12 |
+
|
| 13 |
+
## E2B Features
|
| 14 |
+
|
| 15 |
+
- Full-featured development sandboxes
|
| 16 |
+
- 15-minute default timeout (configurable)
|
| 17 |
+
- Persistent file system during session
|
| 18 |
+
- Support for complex package installations
|
| 19 |
+
- Built-in Python runtime for code execution
|
| 20 |
+
|
| 21 |
+
## Configuration
|
| 22 |
+
|
| 23 |
+
You can adjust E2B settings in `config/app.config.ts`:
|
| 24 |
+
|
| 25 |
+
- `timeoutMinutes`: Sandbox session timeout (default: 15)
|
| 26 |
+
- `vitePort`: Development server port (default: 5173)
|
| 27 |
+
- `viteStartupDelay`: Time to wait for Vite to start (default: 7000ms)
|
| 28 |
+
|
| 29 |
+
## Troubleshooting
|
| 30 |
+
|
| 31 |
+
If you encounter issues:
|
| 32 |
+
|
| 33 |
+
1. Verify your E2B API key is valid
|
| 34 |
+
2. Check the console for detailed error messages
|
| 35 |
+
3. Ensure you have a stable internet connection
|
| 36 |
+
4. Try refreshing the page and creating a new sandbox
|
| 37 |
+
|
| 38 |
+
For more help, visit the [E2B documentation](https://docs.e2b.dev).
|
packages/create-open-lovable/templates/vercel/.env.example
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Lovable Configuration - Vercel Provider
|
| 2 |
+
|
| 3 |
+
# Sandbox Provider
|
| 4 |
+
SANDBOX_PROVIDER=vercel
|
| 5 |
+
|
| 6 |
+
# REQUIRED - Vercel Sandboxes
|
| 7 |
+
# Option 1: OIDC Token (automatic in Vercel environment)
|
| 8 |
+
# Option 2: Personal Access Token (configure below)
|
| 9 |
+
VERCEL_TEAM_ID=your_team_id
|
| 10 |
+
VERCEL_PROJECT_ID=your_project_id
|
| 11 |
+
VERCEL_TOKEN=your_access_token
|
| 12 |
+
|
| 13 |
+
# REQUIRED - Web scraping for cloning websites
|
| 14 |
+
# Get yours at https://firecrawl.dev
|
| 15 |
+
FIRECRAWL_API_KEY=your_firecrawl_api_key_here
|
| 16 |
+
|
| 17 |
+
# OPTIONAL - AI Providers (need at least one)
|
| 18 |
+
# Get yours at https://console.anthropic.com
|
| 19 |
+
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
| 20 |
+
|
| 21 |
+
# Get yours at https://platform.openai.com
|
| 22 |
+
OPENAI_API_KEY=your_openai_api_key_here
|
| 23 |
+
|
| 24 |
+
# Get yours at https://aistudio.google.com/app/apikey
|
| 25 |
+
GEMINI_API_KEY=your_gemini_api_key_here
|
| 26 |
+
|
| 27 |
+
# Get yours at https://console.groq.com
|
| 28 |
+
GROQ_API_KEY=your_groq_api_key_here
|
packages/create-open-lovable/templates/vercel/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Lovable - Vercel Sandbox
|
| 2 |
+
|
| 3 |
+
This project is configured to use Vercel Sandboxes for code execution.
|
| 4 |
+
|
| 5 |
+
## Setup
|
| 6 |
+
|
| 7 |
+
1. Configure Vercel authentication (see below)
|
| 8 |
+
2. Get your Firecrawl API key from [https://firecrawl.dev](https://firecrawl.dev)
|
| 9 |
+
3. Copy `.env.example` to `.env` and add your credentials
|
| 10 |
+
4. Run `npm install` to install dependencies
|
| 11 |
+
5. Run `npm run dev` to start the development server
|
| 12 |
+
|
| 13 |
+
## Vercel Authentication
|
| 14 |
+
|
| 15 |
+
### Option 1: OIDC Token (Automatic for Vercel deployments)
|
| 16 |
+
When running in a Vercel environment, authentication happens automatically via OIDC tokens. No configuration needed!
|
| 17 |
+
|
| 18 |
+
### Option 2: Personal Access Token (For local development)
|
| 19 |
+
1. Create a Personal Access Token in your [Vercel account settings](https://vercel.com/account/tokens)
|
| 20 |
+
2. Get your Team ID from your [team settings](https://vercel.com/teams)
|
| 21 |
+
3. Create a project and get the Project ID
|
| 22 |
+
4. Add these to your `.env` file:
|
| 23 |
+
- `VERCEL_TOKEN`
|
| 24 |
+
- `VERCEL_TEAM_ID`
|
| 25 |
+
- `VERCEL_PROJECT_ID`
|
| 26 |
+
|
| 27 |
+
## Vercel Sandbox Features
|
| 28 |
+
|
| 29 |
+
- Lightweight ephemeral Linux VMs
|
| 30 |
+
- Powered by Firecracker MicroVMs
|
| 31 |
+
- 5-minute default timeout (max 45 minutes)
|
| 32 |
+
- 8 vCPUs maximum
|
| 33 |
+
- Root access for package installation
|
| 34 |
+
- Node 22 runtime included
|
| 35 |
+
|
| 36 |
+
## Configuration
|
| 37 |
+
|
| 38 |
+
You can adjust Vercel settings in `config/app.config.ts`:
|
| 39 |
+
|
| 40 |
+
- `maxDuration`: Sandbox session timeout (default: 5 minutes)
|
| 41 |
+
- Authentication method (OIDC or PAT)
|
| 42 |
+
|
| 43 |
+
## Troubleshooting
|
| 44 |
+
|
| 45 |
+
If you encounter issues:
|
| 46 |
+
|
| 47 |
+
1. Verify your authentication credentials
|
| 48 |
+
2. Check if you're using the correct authentication method
|
| 49 |
+
3. Ensure your Vercel account has sandbox access
|
| 50 |
+
4. Check the console for detailed error messages
|
| 51 |
+
|
| 52 |
+
For more help, visit the [Vercel Sandbox documentation](https://vercel.com/docs/vercel-sandbox).
|
pnpm-lock.yaml
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
postcss.config.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export default {
|
| 2 |
+
plugins: {
|
| 3 |
+
"postcss-import": {},
|
| 4 |
+
"postcss-nesting": {},
|
| 5 |
+
"tailwindcss": {},
|
| 6 |
+
"autoprefixer": {},
|
| 7 |
+
},
|
| 8 |
+
};
|
public/compressor.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"configs": [
|
| 3 |
+
{
|
| 4 |
+
"extension": "avif",
|
| 5 |
+
"quality": 80,
|
| 6 |
+
"effort": 4,
|
| 7 |
+
"scale": 2
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"extension": "webp",
|
| 11 |
+
"quality": 85,
|
| 12 |
+
"effort": 4,
|
| 13 |
+
"scale": 2
|
| 14 |
+
}
|
| 15 |
+
]
|
| 16 |
+
}
|
public/file.svg
ADDED
|
|
public/firecrawl-logo
ADDED
|
Binary file (2.02 kB). View file
|
|
|
public/firecrawl.svg
ADDED
|
|
public/globe.svg
ADDED
|
|
public/window.svg
ADDED
|
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
openai>=1.65.4
|
| 2 |
+
vllm>=0.6.4.post1
|
| 3 |
+
transformers>=4.46.3
|
| 4 |
+
tiktoken>=0.9.0
|
scripts/run.sh
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# export OPENAI_API_KEY=""
|
| 2 |
+
|
| 3 |
+
GPT_VERSION="o3-mini"
|
| 4 |
+
|
| 5 |
+
PAPER_NAME="Transformer"
|
| 6 |
+
PDF_PATH="../examples/Transformer.pdf" # .pdf
|
| 7 |
+
PDF_JSON_PATH="../examples/Transformer.json" # .json
|
| 8 |
+
PDF_JSON_CLEANED_PATH="../examples/Transformer_cleaned.json" # _cleaned.json
|
| 9 |
+
OUTPUT_DIR="../outputs/Transformer"
|
| 10 |
+
OUTPUT_REPO_DIR="../outputs/Transformer_repo"
|
| 11 |
+
|
| 12 |
+
mkdir -p $OUTPUT_DIR
|
| 13 |
+
mkdir -p $OUTPUT_REPO_DIR
|
| 14 |
+
|
| 15 |
+
echo $PAPER_NAME
|
| 16 |
+
|
| 17 |
+
echo "------- Preprocess -------"
|
| 18 |
+
|
| 19 |
+
python ../codes/0_pdf_process.py \
|
| 20 |
+
--input_json_path ${PDF_JSON_PATH} \
|
| 21 |
+
--output_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
echo "------- PaperCoder -------"
|
| 25 |
+
|
| 26 |
+
python ../codes/1_planning.py \
|
| 27 |
+
--paper_name $PAPER_NAME \
|
| 28 |
+
--gpt_version ${GPT_VERSION} \
|
| 29 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 30 |
+
--output_dir ${OUTPUT_DIR}
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
python ../codes/1.1_extract_config.py \
|
| 34 |
+
--paper_name $PAPER_NAME \
|
| 35 |
+
--output_dir ${OUTPUT_DIR}
|
| 36 |
+
|
| 37 |
+
cp -rp ${OUTPUT_DIR}/planning_config.yaml ${OUTPUT_REPO_DIR}/config.yaml
|
| 38 |
+
|
| 39 |
+
python ../codes/2_analyzing.py \
|
| 40 |
+
--paper_name $PAPER_NAME \
|
| 41 |
+
--gpt_version ${GPT_VERSION} \
|
| 42 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 43 |
+
--output_dir ${OUTPUT_DIR}
|
| 44 |
+
|
| 45 |
+
python ../codes/3_coding.py \
|
| 46 |
+
--paper_name $PAPER_NAME \
|
| 47 |
+
--gpt_version ${GPT_VERSION} \
|
| 48 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 49 |
+
--output_dir ${OUTPUT_DIR} \
|
| 50 |
+
--output_repo_dir ${OUTPUT_REPO_DIR} \
|
scripts/run_latex.sh
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# export OPENAI_API_KEY=""
|
| 2 |
+
|
| 3 |
+
GPT_VERSION="o3-mini"
|
| 4 |
+
|
| 5 |
+
PAPER_NAME="Transformer"
|
| 6 |
+
PDF_LATEX_CLEANED_PATH="../examples/Transformer_cleaned.tex" # _cleaned.tex
|
| 7 |
+
OUTPUT_DIR="../outputs/Transformer"
|
| 8 |
+
OUTPUT_REPO_DIR="../outputs/Transformer_repo"
|
| 9 |
+
|
| 10 |
+
mkdir -p $OUTPUT_DIR
|
| 11 |
+
mkdir -p $OUTPUT_REPO_DIR
|
| 12 |
+
|
| 13 |
+
echo $PAPER_NAME
|
| 14 |
+
|
| 15 |
+
echo "------- PaperCoder -------"
|
| 16 |
+
|
| 17 |
+
python ../codes/1_planning.py \
|
| 18 |
+
--paper_name $PAPER_NAME \
|
| 19 |
+
--gpt_version ${GPT_VERSION} \
|
| 20 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 21 |
+
--paper_format LaTeX \
|
| 22 |
+
--output_dir ${OUTPUT_DIR}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
python ../codes/1.1_extract_config.py \
|
| 26 |
+
--paper_name $PAPER_NAME \
|
| 27 |
+
--output_dir ${OUTPUT_DIR}
|
| 28 |
+
|
| 29 |
+
cp -rp ${OUTPUT_DIR}/planning_config.yaml ${OUTPUT_REPO_DIR}/config.yaml
|
| 30 |
+
|
| 31 |
+
python ../codes/2_analyzing.py \
|
| 32 |
+
--paper_name $PAPER_NAME \
|
| 33 |
+
--gpt_version ${GPT_VERSION} \
|
| 34 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 35 |
+
--paper_format LaTeX \
|
| 36 |
+
--output_dir ${OUTPUT_DIR}
|
| 37 |
+
|
| 38 |
+
python ../codes/3_coding.py \
|
| 39 |
+
--paper_name $PAPER_NAME \
|
| 40 |
+
--gpt_version ${GPT_VERSION} \
|
| 41 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 42 |
+
--paper_format LaTeX \
|
| 43 |
+
--output_dir ${OUTPUT_DIR} \
|
| 44 |
+
--output_repo_dir ${OUTPUT_REPO_DIR} \
|
scripts/run_latex_llm.sh
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL_NAME="deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct"
|
| 2 |
+
TP_SIZE=2
|
| 3 |
+
|
| 4 |
+
PAPER_NAME="Transformer"
|
| 5 |
+
PDF_LATEX_CLEANED_PATH="../examples/Transformer_cleaned.tex" # _cleaned.tex
|
| 6 |
+
OUTPUT_DIR="../outputs/Transformer_dscoder"
|
| 7 |
+
OUTPUT_REPO_DIR="../outputs/Transformer_dscoder_repo"
|
| 8 |
+
|
| 9 |
+
mkdir -p $OUTPUT_DIR
|
| 10 |
+
mkdir -p $OUTPUT_REPO_DIR
|
| 11 |
+
|
| 12 |
+
echo $PAPER_NAME
|
| 13 |
+
|
| 14 |
+
echo "------- PaperCoder -------"
|
| 15 |
+
|
| 16 |
+
python ../codes/1_planning_llm.py \
|
| 17 |
+
--paper_name $PAPER_NAME \
|
| 18 |
+
--model_name ${MODEL_NAME} \
|
| 19 |
+
--tp_size ${TP_SIZE} \
|
| 20 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 21 |
+
--paper_format LaTeX \
|
| 22 |
+
--output_dir ${OUTPUT_DIR}
|
| 23 |
+
|
| 24 |
+
python ../codes/1.1_extract_config.py \
|
| 25 |
+
--paper_name $PAPER_NAME \
|
| 26 |
+
--output_dir ${OUTPUT_DIR}
|
| 27 |
+
|
| 28 |
+
cp -rp ${OUTPUT_DIR}/planning_config.yaml ${OUTPUT_REPO_DIR}/config.yaml
|
| 29 |
+
|
| 30 |
+
python ../codes/2_analyzing_llm.py \
|
| 31 |
+
--paper_name $PAPER_NAME \
|
| 32 |
+
--model_name ${MODEL_NAME} \
|
| 33 |
+
--tp_size ${TP_SIZE} \
|
| 34 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 35 |
+
--paper_format LaTeX \
|
| 36 |
+
--output_dir ${OUTPUT_DIR}
|
| 37 |
+
|
| 38 |
+
python ../codes/3_coding_llm.py \
|
| 39 |
+
--paper_name $PAPER_NAME \
|
| 40 |
+
--model_name ${MODEL_NAME} \
|
| 41 |
+
--tp_size ${TP_SIZE} \
|
| 42 |
+
--pdf_latex_path ${PDF_LATEX_CLEANED_PATH} \
|
| 43 |
+
--paper_format LaTeX \
|
| 44 |
+
--output_dir ${OUTPUT_DIR} \
|
| 45 |
+
--output_repo_dir ${OUTPUT_REPO_DIR} \
|
scripts/run_llm.sh
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL_NAME="deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct"
|
| 2 |
+
TP_SIZE=2
|
| 3 |
+
|
| 4 |
+
PAPER_NAME="Transformer"
|
| 5 |
+
PDF_PATH="../examples/Transformer.pdf" # .pdf
|
| 6 |
+
PDF_JSON_PATH="../examples/Transformer.json" # .json
|
| 7 |
+
PDF_JSON_CLEANED_PATH="../examples/Transformer_cleaned.json" # _cleaned.json
|
| 8 |
+
OUTPUT_DIR="../outputs/Transformer_dscoder"
|
| 9 |
+
OUTPUT_REPO_DIR="../outputs/Transformer_dscoder_repo"
|
| 10 |
+
|
| 11 |
+
mkdir -p $OUTPUT_DIR
|
| 12 |
+
mkdir -p $OUTPUT_REPO_DIR
|
| 13 |
+
|
| 14 |
+
echo $PAPER_NAME
|
| 15 |
+
|
| 16 |
+
echo "------- Preprocess -------"
|
| 17 |
+
|
| 18 |
+
python ../codes/0_pdf_process.py \
|
| 19 |
+
--input_json_path ${PDF_JSON_PATH} \
|
| 20 |
+
--output_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
echo "------- PaperCoder -------"
|
| 24 |
+
|
| 25 |
+
python ../codes/1_planning_llm.py \
|
| 26 |
+
--paper_name $PAPER_NAME \
|
| 27 |
+
--model_name ${MODEL_NAME} \
|
| 28 |
+
--tp_size ${TP_SIZE} \
|
| 29 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 30 |
+
--output_dir ${OUTPUT_DIR}
|
| 31 |
+
|
| 32 |
+
python ../codes/1.1_extract_config.py \
|
| 33 |
+
--paper_name $PAPER_NAME \
|
| 34 |
+
--output_dir ${OUTPUT_DIR}
|
| 35 |
+
|
| 36 |
+
cp -rp ${OUTPUT_DIR}/planning_config.yaml ${OUTPUT_REPO_DIR}/config.yaml
|
| 37 |
+
|
| 38 |
+
python ../codes/2_analyzing_llm.py \
|
| 39 |
+
--paper_name $PAPER_NAME \
|
| 40 |
+
--model_name ${MODEL_NAME} \
|
| 41 |
+
--tp_size ${TP_SIZE} \
|
| 42 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 43 |
+
--output_dir ${OUTPUT_DIR}
|
| 44 |
+
|
| 45 |
+
python ../codes/3_coding_llm.py \
|
| 46 |
+
--paper_name $PAPER_NAME \
|
| 47 |
+
--model_name ${MODEL_NAME} \
|
| 48 |
+
--tp_size ${TP_SIZE} \
|
| 49 |
+
--pdf_json_path ${PDF_JSON_CLEANED_PATH} \
|
| 50 |
+
--output_dir ${OUTPUT_DIR} \
|
| 51 |
+
--output_repo_dir ${OUTPUT_REPO_DIR} \
|
styles/additional-styles/custom-fonts.css
ADDED
|
File without changes
|
styles/additional-styles/theme.css
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.form-input:focus,
|
| 2 |
+
.form-textarea:focus,
|
| 3 |
+
.form-multiselect:focus,
|
| 4 |
+
.form-select:focus,
|
| 5 |
+
.form-checkbox:focus,
|
| 6 |
+
.form-radio:focus {
|
| 7 |
+
@apply ring-0;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
/* Hamburger button */
|
| 11 |
+
.hamburger svg > *:nth-child(1),
|
| 12 |
+
.hamburger svg > *:nth-child(2),
|
| 13 |
+
.hamburger svg > *:nth-child(3) {
|
| 14 |
+
transform-origin: center;
|
| 15 |
+
transform: rotate(0deg);
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.hamburger svg > *:nth-child(1) {
|
| 19 |
+
transition:
|
| 20 |
+
y 0.1s 0.25s ease-in,
|
| 21 |
+
transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19),
|
| 22 |
+
opacity 0.1s ease-in;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
.hamburger svg > *:nth-child(2) {
|
| 26 |
+
transition: transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
.hamburger svg > *:nth-child(3) {
|
| 30 |
+
transition:
|
| 31 |
+
y 0.1s 0.25s ease-in,
|
| 32 |
+
transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19),
|
| 33 |
+
width 0.1s 0.25s ease-in;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.hamburger.active svg > *:nth-child(1) {
|
| 37 |
+
opacity: 0;
|
| 38 |
+
y: 11;
|
| 39 |
+
transform: rotate(225deg);
|
| 40 |
+
transition:
|
| 41 |
+
y 0.1s ease-out,
|
| 42 |
+
transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1),
|
| 43 |
+
opacity 0.1s 0.12s ease-out;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.hamburger.active svg > *:nth-child(2) {
|
| 47 |
+
transform: rotate(225deg);
|
| 48 |
+
transition: transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.hamburger.active svg > *:nth-child(3) {
|
| 52 |
+
y: 11;
|
| 53 |
+
transform: rotate(135deg);
|
| 54 |
+
transition:
|
| 55 |
+
y 0.1s ease-out,
|
| 56 |
+
transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1),
|
| 57 |
+
width 0.1s ease-out;
|
| 58 |
+
}
|
styles/additional-styles/utility-patterns.css
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Typography */
|
| 2 |
+
.h1 {
|
| 3 |
+
@apply text-5xl font-bold;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
.h2 {
|
| 7 |
+
@apply text-4xl font-bold;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
.h3 {
|
| 11 |
+
@apply text-3xl font-bold;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.h4 {
|
| 15 |
+
@apply text-2xl font-bold;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
@screen md {
|
| 19 |
+
.h1 {
|
| 20 |
+
@apply text-6xl;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.h2 {
|
| 24 |
+
@apply text-5xl;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.h3 {
|
| 28 |
+
@apply text-4xl;
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
/* Buttons */
|
| 33 |
+
.btn,
|
| 34 |
+
.btn-sm {
|
| 35 |
+
@apply text-sm font-medium inline-flex items-center justify-center border border-transparent rounded-md tracking-normal transition;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.btn {
|
| 39 |
+
@apply px-4 py-2;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
.btn-sm {
|
| 43 |
+
@apply px-2 py-1;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
/* Forms */
|
| 47 |
+
input[type="search"]::-webkit-search-decoration,
|
| 48 |
+
input[type="search"]::-webkit-search-cancel-button,
|
| 49 |
+
input[type="search"]::-webkit-search-results-button,
|
| 50 |
+
input[type="search"]::-webkit-search-results-decoration {
|
| 51 |
+
-webkit-appearance: none;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.form-input,
|
| 55 |
+
.form-textarea,
|
| 56 |
+
.form-multiselect,
|
| 57 |
+
.form-select,
|
| 58 |
+
.form-checkbox,
|
| 59 |
+
.form-radio {
|
| 60 |
+
@apply bg-white border border-zinc-200 focus:border-zinc-400 shadow shadow-black/5;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
.form-input,
|
| 64 |
+
.form-textarea,
|
| 65 |
+
.form-multiselect,
|
| 66 |
+
.form-select,
|
| 67 |
+
.form-checkbox {
|
| 68 |
+
@apply rounded;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.form-input,
|
| 72 |
+
.form-textarea,
|
| 73 |
+
.form-multiselect,
|
| 74 |
+
.form-select {
|
| 75 |
+
@apply text-zinc-600 text-sm px-4 py-2;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.form-input,
|
| 79 |
+
.form-textarea {
|
| 80 |
+
@apply placeholder-zinc-400;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.form-select {
|
| 84 |
+
@apply pr-10;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
.form-checkbox,
|
| 88 |
+
.form-radio {
|
| 89 |
+
@apply text-zinc-800;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
.form-checkbox {
|
| 93 |
+
@apply rounded-sm;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
/* Fix input cursor visibility on Windows Chrome */
|
| 97 |
+
input,
|
| 98 |
+
textarea {
|
| 99 |
+
caret-color: hsl(var(--foreground));
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* Chrome, Safari and Opera */
|
| 103 |
+
.no-scrollbar::-webkit-scrollbar {
|
| 104 |
+
display: none;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.no-scrollbar {
|
| 108 |
+
-ms-overflow-style: none;
|
| 109 |
+
/* IE and Edge */
|
| 110 |
+
scrollbar-width: none;
|
| 111 |
+
/* Firefox */
|
| 112 |
+
}
|
styles/chrome-bug.css
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Chrome has a bug with transitions on load since 2012!
|
| 3 |
+
*
|
| 4 |
+
* To prevent a "pop" of content, you have to disable all transitions until
|
| 5 |
+
* the page is done loading.
|
| 6 |
+
*
|
| 7 |
+
* https://lab.laukstein.com/bug/input
|
| 8 |
+
* https://twitter.com/timer150/status/1345217126680899584
|
| 9 |
+
*/
|
| 10 |
+
body.loading * {
|
| 11 |
+
transition: none !important;
|
| 12 |
+
}
|
styles/colors.json
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"heat-4": {
|
| 3 |
+
"hex": "fa5d190a",
|
| 4 |
+
"p3": "0.980392 0.364706 0.098039 / 0.039216"
|
| 5 |
+
},
|
| 6 |
+
"heat-8": {
|
| 7 |
+
"hex": "fa5d1914",
|
| 8 |
+
"p3": "0.980392 0.364706 0.098039 / 0.078431"
|
| 9 |
+
},
|
| 10 |
+
"heat-12": {
|
| 11 |
+
"hex": "fa5d191f",
|
| 12 |
+
"p3": "0.980392 0.364706 0.098039 / 0.121569"
|
| 13 |
+
},
|
| 14 |
+
"heat-16": {
|
| 15 |
+
"hex": "fa5d1929",
|
| 16 |
+
"p3": "0.980392 0.364706 0.098039 / 0.160784"
|
| 17 |
+
},
|
| 18 |
+
"heat-20": {
|
| 19 |
+
"hex": "fa5d1933",
|
| 20 |
+
"p3": "0.980392 0.364706 0.098039 / 0.200000"
|
| 21 |
+
},
|
| 22 |
+
"heat-40": {
|
| 23 |
+
"hex": "fa5d1966",
|
| 24 |
+
"p3": "0.980392 0.364706 0.098039 / 0.400000"
|
| 25 |
+
},
|
| 26 |
+
"heat-90": {
|
| 27 |
+
"hex": "fa5d19e6",
|
| 28 |
+
"p3": "0.980392 0.364706 0.098039 / 0.900000"
|
| 29 |
+
},
|
| 30 |
+
"heat-100": {
|
| 31 |
+
"hex": "fa5d19ff",
|
| 32 |
+
"p3": "0.980392 0.364706 0.098039 / 1.000000"
|
| 33 |
+
},
|
| 34 |
+
"accent-black": {
|
| 35 |
+
"hex": "262626ff",
|
| 36 |
+
"p3": "0.149020 0.149020 0.149020 / 1.000000"
|
| 37 |
+
},
|
| 38 |
+
"accent-white": {
|
| 39 |
+
"hex": "ffffffff",
|
| 40 |
+
"p3": "1.000000 1.000000 1.000000 / 1.000000"
|
| 41 |
+
},
|
| 42 |
+
"accent-amethyst": {
|
| 43 |
+
"hex": "9061ffff",
|
| 44 |
+
"p3": "0.564706 0.380392 1.000000 / 1.000000"
|
| 45 |
+
},
|
| 46 |
+
"accent-bluetron": {
|
| 47 |
+
"hex": "2a6dfbff",
|
| 48 |
+
"p3": "0.164706 0.427451 0.984314 / 1.000000"
|
| 49 |
+
},
|
| 50 |
+
"accent-crimson": {
|
| 51 |
+
"hex": "eb3424ff",
|
| 52 |
+
"p3": "0.921569 0.203922 0.141176 / 1.000000"
|
| 53 |
+
},
|
| 54 |
+
"accent-forest": {
|
| 55 |
+
"hex": "42c366ff",
|
| 56 |
+
"p3": "0.258824 0.764706 0.400000 / 1.000000"
|
| 57 |
+
},
|
| 58 |
+
"accent-honey": {
|
| 59 |
+
"hex": "ecb730ff",
|
| 60 |
+
"p3": "0.925490 0.717647 0.188235 / 1.000000"
|
| 61 |
+
},
|
| 62 |
+
"black-alpha-1": {
|
| 63 |
+
"hex": "00000003",
|
| 64 |
+
"p3": "0.000000 0.000000 0.000000 / 0.011765"
|
| 65 |
+
},
|
| 66 |
+
"black-alpha-2": {
|
| 67 |
+
"hex": "00000005",
|
| 68 |
+
"p3": "0.000000 0.000000 0.000000 / 0.019608"
|
| 69 |
+
},
|
| 70 |
+
"black-alpha-3": {
|
| 71 |
+
"hex": "00000008",
|
| 72 |
+
"p3": "0.000000 0.000000 0.000000 / 0.031373"
|
| 73 |
+
},
|
| 74 |
+
"black-alpha-4": {
|
| 75 |
+
"hex": "0000000a",
|
| 76 |
+
"p3": "0.000000 0.000000 0.000000 / 0.039216"
|
| 77 |
+
},
|
| 78 |
+
"black-alpha-5": {
|
| 79 |
+
"hex": "0000000d",
|
| 80 |
+
"p3": "0.000000 0.000000 0.000000 / 0.050980"
|
| 81 |
+
},
|
| 82 |
+
"black-alpha-6": {
|
| 83 |
+
"hex": "0000000f",
|
| 84 |
+
"p3": "0.000000 0.000000 0.000000 / 0.058824"
|
| 85 |
+
},
|
| 86 |
+
"black-alpha-7": {
|
| 87 |
+
"hex": "00000012",
|
| 88 |
+
"p3": "0.000000 0.000000 0.000000 / 0.070588"
|
| 89 |
+
},
|
| 90 |
+
"black-alpha-8": {
|
| 91 |
+
"hex": "00000014",
|
| 92 |
+
"p3": "0.000000 0.000000 0.000000 / 0.078431"
|
| 93 |
+
},
|
| 94 |
+
"black-alpha-10": {
|
| 95 |
+
"hex": "0000001a",
|
| 96 |
+
"p3": "0.000000 0.000000 0.000000 / 0.101961"
|
| 97 |
+
},
|
| 98 |
+
"black-alpha-12": {
|
| 99 |
+
"hex": "0000001f",
|
| 100 |
+
"p3": "0.000000 0.000000 0.000000 / 0.121569"
|
| 101 |
+
},
|
| 102 |
+
"black-alpha-16": {
|
| 103 |
+
"hex": "00000029",
|
| 104 |
+
"p3": "0.000000 0.000000 0.000000 / 0.160784"
|
| 105 |
+
},
|
| 106 |
+
"black-alpha-20": {
|
| 107 |
+
"hex": "00000033",
|
| 108 |
+
"p3": "0.000000 0.000000 0.000000 / 0.200000"
|
| 109 |
+
},
|
| 110 |
+
"black-alpha-24": {
|
| 111 |
+
"hex": "0000003d",
|
| 112 |
+
"p3": "0.000000 0.000000 0.000000 / 0.239216"
|
| 113 |
+
},
|
| 114 |
+
"black-alpha-32": {
|
| 115 |
+
"hex": "26262652",
|
| 116 |
+
"p3": "0.149020 0.149020 0.149020 / 0.321569"
|
| 117 |
+
},
|
| 118 |
+
"black-alpha-40": {
|
| 119 |
+
"hex": "26262666",
|
| 120 |
+
"p3": "0.149020 0.149020 0.149020 / 0.400000"
|
| 121 |
+
},
|
| 122 |
+
"black-alpha-48": {
|
| 123 |
+
"hex": "2626267a",
|
| 124 |
+
"p3": "0.149020 0.149020 0.149020 / 0.478431"
|
| 125 |
+
},
|
| 126 |
+
"black-alpha-56": {
|
| 127 |
+
"hex": "2626268f",
|
| 128 |
+
"p3": "0.149020 0.149020 0.149020 / 0.560784"
|
| 129 |
+
},
|
| 130 |
+
"black-alpha-64": {
|
| 131 |
+
"hex": "262626a3",
|
| 132 |
+
"p3": "0.149020 0.149020 0.149020 / 0.639216"
|
| 133 |
+
},
|
| 134 |
+
"black-alpha-72": {
|
| 135 |
+
"hex": "262626b8",
|
| 136 |
+
"p3": "0.149020 0.149020 0.149020 / 0.721569"
|
| 137 |
+
},
|
| 138 |
+
"black-alpha-88": {
|
| 139 |
+
"hex": "262626e0",
|
| 140 |
+
"p3": "0.149020 0.149020 0.149020 / 0.878431"
|
| 141 |
+
},
|
| 142 |
+
"white-alpha-56": {
|
| 143 |
+
"hex": "ffffff8f",
|
| 144 |
+
"p3": "1.000000 1.000000 1.000000 / 0.560784"
|
| 145 |
+
},
|
| 146 |
+
"white-alpha-72": {
|
| 147 |
+
"hex": "ffffffb8",
|
| 148 |
+
"p3": "1.000000 1.000000 1.000000 / 0.721569"
|
| 149 |
+
},
|
| 150 |
+
"border-faint": {
|
| 151 |
+
"hex": "edededff",
|
| 152 |
+
"p3": "0.929412 0.929412 0.929412 / 1.000000"
|
| 153 |
+
},
|
| 154 |
+
"border-muted": {
|
| 155 |
+
"hex": "e8e8e8ff",
|
| 156 |
+
"p3": "0.909804 0.909804 0.909804 / 1.000000"
|
| 157 |
+
},
|
| 158 |
+
"border-loud": {
|
| 159 |
+
"hex": "e6e6e6ff",
|
| 160 |
+
"p3": "0.901961 0.901961 0.901961 / 1.000000"
|
| 161 |
+
},
|
| 162 |
+
"illustrations-faint": {
|
| 163 |
+
"hex": "edededff",
|
| 164 |
+
"p3": "0.929412 0.929412 0.929412 / 1.000000"
|
| 165 |
+
},
|
| 166 |
+
"illustrations-muted": {
|
| 167 |
+
"hex": "e6e6e6ff",
|
| 168 |
+
"p3": "0.901961 0.901961 0.901961 / 1.000000"
|
| 169 |
+
},
|
| 170 |
+
"illustrations-default": {
|
| 171 |
+
"hex": "dbdbdbff",
|
| 172 |
+
"p3": "0.858824 0.858824 0.858824 / 1.000000"
|
| 173 |
+
},
|
| 174 |
+
"background-lighter": {
|
| 175 |
+
"hex": "fbfbfbff",
|
| 176 |
+
"p3": "0.984314 0.984314 0.984314 / 1.000000"
|
| 177 |
+
},
|
| 178 |
+
"background-base": {
|
| 179 |
+
"hex": "f9f9f9ff",
|
| 180 |
+
"p3": "0.976471 0.976471 0.976471 / 1.000000"
|
| 181 |
+
}
|
| 182 |
+
}
|
styles/components/.cursor/rules/component-styles.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Component Styles Rules
|
| 2 |
+
|
| 3 |
+
When working with component-specific CSS in styles/components:
|
| 4 |
+
|
| 5 |
+
## Architecture
|
| 6 |
+
Each component that requires custom CSS has a corresponding file:
|
| 7 |
+
- `button.css` - Fire-inspired button shadows and effects
|
| 8 |
+
- `modal.css` - Modal animations and backdrop effects
|
| 9 |
+
- `spinner.css` - Custom loading animations
|
| 10 |
+
|
| 11 |
+
## Import Strategy
|
| 12 |
+
All component CSS files are imported in `styles/main.css`:
|
| 13 |
+
```css
|
| 14 |
+
/* Component styles */
|
| 15 |
+
@import "./components/button.css";
|
| 16 |
+
@import "./components/modal.css";
|
| 17 |
+
@import "./components/spinner.css";
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
## Guidelines
|
| 21 |
+
1. **Only create CSS files for components that need them** - If Tailwind utilities suffice, don't create a CSS file
|
| 22 |
+
2. **Use P3 colors with sRGB fallbacks** - Ensure wide gamut displays get enhanced colors
|
| 23 |
+
3. **Keep animations performant** - Use transform and opacity for animations
|
| 24 |
+
4. **Component classes should be prefixed** - e.g., `.button-primary`, `.modal-backdrop`
|
| 25 |
+
|
| 26 |
+
## P3 Color Example
|
| 27 |
+
```css
|
| 28 |
+
.button-primary {
|
| 29 |
+
background: #fa5d19; /* sRGB fallback */
|
| 30 |
+
background: color(display-p3 0.9816 0.3634 0.0984); /* P3 color */
|
| 31 |
+
}
|
| 32 |
+
```
|
styles/components/button.css
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.button {
|
| 2 |
+
transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
|
| 3 |
+
scale 0.1s cubic-bezier(0.25, 0.1, 0.25, 1),
|
| 4 |
+
box-shadow 0.1s cubic-bezier(0.25, 0.1, 0.25, 1);
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
.button:active {
|
| 8 |
+
transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1),
|
| 9 |
+
scale 0.05s cubic-bezier(0.25, 0.1, 0.25, 1),
|
| 10 |
+
box-shadow 0.05s cubic-bezier(0.25, 0.1, 0.25, 1);
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
.button-primary {
|
| 14 |
+
background: #ff4c00;
|
| 15 |
+
background: color(display-p3 0.9816 0.3634 0.0984);
|
| 16 |
+
|
| 17 |
+
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
| 18 |
+
0px 2px 4px 0px rgba(255, 77, 0, 0.12),
|
| 19 |
+
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
| 20 |
+
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
| 21 |
+
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
| 22 |
+
|
| 23 |
+
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
| 24 |
+
0px 2px 4px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
| 25 |
+
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
| 26 |
+
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
| 27 |
+
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
.button-primary:hover {
|
| 31 |
+
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
| 32 |
+
0px 4px 8px 0px rgba(255, 77, 0, 0.16),
|
| 33 |
+
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
| 34 |
+
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
| 35 |
+
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
| 36 |
+
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
| 37 |
+
0px 4px 8px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
| 38 |
+
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
| 39 |
+
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
| 40 |
+
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.button-primary:active {
|
| 44 |
+
box-shadow: 0px -6px 12px 0px rgba(255, 0, 0, 0.2) inset,
|
| 45 |
+
0px 2px 4px 0px rgba(255, 77, 0, 0.12),
|
| 46 |
+
0px 1px 1px 0px rgba(255, 77, 0, 0.12),
|
| 47 |
+
0px 0.5px 0.5px 0px rgba(255, 77, 0, 0.16),
|
| 48 |
+
0px 0.25px 0.25px 0px rgba(255, 77, 0, 0.2);
|
| 49 |
+
box-shadow: 0px -6px 12px 0px color(display-p3 0.9804 0.1127 0.098 / 0.2) inset,
|
| 50 |
+
0px 2px 4px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
| 51 |
+
0px 1px 1px 0px color(display-p3 0.9804 0.3647 0.098 / 0.12),
|
| 52 |
+
0px 0.5px 0.5px 0px color(display-p3 0.9804 0.3647 0.098 / 0.16),
|
| 53 |
+
0px 0.25px 0.25px 0px color(display-p3 0.9804 0.3647 0.098 / 0.2);
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
.button-background {
|
| 57 |
+
background: linear-gradient(to bottom, white, transparent);
|
| 58 |
+
|
| 59 |
+
opacity: 0.06;
|
| 60 |
+
|
| 61 |
+
transition: opacity 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.button:hover .button-background {
|
| 65 |
+
opacity: 0.08;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
.button:active .button-background {
|
| 69 |
+
opacity: 0;
|
| 70 |
+
|
| 71 |
+
transition: opacity 0.05s cubic-bezier(0.25, 0.1, 0.25, 1);
|
| 72 |
+
}
|
styles/components/code.css
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.string,
|
| 2 |
+
.language-html .tag:not(.punctuation, .attr-name, .attr-value, .special-attr) {
|
| 3 |
+
color: var(--heat-100) !important;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
.punctuation,
|
| 7 |
+
.operator {
|
| 8 |
+
color: #c2c2c2 !important;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.language-html .attr-name {
|
| 12 |
+
color: var(--black-alpha-64);
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
.comment {
|
| 16 |
+
color: #999999 !important;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
code:not(.language-html) .property:not(.literal-property),
|
| 20 |
+
.class-name,
|
| 21 |
+
code:not(.language-html) .function,
|
| 22 |
+
.language-json .boolean {
|
| 23 |
+
color: #9061ff;
|
| 24 |
+
color: color(display-p3 0.566 0.38 1);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.language-json .property {
|
| 28 |
+
color: inherit !important;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
.prismjs {
|
| 32 |
+
padding-top: 20px;
|
| 33 |
+
@apply text-mono-medium font-mono;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.prismjs code {
|
| 37 |
+
color: var(--accent-black) !important;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.linenumber {
|
| 41 |
+
padding: 0;
|
| 42 |
+
color:white!important;
|
| 43 |
+
font-style: normal;
|
| 44 |
+
}
|
styles/components/index.css
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Component-specific styles from firecrawl-marketing */
|
| 2 |
+
|
| 3 |
+
/* UI Components (for Dashboard v2) */
|
| 4 |
+
@import "./button.css";
|
| 5 |
+
@import "./code.css";
|
| 6 |
+
|
| 7 |
+
/* Additional component CSS will be added as we migrate more components */
|
| 8 |
+
/* @import "./modal.css"; */
|
| 9 |
+
/* @import "./spinner.css"; */
|
| 10 |
+
/* @import "./input.css"; */
|
styles/design-system/.cursor/rules/design-system.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Firecrawl Design System Rules
|
| 2 |
+
|
| 3 |
+
When working with the fire-inspired design system:
|
| 4 |
+
|
| 5 |
+
## Important Note
|
| 6 |
+
- For existing pages: Continue using `styles/main.css`
|
| 7 |
+
- For Dashboard v2 pages: Import `styles/dashboard.css` in the layout
|
| 8 |
+
|
| 9 |
+
## Color System
|
| 10 |
+
Use CSS custom properties with P3 color space for richer colors:
|
| 11 |
+
- **Heat colors**: `--heat-4` through `--heat-100` (fire orange shades)
|
| 12 |
+
- **Accent colors**: `--accent-black`, `--accent-amethyst`, `--accent-bluetron`, `--accent-crimson`
|
| 13 |
+
- **Alpha variants**: Black and white with various opacity levels
|
| 14 |
+
- **UI colors**: Borders, backgrounds, illustrations
|
| 15 |
+
- All colors have sRGB fallbacks for browser compatibility
|
| 16 |
+
|
| 17 |
+
## Typography
|
| 18 |
+
**Font Families:**
|
| 19 |
+
- Display: SuisseIntl (weights: 400, 450, 500, 600, 700)
|
| 20 |
+
- Mono: System monospace stack (SF Mono, Monaco, Inconsolata, etc.)
|
| 21 |
+
|
| 22 |
+
**Type Scale Classes:**
|
| 23 |
+
- Headings: `.title-h1` through `.title-h5`
|
| 24 |
+
- Body: `.body-small`, `.body-medium`, `.body-large`, `.body-x-large`
|
| 25 |
+
- Labels: `.label-small`, `.label-medium`, `.label-large`, `.label-x-large`
|
| 26 |
+
- Mono: `.mono-small`, `.mono-medium`, `.mono-large`
|
| 27 |
+
|
| 28 |
+
## Utilities
|
| 29 |
+
**Gradients:**
|
| 30 |
+
- `.gradient-fire` - Heat gradient
|
| 31 |
+
- `.gradient-heat` - Subtle heat gradient
|
| 32 |
+
- `.gradient-sunset` - Heat to amethyst
|
| 33 |
+
- `.gradient-ocean` - Blue gradient
|
| 34 |
+
|
| 35 |
+
**Layout:**
|
| 36 |
+
- `.container-prose` - Max 65ch width
|
| 37 |
+
- `.center-absolute` - Absolute centering
|
| 38 |
+
- `.stack-*` - Vertical spacing
|
| 39 |
+
- `.layout-sidebar` - Sidebar layout pattern
|
| 40 |
+
|
| 41 |
+
**Effects:**
|
| 42 |
+
- `.blur-backdrop` - Backdrop blur
|
| 43 |
+
- `.border-gradient` - Gradient border
|
| 44 |
+
- `.mask-fade-*` - Fade masks
|
| 45 |
+
- `.focus-ring` - Accessible focus states
|
| 46 |
+
- `.dotted-underline` - SVG dotted underline
|
| 47 |
+
|
| 48 |
+
## Animation Classes
|
| 49 |
+
- `.cursor` - Blinking cursor
|
| 50 |
+
- `.animate-spin-reverse` - Reverse rotation
|
| 51 |
+
- `.animate-flicker` - Fire flicker effect
|
| 52 |
+
- `.animate-glow` - Glowing effect
|
| 53 |
+
- `.transition-*` - Smooth transitions
|
| 54 |
+
|
| 55 |
+
## Usage Example
|
| 56 |
+
```css
|
| 57 |
+
.fire-button {
|
| 58 |
+
background: var(--heat-100);
|
| 59 |
+
color: var(--white);
|
| 60 |
+
padding: 0.75rem 1.5rem;
|
| 61 |
+
border-radius: 0.5rem;
|
| 62 |
+
transition: all 0.3s ease;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.fire-button:hover {
|
| 66 |
+
background: var(--accent-crimson);
|
| 67 |
+
box-shadow: 0 0 40px rgba(250, 93, 25, 0.8);
|
| 68 |
+
}
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
## Component CSS Architecture
|
| 72 |
+
Component-specific styles go in `styles/components/`:
|
| 73 |
+
- Button.css - Fire-inspired button styles
|
| 74 |
+
- Input.css - Input with heat focus states
|
| 75 |
+
- Modal.css - Modal with fire animations
|
| 76 |
+
|
| 77 |
+
## Build Optimization
|
| 78 |
+
- PostCSS handles optimization
|
| 79 |
+
- Tailwind v3 purging via content paths in tailwind.config.js
|
| 80 |
+
- P3 color space with automatic sRGB fallbacks
|
| 81 |
+
- Font preloading for performance
|
styles/design-system/animations.css
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Animation Utilities */
|
| 2 |
+
|
| 3 |
+
/* Cursor blink animation */
|
| 4 |
+
.cursor {
|
| 5 |
+
animation: cursor-blink 0.7s infinite;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
@keyframes cursor-blink {
|
| 9 |
+
0%, 100% {
|
| 10 |
+
opacity: 0;
|
| 11 |
+
}
|
| 12 |
+
50% {
|
| 13 |
+
opacity: 1;
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Reverse spin */
|
| 18 |
+
.animate-spin-reverse {
|
| 19 |
+
animation: spin-reverse 1s linear infinite;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
@keyframes spin-reverse {
|
| 23 |
+
from {
|
| 24 |
+
transform: rotate(360deg);
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/* Fire-inspired animations */
|
| 29 |
+
.animate-flicker {
|
| 30 |
+
animation: flicker 2s ease-in-out infinite;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
@keyframes flicker {
|
| 34 |
+
0%, 100% {
|
| 35 |
+
opacity: 1;
|
| 36 |
+
}
|
| 37 |
+
50% {
|
| 38 |
+
opacity: 0.8;
|
| 39 |
+
transform: scale(0.98);
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.animate-glow {
|
| 44 |
+
animation: glow 2s ease-in-out infinite;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
@keyframes glow {
|
| 48 |
+
0%, 100% {
|
| 49 |
+
box-shadow: 0 0 20px rgba(250, 93, 25, 0.5);
|
| 50 |
+
}
|
| 51 |
+
50% {
|
| 52 |
+
box-shadow: 0 0 40px rgba(250, 93, 25, 0.8);
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/* Smooth transitions */
|
| 57 |
+
.transition-all {
|
| 58 |
+
transition: all 0.3s ease;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.transition-colors {
|
| 62 |
+
transition: color 0.3s ease, background-color 0.3s ease, border-color 0.3s ease;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.transition-transform {
|
| 66 |
+
transition: transform 0.3s ease;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
.transition-opacity {
|
| 70 |
+
transition: opacity 0.3s ease;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
/* Animation delays */
|
| 74 |
+
.delay-100 {
|
| 75 |
+
animation-delay: 100ms;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.delay-200 {
|
| 79 |
+
animation-delay: 200ms;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
.delay-300 {
|
| 83 |
+
animation-delay: 300ms;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
.delay-400 {
|
| 87 |
+
animation-delay: 400ms;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
.delay-500 {
|
| 91 |
+
animation-delay: 500ms;
|
| 92 |
+
}
|
styles/design-system/base/body.css
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Body and Global Styles */
|
| 2 |
+
|
| 3 |
+
/* Hide scrollbars but keep functionality */
|
| 4 |
+
::-webkit-scrollbar {
|
| 5 |
+
width: 0;
|
| 6 |
+
height: 0;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
::-webkit-scrollbar-thumb:hover,
|
| 10 |
+
::-webkit-scrollbar-thumb:active {
|
| 11 |
+
background-color: var(--black-alpha-12);
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
/* Global text rendering */
|
| 15 |
+
* {
|
| 16 |
+
-webkit-font-smoothing: antialiased;
|
| 17 |
+
-moz-osx-font-smoothing: grayscale;
|
| 18 |
+
text-rendering: optimizeLegibility;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
/* Body defaults */
|
| 22 |
+
body {
|
| 23 |
+
font-family: var(--font-sans);
|
| 24 |
+
font-size: 1rem;
|
| 25 |
+
line-height: 1.5;
|
| 26 |
+
color: var(--accent-black);
|
| 27 |
+
background-color: var(--background-base);
|
| 28 |
+
overflow-anchor: none;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Prevent image dragging */
|
| 32 |
+
img,
|
| 33 |
+
video {
|
| 34 |
+
max-width: unset;
|
| 35 |
+
user-select: none;
|
| 36 |
+
-webkit-user-drag: none;
|
| 37 |
+
-khtml-user-drag: none;
|
| 38 |
+
-moz-user-drag: none;
|
| 39 |
+
-o-user-drag: none;
|
| 40 |
+
user-drag: none;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
/* Form elements */
|
| 44 |
+
input,
|
| 45 |
+
input:focus,
|
| 46 |
+
textarea,
|
| 47 |
+
textarea:focus,
|
| 48 |
+
select,
|
| 49 |
+
select:focus {
|
| 50 |
+
outline: 0;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Focus states handled by utilities */
|
| 54 |
+
*:focus {
|
| 55 |
+
outline: 0;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
/* Smooth scrolling */
|
| 59 |
+
html {
|
| 60 |
+
scroll-behavior: smooth;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
@media (prefers-reduced-motion: reduce) {
|
| 64 |
+
html {
|
| 65 |
+
scroll-behavior: auto;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
/* Section defaults */
|
| 70 |
+
section {
|
| 71 |
+
position: relative;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
/* Text selection */
|
| 75 |
+
h1, h2, h3, h4, h5, h6, p {
|
| 76 |
+
user-select: text;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
/* Button defaults */
|
| 80 |
+
button {
|
| 81 |
+
text-align: left;
|
| 82 |
+
user-select: none;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/* Selection color using design system colors */
|
| 86 |
+
*::selection {
|
| 87 |
+
background-color: var(--heat-20);
|
| 88 |
+
color: var(--accent-black);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
/* Links */
|
| 92 |
+
a {
|
| 93 |
+
color: inherit;
|
| 94 |
+
text-decoration: none;
|
| 95 |
+
transition: color 0.2s ease;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
a:hover {
|
| 99 |
+
color: var(--heat-100);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* Code blocks */
|
| 103 |
+
code {
|
| 104 |
+
font-family: var(--font-mono);
|
| 105 |
+
font-size: 0.875em;
|
| 106 |
+
background-color: var(--black-alpha-4);
|
| 107 |
+
padding: 0.125rem 0.25rem;
|
| 108 |
+
border-radius: 0.25rem;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
pre code {
|
| 112 |
+
background-color: transparent;
|
| 113 |
+
padding: 0;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
/* Prevent FOUC */
|
| 117 |
+
html {
|
| 118 |
+
visibility: visible !important;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
/* Responsive text sizing */
|
| 122 |
+
@media (max-width: 768px) {
|
| 123 |
+
html {
|
| 124 |
+
font-size: 15px;
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
@media (min-width: 1536px) {
|
| 129 |
+
html {
|
| 130 |
+
font-size: 17px;
|
| 131 |
+
}
|
| 132 |
+
}
|
styles/design-system/base/layout.css
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Layout Utilities and Helpers */
|
| 2 |
+
|
| 3 |
+
/* Container system */
|
| 4 |
+
.container {
|
| 5 |
+
width: 100%;
|
| 6 |
+
margin-inline: auto;
|
| 7 |
+
padding-inline: var(--container-padding, 1rem);
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
@media (min-width: 640px) {
|
| 11 |
+
.container {
|
| 12 |
+
max-width: 640px;
|
| 13 |
+
padding-inline: 1.5rem;
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
@media (min-width: 768px) {
|
| 18 |
+
.container {
|
| 19 |
+
max-width: 768px;
|
| 20 |
+
padding-inline: 2rem;
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
@media (min-width: 1024px) {
|
| 25 |
+
.container {
|
| 26 |
+
max-width: 1024px;
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
@media (min-width: 1280px) {
|
| 31 |
+
.container {
|
| 32 |
+
max-width: 1280px;
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
@media (min-width: 1536px) {
|
| 37 |
+
.container {
|
| 38 |
+
max-width: 1536px;
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* Layout patterns */
|
| 43 |
+
.layout-grid {
|
| 44 |
+
display: grid;
|
| 45 |
+
gap: var(--gap, 1rem);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
.layout-flex {
|
| 49 |
+
display: flex;
|
| 50 |
+
gap: var(--gap, 1rem);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Common grid patterns */
|
| 54 |
+
.grid-cols-auto-fit {
|
| 55 |
+
grid-template-columns: repeat(auto-fit, minmax(var(--min-width, 250px), 1fr));
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
.grid-cols-auto-fill {
|
| 59 |
+
grid-template-columns: repeat(auto-fill, minmax(var(--min-width, 250px), 1fr));
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/* Sidebar layouts */
|
| 63 |
+
.layout-sidebar {
|
| 64 |
+
display: grid;
|
| 65 |
+
grid-template-columns: var(--sidebar-width, 260px) 1fr;
|
| 66 |
+
gap: var(--gap, 2rem);
|
| 67 |
+
align-items: start;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
@media (max-width: 1024px) {
|
| 71 |
+
.layout-sidebar {
|
| 72 |
+
grid-template-columns: 1fr;
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* Stack layouts */
|
| 77 |
+
.stack {
|
| 78 |
+
display: flex;
|
| 79 |
+
flex-direction: column;
|
| 80 |
+
gap: var(--gap, 1rem);
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.stack-horizontal {
|
| 84 |
+
display: flex;
|
| 85 |
+
flex-direction: row;
|
| 86 |
+
align-items: center;
|
| 87 |
+
gap: var(--gap, 1rem);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* Cluster layout */
|
| 91 |
+
.cluster {
|
| 92 |
+
display: flex;
|
| 93 |
+
flex-wrap: wrap;
|
| 94 |
+
gap: var(--gap, 1rem);
|
| 95 |
+
align-items: center;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/* Center layout */
|
| 99 |
+
.center {
|
| 100 |
+
display: grid;
|
| 101 |
+
place-items: center;
|
| 102 |
+
min-height: var(--min-height, 100vh);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
/* Cover layout */
|
| 106 |
+
.cover {
|
| 107 |
+
display: flex;
|
| 108 |
+
flex-direction: column;
|
| 109 |
+
min-height: var(--min-height, 100vh);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
.cover > * {
|
| 113 |
+
margin-block: 1rem;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.cover > :first-child:not(.centered) {
|
| 117 |
+
margin-block-start: 0;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
.cover > :last-child:not(.centered) {
|
| 121 |
+
margin-block-end: 0;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
.cover > .centered {
|
| 125 |
+
margin-block: auto;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
/* Switcher layout (switches from horizontal to vertical) */
|
| 129 |
+
.switcher {
|
| 130 |
+
display: flex;
|
| 131 |
+
flex-wrap: wrap;
|
| 132 |
+
gap: var(--gap, 1rem);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
.switcher > * {
|
| 136 |
+
flex-grow: 1;
|
| 137 |
+
flex-basis: calc((var(--threshold, 30rem) - 100%) * 999);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
/* Frame layout (for aspect ratios) */
|
| 141 |
+
.frame {
|
| 142 |
+
aspect-ratio: var(--ratio, 16 / 9);
|
| 143 |
+
overflow: hidden;
|
| 144 |
+
display: flex;
|
| 145 |
+
align-items: center;
|
| 146 |
+
justify-content: center;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
.frame > img,
|
| 150 |
+
.frame > video {
|
| 151 |
+
width: 100%;
|
| 152 |
+
height: 100%;
|
| 153 |
+
object-fit: cover;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
/* Reel layout (horizontal scroll) */
|
| 157 |
+
.reel {
|
| 158 |
+
display: flex;
|
| 159 |
+
gap: var(--gap, 1rem);
|
| 160 |
+
overflow-x: auto;
|
| 161 |
+
overflow-y: hidden;
|
| 162 |
+
scrollbar-width: none;
|
| 163 |
+
-webkit-overflow-scrolling: touch;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
.reel::-webkit-scrollbar {
|
| 167 |
+
display: none;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
.reel > * {
|
| 171 |
+
flex: 0 0 auto;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
/* Full bleed */
|
| 175 |
+
.full-bleed {
|
| 176 |
+
width: 100vw;
|
| 177 |
+
margin-inline: calc(50% - 50vw);
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
/* Visually hidden but accessible */
|
| 181 |
+
.sr-only {
|
| 182 |
+
position: absolute;
|
| 183 |
+
width: 1px;
|
| 184 |
+
height: 1px;
|
| 185 |
+
padding: 0;
|
| 186 |
+
margin: -1px;
|
| 187 |
+
overflow: hidden;
|
| 188 |
+
clip: rect(0, 0, 0, 0);
|
| 189 |
+
white-space: nowrap;
|
| 190 |
+
border-width: 0;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
/* Skip to content link */
|
| 194 |
+
.skip-link {
|
| 195 |
+
position: absolute;
|
| 196 |
+
top: 1rem;
|
| 197 |
+
left: 1rem;
|
| 198 |
+
z-index: 999;
|
| 199 |
+
padding: 0.5rem 1rem;
|
| 200 |
+
background-color: var(--accent-black);
|
| 201 |
+
color: var(--white);
|
| 202 |
+
text-decoration: none;
|
| 203 |
+
border-radius: 0.25rem;
|
| 204 |
+
opacity: 0;
|
| 205 |
+
transform: translateY(-100%);
|
| 206 |
+
transition: opacity 0.2s, transform 0.2s;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
.skip-link:focus {
|
| 210 |
+
opacity: 1;
|
| 211 |
+
transform: translateY(0);
|
| 212 |
+
}
|
styles/design-system/base/reset.css
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Modern CSS Reset */
|
| 2 |
+
|
| 3 |
+
/* Box sizing rules */
|
| 4 |
+
*,
|
| 5 |
+
*::before,
|
| 6 |
+
*::after {
|
| 7 |
+
box-sizing: border-box;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
/* Remove default margin */
|
| 11 |
+
body,
|
| 12 |
+
h1,
|
| 13 |
+
h2,
|
| 14 |
+
h3,
|
| 15 |
+
h4,
|
| 16 |
+
h5,
|
| 17 |
+
h6,
|
| 18 |
+
p,
|
| 19 |
+
figure,
|
| 20 |
+
blockquote,
|
| 21 |
+
dl,
|
| 22 |
+
dd {
|
| 23 |
+
margin: 0;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/* Remove list styles on ul, ol elements with a list role */
|
| 27 |
+
ul[role='list'],
|
| 28 |
+
ol[role='list'] {
|
| 29 |
+
list-style: none;
|
| 30 |
+
padding: 0;
|
| 31 |
+
margin: 0;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
/* Set core root defaults */
|
| 35 |
+
html:focus-within {
|
| 36 |
+
scroll-behavior: smooth;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/* Set core body defaults */
|
| 40 |
+
body {
|
| 41 |
+
min-height: 100vh;
|
| 42 |
+
text-rendering: optimizeSpeed;
|
| 43 |
+
line-height: 1.5;
|
| 44 |
+
-webkit-font-smoothing: antialiased;
|
| 45 |
+
-moz-osx-font-smoothing: grayscale;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
/* A elements that don't have a class get default styles */
|
| 49 |
+
a:not([class]) {
|
| 50 |
+
text-decoration-skip-ink: auto;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Make images easier to work with */
|
| 54 |
+
img,
|
| 55 |
+
picture,
|
| 56 |
+
video,
|
| 57 |
+
canvas,
|
| 58 |
+
svg {
|
| 59 |
+
display: block;
|
| 60 |
+
max-width: 100%;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/* Inherit fonts for inputs and buttons */
|
| 64 |
+
input,
|
| 65 |
+
button,
|
| 66 |
+
textarea,
|
| 67 |
+
select {
|
| 68 |
+
font: inherit;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
|
| 72 |
+
@media (prefers-reduced-motion: reduce) {
|
| 73 |
+
html:focus-within {
|
| 74 |
+
scroll-behavior: auto;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
*,
|
| 78 |
+
*::before,
|
| 79 |
+
*::after {
|
| 80 |
+
animation-duration: 0.01ms !important;
|
| 81 |
+
animation-iteration-count: 1 !important;
|
| 82 |
+
transition-duration: 0.01ms !important;
|
| 83 |
+
scroll-behavior: auto !important;
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/* Reset button styles */
|
| 88 |
+
button {
|
| 89 |
+
background: none;
|
| 90 |
+
border: none;
|
| 91 |
+
padding: 0;
|
| 92 |
+
cursor: pointer;
|
| 93 |
+
text-align: inherit;
|
| 94 |
+
color: inherit;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
/* Form elements */
|
| 98 |
+
fieldset {
|
| 99 |
+
margin: 0;
|
| 100 |
+
padding: 0;
|
| 101 |
+
border: 0;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/* Text area */
|
| 105 |
+
textarea {
|
| 106 |
+
resize: vertical;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
/* Remove default focus styles and add custom ones */
|
| 110 |
+
:focus {
|
| 111 |
+
outline: none;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
:focus-visible {
|
| 115 |
+
outline: 2px solid var(--heat-100);
|
| 116 |
+
outline-offset: 2px;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
/* Prevent iOS zoom on form focus */
|
| 120 |
+
@media (hover: none) {
|
| 121 |
+
input[type="text"],
|
| 122 |
+
input[type="email"],
|
| 123 |
+
input[type="password"],
|
| 124 |
+
input[type="number"],
|
| 125 |
+
input[type="tel"],
|
| 126 |
+
input[type="search"],
|
| 127 |
+
input[type="url"],
|
| 128 |
+
textarea,
|
| 129 |
+
select {
|
| 130 |
+
font-size: 16px !important;
|
| 131 |
+
}
|
| 132 |
+
}
|
styles/design-system/colors.css
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Fire Design System Colors */
|
| 2 |
+
/* Define sRGB values first for maximum compatibility */
|
| 3 |
+
:root {
|
| 4 |
+
/* Base colors */
|
| 5 |
+
--white: #ffffff;
|
| 6 |
+
--black: #000000;
|
| 7 |
+
|
| 8 |
+
/* Fire-inspired heat colors */
|
| 9 |
+
--heat-4: rgba(250, 93, 25, 0.039);
|
| 10 |
+
--heat-8: rgba(250, 93, 25, 0.078);
|
| 11 |
+
--heat-12: rgba(250, 93, 25, 0.122);
|
| 12 |
+
--heat-16: rgba(250, 93, 25, 0.161);
|
| 13 |
+
--heat-20: rgba(250, 93, 25, 0.200);
|
| 14 |
+
--heat-40: rgba(250, 93, 25, 0.400);
|
| 15 |
+
--heat-100: #fa5d19;
|
| 16 |
+
--heat-200: #ff6600;
|
| 17 |
+
|
| 18 |
+
/* Accent colors */
|
| 19 |
+
--accent-black: #262626;
|
| 20 |
+
--accent-white: #ffffff;
|
| 21 |
+
--accent-amethyst: #9061ff;
|
| 22 |
+
--accent-bluetron: #2a6dfb;
|
| 23 |
+
--accent-crimson: #eb3424;
|
| 24 |
+
|
| 25 |
+
/* Black alpha variants */
|
| 26 |
+
--black-alpha-1: rgba(0, 0, 0, 0.012);
|
| 27 |
+
--black-alpha-2: rgba(0, 0, 0, 0.020);
|
| 28 |
+
--black-alpha-3: rgba(0, 0, 0, 0.031);
|
| 29 |
+
--black-alpha-4: rgba(0, 0, 0, 0.039);
|
| 30 |
+
--black-alpha-5: rgba(0, 0, 0, 0.051);
|
| 31 |
+
--black-alpha-6: rgba(0, 0, 0, 0.059);
|
| 32 |
+
--black-alpha-7: rgba(0, 0, 0, 0.071);
|
| 33 |
+
--black-alpha-8: rgba(0, 0, 0, 0.078);
|
| 34 |
+
--black-alpha-10: rgba(0, 0, 0, 0.102);
|
| 35 |
+
--black-alpha-12: rgba(0, 0, 0, 0.122);
|
| 36 |
+
--black-alpha-16: rgba(0, 0, 0, 0.161);
|
| 37 |
+
--black-alpha-20: rgba(0, 0, 0, 0.200);
|
| 38 |
+
--black-alpha-24: rgba(0, 0, 0, 0.239);
|
| 39 |
+
--black-alpha-32: rgba(38, 38, 38, 0.322);
|
| 40 |
+
--black-alpha-40: rgba(38, 38, 38, 0.400);
|
| 41 |
+
--black-alpha-48: rgba(38, 38, 38, 0.478);
|
| 42 |
+
--black-alpha-56: rgba(38, 38, 38, 0.561);
|
| 43 |
+
--black-alpha-64: rgba(38, 38, 38, 0.639);
|
| 44 |
+
--black-alpha-72: rgba(38, 38, 38, 0.722);
|
| 45 |
+
--black-alpha-88: rgba(38, 38, 38, 0.878);
|
| 46 |
+
|
| 47 |
+
/* White alpha variants */
|
| 48 |
+
--white-alpha-56: rgba(255, 255, 255, 0.561);
|
| 49 |
+
--white-alpha-72: rgba(255, 255, 255, 0.722);
|
| 50 |
+
|
| 51 |
+
/* Border colors */
|
| 52 |
+
--border-faint: #ededed;
|
| 53 |
+
--border-muted: #e8e8e8;
|
| 54 |
+
--border-loud: #e6e6e6;
|
| 55 |
+
|
| 56 |
+
/* Illustration colors */
|
| 57 |
+
--illustrations-faint: #ededed;
|
| 58 |
+
--illustrations-muted: #e6e6e6;
|
| 59 |
+
--illustrations-default: #dbdbdb;
|
| 60 |
+
|
| 61 |
+
/* Background colors */
|
| 62 |
+
--background-lighter: #fbfbfb;
|
| 63 |
+
--background-base: #f9f9f9;
|
| 64 |
+
|
| 65 |
+
/* Foreground colors */
|
| 66 |
+
--foreground: #262626;
|
| 67 |
+
--foreground-dimmer: rgba(38, 38, 38, 0.722);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
/* P3 color space enhancement for supported browsers */
|
| 71 |
+
@supports (color: color(display-p3 1 1 1)) {
|
| 72 |
+
:root {
|
| 73 |
+
/* Base colors */
|
| 74 |
+
--white: color(display-p3 1 1 1);
|
| 75 |
+
--black: color(display-p3 0 0 0);
|
| 76 |
+
|
| 77 |
+
/* Fire-inspired heat colors */
|
| 78 |
+
--heat-4: color(display-p3 0.980392 0.364706 0.098039 / 0.039216);
|
| 79 |
+
--heat-8: color(display-p3 0.980392 0.364706 0.098039 / 0.078431);
|
| 80 |
+
--heat-12: color(display-p3 0.980392 0.364706 0.098039 / 0.121569);
|
| 81 |
+
--heat-16: color(display-p3 0.980392 0.364706 0.098039 / 0.160784);
|
| 82 |
+
--heat-20: color(display-p3 0.980392 0.364706 0.098039 / 0.200000);
|
| 83 |
+
--heat-40: color(display-p3 0.980392 0.364706 0.098039 / 0.400000);
|
| 84 |
+
--heat-100: color(display-p3 0.980392 0.364706 0.098039 / 1.000000);
|
| 85 |
+
--heat-200: color(display-p3 1.000000 0.400000 0.000000 / 1.000000);
|
| 86 |
+
|
| 87 |
+
/* Accent colors */
|
| 88 |
+
--accent-black: color(display-p3 0.149020 0.149020 0.149020 / 1.000000);
|
| 89 |
+
--accent-white: color(display-p3 1.000000 1.000000 1.000000 / 1.000000);
|
| 90 |
+
--accent-amethyst: color(display-p3 0.564706 0.380392 1.000000 / 1.000000);
|
| 91 |
+
--accent-bluetron: color(display-p3 0.164706 0.427451 0.984314 / 1.000000);
|
| 92 |
+
--accent-crimson: color(display-p3 0.921569 0.203922 0.141176 / 1.000000);
|
| 93 |
+
|
| 94 |
+
/* Black alpha variants */
|
| 95 |
+
--black-alpha-1: color(display-p3 0.000000 0.000000 0.000000 / 0.011765);
|
| 96 |
+
--black-alpha-2: color(display-p3 0.000000 0.000000 0.000000 / 0.019608);
|
| 97 |
+
--black-alpha-3: color(display-p3 0.000000 0.000000 0.000000 / 0.031373);
|
| 98 |
+
--black-alpha-4: color(display-p3 0.000000 0.000000 0.000000 / 0.039216);
|
| 99 |
+
--black-alpha-5: color(display-p3 0.000000 0.000000 0.000000 / 0.050980);
|
| 100 |
+
--black-alpha-6: color(display-p3 0.000000 0.000000 0.000000 / 0.058824);
|
| 101 |
+
--black-alpha-7: color(display-p3 0.000000 0.000000 0.000000 / 0.070588);
|
| 102 |
+
--black-alpha-8: color(display-p3 0.000000 0.000000 0.000000 / 0.078431);
|
| 103 |
+
--black-alpha-10: color(display-p3 0.000000 0.000000 0.000000 / 0.101961);
|
| 104 |
+
--black-alpha-12: color(display-p3 0.000000 0.000000 0.000000 / 0.121569);
|
| 105 |
+
--black-alpha-16: color(display-p3 0.000000 0.000000 0.000000 / 0.160784);
|
| 106 |
+
--black-alpha-20: color(display-p3 0.000000 0.000000 0.000000 / 0.200000);
|
| 107 |
+
--black-alpha-24: color(display-p3 0.000000 0.000000 0.000000 / 0.239216);
|
| 108 |
+
--black-alpha-32: color(display-p3 0.149020 0.149020 0.149020 / 0.321569);
|
| 109 |
+
--black-alpha-40: color(display-p3 0.149020 0.149020 0.149020 / 0.400000);
|
| 110 |
+
--black-alpha-48: color(display-p3 0.149020 0.149020 0.149020 / 0.478431);
|
| 111 |
+
--black-alpha-56: color(display-p3 0.149020 0.149020 0.149020 / 0.560784);
|
| 112 |
+
--black-alpha-64: color(display-p3 0.149020 0.149020 0.149020 / 0.639216);
|
| 113 |
+
--black-alpha-72: color(display-p3 0.149020 0.149020 0.149020 / 0.721569);
|
| 114 |
+
--black-alpha-88: color(display-p3 0.149020 0.149020 0.149020 / 0.878431);
|
| 115 |
+
|
| 116 |
+
/* White alpha variants */
|
| 117 |
+
--white-alpha-56: color(display-p3 1.000000 1.000000 1.000000 / 0.560784);
|
| 118 |
+
--white-alpha-72: color(display-p3 1.000000 1.000000 1.000000 / 0.721569);
|
| 119 |
+
|
| 120 |
+
/* Border colors */
|
| 121 |
+
--border-faint: color(display-p3 0.929412 0.929412 0.929412 / 1.000000);
|
| 122 |
+
--border-muted: color(display-p3 0.909804 0.909804 0.909804 / 1.000000);
|
| 123 |
+
--border-loud: color(display-p3 0.901961 0.901961 0.901961 / 1.000000);
|
| 124 |
+
|
| 125 |
+
/* Illustration colors */
|
| 126 |
+
--illustrations-faint: color(display-p3 0.929412 0.929412 0.929412 / 1.000000);
|
| 127 |
+
--illustrations-muted: color(display-p3 0.901961 0.901961 0.901961 / 1.000000);
|
| 128 |
+
--illustrations-default: color(display-p3 0.858824 0.858824 0.858824 / 1.000000);
|
| 129 |
+
|
| 130 |
+
/* Background colors */
|
| 131 |
+
--background-lighter: color(display-p3 0.984314 0.984314 0.984314 / 1.000000);
|
| 132 |
+
--background-base: color(display-p3 0.976471 0.976471 0.976471 / 1.000000);
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
styles/design-system/fonts.css
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Custom Font Faces */
|
| 2 |
+
/* Using Geist fonts via CSS variables from Next.js font loading */
|
| 3 |
+
/* Fonts are loaded in app/layout.tsx and available as:
|
| 4 |
+
- var(--font-geist-sans)
|
| 5 |
+
- var(--font-geist-mono)
|
| 6 |
+
- var(--font-inter)
|
| 7 |
+
- var(--font-roboto-mono)
|
| 8 |
+
*/
|
styles/design-system/typography.css
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Typography System */
|
| 2 |
+
|
| 3 |
+
/* Font Face Declarations - matching firecrawl-marketing exactly */
|
| 4 |
+
@font-face {
|
| 5 |
+
font-family: 'SuisseIntl';
|
| 6 |
+
src: url('/fonts/SuisseIntl/400.woff2') format('woff2');
|
| 7 |
+
font-weight: 400;
|
| 8 |
+
font-style: normal;
|
| 9 |
+
font-display: swap;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
@font-face {
|
| 13 |
+
font-family: 'SuisseIntl';
|
| 14 |
+
src: url('/fonts/SuisseIntl/450.woff2') format('woff2');
|
| 15 |
+
font-weight: 450;
|
| 16 |
+
font-style: normal;
|
| 17 |
+
font-display: swap;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
@font-face {
|
| 21 |
+
font-family: 'SuisseIntl';
|
| 22 |
+
src: url('/fonts/SuisseIntl/500.woff2') format('woff2');
|
| 23 |
+
font-weight: 500;
|
| 24 |
+
font-style: normal;
|
| 25 |
+
font-display: swap;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
@font-face {
|
| 29 |
+
font-family: 'SuisseIntl';
|
| 30 |
+
src: url('/fonts/SuisseIntl/600.woff2') format('woff2');
|
| 31 |
+
font-weight: 600;
|
| 32 |
+
font-style: normal;
|
| 33 |
+
font-display: swap;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
@font-face {
|
| 37 |
+
font-family: 'SuisseIntl';
|
| 38 |
+
src: url('/fonts/SuisseIntl/700.woff2') format('woff2');
|
| 39 |
+
font-weight: 700;
|
| 40 |
+
font-style: normal;
|
| 41 |
+
font-display: swap;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/* Font Stack Variables */
|
| 45 |
+
:root {
|
| 46 |
+
--font-sans: 'SuisseIntl', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
| 47 |
+
--font-mono: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Roboto Mono', Consolas, monospace;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/* Typography Classes - both semantic and utility variants */
|
| 51 |
+
|
| 52 |
+
/* Text Utilities */
|
| 53 |
+
.text-balance {
|
| 54 |
+
text-wrap: balance;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.text-pretty {
|
| 58 |
+
text-wrap: pretty;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
/* Utility text classes matching firecrawl-marketing - extending base classes */
|
| 62 |
+
.title-h1,
|
| 63 |
+
.text-title-h1 {
|
| 64 |
+
font-size: 4rem; /* 64px */
|
| 65 |
+
line-height: 1.1;
|
| 66 |
+
letter-spacing: -0.02em;
|
| 67 |
+
font-weight: 600;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
.title-h2,
|
| 71 |
+
.text-title-h2 {
|
| 72 |
+
font-size: 2.25rem; /* 36px */
|
| 73 |
+
line-height: 1.2;
|
| 74 |
+
letter-spacing: -0.02em;
|
| 75 |
+
font-weight: 500;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.title-h3,
|
| 79 |
+
.text-title-h3 {
|
| 80 |
+
font-size: 1.875rem; /* 30px */
|
| 81 |
+
line-height: 1.25;
|
| 82 |
+
letter-spacing: -0.02em;
|
| 83 |
+
font-weight: 500;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
.title-h4,
|
| 87 |
+
.text-title-h4 {
|
| 88 |
+
font-size: 1.375rem; /* 22px */
|
| 89 |
+
line-height: 1.3;
|
| 90 |
+
letter-spacing: -0.01em;
|
| 91 |
+
font-weight: 500;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.title-h5,
|
| 95 |
+
.text-title-h5 {
|
| 96 |
+
font-size: 1.125rem; /* 18px */
|
| 97 |
+
line-height: 1.4;
|
| 98 |
+
letter-spacing: -0.01em;
|
| 99 |
+
font-weight: 500;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.body-small,
|
| 103 |
+
.text-body-small {
|
| 104 |
+
font-size: 0.875rem; /* 14px */
|
| 105 |
+
line-height: 1.5;
|
| 106 |
+
font-weight: 400;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
.body-medium,
|
| 110 |
+
.text-body-medium {
|
| 111 |
+
font-size: 1rem; /* 16px */
|
| 112 |
+
line-height: 1.5;
|
| 113 |
+
font-weight: 400;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.body-large,
|
| 117 |
+
.text-body-large {
|
| 118 |
+
font-size: 1.125rem; /* 18px */
|
| 119 |
+
line-height: 1.6;
|
| 120 |
+
font-weight: 400;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.body-x-large,
|
| 124 |
+
.text-body-x-large {
|
| 125 |
+
font-size: 1.375rem; /* 22px */
|
| 126 |
+
line-height: 1.6;
|
| 127 |
+
font-weight: 400;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
.label-small,
|
| 131 |
+
.text-label-small {
|
| 132 |
+
font-size: 0.9375rem; /* 15px */
|
| 133 |
+
line-height: 1.4;
|
| 134 |
+
letter-spacing: 0.02em;
|
| 135 |
+
font-weight: 450;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
.label-medium,
|
| 139 |
+
.text-label-medium {
|
| 140 |
+
font-size: 1rem; /* 16px */
|
| 141 |
+
line-height: 1.4;
|
| 142 |
+
letter-spacing: 0.01em;
|
| 143 |
+
font-weight: 450;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.label-large,
|
| 147 |
+
.text-label-large {
|
| 148 |
+
font-size: 1.125rem; /* 18px */
|
| 149 |
+
line-height: 1.4;
|
| 150 |
+
font-weight: 450;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
.label-x-large,
|
| 154 |
+
.text-label-x-large {
|
| 155 |
+
font-size: 1.375rem; /* 22px */
|
| 156 |
+
line-height: 1.4;
|
| 157 |
+
font-weight: 450;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
.mono-small,
|
| 161 |
+
.text-mono-small {
|
| 162 |
+
font-family: var(--font-mono);
|
| 163 |
+
font-size: 0.75rem; /* 12px */
|
| 164 |
+
line-height: 1.5;
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
.mono-medium,
|
| 168 |
+
.text-mono-medium {
|
| 169 |
+
font-family: var(--font-mono);
|
| 170 |
+
font-size: 0.875rem; /* 14px */
|
| 171 |
+
line-height: 1.5;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
.mono-large,
|
| 175 |
+
.text-mono-large {
|
| 176 |
+
font-family: var(--font-mono);
|
| 177 |
+
font-size: 1rem; /* 16px */
|
| 178 |
+
line-height: 1.5;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
/* Responsive Typography - matching firecrawl-marketing */
|
| 182 |
+
@media (max-width: 1024px) {
|
| 183 |
+
.text-body-large {
|
| 184 |
+
font-size: 18px;
|
| 185 |
+
font-weight: 400;
|
| 186 |
+
line-height: 26px;
|
| 187 |
+
letter-spacing: -0.09px;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
.text-body-medium {
|
| 191 |
+
font-size: 16px;
|
| 192 |
+
font-weight: 400;
|
| 193 |
+
line-height: 24px;
|
| 194 |
+
letter-spacing: 0.16px;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
.text-title-h4 {
|
| 198 |
+
font-size: 22px;
|
| 199 |
+
font-weight: 500;
|
| 200 |
+
line-height: 26px;
|
| 201 |
+
letter-spacing: -0.22px;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
.text-body-x-large {
|
| 205 |
+
font-size: 22px;
|
| 206 |
+
font-weight: 400;
|
| 207 |
+
line-height: 30px;
|
| 208 |
+
letter-spacing: -0.11px;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
.text-label-small {
|
| 212 |
+
font-size: 15px;
|
| 213 |
+
font-weight: 450;
|
| 214 |
+
line-height: 22px;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
.text-label-large {
|
| 218 |
+
font-size: 18px;
|
| 219 |
+
font-weight: 450;
|
| 220 |
+
line-height: 26px;
|
| 221 |
+
letter-spacing: -0.09px;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
.text-label-x-large {
|
| 225 |
+
font-size: 22px;
|
| 226 |
+
font-weight: 450;
|
| 227 |
+
line-height: 30px;
|
| 228 |
+
letter-spacing: -0.11px;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
.text-label-medium {
|
| 232 |
+
font-size: 16px;
|
| 233 |
+
font-weight: 450;
|
| 234 |
+
line-height: 24px;
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
.text-title-h2 {
|
| 238 |
+
font-size: 36px;
|
| 239 |
+
font-weight: 500;
|
| 240 |
+
line-height: 40px;
|
| 241 |
+
letter-spacing: -0.36px;
|
| 242 |
+
}
|
| 243 |
+
}
|
styles/design-system/utilities.css
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Custom Utility Classes */
|
| 2 |
+
|
| 3 |
+
/* Gradient utilities */
|
| 4 |
+
.gradient-fire {
|
| 5 |
+
background: linear-gradient(135deg, var(--heat-100) 0%, var(--accent-crimson) 100%);
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
.gradient-heat {
|
| 9 |
+
background: linear-gradient(135deg, var(--heat-20) 0%, var(--heat-100) 100%);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.gradient-sunset {
|
| 13 |
+
background: linear-gradient(135deg, var(--heat-100) 0%, var(--accent-amethyst) 100%);
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
.gradient-ocean {
|
| 17 |
+
background: linear-gradient(135deg, var(--accent-bluetron) 0%, var(--accent-amethyst) 100%);
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/* Text gradient */
|
| 21 |
+
.text-gradient {
|
| 22 |
+
background-clip: text;
|
| 23 |
+
-webkit-background-clip: text;
|
| 24 |
+
-webkit-text-fill-color: transparent;
|
| 25 |
+
background-color: var(--heat-100); /* Fallback */
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/* Mask utilities */
|
| 29 |
+
.mask-fade-bottom {
|
| 30 |
+
mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
|
| 31 |
+
-webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.mask-fade-edges {
|
| 35 |
+
mask-image: radial-gradient(ellipse at center, black 50%, transparent 100%);
|
| 36 |
+
-webkit-mask-image: radial-gradient(ellipse at center, black 50%, transparent 100%);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.mask-intersect {
|
| 40 |
+
-webkit-mask-composite: source-in; /* For Chrome */
|
| 41 |
+
mask-composite: intersect; /* For Firefox */
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/* Blur utilities */
|
| 45 |
+
.blur-backdrop {
|
| 46 |
+
backdrop-filter: blur(10px);
|
| 47 |
+
-webkit-backdrop-filter: blur(10px);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/* Border utilities */
|
| 51 |
+
.border-gradient {
|
| 52 |
+
position: relative;
|
| 53 |
+
background: var(--white);
|
| 54 |
+
border: 1px solid transparent;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.border-gradient::before {
|
| 58 |
+
content: '';
|
| 59 |
+
position: absolute;
|
| 60 |
+
inset: 0;
|
| 61 |
+
border-radius: inherit;
|
| 62 |
+
padding: 1px;
|
| 63 |
+
background: linear-gradient(135deg, var(--heat-100), var(--accent-crimson));
|
| 64 |
+
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
| 65 |
+
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
| 66 |
+
mask-composite: xor;
|
| 67 |
+
-webkit-mask-composite: xor;
|
| 68 |
+
pointer-events: none;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* Dotted underline - updated from marketing */
|
| 72 |
+
.dotted-underline {
|
| 73 |
+
position: relative;
|
| 74 |
+
display: inline-block;
|
| 75 |
+
line-height: 1.1;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.dotted-underline::before {
|
| 79 |
+
content: "";
|
| 80 |
+
position: absolute;
|
| 81 |
+
bottom: -2px;
|
| 82 |
+
left: 0;
|
| 83 |
+
width: 100%;
|
| 84 |
+
height: 1.7px;
|
| 85 |
+
background-image: url("data:image/svg+xml,%3Csvg width='4' height='2' viewBox='0 0 4 2' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='1.7' height='1.7' rx='0.85' fill='%23D1D1D1' style='fill:%23D1D1D1;fill:color(display-p3 0.8196 0.8196 0.8196);fill-opacity:1;'/%3E%3C/svg%3E%0A");
|
| 86 |
+
background-size: 3.4px 1.7px;
|
| 87 |
+
background-repeat: repeat-x;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* Container utilities */
|
| 91 |
+
.container-prose {
|
| 92 |
+
max-width: 65ch;
|
| 93 |
+
margin-inline: auto;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.container-narrow {
|
| 97 |
+
max-width: 48rem; /* 768px */
|
| 98 |
+
margin-inline: auto;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.container-wide {
|
| 102 |
+
max-width: 80rem; /* 1280px */
|
| 103 |
+
margin-inline: auto;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
/* Centering helpers */
|
| 107 |
+
.center-absolute {
|
| 108 |
+
position: absolute;
|
| 109 |
+
top: 50%;
|
| 110 |
+
left: 50%;
|
| 111 |
+
transform: translate(-50%, -50%);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
.center-flex {
|
| 115 |
+
display: flex;
|
| 116 |
+
align-items: center;
|
| 117 |
+
justify-content: center;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
/* Spacing utilities */
|
| 121 |
+
.stack-sm > * + * {
|
| 122 |
+
margin-top: 0.5rem;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.stack-md > * + * {
|
| 126 |
+
margin-top: 1rem;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
.stack-lg > * + * {
|
| 130 |
+
margin-top: 2rem;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
.stack-xl > * + * {
|
| 134 |
+
margin-top: 3rem;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/* Aspect ratio utilities */
|
| 138 |
+
.aspect-video {
|
| 139 |
+
aspect-ratio: 16 / 9;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
.aspect-square {
|
| 143 |
+
aspect-ratio: 1 / 1;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.aspect-portrait {
|
| 147 |
+
aspect-ratio: 3 / 4;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
/* Selection color */
|
| 151 |
+
::selection {
|
| 152 |
+
background-color: var(--heat-20);
|
| 153 |
+
color: var(--accent-black);
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
/* Focus visible utilities */
|
| 157 |
+
.focus-ring {
|
| 158 |
+
outline: 2px solid transparent;
|
| 159 |
+
outline-offset: 2px;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
.focus-ring:focus-visible {
|
| 163 |
+
outline-color: var(--heat-100);
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
/* Scrollbar styling */
|
| 167 |
+
.scrollbar-thin {
|
| 168 |
+
scrollbar-width: thin;
|
| 169 |
+
scrollbar-color: var(--border-muted) var(--background-lighter);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
.scrollbar-thin::-webkit-scrollbar {
|
| 173 |
+
width: 8px;
|
| 174 |
+
height: 8px;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
.scrollbar-thin::-webkit-scrollbar-track {
|
| 178 |
+
background: var(--background-lighter);
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
.scrollbar-thin::-webkit-scrollbar-thumb {
|
| 182 |
+
background-color: var(--border-muted);
|
| 183 |
+
border-radius: 4px;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
| 187 |
+
background-color: var(--border-loud);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
/* Animation delay utilities */
|
| 191 |
+
.animation-delay-150 {
|
| 192 |
+
animation-delay: 150ms;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
.animation-delay-300 {
|
| 196 |
+
animation-delay: 300ms;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
.animation-delay-450 {
|
| 200 |
+
animation-delay: 450ms;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
.animation-delay-600 {
|
| 204 |
+
animation-delay: 600ms;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
/* Loading animation helpers */
|
| 208 |
+
.animate-shimmer {
|
| 209 |
+
background-size: 400% 100%;
|
| 210 |
+
animation: shimmer 2s ease-in-out infinite;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
@keyframes shimmer {
|
| 214 |
+
0% {
|
| 215 |
+
background-position: -200% 0;
|
| 216 |
+
}
|
| 217 |
+
100% {
|
| 218 |
+
background-position: 200% 0;
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
/* Heat glow effect */
|
| 223 |
+
.heat-glow {
|
| 224 |
+
box-shadow: 0 0 40px rgba(250, 93, 25, 0.3);
|
| 225 |
+
animation: heat-glow 3s ease-in-out infinite;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
@keyframes heat-glow {
|
| 229 |
+
0%, 100% {
|
| 230 |
+
box-shadow: 0 0 20px rgba(250, 93, 25, 0.2);
|
| 231 |
+
}
|
| 232 |
+
50% {
|
| 233 |
+
box-shadow: 0 0 40px rgba(250, 93, 25, 0.4);
|
| 234 |
+
}
|
| 235 |
+
}
|
styles/fire.css
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Fire Design System - New Firecrawl Design System */
|
| 2 |
+
/* This is the new fire-inspired design system used in app and brand pages */
|
| 3 |
+
|
| 4 |
+
/* ALL @import statements must come FIRST before any other CSS */
|
| 5 |
+
|
| 6 |
+
/* Fire Design System Base */
|
| 7 |
+
@import "./design-system/base/reset.css";
|
| 8 |
+
@import "./design-system/base/body.css";
|
| 9 |
+
@import "./design-system/base/layout.css";
|
| 10 |
+
|
| 11 |
+
/* Fire Design System Core */
|
| 12 |
+
@import "./design-system/fonts.css";
|
| 13 |
+
@import "./design-system/colors.css";
|
| 14 |
+
@import "./design-system/typography.css";
|
| 15 |
+
@import "./design-system/animations.css";
|
| 16 |
+
@import "./design-system/utilities.css";
|
| 17 |
+
|
| 18 |
+
/* Tailwind CSS - After all imports */
|
| 19 |
+
@tailwind base;
|
| 20 |
+
@tailwind components;
|
| 21 |
+
@tailwind utilities;
|
| 22 |
+
|
| 23 |
+
/* Container configuration from firecrawl-marketing */
|
| 24 |
+
:root {
|
| 25 |
+
--container-width: 1112px;
|
| 26 |
+
--container-width-padding: 1144px;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Container implementation matching firecrawl-marketing */
|
| 30 |
+
.container {
|
| 31 |
+
max-width: min(calc(100% - 32px), var(--container-width));
|
| 32 |
+
--padding: 16px;
|
| 33 |
+
margin-left: auto;
|
| 34 |
+
margin-right: auto;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
/* Custom container width utilities */
|
| 38 |
+
.cmw-container {
|
| 39 |
+
max-width: var(--container-width);
|
| 40 |
+
padding-left: 16px;
|
| 41 |
+
padding-right: 16px;
|
| 42 |
+
margin-left: auto;
|
| 43 |
+
margin-right: auto;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
@media (max-width: 1024px) {
|
| 47 |
+
:root {
|
| 48 |
+
--container-width: 356px;
|
| 49 |
+
--container-width-padding: var(--container-width);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.container {
|
| 53 |
+
--padding: 0px;
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
/* Marketing pattern utilities */
|
| 58 |
+
.overlay {
|
| 59 |
+
position: absolute;
|
| 60 |
+
top: 0;
|
| 61 |
+
left: 0;
|
| 62 |
+
width: 100%;
|
| 63 |
+
height: 100%;
|
| 64 |
+
border-radius: inherit;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.curvy-rect {
|
| 68 |
+
contain: layout paint;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* Fire-specific utilities layer */
|
| 72 |
+
@layer utilities {
|
| 73 |
+
/* Mask utilities */
|
| 74 |
+
.mask-intersect {
|
| 75 |
+
-webkit-mask-composite: source-in; /* For Chrome */
|
| 76 |
+
mask-composite: intersect; /* Standard */
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
.mask-subtract {
|
| 80 |
+
-webkit-mask-composite: source-out; /* For Chrome */
|
| 81 |
+
mask-composite: subtract; /* Standard */
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
.mask-union {
|
| 85 |
+
-webkit-mask-composite: source-over; /* For Chrome */
|
| 86 |
+
mask-composite: add; /* Standard */
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
/* Fire design pattern utilities */
|
| 90 |
+
.dotted-underline::before {
|
| 91 |
+
content: "";
|
| 92 |
+
position: absolute;
|
| 93 |
+
bottom: -3px;
|
| 94 |
+
left: 0;
|
| 95 |
+
width: 100%;
|
| 96 |
+
height: 1.7px;
|
| 97 |
+
background-image: url("data:image/svg+xml,%3Csvg width='4' height='2' viewBox='0 0 4 2' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='1.7' height='1.7' rx='0.85' fill='%23D1D1D1' style='fill:%23D1D1D1;fill:color(display-p3 0.8196 0.8196 0.8196);fill-opacity:1;'/%3E%3C/svg%3E%0A");
|
| 98 |
+
background-size: 3.4px 1.7px;
|
| 99 |
+
background-repeat: repeat-x;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* inside-border styles moved to inside-border-fix.css to avoid conflicts */
|
| 103 |
+
}
|
styles/inside-border-fix.css
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Fix for inside-border utility */
|
| 2 |
+
.inside-border {
|
| 3 |
+
position: relative;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
.inside-border::before {
|
| 7 |
+
content: "";
|
| 8 |
+
position: absolute;
|
| 9 |
+
inset: 0;
|
| 10 |
+
border-radius: inherit;
|
| 11 |
+
border: 1px solid;
|
| 12 |
+
border-color: inherit;
|
| 13 |
+
transition: all 0.2s;
|
| 14 |
+
pointer-events: none;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
.inside-border-x {
|
| 18 |
+
position: relative;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.inside-border-x::before {
|
| 22 |
+
content: "";
|
| 23 |
+
position: absolute;
|
| 24 |
+
inset: 0;
|
| 25 |
+
border-radius: inherit;
|
| 26 |
+
border-left: 1px solid;
|
| 27 |
+
border-right: 1px solid;
|
| 28 |
+
border-color: inherit;
|
| 29 |
+
transition: all 0.2s;
|
| 30 |
+
pointer-events: none;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.inside-border-y {
|
| 34 |
+
position: relative;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
.inside-border-y::before {
|
| 38 |
+
content: "";
|
| 39 |
+
position: absolute;
|
| 40 |
+
inset: 0;
|
| 41 |
+
border-radius: inherit;
|
| 42 |
+
border-top: 1px solid;
|
| 43 |
+
border-bottom: 1px solid;
|
| 44 |
+
border-color: inherit;
|
| 45 |
+
transition: all 0.2s;
|
| 46 |
+
pointer-events: none;
|
| 47 |
+
}
|
styles/main.css
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Fire Design System - Must be imported first for color definitions */
|
| 2 |
+
@import "./fire.css";
|
| 3 |
+
@import "./components/index.css";
|
| 4 |
+
@import "./inside-border-fix.css";
|
| 5 |
+
|
| 6 |
+
/* Additional styles */
|
| 7 |
+
@import "additional-styles/utility-patterns.css";
|
| 8 |
+
@import "additional-styles/theme.css";
|
| 9 |
+
|
| 10 |
+
@tailwind base;
|
| 11 |
+
@tailwind components;
|
| 12 |
+
@tailwind utilities;
|
| 13 |
+
|
| 14 |
+
.animated {
|
| 15 |
+
-webkit-animation-duration: 1s;
|
| 16 |
+
animation-duration: 1s;
|
| 17 |
+
-webkit-animation-duration: 1s;
|
| 18 |
+
animation-duration: 1s;
|
| 19 |
+
-webkit-animation-fill-mode: both;
|
| 20 |
+
animation-fill-mode: both;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.height-screen-helper {
|
| 24 |
+
min-height: calc(100vh - 80px);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
@layer base {
|
| 28 |
+
:root {
|
| 29 |
+
--background: 0 0% 100%;
|
| 30 |
+
--foreground: 240 10% 3.9%;
|
| 31 |
+
|
| 32 |
+
--card: 0 0% 100%;
|
| 33 |
+
--card-foreground: 240 10% 3.9%;
|
| 34 |
+
|
| 35 |
+
--popover: 0 0% 100%;
|
| 36 |
+
--popover-foreground: 240 10% 3.9%;
|
| 37 |
+
|
| 38 |
+
--primary: 240 5.9% 10%;
|
| 39 |
+
--primary-foreground: 0 0% 98%;
|
| 40 |
+
|
| 41 |
+
--secondary: 240 4.8% 95.9%;
|
| 42 |
+
--secondary-foreground: 240 5.9% 10%;
|
| 43 |
+
|
| 44 |
+
--muted: 240 4.8% 95.9%;
|
| 45 |
+
--muted-foreground: 240 3.8% 46.1%;
|
| 46 |
+
|
| 47 |
+
--accent: 240 4.8% 95.9%;
|
| 48 |
+
--accent-foreground: 240 5.9% 10%;
|
| 49 |
+
|
| 50 |
+
--destructive: 0 84.2% 60.2%;
|
| 51 |
+
--destructive-foreground: 0 0% 98%;
|
| 52 |
+
|
| 53 |
+
--border: 240 5.9% 90%;
|
| 54 |
+
--input: 240 5.9% 90%;
|
| 55 |
+
--ring: 240 10% 3.9%;
|
| 56 |
+
|
| 57 |
+
--radius: 0.5rem;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
/* Temporarily disable dark mode until we migrate to semantic colors */
|
| 61 |
+
/* .dark {
|
| 62 |
+
--background: 240 10% 3.9%;
|
| 63 |
+
--foreground: 0 0% 98%;
|
| 64 |
+
|
| 65 |
+
--card: 240 10% 3.9%;
|
| 66 |
+
--card-foreground: 0 0% 98%;
|
| 67 |
+
|
| 68 |
+
--popover: 240 10% 3.9%;
|
| 69 |
+
--popover-foreground: 0 0% 98%;
|
| 70 |
+
|
| 71 |
+
--primary: 0 0% 98%;
|
| 72 |
+
--primary-foreground: 240 5.9% 10%;
|
| 73 |
+
|
| 74 |
+
--secondary: 240 3.7% 15.9%;
|
| 75 |
+
--secondary-foreground: 0 0% 98%;
|
| 76 |
+
|
| 77 |
+
--muted: 240 3.7% 15.9%;
|
| 78 |
+
--muted-foreground: 240 5% 64.9%;
|
| 79 |
+
|
| 80 |
+
--accent: 240 3.7% 15.9%;
|
| 81 |
+
--accent-foreground: 0 0% 98%;
|
| 82 |
+
|
| 83 |
+
--destructive: 0 62.8% 30.6%;
|
| 84 |
+
--destructive-foreground: 0 0% 98%;
|
| 85 |
+
|
| 86 |
+
--border: 240 3.7% 15.9%;
|
| 87 |
+
--input: 240 3.7% 15.9%;
|
| 88 |
+
--ring: 240 4.9% 83.9%;
|
| 89 |
+
} */
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
@layer utilities {
|
| 93 |
+
/* Hide scrollbar for Chrome, Safari and Opera */
|
| 94 |
+
.no-scrollbar::-webkit-scrollbar {
|
| 95 |
+
display: none;
|
| 96 |
+
}
|
| 97 |
+
/* Hide scrollbar for IE, Edge and Firefox */
|
| 98 |
+
.no-scrollbar {
|
| 99 |
+
-ms-overflow-style: none; /* IE and Edge */
|
| 100 |
+
scrollbar-width: none; /* Firefox */
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
.ReactModal__Overlay {
|
| 105 |
+
opacity: 0;
|
| 106 |
+
transition: opacity 300ms ease-in-out;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
.ReactModal__Overlay--after-open {
|
| 110 |
+
opacity: 1;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
.ReactModal__Overlay--before-close {
|
| 114 |
+
opacity: 0;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
.DialogOverlay {
|
| 118 |
+
background-color: rgba(0, 0, 0, 0.5);
|
| 119 |
+
position: fixed;
|
| 120 |
+
inset: 0;
|
| 121 |
+
animation: overlayShow 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
| 122 |
+
z-index: 100;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.DialogContent {
|
| 126 |
+
background-color: white;
|
| 127 |
+
border-radius: 6px;
|
| 128 |
+
box-shadow:
|
| 129 |
+
hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
|
| 130 |
+
hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
| 131 |
+
position: fixed;
|
| 132 |
+
top: 50%;
|
| 133 |
+
left: 50%;
|
| 134 |
+
transform: translate(-50%, -50%);
|
| 135 |
+
width: 90vw;
|
| 136 |
+
max-width: 650px;
|
| 137 |
+
max-height: 85vh;
|
| 138 |
+
animation: contentShow 500ms cubic-bezier(0.16, 1, 0.3, 1);
|
| 139 |
+
z-index: 101;
|
| 140 |
+
}
|
| 141 |
+
.DialogContent:focus {
|
| 142 |
+
outline: none;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
.DialogTitle {
|
| 146 |
+
margin: 0;
|
| 147 |
+
font-weight: 500;
|
| 148 |
+
color: #000;
|
| 149 |
+
font-size: 17px;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
.DialogDescription {
|
| 153 |
+
margin: 10px 0 20px;
|
| 154 |
+
color: #000;
|
| 155 |
+
font-size: 15px;
|
| 156 |
+
line-height: 1.5;
|
| 157 |
+
}
|
| 158 |
+
.FireButton {
|
| 159 |
+
color: #f8fafc;
|
| 160 |
+
background-color: #111827;
|
| 161 |
+
width: 100%;
|
| 162 |
+
box-shadow:
|
| 163 |
+
0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
| 164 |
+
0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
| 165 |
+
transition: box-shadow 0.3s ease;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.FireButton:hover {
|
| 169 |
+
box-shadow: 0 0 8px 2px #ff5d22af;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
@keyframes overlayShow {
|
| 173 |
+
from {
|
| 174 |
+
opacity: 0;
|
| 175 |
+
}
|
| 176 |
+
to {
|
| 177 |
+
opacity: 1;
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
@keyframes contentShow {
|
| 182 |
+
from {
|
| 183 |
+
opacity: 0;
|
| 184 |
+
transform: translate(-50%, -48%) scale(0.96);
|
| 185 |
+
}
|
| 186 |
+
to {
|
| 187 |
+
opacity: 1;
|
| 188 |
+
transform: translate(-50%, -50%) scale(1);
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
.blog-heading:target {
|
| 193 |
+
padding-bottom: 120px !important;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
@layer utilities {
|
| 197 |
+
.extra-space {
|
| 198 |
+
position: relative;
|
| 199 |
+
|
| 200 |
+
&::after {
|
| 201 |
+
--target-size: 20px;
|
| 202 |
+
|
| 203 |
+
content: '';
|
| 204 |
+
position: absolute;
|
| 205 |
+
inset: var(--target-size);
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
.marquee-animation {
|
| 210 |
+
animation: marquee var(--speed, 10s) linear infinite
|
| 211 |
+
var(--direction, forwards);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
@keyframes marquee {
|
| 215 |
+
to {
|
| 216 |
+
transform: translateX(-50%);
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
/* Loading state animations */
|
| 221 |
+
@keyframes fade-in-up {
|
| 222 |
+
from {
|
| 223 |
+
opacity: 0;
|
| 224 |
+
transform: translateY(20px);
|
| 225 |
+
}
|
| 226 |
+
to {
|
| 227 |
+
opacity: 1;
|
| 228 |
+
transform: translateY(0);
|
| 229 |
+
}
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
@keyframes pulse-subtle {
|
| 233 |
+
0%, 100% {
|
| 234 |
+
opacity: 1;
|
| 235 |
+
}
|
| 236 |
+
50% {
|
| 237 |
+
opacity: 0.95;
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
@keyframes text-shimmer {
|
| 242 |
+
0% {
|
| 243 |
+
background-position: -200% center;
|
| 244 |
+
}
|
| 245 |
+
100% {
|
| 246 |
+
background-position: 200% center;
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
.animate-fade-in-up {
|
| 251 |
+
animation: fade-in-up 0.6s ease-out forwards;
|
| 252 |
+
opacity: 0;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
.animate-pulse-subtle {
|
| 256 |
+
animation: pulse-subtle 2s ease-in-out infinite;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
.animate-text-shimmer {
|
| 260 |
+
background: linear-gradient(
|
| 261 |
+
90deg,
|
| 262 |
+
rgb(156 163 175) 0%,
|
| 263 |
+
rgb(229 231 235) 50%,
|
| 264 |
+
rgb(156 163 175) 100%
|
| 265 |
+
);
|
| 266 |
+
background-size: 200% auto;
|
| 267 |
+
-webkit-background-clip: text;
|
| 268 |
+
-webkit-text-fill-color: transparent;
|
| 269 |
+
background-clip: text;
|
| 270 |
+
animation: text-shimmer 3s linear infinite;
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
.grecaptcha-badge { visibility: hidden; }
|
| 275 |
+
|
| 276 |
+
/* Remove all focus styles from hero input */
|
| 277 |
+
input[type="text"]:focus,
|
| 278 |
+
input[type="text"]:focus-visible {
|
| 279 |
+
outline: none !important;
|
| 280 |
+
box-shadow: none !important;
|
| 281 |
+
border-color: inherit !important;
|
| 282 |
+
}
|
tailwind.config.ts
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
| 2 |
+
import defaultTheme from "tailwindcss/defaultTheme";
|
| 3 |
+
import type { Config } from "tailwindcss";
|
| 4 |
+
|
| 5 |
+
import colorsJson from "./colors.json";
|
| 6 |
+
|
| 7 |
+
const colors = Object.keys(colorsJson).reduce(
|
| 8 |
+
(acc, key) => {
|
| 9 |
+
acc[key] = `var(--${key})`;
|
| 10 |
+
|
| 11 |
+
return acc;
|
| 12 |
+
},
|
| 13 |
+
{} as Record<string, string>
|
| 14 |
+
);
|
| 15 |
+
|
| 16 |
+
const sizes = Array.from({ length: 1000 }, (_, i) => i).reduce(
|
| 17 |
+
(acc, curr) => {
|
| 18 |
+
acc[curr] = `${curr}px`;
|
| 19 |
+
|
| 20 |
+
return acc;
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
max: "max-content",
|
| 24 |
+
unset: "unset",
|
| 25 |
+
full: "100%",
|
| 26 |
+
inherit: "inherit",
|
| 27 |
+
"1/2": "50%",
|
| 28 |
+
"1/3": "33.3%",
|
| 29 |
+
"2/3": "66.6%",
|
| 30 |
+
"1/4": "25%",
|
| 31 |
+
"1/6": "16.6%",
|
| 32 |
+
"2/6": "33.3%",
|
| 33 |
+
"3/6": "50%",
|
| 34 |
+
"4/6": "66.6%",
|
| 35 |
+
"5/6": "83.3%"
|
| 36 |
+
} as Record<string, string>
|
| 37 |
+
);
|
| 38 |
+
|
| 39 |
+
const opacities = Array.from({ length: 100 }, (_, i) => i).reduce(
|
| 40 |
+
(acc, curr) => {
|
| 41 |
+
acc[curr] = curr / 100 + "";
|
| 42 |
+
|
| 43 |
+
return acc;
|
| 44 |
+
},
|
| 45 |
+
{} as Record<string, string>
|
| 46 |
+
);
|
| 47 |
+
|
| 48 |
+
const transitionDurations = Array.from({ length: 60 }, (_, i) => i).reduce(
|
| 49 |
+
(acc, curr) => {
|
| 50 |
+
acc[curr] = curr * 50 + "";
|
| 51 |
+
|
| 52 |
+
return acc;
|
| 53 |
+
},
|
| 54 |
+
{} as Record<string, string>
|
| 55 |
+
);
|
| 56 |
+
|
| 57 |
+
const themeConfig: Config = {
|
| 58 |
+
darkMode: "class",
|
| 59 |
+
content: [
|
| 60 |
+
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
| 61 |
+
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
| 62 |
+
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
| 63 |
+
"./components-new/**/*.{js,ts,jsx,tsx,mdx}",
|
| 64 |
+
"./styling-reference/ai-ready-website/app/**/*.{ts,tsx}",
|
| 65 |
+
"./styling-reference/ai-ready-website/components/**/*.{ts,tsx}",
|
| 66 |
+
"./styling-reference/ai-ready-website/components-new/**/*.{ts,tsx}",
|
| 67 |
+
],
|
| 68 |
+
theme: {
|
| 69 |
+
container: {
|
| 70 |
+
center: true,
|
| 71 |
+
padding: "2rem",
|
| 72 |
+
screens: {
|
| 73 |
+
"2xl": "1400px",
|
| 74 |
+
},
|
| 75 |
+
},
|
| 76 |
+
extend: {
|
| 77 |
+
fontFamily: {
|
| 78 |
+
sans: ["var(--font-geist-sans)", "var(--font-inter)", ...defaultTheme.fontFamily.sans],
|
| 79 |
+
mono: ["var(--font-geist-mono)", ...defaultTheme.fontFamily.mono],
|
| 80 |
+
ascii: ["var(--font-roboto-mono)", ...defaultTheme.fontFamily.mono]
|
| 81 |
+
},
|
| 82 |
+
fontSize: {
|
| 83 |
+
"title-h1": [
|
| 84 |
+
"60px",
|
| 85 |
+
{
|
| 86 |
+
"lineHeight": "64px",
|
| 87 |
+
"letterSpacing": "-0.3px",
|
| 88 |
+
"fontWeight": "500"
|
| 89 |
+
}
|
| 90 |
+
],
|
| 91 |
+
"title-h2": [
|
| 92 |
+
"52px",
|
| 93 |
+
{
|
| 94 |
+
"lineHeight": "56px",
|
| 95 |
+
"letterSpacing": "-0.52px",
|
| 96 |
+
"fontWeight": "500"
|
| 97 |
+
}
|
| 98 |
+
],
|
| 99 |
+
"title-h3": [
|
| 100 |
+
"40px",
|
| 101 |
+
{
|
| 102 |
+
"lineHeight": "44px",
|
| 103 |
+
"letterSpacing": "-0.4px",
|
| 104 |
+
"fontWeight": "500"
|
| 105 |
+
}
|
| 106 |
+
],
|
| 107 |
+
"title-h4": [
|
| 108 |
+
"32px",
|
| 109 |
+
{
|
| 110 |
+
"lineHeight": "36px",
|
| 111 |
+
"letterSpacing": "-0.32px",
|
| 112 |
+
"fontWeight": "500"
|
| 113 |
+
}
|
| 114 |
+
],
|
| 115 |
+
"title-h5": [
|
| 116 |
+
"24px",
|
| 117 |
+
{
|
| 118 |
+
"lineHeight": "32px",
|
| 119 |
+
"letterSpacing": "-0.24px",
|
| 120 |
+
"fontWeight": "500"
|
| 121 |
+
}
|
| 122 |
+
],
|
| 123 |
+
"body-x-large": [
|
| 124 |
+
"20px",
|
| 125 |
+
{
|
| 126 |
+
"lineHeight": "28px",
|
| 127 |
+
"letterSpacing": "-0.1px",
|
| 128 |
+
"fontWeight": "400"
|
| 129 |
+
}
|
| 130 |
+
],
|
| 131 |
+
"body-large": [
|
| 132 |
+
"16px",
|
| 133 |
+
{
|
| 134 |
+
"lineHeight": "24px",
|
| 135 |
+
"letterSpacing": "0px",
|
| 136 |
+
"fontWeight": "400"
|
| 137 |
+
}
|
| 138 |
+
],
|
| 139 |
+
"body-medium": [
|
| 140 |
+
"14px",
|
| 141 |
+
{
|
| 142 |
+
"lineHeight": "20px",
|
| 143 |
+
"letterSpacing": "0.14px",
|
| 144 |
+
"fontWeight": "400"
|
| 145 |
+
}
|
| 146 |
+
],
|
| 147 |
+
"body-small": [
|
| 148 |
+
"13px",
|
| 149 |
+
{
|
| 150 |
+
"lineHeight": "20px",
|
| 151 |
+
"letterSpacing": "0px",
|
| 152 |
+
"fontWeight": "400"
|
| 153 |
+
}
|
| 154 |
+
],
|
| 155 |
+
"body-input": [
|
| 156 |
+
"15px",
|
| 157 |
+
{
|
| 158 |
+
"lineHeight": "24px",
|
| 159 |
+
"letterSpacing": "0px",
|
| 160 |
+
"fontWeight": "400"
|
| 161 |
+
}
|
| 162 |
+
],
|
| 163 |
+
"label-x-large": [
|
| 164 |
+
"20px",
|
| 165 |
+
{
|
| 166 |
+
"lineHeight": "28px",
|
| 167 |
+
"letterSpacing": "-0.1px",
|
| 168 |
+
"fontWeight": "450"
|
| 169 |
+
}
|
| 170 |
+
],
|
| 171 |
+
"label-large": [
|
| 172 |
+
"16px",
|
| 173 |
+
{
|
| 174 |
+
"lineHeight": "24px",
|
| 175 |
+
"letterSpacing": "0px",
|
| 176 |
+
"fontWeight": "450"
|
| 177 |
+
}
|
| 178 |
+
],
|
| 179 |
+
"label-medium": [
|
| 180 |
+
"14px",
|
| 181 |
+
{
|
| 182 |
+
"lineHeight": "20px",
|
| 183 |
+
"letterSpacing": "0px",
|
| 184 |
+
"fontWeight": "450"
|
| 185 |
+
}
|
| 186 |
+
],
|
| 187 |
+
"label-small": [
|
| 188 |
+
"13px",
|
| 189 |
+
{
|
| 190 |
+
"lineHeight": "20px",
|
| 191 |
+
"letterSpacing": "0px",
|
| 192 |
+
"fontWeight": "450"
|
| 193 |
+
}
|
| 194 |
+
],
|
| 195 |
+
"label-x-small": [
|
| 196 |
+
"12px",
|
| 197 |
+
{
|
| 198 |
+
"lineHeight": "20px",
|
| 199 |
+
"letterSpacing": "0px",
|
| 200 |
+
"fontWeight": "450"
|
| 201 |
+
}
|
| 202 |
+
],
|
| 203 |
+
"mono-medium": [
|
| 204 |
+
"14px",
|
| 205 |
+
{
|
| 206 |
+
"lineHeight": "22px",
|
| 207 |
+
"letterSpacing": "0px",
|
| 208 |
+
"fontWeight": "400"
|
| 209 |
+
}
|
| 210 |
+
],
|
| 211 |
+
"mono-small": [
|
| 212 |
+
"13px",
|
| 213 |
+
{
|
| 214 |
+
"lineHeight": "20px",
|
| 215 |
+
"letterSpacing": "0px",
|
| 216 |
+
"fontWeight": "500"
|
| 217 |
+
}
|
| 218 |
+
],
|
| 219 |
+
"mono-x-small": [
|
| 220 |
+
"12px",
|
| 221 |
+
{
|
| 222 |
+
"lineHeight": "16px",
|
| 223 |
+
"letterSpacing": "0px",
|
| 224 |
+
"fontWeight": "400"
|
| 225 |
+
}
|
| 226 |
+
],
|
| 227 |
+
"title-blog": [
|
| 228 |
+
"28px",
|
| 229 |
+
{
|
| 230 |
+
"lineHeight": "36px",
|
| 231 |
+
"letterSpacing": "-0.28px",
|
| 232 |
+
"fontWeight": "500"
|
| 233 |
+
}
|
| 234 |
+
]
|
| 235 |
+
},
|
| 236 |
+
colors: {
|
| 237 |
+
transparent: "transparent",
|
| 238 |
+
current: "currentColor",
|
| 239 |
+
border: "hsl(var(--border))",
|
| 240 |
+
input: "hsl(var(--input))",
|
| 241 |
+
ring: "hsl(var(--ring))",
|
| 242 |
+
background: "hsl(var(--background))",
|
| 243 |
+
foreground: "hsl(var(--foreground))",
|
| 244 |
+
primary: {
|
| 245 |
+
DEFAULT: "hsl(var(--primary))",
|
| 246 |
+
foreground: "hsl(var(--primary-foreground))",
|
| 247 |
+
},
|
| 248 |
+
secondary: {
|
| 249 |
+
DEFAULT: "hsl(var(--secondary))",
|
| 250 |
+
foreground: "hsl(var(--secondary-foreground))",
|
| 251 |
+
},
|
| 252 |
+
destructive: {
|
| 253 |
+
DEFAULT: "hsl(var(--destructive))",
|
| 254 |
+
foreground: "hsl(var(--destructive-foreground))",
|
| 255 |
+
},
|
| 256 |
+
muted: {
|
| 257 |
+
DEFAULT: "hsl(var(--muted))",
|
| 258 |
+
foreground: "hsl(var(--muted-foreground))",
|
| 259 |
+
},
|
| 260 |
+
accent: {
|
| 261 |
+
DEFAULT: "hsl(var(--accent))",
|
| 262 |
+
foreground: "hsl(var(--accent-foreground))",
|
| 263 |
+
},
|
| 264 |
+
popover: {
|
| 265 |
+
DEFAULT: "hsl(var(--popover))",
|
| 266 |
+
foreground: "hsl(var(--popover-foreground))",
|
| 267 |
+
},
|
| 268 |
+
card: {
|
| 269 |
+
DEFAULT: "hsl(var(--card))",
|
| 270 |
+
foreground: "hsl(var(--card-foreground))",
|
| 271 |
+
},
|
| 272 |
+
...colors
|
| 273 |
+
},
|
| 274 |
+
screens: {
|
| 275 |
+
xs: { min: "390px" },
|
| 276 |
+
"xs-max": { max: "389px" },
|
| 277 |
+
sm: { min: "576px" },
|
| 278 |
+
"sm-max": { max: "575px" },
|
| 279 |
+
md: { min: "768px" },
|
| 280 |
+
"md-max": { max: "767px" },
|
| 281 |
+
lg: { min: "996px" },
|
| 282 |
+
"lg-max": { max: "995px" },
|
| 283 |
+
xl: { min: "1200px" },
|
| 284 |
+
"xl-max": { max: "1199px" }
|
| 285 |
+
},
|
| 286 |
+
opacity: opacities,
|
| 287 |
+
spacing: {
|
| 288 |
+
...sizes,
|
| 289 |
+
'root': 'var(--root-padding)'
|
| 290 |
+
},
|
| 291 |
+
width: sizes,
|
| 292 |
+
maxWidth: sizes,
|
| 293 |
+
height: sizes,
|
| 294 |
+
inset: sizes,
|
| 295 |
+
borderWidth: sizes,
|
| 296 |
+
backdropBlur: Array.from({ length: 20 }, (_, i) => i).reduce(
|
| 297 |
+
(acc, curr) => {
|
| 298 |
+
acc[curr] = curr + "px";
|
| 299 |
+
|
| 300 |
+
return acc;
|
| 301 |
+
},
|
| 302 |
+
{} as Record<string, string>
|
| 303 |
+
),
|
| 304 |
+
transitionTimingFunction: { DEFAULT: "cubic-bezier(0.25, 0.1, 0.25, 1)" },
|
| 305 |
+
transitionDuration: {
|
| 306 |
+
DEFAULT: "200ms",
|
| 307 |
+
...transitionDurations
|
| 308 |
+
},
|
| 309 |
+
transitionDelay: {
|
| 310 |
+
...transitionDurations
|
| 311 |
+
},
|
| 312 |
+
borderRadius: (() => {
|
| 313 |
+
const radius: Record<string | number, string> = {
|
| 314 |
+
full: "999px",
|
| 315 |
+
inherit: "inherit",
|
| 316 |
+
0: "0px",
|
| 317 |
+
lg: "var(--radius)",
|
| 318 |
+
md: "calc(var(--radius) - 2px)",
|
| 319 |
+
sm: "calc(var(--radius) - 4px)",
|
| 320 |
+
};
|
| 321 |
+
|
| 322 |
+
for (let i = 1; i <= 32; i += 1) {
|
| 323 |
+
radius[i] = `${i}px`;
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
return radius;
|
| 327 |
+
})()
|
| 328 |
+
}
|
| 329 |
+
},
|
| 330 |
+
plugins: [
|
| 331 |
+
({
|
| 332 |
+
addUtilities, matchUtilities
|
| 333 |
+
}: any) => {
|
| 334 |
+
addUtilities({
|
| 335 |
+
// Inside-border utilities are defined in inside-border-fix.css to avoid Tailwind variant conflicts
|
| 336 |
+
'.mask-border': {
|
| 337 |
+
"mask": "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
|
| 338 |
+
"mask-composite": "exclude",
|
| 339 |
+
"pointer-events": "none"
|
| 340 |
+
},
|
| 341 |
+
".center-x": { "@apply absolute left-1/2 -translate-x-1/2": {} },
|
| 342 |
+
".center-y": { "@apply absolute top-1/2 -translate-y-1/2": {} },
|
| 343 |
+
".center": { "@apply absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2": {} },
|
| 344 |
+
".flex-center": { "@apply flex items-center justify-center": {} },
|
| 345 |
+
".overlay": { "@apply absolute top-0 left-0 w-full h-full rounded-inherit": {} },
|
| 346 |
+
".text-gradient": { "@apply !bg-clip-text !text-transparent": {} }
|
| 347 |
+
});
|
| 348 |
+
matchUtilities(
|
| 349 |
+
{
|
| 350 |
+
'cw': (value: string) => {
|
| 351 |
+
const width = parseInt(value);
|
| 352 |
+
|
| 353 |
+
return {
|
| 354 |
+
width: value,
|
| 355 |
+
left: `calc(50% - ${width / 2}px)`
|
| 356 |
+
};
|
| 357 |
+
},
|
| 358 |
+
'ch': (value: string) => {
|
| 359 |
+
const height = parseInt(value);
|
| 360 |
+
|
| 361 |
+
return {
|
| 362 |
+
height: value,
|
| 363 |
+
top: `calc(50% - ${height / 2}px)`
|
| 364 |
+
};
|
| 365 |
+
},
|
| 366 |
+
'cs': (value: string) => {
|
| 367 |
+
const size = parseInt(value);
|
| 368 |
+
|
| 369 |
+
return {
|
| 370 |
+
width: size,
|
| 371 |
+
height: size,
|
| 372 |
+
left: `calc(50% - ${size / 2}px)`,
|
| 373 |
+
top: `calc(50% - ${size / 2}px)`
|
| 374 |
+
};
|
| 375 |
+
},
|
| 376 |
+
'cmw': (value: string) => {
|
| 377 |
+
const [maxWidth, paddingX] = value.split(',').map((v) => parseInt(v));
|
| 378 |
+
|
| 379 |
+
const width = paddingX ? `calc(100% - ${paddingX * 2}px)` : '100%';
|
| 380 |
+
|
| 381 |
+
return {
|
| 382 |
+
maxWidth: maxWidth,
|
| 383 |
+
width,
|
| 384 |
+
left: `calc(50% - (min(${maxWidth}px, ${width}) / 2))`
|
| 385 |
+
};
|
| 386 |
+
},
|
| 387 |
+
'mw': (value: string) => {
|
| 388 |
+
const [maxWidth, paddingX] = value.split(',').map((v) => parseInt(v));
|
| 389 |
+
|
| 390 |
+
const width = paddingX ? `calc(100% - ${paddingX * 2}px)` : '100%';
|
| 391 |
+
|
| 392 |
+
return {
|
| 393 |
+
maxWidth: maxWidth,
|
| 394 |
+
width
|
| 395 |
+
};
|
| 396 |
+
}
|
| 397 |
+
},
|
| 398 |
+
{ values: sizes }
|
| 399 |
+
);
|
| 400 |
+
},
|
| 401 |
+
require("tailwind-gradient-mask-image"),
|
| 402 |
+
require("@tailwindcss/typography"),
|
| 403 |
+
]
|
| 404 |
+
};
|
| 405 |
+
|
| 406 |
+
export default themeConfig;
|
tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2017",
|
| 4 |
+
"lib": ["dom", "dom.iterable", "esnext"],
|
| 5 |
+
"allowJs": true,
|
| 6 |
+
"skipLibCheck": true,
|
| 7 |
+
"strict": true,
|
| 8 |
+
"noEmit": true,
|
| 9 |
+
"esModuleInterop": true,
|
| 10 |
+
"module": "esnext",
|
| 11 |
+
"moduleResolution": "bundler",
|
| 12 |
+
"resolveJsonModule": true,
|
| 13 |
+
"isolatedModules": true,
|
| 14 |
+
"jsx": "preserve",
|
| 15 |
+
"incremental": true,
|
| 16 |
+
"plugins": [
|
| 17 |
+
{
|
| 18 |
+
"name": "next"
|
| 19 |
+
}
|
| 20 |
+
],
|
| 21 |
+
"paths": {
|
| 22 |
+
"@/*": ["./*"]
|
| 23 |
+
}
|
| 24 |
+
},
|
| 25 |
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
| 26 |
+
"exclude": ["node_modules", "examples", "tests", "lib/e2b-backends/archive", "styles"]
|
| 27 |
+
}
|
types/conversation.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Conversation tracking types for maintaining context across interactions
|
| 2 |
+
|
| 3 |
+
export interface ConversationMessage {
|
| 4 |
+
id: string;
|
| 5 |
+
role: 'user' | 'assistant';
|
| 6 |
+
content: string;
|
| 7 |
+
timestamp: number;
|
| 8 |
+
metadata?: {
|
| 9 |
+
editedFiles?: string[]; // Files edited in this interaction
|
| 10 |
+
addedPackages?: string[]; // Packages added in this interaction
|
| 11 |
+
editType?: string; // Type of edit performed
|
| 12 |
+
sandboxId?: string; // Sandbox ID at time of message
|
| 13 |
+
};
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
export interface ConversationEdit {
|
| 17 |
+
timestamp: number;
|
| 18 |
+
userRequest: string;
|
| 19 |
+
editType: string;
|
| 20 |
+
targetFiles: string[];
|
| 21 |
+
confidence: number;
|
| 22 |
+
outcome: 'success' | 'partial' | 'failed';
|
| 23 |
+
errorMessage?: string;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
export interface ConversationContext {
|
| 27 |
+
messages: ConversationMessage[];
|
| 28 |
+
edits: ConversationEdit[];
|
| 29 |
+
currentTopic?: string; // Current focus area (e.g., "header styling", "hero section")
|
| 30 |
+
projectEvolution: {
|
| 31 |
+
initialState?: string; // Description of initial project state
|
| 32 |
+
majorChanges: Array<{
|
| 33 |
+
timestamp: number;
|
| 34 |
+
description: string;
|
| 35 |
+
filesAffected: string[];
|
| 36 |
+
}>;
|
| 37 |
+
};
|
| 38 |
+
userPreferences: {
|
| 39 |
+
editStyle?: 'targeted' | 'comprehensive'; // How the user prefers edits
|
| 40 |
+
commonRequests?: string[]; // Common patterns in user requests
|
| 41 |
+
packagePreferences?: string[]; // Commonly used packages
|
| 42 |
+
};
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
export interface ConversationState {
|
| 46 |
+
conversationId: string;
|
| 47 |
+
startedAt: number;
|
| 48 |
+
lastUpdated: number;
|
| 49 |
+
context: ConversationContext;
|
| 50 |
+
}
|
types/file-manifest.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// File manifest types for enhanced edit tracking
|
| 2 |
+
|
| 3 |
+
export interface FileInfo {
|
| 4 |
+
content: string;
|
| 5 |
+
type: 'component' | 'page' | 'style' | 'config' | 'utility' | 'layout' | 'hook' | 'context';
|
| 6 |
+
exports?: string[]; // Named exports and default export
|
| 7 |
+
imports?: ImportInfo[]; // Dependencies
|
| 8 |
+
lastModified: number;
|
| 9 |
+
componentInfo?: ComponentInfo; // For React components
|
| 10 |
+
path: string;
|
| 11 |
+
relativePath: string; // Path relative to src/
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
export interface ImportInfo {
|
| 15 |
+
source: string; // e.g., './Header', 'react', '@/components/Button'
|
| 16 |
+
imports: string[]; // Named imports
|
| 17 |
+
defaultImport?: string; // Default import name
|
| 18 |
+
isLocal: boolean; // true if starts with './' or '@/'
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
export interface ComponentInfo {
|
| 22 |
+
name: string;
|
| 23 |
+
props?: string[]; // Prop names if detectable
|
| 24 |
+
hooks?: string[]; // Hooks used (useState, useEffect, etc)
|
| 25 |
+
hasState: boolean;
|
| 26 |
+
childComponents?: string[]; // Components rendered inside
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
export interface RouteInfo {
|
| 30 |
+
path: string; // Route path (e.g., '/videos', '/about')
|
| 31 |
+
component: string; // Component file path
|
| 32 |
+
layout?: string; // Layout component if any
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
export interface ComponentTree {
|
| 36 |
+
[componentName: string]: {
|
| 37 |
+
file: string;
|
| 38 |
+
imports: string[]; // Components it imports
|
| 39 |
+
importedBy: string[]; // Components that import it
|
| 40 |
+
type: 'page' | 'layout' | 'component';
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
export interface FileManifest {
|
| 45 |
+
files: Record<string, FileInfo>;
|
| 46 |
+
routes: RouteInfo[];
|
| 47 |
+
componentTree: ComponentTree;
|
| 48 |
+
entryPoint: string; // Usually App.jsx or main.jsx
|
| 49 |
+
styleFiles: string[]; // All CSS files
|
| 50 |
+
timestamp: number;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
// Edit classification types
|
| 54 |
+
export enum EditType {
|
| 55 |
+
UPDATE_COMPONENT = 'UPDATE_COMPONENT', // "update the header", "change button color"
|
| 56 |
+
ADD_FEATURE = 'ADD_FEATURE', // "add a videos page", "create new component"
|
| 57 |
+
FIX_ISSUE = 'FIX_ISSUE', // "fix the styling", "resolve error"
|
| 58 |
+
REFACTOR = 'REFACTOR', // "reorganize", "clean up"
|
| 59 |
+
FULL_REBUILD = 'FULL_REBUILD', // "start over", "recreate everything"
|
| 60 |
+
UPDATE_STYLE = 'UPDATE_STYLE', // "change colors", "update theme"
|
| 61 |
+
ADD_DEPENDENCY = 'ADD_DEPENDENCY' // "install package", "add library"
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
export interface EditIntent {
|
| 65 |
+
type: EditType;
|
| 66 |
+
targetFiles: string[]; // Predicted files to edit
|
| 67 |
+
confidence: number; // 0-1 confidence score
|
| 68 |
+
description: string; // Human-readable description
|
| 69 |
+
suggestedContext: string[]; // Additional files to include for context
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
// Patterns for intent detection
|
| 73 |
+
export interface IntentPattern {
|
| 74 |
+
patterns: RegExp[];
|
| 75 |
+
type: EditType;
|
| 76 |
+
fileResolver: (prompt: string, manifest: FileManifest) => string[];
|
| 77 |
+
}
|
types/sandbox.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Global types for sandbox file management
|
| 2 |
+
|
| 3 |
+
export interface SandboxFile {
|
| 4 |
+
content: string;
|
| 5 |
+
lastModified: number;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
export interface SandboxFileCache {
|
| 9 |
+
files: Record<string, SandboxFile>;
|
| 10 |
+
lastSync: number;
|
| 11 |
+
sandboxId: string;
|
| 12 |
+
manifest?: any; // FileManifest type from file-manifest.ts
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
export interface SandboxState {
|
| 16 |
+
fileCache: SandboxFileCache | null;
|
| 17 |
+
sandbox: any; // E2B sandbox instance
|
| 18 |
+
sandboxData: {
|
| 19 |
+
sandboxId: string;
|
| 20 |
+
url: string;
|
| 21 |
+
} | null;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
// Declare global types
|
| 25 |
+
declare global {
|
| 26 |
+
var activeSandbox: any;
|
| 27 |
+
var sandboxState: SandboxState;
|
| 28 |
+
var existingFiles: Set<string>;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
export {};
|
utils/cn.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import classNames from "classnames";
|
| 2 |
+
|
| 3 |
+
export function cn(...classes: classNames.ArgumentArray) {
|
| 4 |
+
return classNames(...classes);
|
| 5 |
+
}
|