diff --git a/.automaker/context/gemini.md b/.automaker/context/gemini.md new file mode 100644 index 00000000..4ef2912a --- /dev/null +++ b/.automaker/context/gemini.md @@ -0,0 +1,70 @@ +You are a very strong reasoner and planner. Use these critical instructions to structure your plans, thoughts, and responses. + +Before taking any action (either tool calls or responses to the user), you must proactively, methodically, and independently plan and reason about: + +1. Logical dependencies and constraints: + +Analyze the intended action against the following factors. Resolve conflicts in order of importance: + +1.1) Policy-based rules, mandatory prerequisites, and constraints. +1.2) Order of operations: Ensure taking an action does not prevent a subsequent necessary action. +ā1.2.1) The user may request actions in a random order, but you may need to reorder operations to maximize successful completion of the task. +1.3) Other prerequisites (information and/or actions needed). +1.4) Explicit user constraints or preferences. + +2. Risk assessment: + +What are the consequences of taking the action? Will the new state cause any future issues? + +2.1) For exploratory tasks (like searches), missing optional parameters is a LOW risk. +Prefer calling the tool with the available information over asking the user, unless your Rule 1 (Logical Dependencies) reasoning determines that optional information is required for a later step in your plan. + +3. Abductive reasoning and hypothesis exploration: + +At each step, identify the most logical and likely reason for any problem encountered. + +3.1) Look beyond immediate or obvious causes. The most likely reason may not be the simplest and may require deeper inference. +3.2) Hypotheses may require additional research. Each hypothesis may take multiple steps to test. +3.3) Prioritize hypotheses based on likelihood, but do not discard less likely ones prematurely. A low-probability event may still be the root cause. + +4. Outcome evaluation and adaptability: + +Does the previous observation require any changes to your plan? + +4.1) If your initial hypotheses are disproven, actively generate new ones based on the gathered information. + +5. Information availability: + +Incorporate all applicable and alternative sources of information, including: + +5.1) Using available tools and their capabilities +5.2) All policies, rules, checklists, and constraints +5.3) Previous observations and conversation history +5.4) Information only available by asking the user + +6. Precision and Grounding: + +Ensure your reasoning is extremely precise and relevant to each exact ongoing situation. + +6.1) Verify your claims by quoting the exact applicable information (including policies) when referring to them. + +7. Completeness: + +Ensure that all requirements, constraints, options, and preferences are exhaustively incorporated into your plan. + +7.1) Resolve conflicts using the order of importance in #1. +7.2) Avoid premature conclusions: There may be multiple relevant options for a given situation. +ā7.2.1) To check for whether an option is relevant, reason about all information sources from #5. +ā7.2.2) You may need to consult the user to even know whether something is applicable. Do not assume it is not applicable without checking. +7.3) Review applicable sources of information from #5 to confirm which are relevant to the current state. + +8. Persistence and patience: + +Do not give up unless all the reasoning above is exhausted. + +8.1) Don't be dissuaded by time taken or user frustration. +8.2) This persistence must be intelligent: On transient errors (e.g. please try again), you must retry unless an explicit retry limit (e.g., max x tries) has been reached. If such a limit is hit, you must stop. On other errors, you must change your strategy or arguments, not repeat the same failed call. + +9. Inhibit your response: + +Only take an action after all the above reasoning is completed. Once you've taken an action, you cannot take it back. diff --git a/app/electron/auto-mode-service.js b/app/electron/auto-mode-service.js index a39ba88f..412973d9 100644 --- a/app/electron/auto-mode-service.js +++ b/app/electron/auto-mode-service.js @@ -32,7 +32,7 @@ class AutoModeService { query: null, projectPath: null, sendToRenderer: null, - isActive: () => this.runningFeatures.has(featureId) + isActive: () => this.runningFeatures.has(featureId), }; return context; } @@ -126,7 +126,11 @@ class AutoModeService { console.log(`[AutoMode] Running feature: ${feature.description}`); // Update feature status to in_progress - await featureLoader.updateFeatureStatus(featureId, "in_progress", projectPath); + await featureLoader.updateFeatureStatus( + featureId, + "in_progress", + projectPath + ); sendToRenderer({ type: "auto_mode_feature_start", @@ -135,7 +139,12 @@ class AutoModeService { }); // Implement the feature - const result = await featureExecutor.implementFeature(feature, projectPath, sendToRenderer, execution); + const result = await featureExecutor.implementFeature( + feature, + projectPath, + sendToRenderer, + execution + ); // Update feature status based on result // For skipTests features, go to waiting_approval on success instead of verified @@ -145,7 +154,11 @@ class AutoModeService { } else { newStatus = "backlog"; } - await featureLoader.updateFeatureStatus(feature.id, newStatus, projectPath); + await featureLoader.updateFeatureStatus( + feature.id, + newStatus, + projectPath + ); // Delete context file only if verified (not for waiting_approval) if (newStatus === "verified") { @@ -214,11 +227,20 @@ class AutoModeService { }); // Verify the feature by running tests - const result = await featureVerifier.verifyFeatureTests(feature, projectPath, sendToRenderer, execution); + const result = await featureVerifier.verifyFeatureTests( + feature, + projectPath, + sendToRenderer, + execution + ); // Update feature status based on result const newStatus = result.passes ? "verified" : "in_progress"; - await featureLoader.updateFeatureStatus(featureId, newStatus, projectPath); + await featureLoader.updateFeatureStatus( + featureId, + newStatus, + projectPath + ); // Delete context file if verified if (newStatus === "verified") { @@ -287,10 +309,19 @@ class AutoModeService { }); // Read existing context - const previousContext = await contextManager.readContextFile(projectPath, featureId); + const previousContext = await contextManager.readContextFile( + projectPath, + featureId + ); // Resume implementation with context - const result = await featureExecutor.resumeFeatureWithContext(feature, projectPath, sendToRenderer, previousContext, execution); + const result = await featureExecutor.resumeFeatureWithContext( + feature, + projectPath, + sendToRenderer, + previousContext, + execution + ); // If the agent ends early without finishing, automatically re-run let attempts = 0; @@ -304,11 +335,16 @@ class AutoModeService { if (updatedFeature && updatedFeature.status === "in_progress") { attempts++; - console.log(`[AutoMode] Feature ended early, auto-retrying (attempt ${attempts}/${maxAttempts})...`); + console.log( + `[AutoMode] Feature ended early, auto-retrying (attempt ${attempts}/${maxAttempts})...` + ); // Update context file with retry message - await contextManager.writeToContextFile(projectPath, featureId, - `\n\nš Auto-retry #${attempts} - Continuing implementation...\n\n`); + await contextManager.writeToContextFile( + projectPath, + featureId, + `\n\nš Auto-retry #${attempts} - Continuing implementation...\n\n` + ); sendToRenderer({ type: "auto_mode_progress", @@ -317,10 +353,19 @@ class AutoModeService { }); // Read updated context - const retryContext = await contextManager.readContextFile(projectPath, featureId); + const retryContext = await contextManager.readContextFile( + projectPath, + featureId + ); // Resume again with full context - finalResult = await featureExecutor.resumeFeatureWithContext(feature, projectPath, sendToRenderer, retryContext, execution); + finalResult = await featureExecutor.resumeFeatureWithContext( + feature, + projectPath, + sendToRenderer, + retryContext, + execution + ); } else { break; } @@ -334,7 +379,11 @@ class AutoModeService { } else { newStatus = "in_progress"; } - await featureLoader.updateFeatureStatus(featureId, newStatus, projectPath); + await featureLoader.updateFeatureStatus( + featureId, + newStatus, + projectPath + ); // Delete context file only if verified (not for waiting_approval) if (newStatus === "verified") { @@ -389,7 +438,9 @@ class AutoModeService { // Skip if this feature is already running (via manual trigger) if (this.runningFeatures.has(currentFeatureId)) { - console.log(`[AutoMode] Skipping ${currentFeatureId} - already running`); + console.log( + `[AutoMode] Skipping ${currentFeatureId} - already running` + ); await this.sleep(3000); continue; } @@ -409,7 +460,12 @@ class AutoModeService { this.runningFeatures.set(currentFeatureId, execution); // Implement the feature - const result = await featureExecutor.implementFeature(nextFeature, projectPath, sendToRenderer, execution); + const result = await featureExecutor.implementFeature( + nextFeature, + projectPath, + sendToRenderer, + execution + ); // Update feature status based on result // For skipTests features, go to waiting_approval on success instead of verified @@ -419,7 +475,11 @@ class AutoModeService { } else { newStatus = "backlog"; } - await featureLoader.updateFeatureStatus(nextFeature.id, newStatus, projectPath); + await featureLoader.updateFeatureStatus( + nextFeature.id, + newStatus, + projectPath + ); // Delete context file only if verified (not for waiting_approval) if (newStatus === "verified") { @@ -495,7 +555,12 @@ class AutoModeService { }); // Perform the analysis - const result = await projectAnalyzer.runProjectAnalysis(projectPath, analysisId, sendToRenderer, execution); + const result = await projectAnalyzer.runProjectAnalysis( + projectPath, + analysisId, + sendToRenderer, + execution + ); sendToRenderer({ type: "auto_mode_feature_complete", @@ -543,13 +608,21 @@ class AutoModeService { * Follow-up on a feature with additional prompt * This continues work on a feature that's in waiting_approval status */ - async followUpFeature({ projectPath, featureId, prompt, imagePaths, sendToRenderer }) { + async followUpFeature({ + projectPath, + featureId, + prompt, + imagePaths, + sendToRenderer, + }) { // Check if this feature is already running if (this.runningFeatures.has(featureId)) { throw new Error(`Feature ${featureId} is already running`); } - console.log(`[AutoMode] Follow-up on feature: ${featureId} with prompt: ${prompt}`); + console.log( + `[AutoMode] Follow-up on feature: ${featureId} with prompt: ${prompt}` + ); // Register this feature as running const execution = this.createExecutionContext(featureId); @@ -559,7 +632,14 @@ class AutoModeService { // Start the async work in the background (don't await) // This allows the API to return immediately so the modal can close - this.runFollowUpWork({ projectPath, featureId, prompt, imagePaths, sendToRenderer, execution }).catch((error) => { + this.runFollowUpWork({ + projectPath, + featureId, + prompt, + imagePaths, + sendToRenderer, + execution, + }).catch((error) => { console.error("[AutoMode] Follow-up work error:", error); this.runningFeatures.delete(featureId); }); @@ -571,7 +651,14 @@ class AutoModeService { /** * Internal method to run follow-up work asynchronously */ - async runFollowUpWork({ projectPath, featureId, prompt, imagePaths, sendToRenderer, execution }) { + async runFollowUpWork({ + projectPath, + featureId, + prompt, + imagePaths, + sendToRenderer, + execution, + }) { try { // Load features const features = await featureLoader.loadFeatures(projectPath); @@ -584,7 +671,11 @@ class AutoModeService { console.log(`[AutoMode] Following up on feature: ${feature.description}`); // Update status to in_progress - await featureLoader.updateFeatureStatus(featureId, "in_progress", projectPath); + await featureLoader.updateFeatureStatus( + featureId, + "in_progress", + projectPath + ); sendToRenderer({ type: "auto_mode_feature_start", @@ -593,11 +684,18 @@ class AutoModeService { }); // Read existing context and append follow-up prompt - const previousContext = await contextManager.readContextFile(projectPath, featureId); + const previousContext = await contextManager.readContextFile( + projectPath, + featureId + ); // Append follow-up prompt to context const followUpContext = `${previousContext}\n\n## Follow-up Instructions\n\n${prompt}`; - await contextManager.writeToContextFile(projectPath, featureId, `\n\n## Follow-up Instructions\n\n${prompt}`); + await contextManager.writeToContextFile( + projectPath, + featureId, + `\n\n## Follow-up Instructions\n\n${prompt}` + ); // Resume implementation with follow-up context and optional images const result = await featureExecutor.resumeFeatureWithContext( @@ -610,10 +708,16 @@ class AutoModeService { // For skipTests features, go to waiting_approval on success instead of verified const newStatus = result.passes - ? (feature.skipTests ? "waiting_approval" : "verified") + ? feature.skipTests + ? "waiting_approval" + : "verified" : "in_progress"; - await featureLoader.updateFeatureStatus(feature.id, newStatus, projectPath); + await featureLoader.updateFeatureStatus( + feature.id, + newStatus, + projectPath + ); // Delete context file if verified (only for non-skipTests) if (newStatus === "verified") { @@ -674,10 +778,19 @@ class AutoModeService { }); // Run git commit via the agent - const commitResult = await featureExecutor.commitChangesOnly(feature, projectPath, sendToRenderer, execution); + const commitResult = await featureExecutor.commitChangesOnly( + feature, + projectPath, + sendToRenderer, + execution + ); // Update status to verified - await featureLoader.updateFeatureStatus(featureId, "verified", projectPath); + await featureLoader.updateFeatureStatus( + featureId, + "verified", + projectPath + ); // Delete context file await contextManager.deleteContextFile(projectPath, featureId); diff --git a/app/electron/services/prompt-builder.js b/app/electron/services/prompt-builder.js index 4ec4c257..cd75ac36 100644 --- a/app/electron/services/prompt-builder.js +++ b/app/electron/services/prompt-builder.js @@ -25,17 +25,25 @@ ${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")} 1. Read the project files to understand the current codebase structure 2. Implement the feature according to the description and steps -${feature.skipTests - ? "3. Test the implementation manually (no automated tests needed for skipTests features)" - : "3. Write Playwright tests to verify the feature works correctly\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"} -${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json -${feature.skipTests - ? "5. **DO NOT commit changes** - the user will review and commit manually" - : "7. Commit your changes with git"} +${ + feature.skipTests + ? "3. Test the implementation manually (no automated tests needed for skipTests features)" + : "3. Write Playwright tests to verify the feature works correctly\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification" +} +${ + feature.skipTests ? "4" : "6" +}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json +${ + feature.skipTests + ? "5. **DO NOT commit changes** - the user will review and commit manually" + : "7. Commit your changes with git" +} **IMPORTANT - Updating Feature Status:** -When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: +When you have completed the feature${ + feature.skipTests ? "" : " and all tests pass" + }, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: - Call the tool with: featureId="${feature.id}" and status="verified" - **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes" - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions @@ -51,7 +59,9 @@ When calling UpdateFeatureStatus, you MUST include a summary parameter that desc Example: \`\`\` -UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") +UpdateFeatureStatus(featureId="${ + feature.id + }", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") \`\`\` The summary will be displayed on the Kanban card so the user can see what was done without checking the code. @@ -61,14 +71,18 @@ The summary will be displayed on the Kanban card so the user can see what was do - Focus ONLY on implementing this specific feature - Write clean, production-quality code - Add proper error handling -${feature.skipTests - ? "- Skip automated testing (skipTests=true) - user will manually verify" - : "- Write comprehensive Playwright tests\n- Ensure all existing tests still pass\n- Mark the feature as passing only when all tests are green\n- **CRITICAL: Delete test files after verification** - tests accumulate and become brittle"} +${ + feature.skipTests + ? "- Skip automated testing (skipTests=true) - user will manually verify" + : "- Write comprehensive Playwright tests\n- Ensure all existing tests still pass\n- Mark the feature as passing only when all tests are green\n- **CRITICAL: Delete test files after verification** - tests accumulate and become brittle" +} - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Always include a summary when marking feature as verified** -${feature.skipTests - ? "- **DO NOT commit changes** - user will review and commit manually" - : "- Make a git commit when complete"} +${ + feature.skipTests + ? "- **DO NOT commit changes** - user will review and commit manually" + : "- Make a git commit when complete" +} **Testing Utilities (CRITICAL):** @@ -119,9 +133,10 @@ ${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")} 1. Read the project files to understand the current implementation 2. If the feature is not fully implemented, continue implementing it -${feature.skipTests - ? "3. Test the implementation manually (no automated tests needed for skipTests features)" - : `3. Write or update Playwright tests to verify the feature works correctly +${ + feature.skipTests + ? "3. Test the implementation manually (no automated tests needed for skipTests features)" + : `3. Write or update Playwright tests to verify the feature works correctly 4. Run the Playwright tests: npx playwright test tests/[feature-name].spec.ts 5. Check if all tests pass 6. **If ANY tests fail:** @@ -131,15 +146,22 @@ ${feature.skipTests - Re-run the tests to verify the fixes - **REPEAT this process until ALL tests pass** 7. **If ALL tests pass:** - - **DELETE the test file(s) for this feature** - tests are only for immediate verification`} -${feature.skipTests ? "4" : "8"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json -${feature.skipTests - ? "5. **DO NOT commit changes** - the user will review and commit manually" - : "9. Explain what was implemented/fixed and that all tests passed\n10. Commit your changes with git"} + - **DELETE the test file(s) for this feature** - tests are only for immediate verification` +} +${ + feature.skipTests ? "4" : "8" +}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json +${ + feature.skipTests + ? "5. **DO NOT commit changes** - the user will review and commit manually" + : "9. Explain what was implemented/fixed and that all tests passed\n10. Commit your changes with git" +} **IMPORTANT - Updating Feature Status:** -When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: +When you have completed the feature${ + feature.skipTests ? "" : " and all tests pass" + }, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: - Call the tool with: featureId="${feature.id}" and status="verified" - **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes" - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions @@ -155,7 +177,9 @@ When calling UpdateFeatureStatus, you MUST include a summary parameter that desc Example: \`\`\` -UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") +UpdateFeatureStatus(featureId="${ + feature.id + }", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") \`\`\` The summary will be displayed on the Kanban card so the user can see what was done without checking the code. @@ -173,9 +197,11 @@ rm tests/[feature-name].spec.ts \`\`\` **Important:** -${feature.skipTests - ? "- Skip automated testing (skipTests=true) - user will manually verify\n- **DO NOT commit changes** - user will review and commit manually" - : "- **CONTINUE IMPLEMENTING until all tests pass** - don't stop at the first failure\n- Only mark as verified if Playwright tests pass\n- **CRITICAL: Delete test files after they pass** - tests should not accumulate\n- Update test utilities if functionality changed\n- Make a git commit when the feature is complete\n- Be thorough and persistent in fixing issues"} +${ + feature.skipTests + ? "- Skip automated testing (skipTests=true) - user will manually verify\n- **DO NOT commit changes** - user will review and commit manually" + : "- **CONTINUE IMPLEMENTING until all tests pass** - don't stop at the first failure\n- Only mark as verified if Playwright tests pass\n- **CRITICAL: Delete test files after they pass** - tests should not accumulate\n- Update test utilities if functionality changed\n- Make a git commit when the feature is complete\n- Be thorough and persistent in fixing issues" +} - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Always include a summary when marking feature as verified** @@ -211,17 +237,25 @@ Continue where you left off and complete the feature implementation: 1. Review the previous work context above to understand what has been done 2. Continue implementing the feature according to the description and steps -${feature.skipTests - ? "3. Test the implementation manually (no automated tests needed for skipTests features)" - : "3. Write Playwright tests to verify the feature works correctly (if not already done)\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"} -${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json -${feature.skipTests - ? "5. **DO NOT commit changes** - the user will review and commit manually" - : "7. Commit your changes with git"} +${ + feature.skipTests + ? "3. Test the implementation manually (no automated tests needed for skipTests features)" + : "3. Write Playwright tests to verify the feature works correctly (if not already done)\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification" +} +${ + feature.skipTests ? "4" : "6" +}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json +${ + feature.skipTests + ? "5. **DO NOT commit changes** - the user will review and commit manually" + : "7. Commit your changes with git" +} **IMPORTANT - Updating Feature Status:** -When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: +When you have completed the feature${ + feature.skipTests ? "" : " and all tests pass" + }, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: - Call the tool with: featureId="${feature.id}" and status="verified" - **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes" - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions @@ -237,7 +271,9 @@ When calling UpdateFeatureStatus, you MUST include a summary parameter that desc Example: \`\`\` -UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") +UpdateFeatureStatus(featureId="${ + feature.id + }", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.") \`\`\` The summary will be displayed on the Kanban card so the user can see what was done without checking the code. @@ -247,14 +283,18 @@ The summary will be displayed on the Kanban card so the user can see what was do - Review what was already done in the previous context - Don't redo work that's already complete - continue from where it left off - Focus on completing any remaining tasks -${feature.skipTests - ? "- Skip automated testing (skipTests=true) - user will manually verify" - : "- Write comprehensive Playwright tests if not already done\n- Ensure all tests pass before marking as verified\n- **CRITICAL: Delete test files after verification**"} +${ + feature.skipTests + ? "- Skip automated testing (skipTests=true) - user will manually verify" + : "- Write comprehensive Playwright tests if not already done\n- Ensure all tests pass before marking as verified\n- **CRITICAL: Delete test files after verification**" +} - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Always include a summary when marking feature as verified** -${feature.skipTests - ? "- **DO NOT commit changes** - user will review and commit manually" - : "- Make a git commit when complete"} +${ + feature.skipTests + ? "- **DO NOT commit changes** - user will review and commit manually" + : "- Make a git commit when complete" +} Begin by assessing what's been done and what remains to be completed.`; } diff --git a/app/src/app/globals.css b/app/src/app/globals.css index 83a7a25a..af2f97c0 100644 --- a/app/src/app/globals.css +++ b/app/src/app/globals.css @@ -2,6 +2,16 @@ @import "tw-animate-css"; @custom-variant dark (&:is(.dark *)); +@custom-variant retro (&:is(.retro *)); +@custom-variant dracula (&:is(.dracula *)); +@custom-variant nord (&:is(.nord *)); +@custom-variant monokai (&:is(.monokai *)); +@custom-variant tokyonight (&:is(.tokyonight *)); +@custom-variant solarized (&:is(.solarized *)); +@custom-variant gruvbox (&:is(.gruvbox *)); +@custom-variant catppuccin (&:is(.catppuccin *)); +@custom-variant onedark (&:is(.onedark *)); +@custom-variant synthwave (&:is(.synthwave *)); @theme inline { --color-background: var(--background); @@ -62,6 +72,7 @@ } :root { + /* Default to light mode */ --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); @@ -94,6 +105,57 @@ --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); + --background-50: oklch(1 0 0 / 0.5); + --background-80: oklch(1 0 0 / 0.8); + --foreground-secondary: oklch(0.4 0 0); + --foreground-muted: oklch(0.556 0 0); + --border-glass: oklch(0.145 0 0 / 0.1); + --brand-400: oklch(0.6 0.22 265); + --brand-500: oklch(0.55 0.25 265); + --brand-600: oklch(0.5 0.28 270); +} + +.light { + /* Explicit light mode - same as root but ensures it overrides any dark defaults */ + --background: oklch(1 0 0); /* White */ + --background-50: oklch(1 0 0 / 0.5); + --background-80: oklch(1 0 0 / 0.8); + --foreground: oklch(0.145 0 0); /* Dark text */ + --foreground-secondary: oklch(0.4 0 0); + --foreground-muted: oklch(0.556 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.55 0.25 265); + --primary-foreground: oklch(1 0 0); + --brand-400: oklch(0.6 0.22 265); + --brand-500: oklch(0.55 0.25 265); + --brand-600: oklch(0.5 0.28 270); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.95 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --border-glass: oklch(0.145 0 0 / 0.1); + --input: oklch(1 0 0); + --ring: oklch(0.55 0.25 265); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.98 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.55 0.25 265); + --sidebar-primary-foreground: oklch(1 0 0); + --sidebar-accent: oklch(0.95 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.9 0 0); + --sidebar-ring: oklch(0.55 0.25 265); } .dark { @@ -153,34 +215,634 @@ --sidebar-ring: oklch(0.55 0.25 265); } +.retro { + /* Retro / Cyberpunk Theme */ + --background: oklch(0 0 0); /* Pure Black */ + --background-50: oklch(0 0 0 / 0.5); + --background-80: oklch(0 0 0 / 0.8); + + /* Neon Green Text */ + --foreground: oklch(0.85 0.25 145); /* Neon Green */ + --foreground-secondary: oklch(0.7 0.2 145); + --foreground-muted: oklch(0.5 0.15 145); + + /* Hard Edges */ + --radius: 0px; + + /* UI Elements */ + --card: oklch(0 0 0); /* Black card */ + --card-foreground: oklch(0.85 0.25 145); + --popover: oklch(0.05 0.05 145); + --popover-foreground: oklch(0.85 0.25 145); + + --primary: oklch(0.85 0.25 145); /* Neon Green */ + --primary-foreground: oklch(0 0 0); /* Black text on green */ + + --brand-400: oklch(0.85 0.25 145); + --brand-500: oklch(0.85 0.25 145); + --brand-600: oklch(0.75 0.25 145); + + --secondary: oklch(0.1 0.1 145); /* Dark Green bg */ + --secondary-foreground: oklch(0.85 0.25 145); + + --muted: oklch(0.1 0.05 145); + --muted-foreground: oklch(0.5 0.15 145); + + --accent: oklch(0.2 0.2 145); /* Brighter green accent */ + --accent-foreground: oklch(0.85 0.25 145); + + --destructive: oklch(0.6 0.25 25); /* Keep red for destructive */ + + --border: oklch(0.3 0.15 145); /* Visible Green Border */ + --border-glass: oklch(0.85 0.25 145 / 0.3); + + --input: oklch(0.1 0.1 145); + --ring: oklch(0.85 0.25 145); + + /* Charts - various neons */ + --chart-1: oklch(0.85 0.25 145); /* Green */ + --chart-2: oklch(0.8 0.25 300); /* Purple Neon */ + --chart-3: oklch(0.8 0.25 200); /* Cyan Neon */ + --chart-4: oklch(0.8 0.25 60); /* Yellow Neon */ + --chart-5: oklch(0.8 0.25 20); /* Red Neon */ + + /* Sidebar */ + --sidebar: oklch(0 0 0); + --sidebar-foreground: oklch(0.85 0.25 145); + --sidebar-primary: oklch(0.85 0.25 145); + --sidebar-primary-foreground: oklch(0 0 0); + --sidebar-accent: oklch(0.1 0.1 145); + --sidebar-accent-foreground: oklch(0.85 0.25 145); + --sidebar-border: oklch(0.3 0.15 145); + --sidebar-ring: oklch(0.85 0.25 145); + + /* Fonts */ + --font-sans: var(--font-geist-mono); /* Force Mono everywhere */ +} + +/* ======================================== + DRACULA THEME + Inspired by the popular Dracula VS Code theme + ======================================== */ +.dracula { + --background: oklch(0.18 0.02 280); /* #282a36 */ + --background-50: oklch(0.18 0.02 280 / 0.5); + --background-80: oklch(0.18 0.02 280 / 0.8); + + --foreground: oklch(0.95 0.01 280); /* #f8f8f2 */ + --foreground-secondary: oklch(0.7 0.05 280); + --foreground-muted: oklch(0.55 0.08 280); /* #6272a4 */ + + --card: oklch(0.22 0.02 280); /* #44475a */ + --card-foreground: oklch(0.95 0.01 280); + --popover: oklch(0.2 0.02 280); + --popover-foreground: oklch(0.95 0.01 280); + + --primary: oklch(0.7 0.2 320); /* #bd93f9 purple */ + --primary-foreground: oklch(0.18 0.02 280); + + --brand-400: oklch(0.75 0.2 320); + --brand-500: oklch(0.7 0.2 320); /* #bd93f9 */ + --brand-600: oklch(0.65 0.22 320); + + --secondary: oklch(0.28 0.03 280); /* #44475a */ + --secondary-foreground: oklch(0.95 0.01 280); + + --muted: oklch(0.28 0.03 280); + --muted-foreground: oklch(0.55 0.08 280); /* #6272a4 */ + + --accent: oklch(0.32 0.04 280); + --accent-foreground: oklch(0.95 0.01 280); + + --destructive: oklch(0.65 0.25 15); /* #ff5555 */ + + --border: oklch(0.35 0.05 280); + --border-glass: oklch(0.7 0.2 320 / 0.3); + + --input: oklch(0.22 0.02 280); + --ring: oklch(0.7 0.2 320); + + --chart-1: oklch(0.7 0.2 320); /* Purple */ + --chart-2: oklch(0.75 0.2 180); /* Cyan #8be9fd */ + --chart-3: oklch(0.8 0.2 130); /* Green #50fa7b */ + --chart-4: oklch(0.7 0.25 350); /* Pink #ff79c6 */ + --chart-5: oklch(0.85 0.2 90); /* Yellow #f1fa8c */ + + --sidebar: oklch(0.16 0.02 280); + --sidebar-foreground: oklch(0.95 0.01 280); + --sidebar-primary: oklch(0.7 0.2 320); + --sidebar-primary-foreground: oklch(0.18 0.02 280); + --sidebar-accent: oklch(0.28 0.03 280); + --sidebar-accent-foreground: oklch(0.95 0.01 280); + --sidebar-border: oklch(0.35 0.05 280); + --sidebar-ring: oklch(0.7 0.2 320); +} + +/* ======================================== + NORD THEME + Inspired by the Arctic, north-bluish color palette + ======================================== */ +.nord { + --background: oklch(0.23 0.02 240); /* #2e3440 */ + --background-50: oklch(0.23 0.02 240 / 0.5); + --background-80: oklch(0.23 0.02 240 / 0.8); + + --foreground: oklch(0.9 0.01 230); /* #eceff4 */ + --foreground-secondary: oklch(0.75 0.02 230); /* #d8dee9 */ + --foreground-muted: oklch(0.6 0.03 230); /* #4c566a */ + + --card: oklch(0.27 0.02 240); /* #3b4252 */ + --card-foreground: oklch(0.9 0.01 230); + --popover: oklch(0.25 0.02 240); + --popover-foreground: oklch(0.9 0.01 230); + + --primary: oklch(0.7 0.12 220); /* #88c0d0 frost */ + --primary-foreground: oklch(0.23 0.02 240); + + --brand-400: oklch(0.75 0.12 220); + --brand-500: oklch(0.7 0.12 220); /* #88c0d0 */ + --brand-600: oklch(0.65 0.14 220); /* #81a1c1 */ + + --secondary: oklch(0.31 0.02 240); /* #434c5e */ + --secondary-foreground: oklch(0.9 0.01 230); + + --muted: oklch(0.31 0.02 240); + --muted-foreground: oklch(0.55 0.03 230); + + --accent: oklch(0.35 0.03 240); /* #4c566a */ + --accent-foreground: oklch(0.9 0.01 230); + + --destructive: oklch(0.65 0.2 15); /* #bf616a */ + + --border: oklch(0.35 0.03 240); + --border-glass: oklch(0.7 0.12 220 / 0.3); + + --input: oklch(0.27 0.02 240); + --ring: oklch(0.7 0.12 220); + + --chart-1: oklch(0.7 0.12 220); /* Frost blue */ + --chart-2: oklch(0.65 0.14 220); /* #81a1c1 */ + --chart-3: oklch(0.7 0.15 140); /* #a3be8c green */ + --chart-4: oklch(0.7 0.2 320); /* #b48ead purple */ + --chart-5: oklch(0.75 0.15 70); /* #ebcb8b yellow */ + + --sidebar: oklch(0.21 0.02 240); + --sidebar-foreground: oklch(0.9 0.01 230); + --sidebar-primary: oklch(0.7 0.12 220); + --sidebar-primary-foreground: oklch(0.23 0.02 240); + --sidebar-accent: oklch(0.31 0.02 240); + --sidebar-accent-foreground: oklch(0.9 0.01 230); + --sidebar-border: oklch(0.35 0.03 240); + --sidebar-ring: oklch(0.7 0.12 220); +} + +/* ======================================== + MONOKAI THEME + The classic Monokai color scheme + ======================================== */ +.monokai { + --background: oklch(0.17 0.01 90); /* #272822 */ + --background-50: oklch(0.17 0.01 90 / 0.5); + --background-80: oklch(0.17 0.01 90 / 0.8); + + --foreground: oklch(0.95 0.02 100); /* #f8f8f2 */ + --foreground-secondary: oklch(0.8 0.02 100); + --foreground-muted: oklch(0.55 0.04 100); /* #75715e */ + + --card: oklch(0.22 0.01 90); /* #3e3d32 */ + --card-foreground: oklch(0.95 0.02 100); + --popover: oklch(0.2 0.01 90); + --popover-foreground: oklch(0.95 0.02 100); + + --primary: oklch(0.8 0.2 350); /* #f92672 pink */ + --primary-foreground: oklch(0.17 0.01 90); + + --brand-400: oklch(0.85 0.2 350); + --brand-500: oklch(0.8 0.2 350); /* #f92672 */ + --brand-600: oklch(0.75 0.22 350); + + --secondary: oklch(0.25 0.02 90); + --secondary-foreground: oklch(0.95 0.02 100); + + --muted: oklch(0.25 0.02 90); + --muted-foreground: oklch(0.55 0.04 100); + + --accent: oklch(0.3 0.02 90); + --accent-foreground: oklch(0.95 0.02 100); + + --destructive: oklch(0.65 0.25 15); /* red */ + + --border: oklch(0.35 0.03 90); + --border-glass: oklch(0.8 0.2 350 / 0.3); + + --input: oklch(0.22 0.01 90); + --ring: oklch(0.8 0.2 350); + + --chart-1: oklch(0.8 0.2 350); /* Pink #f92672 */ + --chart-2: oklch(0.85 0.2 90); /* Yellow #e6db74 */ + --chart-3: oklch(0.8 0.2 140); /* Green #a6e22e */ + --chart-4: oklch(0.75 0.2 200); /* Cyan #66d9ef */ + --chart-5: oklch(0.75 0.2 30); /* Orange #fd971f */ + + --sidebar: oklch(0.15 0.01 90); + --sidebar-foreground: oklch(0.95 0.02 100); + --sidebar-primary: oklch(0.8 0.2 350); + --sidebar-primary-foreground: oklch(0.17 0.01 90); + --sidebar-accent: oklch(0.25 0.02 90); + --sidebar-accent-foreground: oklch(0.95 0.02 100); + --sidebar-border: oklch(0.35 0.03 90); + --sidebar-ring: oklch(0.8 0.2 350); +} + +/* ======================================== + TOKYO NIGHT THEME + A clean dark theme celebrating Tokyo at night + ======================================== */ +.tokyonight { + --background: oklch(0.16 0.03 260); /* #1a1b26 */ + --background-50: oklch(0.16 0.03 260 / 0.5); + --background-80: oklch(0.16 0.03 260 / 0.8); + + --foreground: oklch(0.85 0.02 250); /* #a9b1d6 */ + --foreground-secondary: oklch(0.7 0.03 250); + --foreground-muted: oklch(0.5 0.04 250); /* #565f89 */ + + --card: oklch(0.2 0.03 260); /* #24283b */ + --card-foreground: oklch(0.85 0.02 250); + --popover: oklch(0.18 0.03 260); + --popover-foreground: oklch(0.85 0.02 250); + + --primary: oklch(0.7 0.18 280); /* #7aa2f7 blue */ + --primary-foreground: oklch(0.16 0.03 260); + + --brand-400: oklch(0.75 0.18 280); + --brand-500: oklch(0.7 0.18 280); /* #7aa2f7 */ + --brand-600: oklch(0.65 0.2 280); /* #7dcfff */ + + --secondary: oklch(0.24 0.03 260); /* #292e42 */ + --secondary-foreground: oklch(0.85 0.02 250); + + --muted: oklch(0.24 0.03 260); + --muted-foreground: oklch(0.5 0.04 250); + + --accent: oklch(0.28 0.04 260); + --accent-foreground: oklch(0.85 0.02 250); + + --destructive: oklch(0.65 0.2 15); /* #f7768e */ + + --border: oklch(0.32 0.04 260); + --border-glass: oklch(0.7 0.18 280 / 0.3); + + --input: oklch(0.2 0.03 260); + --ring: oklch(0.7 0.18 280); + + --chart-1: oklch(0.7 0.18 280); /* Blue #7aa2f7 */ + --chart-2: oklch(0.75 0.18 200); /* Cyan #7dcfff */ + --chart-3: oklch(0.75 0.18 140); /* Green #9ece6a */ + --chart-4: oklch(0.7 0.2 320); /* Magenta #bb9af7 */ + --chart-5: oklch(0.8 0.18 70); /* Yellow #e0af68 */ + + --sidebar: oklch(0.14 0.03 260); + --sidebar-foreground: oklch(0.85 0.02 250); + --sidebar-primary: oklch(0.7 0.18 280); + --sidebar-primary-foreground: oklch(0.16 0.03 260); + --sidebar-accent: oklch(0.24 0.03 260); + --sidebar-accent-foreground: oklch(0.85 0.02 250); + --sidebar-border: oklch(0.32 0.04 260); + --sidebar-ring: oklch(0.7 0.18 280); +} + +/* ======================================== + SOLARIZED DARK THEME + The classic color scheme by Ethan Schoonover + ======================================== */ +.solarized { + --background: oklch(0.2 0.02 230); /* #002b36 base03 */ + --background-50: oklch(0.2 0.02 230 / 0.5); + --background-80: oklch(0.2 0.02 230 / 0.8); + + --foreground: oklch(0.75 0.02 90); /* #839496 base0 */ + --foreground-secondary: oklch(0.6 0.03 200); /* #657b83 base00 */ + --foreground-muted: oklch(0.5 0.04 200); /* #586e75 base01 */ + + --card: oklch(0.23 0.02 230); /* #073642 base02 */ + --card-foreground: oklch(0.75 0.02 90); + --popover: oklch(0.22 0.02 230); + --popover-foreground: oklch(0.75 0.02 90); + + --primary: oklch(0.65 0.15 220); /* #268bd2 blue */ + --primary-foreground: oklch(0.2 0.02 230); + + --brand-400: oklch(0.7 0.15 220); + --brand-500: oklch(0.65 0.15 220); /* #268bd2 */ + --brand-600: oklch(0.6 0.17 220); + + --secondary: oklch(0.25 0.02 230); + --secondary-foreground: oklch(0.75 0.02 90); + + --muted: oklch(0.25 0.02 230); + --muted-foreground: oklch(0.5 0.04 200); + + --accent: oklch(0.28 0.03 230); + --accent-foreground: oklch(0.75 0.02 90); + + --destructive: oklch(0.55 0.2 25); /* #dc322f red */ + + --border: oklch(0.35 0.03 230); + --border-glass: oklch(0.65 0.15 220 / 0.3); + + --input: oklch(0.23 0.02 230); + --ring: oklch(0.65 0.15 220); + + --chart-1: oklch(0.65 0.15 220); /* Blue */ + --chart-2: oklch(0.6 0.18 180); /* Cyan #2aa198 */ + --chart-3: oklch(0.65 0.2 140); /* Green #859900 */ + --chart-4: oklch(0.7 0.18 55); /* Yellow #b58900 */ + --chart-5: oklch(0.6 0.2 30); /* Orange #cb4b16 */ + + --sidebar: oklch(0.18 0.02 230); + --sidebar-foreground: oklch(0.75 0.02 90); + --sidebar-primary: oklch(0.65 0.15 220); + --sidebar-primary-foreground: oklch(0.2 0.02 230); + --sidebar-accent: oklch(0.25 0.02 230); + --sidebar-accent-foreground: oklch(0.75 0.02 90); + --sidebar-border: oklch(0.35 0.03 230); + --sidebar-ring: oklch(0.65 0.15 220); +} + +/* ======================================== + GRUVBOX THEME + Retro groove color scheme + ======================================== */ +.gruvbox { + --background: oklch(0.18 0.02 60); /* #282828 bg */ + --background-50: oklch(0.18 0.02 60 / 0.5); + --background-80: oklch(0.18 0.02 60 / 0.8); + + --foreground: oklch(0.85 0.05 85); /* #ebdbb2 fg */ + --foreground-secondary: oklch(0.7 0.04 85); /* #d5c4a1 */ + --foreground-muted: oklch(0.55 0.04 85); /* #928374 */ + + --card: oklch(0.22 0.02 60); /* #3c3836 bg1 */ + --card-foreground: oklch(0.85 0.05 85); + --popover: oklch(0.2 0.02 60); + --popover-foreground: oklch(0.85 0.05 85); + + --primary: oklch(0.7 0.18 55); /* #fabd2f yellow */ + --primary-foreground: oklch(0.18 0.02 60); + + --brand-400: oklch(0.75 0.18 55); + --brand-500: oklch(0.7 0.18 55); /* Yellow */ + --brand-600: oklch(0.65 0.2 55); + + --secondary: oklch(0.26 0.02 60); /* #504945 bg2 */ + --secondary-foreground: oklch(0.85 0.05 85); + + --muted: oklch(0.26 0.02 60); + --muted-foreground: oklch(0.55 0.04 85); + + --accent: oklch(0.3 0.03 60); + --accent-foreground: oklch(0.85 0.05 85); + + --destructive: oklch(0.55 0.22 25); /* #fb4934 red */ + + --border: oklch(0.35 0.03 60); + --border-glass: oklch(0.7 0.18 55 / 0.3); + + --input: oklch(0.22 0.02 60); + --ring: oklch(0.7 0.18 55); + + --chart-1: oklch(0.7 0.18 55); /* Yellow */ + --chart-2: oklch(0.65 0.2 140); /* Green #b8bb26 */ + --chart-3: oklch(0.7 0.15 200); /* Aqua #8ec07c */ + --chart-4: oklch(0.6 0.2 30); /* Orange #fe8019 */ + --chart-5: oklch(0.6 0.2 320); /* Purple #d3869b */ + + --sidebar: oklch(0.16 0.02 60); + --sidebar-foreground: oklch(0.85 0.05 85); + --sidebar-primary: oklch(0.7 0.18 55); + --sidebar-primary-foreground: oklch(0.18 0.02 60); + --sidebar-accent: oklch(0.26 0.02 60); + --sidebar-accent-foreground: oklch(0.85 0.05 85); + --sidebar-border: oklch(0.35 0.03 60); + --sidebar-ring: oklch(0.7 0.18 55); +} + +/* ======================================== + CATPPUCCIN MOCHA THEME + Soothing pastel theme for the high-spirited + ======================================== */ +.catppuccin { + --background: oklch(0.18 0.02 260); /* #1e1e2e base */ + --background-50: oklch(0.18 0.02 260 / 0.5); + --background-80: oklch(0.18 0.02 260 / 0.8); + + --foreground: oklch(0.9 0.01 280); /* #cdd6f4 text */ + --foreground-secondary: oklch(0.75 0.02 280); /* #bac2de subtext1 */ + --foreground-muted: oklch(0.6 0.03 280); /* #a6adc8 subtext0 */ + + --card: oklch(0.22 0.02 260); /* #313244 surface0 */ + --card-foreground: oklch(0.9 0.01 280); + --popover: oklch(0.2 0.02 260); + --popover-foreground: oklch(0.9 0.01 280); + + --primary: oklch(0.75 0.15 280); /* #cba6f7 mauve */ + --primary-foreground: oklch(0.18 0.02 260); + + --brand-400: oklch(0.8 0.15 280); + --brand-500: oklch(0.75 0.15 280); /* Mauve */ + --brand-600: oklch(0.7 0.17 280); + + --secondary: oklch(0.26 0.02 260); /* #45475a surface1 */ + --secondary-foreground: oklch(0.9 0.01 280); + + --muted: oklch(0.26 0.02 260); + --muted-foreground: oklch(0.6 0.03 280); + + --accent: oklch(0.3 0.03 260); /* #585b70 surface2 */ + --accent-foreground: oklch(0.9 0.01 280); + + --destructive: oklch(0.65 0.2 15); /* #f38ba8 red */ + + --border: oklch(0.35 0.03 260); + --border-glass: oklch(0.75 0.15 280 / 0.3); + + --input: oklch(0.22 0.02 260); + --ring: oklch(0.75 0.15 280); + + --chart-1: oklch(0.75 0.15 280); /* Mauve */ + --chart-2: oklch(0.75 0.15 220); /* Blue #89b4fa */ + --chart-3: oklch(0.8 0.15 160); /* Green #a6e3a1 */ + --chart-4: oklch(0.8 0.15 350); /* Pink #f5c2e7 */ + --chart-5: oklch(0.85 0.12 90); /* Yellow #f9e2af */ + + --sidebar: oklch(0.16 0.02 260); /* #181825 mantle */ + --sidebar-foreground: oklch(0.9 0.01 280); + --sidebar-primary: oklch(0.75 0.15 280); + --sidebar-primary-foreground: oklch(0.18 0.02 260); + --sidebar-accent: oklch(0.26 0.02 260); + --sidebar-accent-foreground: oklch(0.9 0.01 280); + --sidebar-border: oklch(0.35 0.03 260); + --sidebar-ring: oklch(0.75 0.15 280); +} + +/* ======================================== + ONE DARK THEME + Atom's iconic One Dark theme + ======================================== */ +.onedark { + --background: oklch(0.19 0.01 250); /* #282c34 */ + --background-50: oklch(0.19 0.01 250 / 0.5); + --background-80: oklch(0.19 0.01 250 / 0.8); + + --foreground: oklch(0.85 0.02 240); /* #abb2bf */ + --foreground-secondary: oklch(0.7 0.02 240); + --foreground-muted: oklch(0.5 0.03 240); /* #5c6370 */ + + --card: oklch(0.23 0.01 250); /* #21252b */ + --card-foreground: oklch(0.85 0.02 240); + --popover: oklch(0.21 0.01 250); + --popover-foreground: oklch(0.85 0.02 240); + + --primary: oklch(0.7 0.18 230); /* #61afef blue */ + --primary-foreground: oklch(0.19 0.01 250); + + --brand-400: oklch(0.75 0.18 230); + --brand-500: oklch(0.7 0.18 230); /* Blue */ + --brand-600: oklch(0.65 0.2 230); + + --secondary: oklch(0.25 0.01 250); + --secondary-foreground: oklch(0.85 0.02 240); + + --muted: oklch(0.25 0.01 250); + --muted-foreground: oklch(0.5 0.03 240); + + --accent: oklch(0.28 0.02 250); + --accent-foreground: oklch(0.85 0.02 240); + + --destructive: oklch(0.6 0.2 20); /* #e06c75 red */ + + --border: oklch(0.35 0.02 250); + --border-glass: oklch(0.7 0.18 230 / 0.3); + + --input: oklch(0.23 0.01 250); + --ring: oklch(0.7 0.18 230); + + --chart-1: oklch(0.7 0.18 230); /* Blue */ + --chart-2: oklch(0.75 0.15 320); /* Magenta #c678dd */ + --chart-3: oklch(0.75 0.18 150); /* Green #98c379 */ + --chart-4: oklch(0.8 0.15 80); /* Yellow #e5c07b */ + --chart-5: oklch(0.7 0.15 180); /* Cyan #56b6c2 */ + + --sidebar: oklch(0.17 0.01 250); + --sidebar-foreground: oklch(0.85 0.02 240); + --sidebar-primary: oklch(0.7 0.18 230); + --sidebar-primary-foreground: oklch(0.19 0.01 250); + --sidebar-accent: oklch(0.25 0.01 250); + --sidebar-accent-foreground: oklch(0.85 0.02 240); + --sidebar-border: oklch(0.35 0.02 250); + --sidebar-ring: oklch(0.7 0.18 230); +} + +/* ======================================== + SYNTHWAVE '84 THEME + Neon dreams of the 80s + ======================================== */ +.synthwave { + --background: oklch(0.15 0.05 290); /* #262335 */ + --background-50: oklch(0.15 0.05 290 / 0.5); + --background-80: oklch(0.15 0.05 290 / 0.8); + + --foreground: oklch(0.95 0.02 320); /* #ffffff with warm tint */ + --foreground-secondary: oklch(0.75 0.05 320); + --foreground-muted: oklch(0.55 0.08 290); + + --card: oklch(0.2 0.06 290); /* #34294f */ + --card-foreground: oklch(0.95 0.02 320); + --popover: oklch(0.18 0.05 290); + --popover-foreground: oklch(0.95 0.02 320); + + --primary: oklch(0.7 0.28 350); /* #f97e72 hot pink */ + --primary-foreground: oklch(0.15 0.05 290); + + --brand-400: oklch(0.75 0.28 350); + --brand-500: oklch(0.7 0.28 350); /* Hot pink */ + --brand-600: oklch(0.65 0.3 350); + + --secondary: oklch(0.25 0.07 290); + --secondary-foreground: oklch(0.95 0.02 320); + + --muted: oklch(0.25 0.07 290); + --muted-foreground: oklch(0.55 0.08 290); + + --accent: oklch(0.3 0.08 290); + --accent-foreground: oklch(0.95 0.02 320); + + --destructive: oklch(0.6 0.25 15); + + --border: oklch(0.4 0.1 290); + --border-glass: oklch(0.7 0.28 350 / 0.3); + + --input: oklch(0.2 0.06 290); + --ring: oklch(0.7 0.28 350); + + --chart-1: oklch(0.7 0.28 350); /* Hot pink */ + --chart-2: oklch(0.8 0.25 200); /* Cyan #72f1b8 */ + --chart-3: oklch(0.85 0.2 60); /* Yellow #fede5d */ + --chart-4: oklch(0.7 0.25 280); /* Purple #ff7edb */ + --chart-5: oklch(0.7 0.2 30); /* Orange #f97e72 */ + + --sidebar: oklch(0.13 0.05 290); + --sidebar-foreground: oklch(0.95 0.02 320); + --sidebar-primary: oklch(0.7 0.28 350); + --sidebar-primary-foreground: oklch(0.15 0.05 290); + --sidebar-accent: oklch(0.25 0.07 290); + --sidebar-accent-foreground: oklch(0.95 0.02 320); + --sidebar-border: oklch(0.4 0.1 290); + --sidebar-ring: oklch(0.7 0.28 350); +} + @layer base { * { @apply border-border outline-ring/50; } + html { + @apply bg-background; + } body { @apply bg-background text-foreground; + background-color: var(--background); } } -/* Custom scrollbar for dark mode */ -.dark ::-webkit-scrollbar { +/* Custom scrollbar for dark themes */ +:is(.dark, .retro, .dracula, .nord, .monokai, .tokyonight, .solarized, .gruvbox, .catppuccin, .onedark, .synthwave) ::-webkit-scrollbar { width: 8px; height: 8px; } -.dark ::-webkit-scrollbar-track { - background: oklch(0.15 0 0); +:is(.dark, .retro, .dracula, .nord, .monokai, .tokyonight, .solarized, .gruvbox, .catppuccin, .onedark, .synthwave) ::-webkit-scrollbar-track { + background: var(--muted); } -.dark ::-webkit-scrollbar-thumb { +:is(.dark, .retro) ::-webkit-scrollbar-thumb { background: oklch(0.3 0 0); border-radius: 4px; } -.dark ::-webkit-scrollbar-thumb:hover { +:is(.dark, .retro) ::-webkit-scrollbar-thumb:hover { background: oklch(0.4 0 0); } +/* Retro Scrollbar override */ +.retro ::-webkit-scrollbar-thumb { + background: var(--primary); + border-radius: 0; +} +.retro ::-webkit-scrollbar-track { + background: var(--background); +} + /* Glass morphism utilities */ @layer utilities { .glass { @@ -219,11 +881,23 @@ /* Glass morphism background utilities */ .bg-glass { - background: oklch(0.04 0 0 / 0.5); + background: var(--card); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); } .bg-glass-80 { - background: oklch(0.04 0 0 / 0.8); + background: var(--popover); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + } + + .light .bg-glass { + background: oklch(1 0 0 / 0.8); + } + + .light .bg-glass-80 { + background: oklch(1 0 0 / 0.95); } /* Hover state utilities */ @@ -245,10 +919,449 @@ /* Content area background */ .content-bg { + background: var(--background); + } + + .light .content-bg { + background: linear-gradient(135deg, oklch(0.99 0 0), oklch(0.98 0 0), oklch(0.99 0 0)); + } + + .dark .content-bg { background: linear-gradient(135deg, oklch(0.04 0 0), oklch(0.08 0 0), oklch(0.04 0 0)); } } +/* Retro Overrides for Utilities */ +.retro .glass, +.retro .glass-subtle, +.retro .glass-strong, +.retro .bg-glass, +.retro .bg-glass-80 { + backdrop-filter: none; + background: var(--background); + border: 1px solid var(--border); +} + +.retro .gradient-brand { + background: var(--primary); + color: var(--primary-foreground); +} + +.retro .content-bg { + background: + linear-gradient(rgba(0, 255, 65, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(0, 255, 65, 0.03) 1px, transparent 1px), + var(--background); + background-size: 20px 20px; +} + +.retro * { + border-radius: 0 !important; +} + +/* Animated Outline Button Styles */ +.animated-outline-gradient { + /* Default gradient - purple to blue */ + background: conic-gradient(from 90deg at 50% 50%, #a855f7 0%, #3b82f6 50%, #a855f7 100%); +} + +/* Light mode - deeper purple to blue gradient for better visibility */ +.light .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #7c3aed 0%, #2563eb 50%, #7c3aed 100%); +} + +.light .animated-outline-inner { + background: oklch(100% 0 0) !important; + color: #7c3aed !important; + border: 1px solid oklch(92% 0 0); +} + +.light [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(97% 0.02 270) !important; + color: #5b21b6 !important; +} + +/* Dark mode - purple to blue gradient */ +.dark .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #a855f7 0%, #3b82f6 50%, #a855f7 100%); +} + +.dark .animated-outline-inner { + background: oklch(0.15 0 0) !important; + color: #c084fc !important; +} + +.dark [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.2 0.02 270) !important; + color: #e9d5ff !important; +} + +/* Retro mode - unique scanline + neon effect */ +.retro .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #00ff41 0%, #00ffff 25%, #ff00ff 50%, #00ffff 75%, #00ff41 100%); + animation: spin 2s linear infinite, retro-glow 1s ease-in-out infinite alternate; +} + +@keyframes retro-glow { + from { + filter: brightness(1) drop-shadow(0 0 2px #00ff41); + } + to { + filter: brightness(1.2) drop-shadow(0 0 8px #00ff41); + } +} + +.retro [data-slot="button"][class*="animated-outline"] { + border-radius: 0 !important; +} + +.retro .animated-outline-inner { + background: oklch(0 0 0) !important; + color: #00ff41 !important; + border-radius: 0 !important; + text-shadow: 0 0 5px #00ff41; + font-family: var(--font-geist-mono), monospace; + text-transform: uppercase; + letter-spacing: 0.1em; +} + +.retro [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.1 0.1 145) !important; + color: #00ff41 !important; + box-shadow: + 0 0 10px #00ff41, + 0 0 20px #00ff41, + inset 0 0 10px rgba(0, 255, 65, 0.1); + text-shadow: 0 0 10px #00ff41, 0 0 20px #00ff41; +} + +/* Dracula animated-outline - purple/pink */ +.dracula .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #bd93f9 0%, #ff79c6 50%, #bd93f9 100%); +} + +.dracula .animated-outline-inner { + background: oklch(0.18 0.02 280) !important; + color: #bd93f9 !important; +} + +.dracula [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.24 0.03 280) !important; + color: #ff79c6 !important; +} + +/* Nord animated-outline - frost blue */ +.nord .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #88c0d0 0%, #81a1c1 50%, #88c0d0 100%); +} + +.nord .animated-outline-inner { + background: oklch(0.23 0.02 240) !important; + color: #88c0d0 !important; +} + +.nord [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.28 0.03 240) !important; + color: #8fbcbb !important; +} + +/* Monokai animated-outline - pink/yellow */ +.monokai .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #f92672 0%, #e6db74 50%, #f92672 100%); +} + +.monokai .animated-outline-inner { + background: oklch(0.17 0.01 90) !important; + color: #f92672 !important; +} + +.monokai [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.22 0.02 90) !important; + color: #e6db74 !important; +} + +/* Tokyo Night animated-outline - blue/magenta */ +.tokyonight .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #7aa2f7 0%, #bb9af7 50%, #7aa2f7 100%); +} + +.tokyonight .animated-outline-inner { + background: oklch(0.16 0.03 260) !important; + color: #7aa2f7 !important; +} + +.tokyonight [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.22 0.04 260) !important; + color: #bb9af7 !important; +} + +/* Solarized animated-outline - blue/cyan */ +.solarized .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #268bd2 0%, #2aa198 50%, #268bd2 100%); +} + +.solarized .animated-outline-inner { + background: oklch(0.2 0.02 230) !important; + color: #268bd2 !important; +} + +.solarized [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.25 0.03 230) !important; + color: #2aa198 !important; +} + +/* Gruvbox animated-outline - yellow/orange */ +.gruvbox .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #fabd2f 0%, #fe8019 50%, #fabd2f 100%); +} + +.gruvbox .animated-outline-inner { + background: oklch(0.18 0.02 60) !important; + color: #fabd2f !important; +} + +.gruvbox [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.24 0.03 60) !important; + color: #fe8019 !important; +} + +/* Catppuccin animated-outline - mauve/pink */ +.catppuccin .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #cba6f7 0%, #f5c2e7 50%, #cba6f7 100%); +} + +.catppuccin .animated-outline-inner { + background: oklch(0.18 0.02 260) !important; + color: #cba6f7 !important; +} + +.catppuccin [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.24 0.03 260) !important; + color: #f5c2e7 !important; +} + +/* One Dark animated-outline - blue/magenta */ +.onedark .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #61afef 0%, #c678dd 50%, #61afef 100%); +} + +.onedark .animated-outline-inner { + background: oklch(0.19 0.01 250) !important; + color: #61afef !important; +} + +.onedark [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.25 0.02 250) !important; + color: #c678dd !important; +} + +/* Synthwave animated-outline - hot pink/cyan with glow */ +.synthwave .animated-outline-gradient { + background: conic-gradient(from 90deg at 50% 50%, #f97e72 0%, #72f1b8 25%, #ff7edb 50%, #72f1b8 75%, #f97e72 100%); + animation: spin 2s linear infinite, synthwave-glow 1.5s ease-in-out infinite alternate; +} + +@keyframes synthwave-glow { + from { + filter: brightness(1) drop-shadow(0 0 3px #f97e72); + } + to { + filter: brightness(1.3) drop-shadow(0 0 10px #ff7edb); + } +} + +.synthwave .animated-outline-inner { + background: oklch(0.15 0.05 290) !important; + color: #f97e72 !important; + text-shadow: 0 0 8px #f97e72; +} + +.synthwave [data-slot="button"][class*="animated-outline"]:hover .animated-outline-inner { + background: oklch(0.22 0.07 290) !important; + color: #72f1b8 !important; + text-shadow: 0 0 12px #72f1b8; + box-shadow: 0 0 15px rgba(114, 241, 184, 0.3); +} + +/* Slider Theme Styles */ +.light .slider-track { + background: oklch(90% 0 0); +} + +.light .slider-range { + background: linear-gradient(to right, #7c3aed, #2563eb); +} + +.light .slider-thumb { + background: oklch(100% 0 0); + border-color: oklch(80% 0 0); +} + +.dark .slider-track { + background: oklch(0.2 0 0); +} + +.dark .slider-range { + background: linear-gradient(to right, #a855f7, #3b82f6); +} + +.dark .slider-thumb { + background: oklch(0.25 0 0); + border-color: oklch(0.4 0 0); +} + +.retro .slider-track { + background: oklch(0.15 0.05 145); + border: 1px solid #00ff41; + border-radius: 0 !important; +} + +.retro .slider-range { + background: #00ff41; + box-shadow: 0 0 10px #00ff41, 0 0 5px #00ff41; + border-radius: 0 !important; +} + +.retro .slider-thumb { + background: oklch(0 0 0); + border: 2px solid #00ff41; + border-radius: 0 !important; + box-shadow: 0 0 8px #00ff41; +} + +.retro .slider-thumb:hover { + background: oklch(0.1 0.1 145); + box-shadow: 0 0 12px #00ff41, 0 0 20px #00ff41; +} + +/* Dracula slider */ +.dracula .slider-track { + background: oklch(0.28 0.03 280); +} + +.dracula .slider-range { + background: linear-gradient(to right, #bd93f9, #ff79c6); +} + +.dracula .slider-thumb { + background: oklch(0.22 0.02 280); + border-color: #bd93f9; +} + +/* Nord slider */ +.nord .slider-track { + background: oklch(0.31 0.02 240); +} + +.nord .slider-range { + background: linear-gradient(to right, #88c0d0, #81a1c1); +} + +.nord .slider-thumb { + background: oklch(0.27 0.02 240); + border-color: #88c0d0; +} + +/* Monokai slider */ +.monokai .slider-track { + background: oklch(0.25 0.02 90); +} + +.monokai .slider-range { + background: linear-gradient(to right, #f92672, #fd971f); +} + +.monokai .slider-thumb { + background: oklch(0.22 0.01 90); + border-color: #f92672; +} + +/* Tokyo Night slider */ +.tokyonight .slider-track { + background: oklch(0.24 0.03 260); +} + +.tokyonight .slider-range { + background: linear-gradient(to right, #7aa2f7, #bb9af7); +} + +.tokyonight .slider-thumb { + background: oklch(0.2 0.03 260); + border-color: #7aa2f7; +} + +/* Solarized slider */ +.solarized .slider-track { + background: oklch(0.25 0.02 230); +} + +.solarized .slider-range { + background: linear-gradient(to right, #268bd2, #2aa198); +} + +.solarized .slider-thumb { + background: oklch(0.23 0.02 230); + border-color: #268bd2; +} + +/* Gruvbox slider */ +.gruvbox .slider-track { + background: oklch(0.26 0.02 60); +} + +.gruvbox .slider-range { + background: linear-gradient(to right, #fabd2f, #fe8019); +} + +.gruvbox .slider-thumb { + background: oklch(0.22 0.02 60); + border-color: #fabd2f; +} + +/* Catppuccin slider */ +.catppuccin .slider-track { + background: oklch(0.26 0.02 260); +} + +.catppuccin .slider-range { + background: linear-gradient(to right, #cba6f7, #89b4fa); +} + +.catppuccin .slider-thumb { + background: oklch(0.22 0.02 260); + border-color: #cba6f7; +} + +/* One Dark slider */ +.onedark .slider-track { + background: oklch(0.25 0.01 250); +} + +.onedark .slider-range { + background: linear-gradient(to right, #61afef, #c678dd); +} + +.onedark .slider-thumb { + background: oklch(0.23 0.01 250); + border-color: #61afef; +} + +/* Synthwave slider */ +.synthwave .slider-track { + background: oklch(0.25 0.07 290); +} + +.synthwave .slider-range { + background: linear-gradient(to right, #f97e72, #ff7edb); + box-shadow: 0 0 10px #f97e72, 0 0 5px #ff7edb; +} + +.synthwave .slider-thumb { + background: oklch(0.2 0.06 290); + border-color: #f97e72; + box-shadow: 0 0 8px #f97e72; +} + /* Electron title bar drag region */ .titlebar-drag-region { -webkit-app-region: drag; diff --git a/app/src/app/layout.tsx b/app/src/app/layout.tsx index b968ddf9..017418b9 100644 --- a/app/src/app/layout.tsx +++ b/app/src/app/layout.tsx @@ -26,7 +26,7 @@ export default function RootLayout({ return (
{children}