Skip to content

Comments

feat: Twitter-style UI theme with custom theme override system#93

Merged
leonvanzyl merged 3 commits intoAutoForgeAI:masterfrom
nioasoft:feat/twitter-ui-theme
Jan 26, 2026
Merged

feat: Twitter-style UI theme with custom theme override system#93
leonvanzyl merged 3 commits intoAutoForgeAI:masterfrom
nioasoft:feat/twitter-ui-theme

Conversation

@nioasoft
Copy link

@nioasoft nioasoft commented Jan 24, 2026

Summary

A fresh, modern UI theme inspired by Twitter/X design language, plus a flexible theme override system that allows users to customize the look without modifying core files.

Features

Twitter-style UI Theme

  • Modern, clean design with Twitter/X-inspired aesthetics
  • Improved visual hierarchy and readability
  • Better contrast and spacing
  • Polished animations and transitions

Custom Theme Override System

  • New ui/src/styles/custom-theme.css for user customizations
  • Overrides are applied on top of the base theme
  • Survives updates - users can keep their customizations
  • Well-documented CSS variables for easy tweaking

Documentation

  • Added CUSTOM_UPDATES.md with theme customization guide
  • Examples of common customizations

Screenshots

The new theme has received positive feedback from users who prefer a cleaner, more modern look.

Test plan

  • Run npm run dev in ui/ directory
  • Verify theme loads correctly
  • Test custom-theme.css overrides work
  • Check responsive behavior on different screen sizes
  • Verify dark mode still works (if applicable)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added per-project database health monitoring endpoint.
    • Added comprehensive "Custom Updates" documentation detailing UI and backend deviations.
  • Style

    • Updated UI theme to a cleaner, Twitter-inspired design with simplified borders, no shadows, and refined typography.
    • Improved Kanban column styling and color theming.
  • Documentation

    • Expanded Playwright configuration docs and changed defaults to Firefox with headless enabled.

✏️ Tip: You can customize this high-level summary in your review settings.

nioasoft and others added 2 commits January 24, 2026 22:47
Create custom-theme.css for theme overrides that won't conflict
with upstream updates. The file loads after globals.css, so its
CSS variables take precedence.

This approach ensures:
- Zero merge conflicts on git pull (new file, not in upstream)
- Theme persists across upstream updates
- Easy to modify without touching upstream code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
UI Changes:
- Replace neobrutalism with clean Twitter/Supabase-style design
- Remove all shadows, use thin borders (1px)
- Single accent color (Twitter blue) for all status indicators
- Rounded corners (1.3rem base)
- Fix dark mode contrast and visibility
- Make KanbanColumn themeable via CSS classes

Backend Changes:
- Default Playwright browser changed to Firefox (lower CPU)
- Default Playwright mode changed to headless (saves resources)
- Add PLAYWRIGHT_BROWSER env var support

Documentation:
- Add CUSTOM_UPDATES.md with all customizations documented
- Update .env.example with new Playwright options

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

Updates Playwright defaults and helpers (default browser Firefox, headless true), adds robust SQLite connection and a DB-health endpoint, introduces a Twitter-style global theme CSS and Kanban column class-based coloring, and expands documentation and revert/update checklists.

Changes

Cohort / File(s) Summary
Configuration & Documentation
.env.example, CUSTOM_UPDATES.md
Expands Playwright env docs (browser choices, headless guidance), adds comprehensive upstream-deviation doc, update/revert checklists, and file-level change descriptions.
Playwright Configuration & Client
client.py
Adds DEFAULT_PLAYWRIGHT_BROWSER ("firefox") and get_playwright_browser(); changes DEFAULT_PLAYWRIGHT_HEADLESSTrue; updates headless parsing and runtime logging; passes explicit --browser and conditional --headless; enables agent-specific --isolated.
SQLite Robust DB & API
api/database.py, progress.py, server/routers/projects.py, server/schemas.py
Introduces robust DB connection helpers (connection with retry, health checks), switches progress usage to robust connections, and adds a per-project DB-health REST endpoint and schema.
UI Theme & Components
ui/src/styles/custom-theme.css, ui/src/components/KanbanColumn.tsx, ui/src/main.tsx
Adds global Twitter-inspired theme CSS, imports it in main.tsx, and refactors KanbanColumn to use class-based column color states and simplified header/count styling.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Server
participant DB
Client->>Server: GET /projects/{id}/db-health
Server->>DB: open robust connection (with retry)
DB-->>Server: health status / OK or error
Server-->>Client: HTTP 200 { healthy: true } / 500 { healthy: false }

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Soft paws tap on keys tonight,

Firefox sleeps with headless light,
Borders trimmed and shadows gone,
Columns dressed in Twitter’s song,
Databases hum — robust and bright. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: Twitter-style UI theme with custom theme override system' clearly matches the main changeset—adding a Twitter-inspired theme and override mechanism—as confirmed by the extensive CSS additions, theme documentation, and KanbanColumn themeing changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client.py (1)

46-55: Handle invalid PLAYWRIGHT_HEADLESS values explicitly.

Right now any unexpected value silently resolves to False, which can surprise users and flip behavior. Consider validating and falling back to the default with a warning.

🔧 Suggested validation
-    value = os.getenv("PLAYWRIGHT_HEADLESS", str(DEFAULT_PLAYWRIGHT_HEADLESS).lower()).lower()
-    # Accept various truthy/falsy values
-    return value in ("true", "1", "yes", "on")
+    value = os.getenv("PLAYWRIGHT_HEADLESS", str(DEFAULT_PLAYWRIGHT_HEADLESS).lower()).strip().lower()
+    truthy = {"true", "1", "yes", "on"}
+    falsy = {"false", "0", "no", "off"}
+    if value not in truthy | falsy:
+        print(f"   - Warning: Invalid PLAYWRIGHT_HEADLESS='{value}', defaulting to {DEFAULT_PLAYWRIGHT_HEADLESS}")
+        return DEFAULT_PLAYWRIGHT_HEADLESS
+    return value in truthy
🤖 Fix all issues with AI agents
In `@client.py`:
- Around line 28-31: The get_playwright_browser() function should validate the
environment value against an allowlist of MCP-supported browsers ("chrome",
"firefox", "webkit", "msedge"); if the env var is missing or not in that set,
log a warning and return the DEFAULT_PLAYWRIGHT_BROWSER constant instead of
passing the invalid value to `@playwright/mcp`. Locate get_playwright_browser and
DEFAULT_PLAYWRIGHT_BROWSER in the file, implement the allowlist check, emit a
clear warning when falling back, and ensure only allowed values are returned to
the caller.

In `@ui/src/styles/custom-theme.css`:
- Around line 87-89: The global rule that strips box-shadow for all elements ("*
{ box-shadow: none !important; }") removes focus rings and, together with
removed outlines on inputs, breaks keyboard focus visibility; restore accessible
focus indicators by removing the global override and instead add explicit
:focus-visible rules for interactive elements (e.g., input, button, a,
.your-focusable-class) to apply a visible outline or box-shadow (and ensure
inputs retain their outline on :focus-visible); locate the "*" rule and the
input outline removal and replace them with scoped :focus-visible styling to
preserve keyboard focus while keeping visual design for non-focused states.
- Around line 269-279: The rule is incorrectly blanket-disabling all translate
utilities ([class*="translate-x"], [class*="translate-y"]) which breaks layouts;
remove those selectors from the global rule and only keep the hover-specific
selectors ([class*="hover:translate"], [class*="hover:-translate"]) so you still
neutralize hover-based neo effects but do not zero out core translate utilities
like -translate-x-1/2 used for centering.
🧹 Nitpick comments (2)
client.py (1)

247-257: Avoid double-reading headless configuration.

Read once so the logged value always matches the applied value and avoids redundant env parsing.

♻️ Suggested refactor
-        browser = get_playwright_browser()
+        browser = get_playwright_browser()
+        headless = get_playwright_headless()
         playwright_args = [
             "@playwright/mcp@latest",
             "--viewport-size", "1280x720",
             "--browser", browser,
         ]
-        if get_playwright_headless():
+        if headless:
             playwright_args.append("--headless")
-        print(f"   - Browser: {browser} (headless={get_playwright_headless()})")
+        print(f"   - Browser: {browser} (headless={headless})")
CUSTOM_UPDATES.md (1)

270-275: Add UI lint step to the update checklist.

The checklist currently includes npm run build but omits npm run lint, which is part of the UI workflow.

📘 Suggested doc update
 ### UI Changes
 - [ ] `ui/src/styles/custom-theme.css` is preserved
 - [ ] `ui/src/components/KanbanColumn.tsx` changes are preserved
+- [ ] Run `npm run lint` in `ui/` directory
 - [ ] Run `npm run build` in `ui/` directory
 - [ ] Test both light and dark modes

As per coding guidelines, ...

Comment on lines +28 to +31
# Default browser for Playwright - can be overridden via PLAYWRIGHT_BROWSER env var
# Options: chrome, firefox, webkit, msedge
# Firefox is recommended for lower CPU usage
DEFAULT_PLAYWRIGHT_BROWSER = "firefox"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the client.py file to see the current implementation
find . -name "client.py" -type f | head -20

Repository: leonvanzyl/autocoder

Length of output: 75


🏁 Script executed:

# Also search for any existing validation or usage of PLAYWRIGHT_BROWSER
rg "PLAYWRIGHT_BROWSER|get_playwright_browser" --type py

Repository: leonvanzyl/autocoder

Length of output: 482


🌐 Web query:

@playwright/mcp CLI documentation supported browser values --browser parameter

💡 Result:

For the @playwright/mcp CLI, the --browser <browser> option supports these values: chrome, firefox, webkit, msedge. [1]

(Example in Playwright’s MCP docs: --browser msedge.) [2]

Sources: [1][2]


🏁 Script executed:

cat -n client.py | head -100

Repository: leonvanzyl/autocoder

Length of output: 4572


🏁 Script executed:

# Check how the browser variable is actually used after get_playwright_browser()
rg -A 5 "get_playwright_browser()" --type py

Repository: leonvanzyl/autocoder

Length of output: 593


🏁 Script executed:

rg -B 5 -A 10 "playwright_args = \[" --type py

Repository: leonvanzyl/autocoder

Length of output: 910


🏁 Script executed:

# Check if there's any error handling or try-catch around MCP invocation
rg -B 3 -A 3 "@playwright/mcp" --type py

Repository: leonvanzyl/autocoder

Length of output: 404


Add validation to get_playwright_browser() to prevent MCP startup failures.

The function currently passes any value to @playwright/mcp CLI without validation. Invalid browser values cause hard-fail at startup. Add an allowlist matching MCP's supported values (chrome, firefox, webkit, msedge) with a warning and fallback to the default.

🔧 Suggested validation
+# Allowed Playwright MCP browser values
+ALLOWED_PLAYWRIGHT_BROWSERS = {"chrome", "firefox", "webkit", "msedge"}
+
 def get_playwright_browser() -> str:
     """
     Get the browser to use for Playwright.
 
     Reads from PLAYWRIGHT_BROWSER environment variable, defaults to firefox.
     Options: chrome, firefox, webkit, msedge
     Firefox is recommended for lower CPU usage.
     """
-    return os.getenv("PLAYWRIGHT_BROWSER", DEFAULT_PLAYWRIGHT_BROWSER).lower()
+    browser = os.getenv("PLAYWRIGHT_BROWSER", DEFAULT_PLAYWRIGHT_BROWSER).strip().lower()
+    if browser not in ALLOWED_PLAYWRIGHT_BROWSERS:
+        print(f"   - Warning: Invalid PLAYWRIGHT_BROWSER='{browser}', defaulting to {DEFAULT_PLAYWRIGHT_BROWSER}")
+        return DEFAULT_PLAYWRIGHT_BROWSER
+    return browser
🤖 Prompt for AI Agents
In `@client.py` around lines 28 - 31, The get_playwright_browser() function should
validate the environment value against an allowlist of MCP-supported browsers
("chrome", "firefox", "webkit", "msedge"); if the env var is missing or not in
that set, log a warning and return the DEFAULT_PLAYWRIGHT_BROWSER constant
instead of passing the invalid value to `@playwright/mcp`. Locate
get_playwright_browser and DEFAULT_PLAYWRIGHT_BROWSER in the file, implement the
allowlist check, emit a clear warning when falling back, and ensure only allowed
values are returned to the caller.

Comment on lines +87 to +89
* {
box-shadow: none !important;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restore visible focus indicators after shadow/outline removal.

Line 87-89 removes box-shadows globally (often used for focus rings), and Line 172 removes outlines on inputs. This can eliminate keyboard focus visibility across the UI, which is an accessibility blocker. Add explicit :focus-visible styles (or avoid removing outlines) to preserve focus states.

🛠️ Suggested fix
 * {
   box-shadow: none !important;
 }
+
+*:focus-visible {
+  outline: 2px solid var(--color-neo-accent);
+  outline-offset: 2px;
+}
@@
 .neo-input:focus,
 .neo-textarea:focus,
 input:focus,
 textarea:focus,
 select:focus {
   box-shadow: none !important;
   border-color: var(--color-neo-accent) !important;
-  outline: none !important;
+  outline: 2px solid var(--color-neo-accent) !important;
+  outline-offset: 2px;
 }

Also applies to: 165-173

🤖 Prompt for AI Agents
In `@ui/src/styles/custom-theme.css` around lines 87 - 89, The global rule that
strips box-shadow for all elements ("* { box-shadow: none !important; }")
removes focus rings and, together with removed outlines on inputs, breaks
keyboard focus visibility; restore accessible focus indicators by removing the
global override and instead add explicit :focus-visible rules for interactive
elements (e.g., input, button, a, .your-focusable-class) to apply a visible
outline or box-shadow (and ensure inputs retain their outline on
:focus-visible); locate the "*" rule and the input outline removal and replace
them with scoped :focus-visible styling to preserve keyboard focus while keeping
visual design for non-focused states.

Comment on lines +269 to +279
/* ===== REMOVE NEO EFFECTS ===== */
[class*="shadow-neo"],
[class*="shadow-"] {
box-shadow: none !important;
}

[class*="hover:translate"],
[class*="hover:-translate"],
[class*="translate-x"],
[class*="translate-y"] {
transform: none !important;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t blanket-disable translate-x/y utilities.

This will break layout patterns that rely on translate utilities (e.g., centering with -translate-x-1/2). Keep the hover-only overrides but don’t zero out all translate classes.

🛠️ Suggested fix
 [class*="hover:translate"],
-[class*="hover:-translate"],
-[class*="translate-x"],
-[class*="translate-y"] {
+[class*="hover:-translate"] {
   transform: none !important;
 }
🤖 Prompt for AI Agents
In `@ui/src/styles/custom-theme.css` around lines 269 - 279, The rule is
incorrectly blanket-disabling all translate utilities ([class*="translate-x"],
[class*="translate-y"]) which breaks layouts; remove those selectors from the
global rule and only keep the hover-specific selectors
([class*="hover:translate"], [class*="hover:-translate"]) so you still
neutralize hover-based neo effects but do not zero out core translate utilities
like -translate-x-1/2 used for centering.

Add focus-visible styles for keyboard navigation accessibility and
improve PLAYWRIGHT_HEADLESS environment variable validation to warn
users about invalid values instead of silently defaulting.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leonvanzyl leonvanzyl merged commit b6c7f05 into AutoForgeAI:master Jan 26, 2026
1 check passed
@leonvanzyl
Copy link
Collaborator

Thanks

leonvanzyl added a commit that referenced this pull request Jan 26, 2026
- Remove translate-x/translate-y CSS selectors that broke layout utilities
  (AssistantPanel slide animation, DebugLogViewer resize handle)
- Add browser validation to get_playwright_browser() with warning for
  invalid values (matches get_playwright_headless() behavior)
- Remove phantom SQLite documentation from CUSTOM_UPDATES.md that
  described features not present in PR #93
- Update checklist and revert instructions to match actual changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
rudiheydra added a commit to rudiheydra/AutoBuildr that referenced this pull request Jan 27, 2026
…I#93

- Created tests/test_graph_cycle_protection.py with 33 unit tests:
  - TestResolveDependenciesKahnsAlgorithm: Verifies Kahn's algo cycle detection
  - TestDetectCyclesVisitedTracking: Verifies visited/rec_stack sets
  - TestComputeSchedulingScoresQueuedTracking: Verifies BFS visited tracking
  - TestWouldCreateCircularDependencyVisited: Verifies DFS visited set
  - TestIterationLimitsLogging: Verifies logging on limit exceeded
  - TestCycleProtectionCodeAudit: Static analysis of protection mechanisms
  - TestEdgeCases: Empty lists, None deps, missing keys

- Created tests/verify_feature_93.py verification script

All 5 verification steps pass:
1. resolve_dependencies() uses in_degree tracking (Kahn's algo)
2. _detect_cycles() uses visited + rec_stack sets
3. compute_scheduling_scores() uses visited set + iteration limit
4. would_create_circular_dependency() uses visited set + depth limit
5. All functions have iteration/depth limits

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
rudiheydra added a commit to rudiheydra/AutoBuildr that referenced this pull request Jan 27, 2026
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CoreAspectStu pushed a commit to CoreAspectStu/autocoder-custom that referenced this pull request Feb 9, 2026
feat: Twitter-style UI theme with custom theme override system
CoreAspectStu pushed a commit to CoreAspectStu/autocoder-custom that referenced this pull request Feb 9, 2026
- Remove translate-x/translate-y CSS selectors that broke layout utilities
  (AssistantPanel slide animation, DebugLogViewer resize handle)
- Add browser validation to get_playwright_browser() with warning for
  invalid values (matches get_playwright_headless() behavior)
- Remove phantom SQLite documentation from CUSTOM_UPDATES.md that
  described features not present in PR AutoForgeAI#93
- Update checklist and revert instructions to match actual changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants