Skip to content

feat: add realtime-collab example - complex collaborative dashboard#11

Closed
connerohnesorge wants to merge 4 commits intomainfrom
feat/realtime-collab-example
Closed

feat: add realtime-collab example - complex collaborative dashboard#11
connerohnesorge wants to merge 4 commits intomainfrom
feat/realtime-collab-example

Conversation

@connerohnesorge
Copy link
Owner

@connerohnesorge connerohnesorge commented Jun 13, 2025

Summary

This PR adds a sophisticated real-time collaborative dashboard example that demonstrates Twerge's capability to optimize TailwindCSS classes in production-ready applications with complex state management.

Features Added

Real-time Collaboration

  • WebSocket-powered live collaboration with Gorilla WebSocket
  • Real-time cursor tracking and user presence indicators
  • Multi-room support for different collaboration contexts
  • Live typing indicators and instant notifications

🏗️ Complex Architecture

  • 15+ files with complete implementation (~4,500 lines of code)
  • Comprehensive data models with 20+ types
  • In-memory data store with realistic sample data
  • RESTful API with 20+ endpoints
  • WebSocket hub managing real-time connections

🎨 UI Complexity

  • 150+ unique component states across different scenarios
  • Responsive design optimized for mobile/tablet/desktop
  • Dark/light theme support throughout
  • Interactive states (hover, focus, active, loading)
  • Complex conditional styling based on user roles and data

📊 Example Includes

  • Dashboard with real-time metrics and activity feeds
  • Project management with role-based permissions
  • Document collaboration with version control
  • Team member management with online presence
  • System health monitoring
  • Advanced search and filtering

Technical Implementation

  • Backend: Go with Chi router for HTTP handling
  • WebSockets: Gorilla WebSocket for real-time features
  • Templates: a-h/templ for type-safe HTML generation
  • Frontend: HTMX + Alpine.js for interactivity
  • CSS: TailwindCSS optimized with Twerge
  • Code Generation: Processes 62 component instances

Testing

The example has been tested and verified to:

  • ✅ Compile successfully
  • ✅ Run without errors (starts server on :8080)
  • ✅ Generate optimized classes with go run gen.go
  • ✅ Handle edge cases (empty data, offline users, etc.)

Files Added

examples/realtime-collab/
├── types/models.go          # Comprehensive data models
├── data/store.go            # In-memory store with sample data
├── handlers/handlers.go     # HTTP and WebSocket handlers
├── websocket/hub.go         # WebSocket hub implementation
├── views/dashboard.templ    # Dashboard UI components
├── views/project.templ      # Project view components
├── main.go                  # Application entry point
├── gen.go                   # Twerge code generation
├── go.mod                   # Module definition
├── package.json             # NPM dependencies
├── tailwind.config.js       # TailwindCSS configuration
├── input.css                # Custom styles and utilities
└── README.md                # Comprehensive documentation

How to Run

cd examples/realtime-collab
go mod tidy
npm install
go run gen.go
npx tailwindcss -i input.css -o _static/dist/styles.css --minify
templ generate
go run main.go
# Open http://localhost:8080

Why This Matters

This example demonstrates that Twerge can handle enterprise-level applications with:

  • Complex real-time features
  • Multiple concurrent users
  • Sophisticated UI state management
  • Production-ready architecture

It serves as a comprehensive reference for building collaborative applications while leveraging Twerge's optimization capabilities.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Introduced a full-featured real-time collaborative dashboard example with live user presence, cursor tracking, notifications, multi-room support, and advanced project/document management.
    • Added an admin dashboard example with responsive sidebar, metrics grid, sortable tables, dark mode, and Playwright end-to-end tests.
    • Provided a simple dashboard and blog CMS examples demonstrating Twerge's CSS optimization and templating.
    • Included comprehensive Go and Node.js project setups, with code generation, optimized Tailwind CSS integration, and custom utility classes.
    • Added rich documentation and specifications for admin dashboards, blog CMS, design systems, e-commerce catalogs, and dynamic form validation.
  • Documentation

    • Added detailed guides, READMEs, and specs covering usage, architecture, workflows, performance benefits, and real-world integration patterns for all new examples and features.
  • Tests

    • Introduced Playwright test suites for admin dashboard UI, navigation, tables, responsiveness, and accessibility.
  • Chores

    • Updated dependencies and configuration files to support new examples and features.
    • Improved .gitignore management and project structure for clarity and maintainability.
  • Style

    • Added new and extended CSS files with custom utility classes, responsive design, dark mode, and accessibility enhancements.
  • Refactor

    • Updated generated template code for improved error reporting and version consistency.

connerohnesorge and others added 4 commits June 9, 2025 06:56
… dashboard

This example showcases Twerge's capability to optimize TailwindCSS classes in a
production-ready collaborative application featuring:

- Real-time WebSocket collaboration with live cursors and presence indicators
- Complex dashboard with 150+ unique component states
- Multi-user project management with role-based permissions
- Document collaboration with version control and comments
- Responsive design optimized for mobile/tablet/desktop
- Dark/light theme support with system health monitoring
- Interactive components with hover/focus/active states
- Comprehensive data models and in-memory store
- 62 component instances for thorough Twerge optimization testing

The example includes:
- 15+ files with complete implementation
- WebSocket hub for real-time communication
- RESTful API with 20+ endpoints
- Templ templates with complex conditional styling
- TailwindCSS configuration with custom utilities
- Code generation script covering all component states
- Comprehensive documentation and setup instructions

This demonstrates how Twerge can handle enterprise-level applications with
complex state management while maintaining excellent developer experience
and optimized runtime performance.

🤖 Generated with [Claude Code](https://claude.ai/code)

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

coderabbitai bot commented Jun 13, 2025

Walkthrough

This update introduces two comprehensive real-world example projects—an admin dashboard and a realtime collaborative dashboard—demonstrating Twerge's capabilities in optimizing TailwindCSS usage in Go templ applications. It adds all supporting source code, templates, CSS, tests, and documentation for these examples, alongside new specifications for design system, blog CMS, e-commerce catalog, and form validation use cases. Minor fixes and documentation improvements are also included.

Changes

File(s) / Path(s) Change Summary
.claude/settings.json Added configuration for Bash command permissions and MCP server setup.
.gitignore Reordered .direnv and .vscode entries; removed CLAUDE.md from ignore list.
CLAUDE.md Added comprehensive documentation for Twerge library, including architecture, usage, workflows, and best practices.
LLMS.txt Expanded from brief intro to full usage and integration guide for Twerge, with detailed examples and workflows.
examples/admin-dashboard/** (multiple files) Added a full admin dashboard example: Go source code, templates, generated class cache, CSS, Playwright tests, Tailwind config, npm/package files, and supporting assets.
examples/dashboard/views/*.go Updated error reporting file paths in generated template code for accuracy; updated templ version comments.
examples/realtime-collab/** (multiple files) Added a realtime collaborative dashboard example: in-memory data store, handlers, WebSocket hub, Go types, templates, CSS, Tailwind config, npm/package files, and a comprehensive README.
examples/simple/views/view_templ.go Added a generated Go template for a simple example with header, main, and footer using Twerge and TailwindCSS classes.
examples/simple-debug/views/view_templ.go Updated error reporting file paths and templ version comment in generated template code.
go.mod Updated github.com/a-h/templ dependency from v0.3.857 to v0.3.898.
input.css Added new CSS file with .tw-0 through .tw-23 utility classes using Tailwind's @apply.
specs/admin-dashboard.md Added specification for admin dashboard use case, including templating, performance benefits, and code generation workflow.
specs/blog-cms.md Added specification for blog CMS with theming, typography, comment system, tag cloud, and performance optimization.
specs/design-system.md Added comprehensive design system component library spec, with tokens, buttons, cards, inputs, toasts, modals, and documentation-driven demos.
specs/ecommerce-catalog.md Added e-commerce product catalog spec with dynamic product cards, variant selectors, cart items, filter sidebar, and codegen integration.
specs/form-validation.md Added dynamic form validation system spec with multi-step forms, async validation, accessibility, and codegen integration.

Sequence Diagram(s)

Admin Dashboard Code Generation and Build Workflow

sequenceDiagram
    participant Dev as Developer
    participant Gen as gen.go (Admin Dashboard)
    participant Twerge as Twerge CodeGen
    participant Tailwind as Tailwind CLI

    Dev->>Gen: Run gen.go
    Gen->>Twerge: Generate Go, CSS, HTML from components
    Twerge-->>Gen: Output classes.go, input.css, classes.html
    Gen->>Tailwind: Run Tailwind build on input.css
    Tailwind-->>Gen: Output bundled CSS
Loading

Realtime Collab Dashboard Server Startup and Real-Time Flow

sequenceDiagram
    participant Main as main.go
    participant Store as Data Store
    participant Hub as WebSocket Hub
    participant Handlers as HTTP Handlers
    participant User as Browser/User

    Main->>Store: Initialize sample data
    Main->>Hub: Start WebSocket hub
    Main->>Handlers: Setup HTTP routes (REST, WS)
    User->>Handlers: HTTP/WebSocket requests
    Handlers->>Store: Data queries/updates
    Handlers->>Hub: Real-time events (presence, cursor, typing)
    Hub->>User: Broadcast real-time updates
Loading

Twerge Code Generation (Generalized)

sequenceDiagram
    participant Dev as Developer
    participant Gen as gen.go (Example)
    participant Views as Templated Components
    participant Twerge as Twerge CodeGen

    Dev->>Gen: Run code generation
    Gen->>Views: Instantiate components with various states
    Gen->>Twerge: Pass components to CodeGen
    Twerge-->>Gen: Output optimized Go, CSS, HTML
Loading

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (1.64.8)

level=warning msg="[runner] Can't run linter goanalysis_metalinter: buildir: failed to load package : could not load export data: no export data for "github.com/conneroisu/twerge""
level=error msg="Running error: can't run linter goanalysis_metalinter\nbuildir: failed to load package : could not load export data: no export data for "github.com/conneroisu/twerge""

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch feat/realtime-collab-example
  • Post Copyable Unit Tests in Comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 30

♻️ Duplicate comments (1)
examples/realtime-collab/handlers/handlers.go (1)

512-515: Ditto: byte length in calculateReadTime

Same issue as above – switch to word count via strings.Fields.

🧹 Nitpick comments (34)
.claude/settings.json (1)

12-20: Pin Playwright MCP server version
Using @playwright/mcp@latest can introduce unintended updates. Consider specifying an exact version (e.g., @playwright/mcp@1.x) to guarantee reproducible test runs.

input.css (1)

1-7: Add generated-file notice
This file is auto-generated between /* twerge:begin */ and /* twerge:end */. Please insert a header like /* Generated by Twerge – do not edit manually */ and document its generation step.

.gitignore (2)

12-12: Group IDE entries consistently
Consider placing .vscode alongside .idea to keep all editor/IDE patterns in one section.


14-14: Reposition .direnv near .env
Since both relate to environment configs, moving .direnv next to .env improves readability and grouping in the ignore list.

examples/realtime-collab/package.json (1)

6-15: *Scripts are nix-only; breaks on Windows shells

rm -rf and chained quotes are POSIX-specific. If cross-platform support matters, replace with rimraf (already a zero-dep npm package) and use npm-run-all / cross-env for command-chaining.

-    "clean": "rm -rf _static/dist classes/classes.go classes/classes.html"
+    "clean": "rimraf _static/dist classes"

Likewise, consider concurrently’s JSON syntax to avoid escaped quotes:

-    "dev": "concurrently \"npm run dev:css\" \"npm run dev:templ\" \"go run main.go\"",
+    "dev": "concurrently -n css,templ,go \"npm:dev:css\" \"npm:dev:templ\" \"go run main.go\"",
examples/realtime-collab/main.go (1)

43-46: Duplicate host prefix in log output

server.Addr already contains the leading : (e.g. :8080).
http://localhost%s therefore prints http://localhost:8080 – fine.
However log.Printf("🚀 Server starting on %s", server.Addr) will show :8080, not the full URL. Consider harmonising the messages for clarity.

examples/admin-dashboard/main.go (1)

45-66: Re-implementing a static file server is unnecessary

Instead of manual slicing and switch logic, use http.StripPrefix + http.FileServer:

http.Handle("/static/",
    http.StripPrefix("/static/",
        http.FileServer(http.Dir("static"))))

Reduces code and automatically sets correct MIME types.

examples/admin-dashboard/input.css (1)

6-23: Add Firefox-friendly scrollbar rules

The custom .scrollbar-thin rules only style WebKit browsers. Firefox will silently ignore them unless you also set the scrollbar-width and, optionally, scrollbar-color properties.

 @layer utilities {
   .scrollbar-thin::-webkit-scrollbar {
     width: 6px;
     height: 6px;
   }
+
+  /* Firefox */
+  .scrollbar-thin {
+    scrollbar-width: thin;            /* 6 px track */
+    scrollbar-color: theme(colors.gray.400) transparent;
+  }
examples/admin-dashboard/gen.go (4)

17-31: Avoid silent working-directory failures

os.Chdir(*cwd) will panic if the path is invalid, but the panic message loses the user-supplied path. Wrap the error to make debugging easier:

-    err := os.Chdir(*cwd)
-    if err != nil {
-        panic(err)
-    }
+    if err := os.Chdir(*cwd); err != nil {
+        panic(fmt.Errorf("cannot chdir to %q: %w", *cwd, err))
+    }

38-40: Use separate timers for each phase

start is overwritten, which makes the first defer print a meaningless duration. Track phase timers instead:

- start := time.Now()
- defer func() { fmt.Printf("(update-css) Done in %s.\n", time.Since(start)) }()
+ overallStart := time.Now()
+ defer func() { fmt.Printf("(update-css) Done in %s.\n", time.Since(overallStart)) }()

41-71: Pass components as a slice for readability

The 25-argument call to twerge.CodeGen is hard to scan and easy to break. Consider assembling the components in a slice and splatting:

 comps := []templ.Component{
     views.Dashboard(false),
     views.Dashboard(true),
     // …snip…
     views.StatusBadge(false),
 }
 if err := twerge.CodeGen(twerge.Default(),
     "classes/classes.go",
     "input.css",
     "classes/classes.html",
-    // Dashboard with sidebar open
-    // …
-    views.StatusBadge(false),
- );
+    comps...);  // spread

86-91: Fail gracefully when Tailwind is missing

exec.Command("tailwindcss", …) will return “executable file not found” only after attempting to run. A quick pre-flight avoids an opaque stack trace:

 func runTailwind() {
@@
-    cmd := exec.Command("tailwindcss", "-i", "input.css", "-o", "static/dist/styles.css")
+    bin, lookErr := exec.LookPath("tailwindcss")
+    if lookErr != nil {
+        panic("tailwindcss CLI not found in PATH")
+    }
+    cmd := exec.Command(bin, "-i", "input.css", "-o", "static/dist/styles.css")
examples/admin-dashboard/playwright.config.js (1)

70-75: Increase dev-server startup timeout

Large Go builds or first-run module downloads regularly exceed 10 s. A 60 s window is safer for CI:

-    timeout: 10000,
+    timeout: 60000,
examples/realtime-collab/tailwind.config.js (1)

201-226: Unused hasSubmenu param & extra perf cost

getNavItemClasses() is called with hasSubmenu but the function discards it.
Drop the arg or use it to append the "group" class inside the helper to avoid repeated string concatenation and additional Twerge look-ups.

examples/admin-dashboard/views/dashboard.templ (1)

247-256: strconv imported globally for tiny template need

strconv.Itoa inside template loops is OK but the global import pulls it into every compilation unit.
Consider localising with {{ $i := printf "%d" (add 1 i) }} or move sample-data generation to Go code to keep templates clean.

examples/admin-dashboard/tests/dashboard.test.js (1)

141-157: toHaveClass(/tw-0/) assumes body only has one Twerge class

body may receive multiple short classes over time; regex anchored to single token will break.

Use expect(await page.evaluate(() => document.body.className)).toMatch(/tw-\d+/) or drop style assertions in favour of functional checks.

specs/admin-dashboard.md (1)

161-176: Code snippet passes generator twice

g.CodeGen(g, ...) is incorrect API based on earlier examples. Should be twerge.CodeGen(g, ...) or g.CodeGen(...) depending on signature.

Fix before developers copy-paste.

LLMS.txt (1)

73-87: Duplicate generator parameter

err := g.CodeGen( g, "views/gen_twerge.go", ...

g shouldn’t be both receiver and first arg.

err := g.CodeGen(
    "views/gen_twerge.go",
    ...
)
examples/realtime-collab/input.css (1)

38-49: Glassmorphism blocks lack graceful fallback & are costly to render

backdrop-filter is still unsupported in several browsers and incurs a noticeable GPU cost. Consider:

-.glass {
-  background: rgba(255, 255, 255, 0.1);
-  backdrop-filter: blur(10px);
-  border: 1px solid rgba(255, 255, 255, 0.2);
-}
+/* Fallback first, heavy effect last */
+.glass {
+  background: rgba(255, 255, 255, 0.8); /* ≤ Safari <15, Firefox <103 */
+  @apply bg-white/10;                   /* Tailwind utility */
+  border: 1px solid rgb(255 255 255 / .2);
+  @supports (backdrop-filter: blur(10px)) {
+    background: rgba(255, 255, 255, 0.1);
+    backdrop-filter: blur(10px);
+  }
+}

This preserves readability when the property is missing and avoids unnecessary GPU work on low-end devices.

examples/realtime-collab/gen.go (2)

223-240: Non-deterministic stats hamper reproducible builds

createMinimalStats (and most helpers) call time.Now(). Every run regenerates different timestamps which changes the generated HTML and CSS fingerprints, breaking cacheability.

Consider injecting a fixed now time.Time (e.g. via a flag) and using it across helpers for deterministic output.


323-338: Minor: notifications slice pre-allocation

Inside createManyNotifications you append 15 items but start from an empty slice. Small, but pre-allocating improves clarity and avoids re-allocations:

notifications := make([]types.Notification, 0, 15)
CLAUDE.md (1)

1-4: Consider renaming CLAUDE.md to DEVELOPER_GUIDE.md

The content is a general developer manual, not specific to Claude. A conventional name makes it discoverable to humans and documentation tooling.

specs/blog-cms.md (1)

140-161: Code snippet will not compile (min, strconv, slices missing)

Readers copying the snippet will hit undefined identifiers/imports. Add the required imports or helper functions, e.g.:

import (
    "strconv"
    "slices"
    "math"
)

func min(a, b int) int { if a < b { return a }; return b }
examples/realtime-collab/websocket/hub.go (1)

532-534: Improve message ID generation to avoid collisions

Using UnixNano for message IDs could result in collisions in high-frequency scenarios. Consider using a more robust ID generation method.

+import "github.com/google/uuid"

 func generateMessageID() string {
-	return fmt.Sprintf("%d", time.Now().UnixNano())
+	return uuid.New().String()
 }

Alternatively, if you want to avoid external dependencies:

+import "crypto/rand"
+import "encoding/hex"

 func generateMessageID() string {
-	return fmt.Sprintf("%d", time.Now().UnixNano())
+	bytes := make([]byte, 16)
+	if _, err := rand.Read(bytes); err != nil {
+		// Fallback to timestamp if random generation fails
+		return fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Int())
+	}
+	return hex.EncodeToString(bytes)
 }
examples/realtime-collab/handlers/handlers.go (1)

240-255: Broadcast may reference stale project name

After UpdateProject, the in-memory copy project isn’t refreshed, so a rename broadcast shows the old name. Fetch the updated record before emitting the activity.

examples/realtime-collab/types/models.go (1)

244-253: Consider omitempty on optional Metadata & booleans

Large zero-value payloads bloat network traffic. Adding omitempty to Metadata, IsImportant etc. keeps JSON lean.

specs/design-system.md (8)

41-64: Clarify default enum fallback.
Using default in the const block is fine, but in the generated get…Classes functions you recurse for the primary case. Consider making the default case explicit (VariantPrimary) without recursion to improve readability.


67-107: Break up long class concatenation and add ARIA attributes.
The inline string concatenation is hard to maintain. Consider building class lists via slices/join or helper functions. Also add aria-busy={loading} to the <button> for accessibility during loading states.


115-130: Duplicate size cases.
SizeSM and SizeMD currently return the same classes. If this is intentional, document it; otherwise, adjust the MD case to its intended padding/text size.


132-173: Consolidate variant styling logic.
The getButtonVariantClasses function is lengthy and repeats dark-mode prefixes. Consider extracting shared patterns or using a small DSL/helper to reduce duplication.


175-183: Enhance loading state behavior.
When loading is true you set cursor-wait but interactions are still possible. Consider adding pointer-events-none or disabling the button to prevent clicks during the load state.


284-348: Explicit error state rather than default.
default in getInputStateClasses maps to an “error” style, but there’s no StateError enum. Introduce StateError or rename the default to avoid conflating an unrecognized state with the error state.


596-668: Extract nested template into subcomponents.
The demo rendering loop is deeply nested. For readability and maintainability, consider breaking out the code table, preview, and details into smaller helper templates.


674-689: Prefer semantic class names over numeric.
Using generic .tw-1, .tw-2, etc. may conflict later. Consider .tw-modal-backdrop, .tw-modal-center or clearly document the numbering scheme.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9920fd7 and 525d9bf.

⛔ Files ignored due to path filters (4)
  • cmd/conneroh/_static/dist/style.css is excluded by !**/dist/**
  • examples/admin-dashboard/go.sum is excluded by !**/*.sum
  • examples/admin-dashboard/static/dist/styles.css is excluded by !**/dist/**
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (42)
  • .claude/settings.json (1 hunks)
  • .gitignore (1 hunks)
  • CLAUDE.md (1 hunks)
  • LLMS.txt (1 hunks)
  • examples/admin-dashboard/classes/classes.go (1 hunks)
  • examples/admin-dashboard/classes/classes.html (1 hunks)
  • examples/admin-dashboard/gen.go (1 hunks)
  • examples/admin-dashboard/go.mod (1 hunks)
  • examples/admin-dashboard/input.css (1 hunks)
  • examples/admin-dashboard/main.go (1 hunks)
  • examples/admin-dashboard/package.json (1 hunks)
  • examples/admin-dashboard/playwright.config.js (1 hunks)
  • examples/admin-dashboard/tailwind.config.js (1 hunks)
  • examples/admin-dashboard/tests/dashboard.test.js (1 hunks)
  • examples/admin-dashboard/views/dashboard.templ (1 hunks)
  • examples/admin-dashboard/views/dashboard_templ.go (1 hunks)
  • examples/dashboard/views/dashboard_templ.go (52 hunks)
  • examples/dashboard/views/report_templ.go (89 hunks)
  • examples/dashboard/views/settings_templ.go (51 hunks)
  • examples/dashboard/views/view_templ.go (15 hunks)
  • examples/realtime-collab/README.md (1 hunks)
  • examples/realtime-collab/data/store.go (1 hunks)
  • examples/realtime-collab/gen.go (1 hunks)
  • examples/realtime-collab/go.mod (1 hunks)
  • examples/realtime-collab/handlers/handlers.go (1 hunks)
  • examples/realtime-collab/input.css (1 hunks)
  • examples/realtime-collab/main.go (1 hunks)
  • examples/realtime-collab/package.json (1 hunks)
  • examples/realtime-collab/tailwind.config.js (1 hunks)
  • examples/realtime-collab/types/models.go (1 hunks)
  • examples/realtime-collab/views/dashboard.templ (1 hunks)
  • examples/realtime-collab/views/project.templ (1 hunks)
  • examples/realtime-collab/websocket/hub.go (1 hunks)
  • examples/simple-debug/views/view_templ.go (23 hunks)
  • examples/simple/views/view_templ.go (1 hunks)
  • go.mod (1 hunks)
  • input.css (1 hunks)
  • specs/admin-dashboard.md (1 hunks)
  • specs/blog-cms.md (1 hunks)
  • specs/design-system.md (1 hunks)
  • specs/ecommerce-catalog.md (1 hunks)
  • specs/form-validation.md (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
examples/admin-dashboard/playwright.config.js (1)
examples/admin-dashboard/tests/dashboard.test.js (1)
  • require (2-2)
examples/admin-dashboard/gen.go (2)
tw.go (1)
  • CodeGen (26-56)
examples/admin-dashboard/views/dashboard_templ.go (9)
  • Dashboard (31-248)
  • Sidebar (251-440)
  • Header (443-787)
  • MetricsGrid (1029-1097)
  • NavItem (790-1026)
  • MetricCard (1100-1282)
  • DataTable (1285-1499)
  • TableHeader (1502-1620)
  • StatusBadge (1623-1689)
examples/admin-dashboard/classes/classes.go (1)
twerge.go (3)
  • Default (35-35)
  • Handler (72-76)
  • CacheValue (17-26)
examples/realtime-collab/gen.go (6)
examples/realtime-collab/data/store.go (1)
  • NewStore (33-48)
examples/realtime-collab/views/dashboard_templ.go (12)
  • DashboardLayout (17-182)
  • NavigationSidebar (184-545)
  • SystemHealthWidget (789-953)
  • TopBar (1155-1378)
  • DashboardContent (2176-2323)
  • WelcomeHero (2325-2581)
  • StatsOverview (2583-2648)
  • RecentActivityFeed (2881-3122)
  • ProjectStatusChart (3534-3633)
  • TopContributors (3813-3922)
  • ActiveProjects (4241-4428)
  • NotificationCenter (4948-5267)
examples/realtime-collab/types/models.go (54)
  • Notification (333-346)
  • ActivityEvent (244-253)
  • Project (42-58)
  • Document (123-143)
  • User (7-20)
  • StatusOffline (28-28)
  • RoleViewer (38-38)
  • StatusBusy (27-27)
  • RoleEditor (37-37)
  • StatusOnline (25-25)
  • RoleGuest (39-39)
  • RoleAdmin (35-35)
  • DashboardStats (414-429)
  • ProjectStatus (78-78)
  • ProjectStatusDraft (81-81)
  • ProjectPriority (89-89)
  • PriorityLow (92-92)
  • ChartDataPoint (431-436)
  • SystemHealth (438-446)
  • ProjectStatusActive (82-82)
  • ProjectStatusCompleted (84-84)
  • ProjectStatusOnHold (83-83)
  • PriorityCritical (95-95)
  • PriorityHigh (94-94)
  • PriorityMedium (93-93)
  • ProjectStatusArchived (85-85)
  • HealthStatusHealthy (451-451)
  • HealthStatusWarning (452-452)
  • HealthStatusCritical (453-453)
  • NotificationType (348-348)
  • NotificationTypeInfo (351-351)
  • NotificationTypeWarning (353-353)
  • NotificationTypeSuccess (352-352)
  • NotificationPriority (358-358)
  • NotificationPriorityLow (361-361)
  • NotificationPriorityMedium (362-362)
  • NotificationPriorityHigh (363-363)
  • ActivityType (255-255)
  • ActivityDocumentCreated (264-264)
  • ActivityDocumentUpdated (265-265)
  • ActivityCommentAdded (267-267)
  • ActivityProjectUpdated (259-259)
  • ActivityMemberAdded (261-261)
  • ActivityTarget (273-277)
  • ProjectAnalytics (111-121)
  • DocumentType (145-145)
  • DocumentStatus (157-157)
  • ProjectMember (60-66)
  • ProjectRole (68-68)
  • ProjectRoleOwner (71-71)
  • ProjectRoleAdmin (72-72)
  • ProjectRoleCollaborator (73-73)
  • ProjectRoleReviewer (74-74)
  • ProjectRoleObserver (75-75)
examples/realtime-collab/views/project_templ.go (10)
  • ProjectView (17-178)
  • ProjectSidebar (180-538)
  • ProjectHeader (1005-1226)
  • ProjectContent (1860-2003)
  • ProjectOverview (2005-2677)
  • QuickStats (2679-2744)
  • RecentDocuments (2986-3161)
  • ProjectTimeline (3779-3954)
  • TeamMembers (4455-4620)
  • ProjectTasks (5019-5216)
tw.go (1)
  • CodeGen (26-56)
twerge.go (1)
  • Default (35-35)
examples/realtime-collab/websocket/hub.go (1)
examples/realtime-collab/types/models.go (15)
  • Room (322-331)
  • User (7-20)
  • Cursor (279-287)
  • UserStatus (22-22)
  • WebSocketMessage (296-303)
  • MessageTypeUserJoined (310-310)
  • MessageTypeUserLeft (311-311)
  • MessageTypeJoinRoom (308-308)
  • MessageTypeLeaveRoom (309-309)
  • MessageTypeCursorMove (313-313)
  • Selection (289-294)
  • MessageTypeUserTyping (312-312)
  • MessageTypeDocumentChange (314-314)
  • MessageTypeCommentAdded (315-315)
  • MessageTypePresenceUpdate (317-317)
🪛 HTMLHint (1.5.0)
examples/admin-dashboard/classes/classes.html

[error] 4-4: Doctype must be declared before any non-comment content.

(doctype-first)

🪛 LanguageTool
examples/realtime-collab/README.md

[style] ~342-~342: Consider using a less common alternative to make your writing sound more unique and professional.
Context: ...collaborative applications with Twerge. Feel free to: 1. Extend the data models - Add n...

(FEEL_FREE_TO_STYLE_ME)

CLAUDE.md

[uncategorized] ~472-~472: Loose punctuation mark.
Context: ...-ready implementations: - simple/: Basic integration pattern, minimal setu...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: checks
🔇 Additional comments (31)
go.mod (1)

6-6: Verify the templ dependency version
Ensure that v0.3.898 is released and compatible with the new collaborative and admin-dashboard examples. After merging, run go mod tidy to confirm all imports resolve correctly.

.claude/settings.json (1)

3-11: Permissions configuration looks appropriate
The allow-list for nix develop -c :* and npm run test:* and deny-list for curl:* align with the intended security posture.

examples/dashboard/views/view_templ.go (2)

3-3: Bump templ version to v0.3.898
Updated the generated code comment to reflect the new templ runtime version.


41-41: Use full relative file path in error reports
All templ.Error return statements now include examples/dashboard/views/view.templ for clearer error context. This matches the conventions in other example templates.

Also applies to: 63-63, 85-85, 108-108, 130-130, 152-152, 174-174, 196-196, 218-218, 240-240, 262-262, 288-288, 310-310, 332-332

examples/simple-debug/views/view_templ.go (2)

3-3: Bump templ version to v0.3.898
The generated code comment is updated to the current templ runtime version.


50-50: Use full relative file path in error reports
The templ.Error returns now reference examples/simple-debug/views/view.templ, ensuring consistent and accurate error reporting across templates.

Also applies to: 72-72, 94-94, 116-116, 138-138, 160-160, 182-182, 204-204, 226-226, 248-248, 270-270, 292-292, 314-314, 336-336, 358-358, 381-381, 403-403, 425-425, 447-447, 469-469, 491-491, 513-513

examples/admin-dashboard/classes/classes.html (1)

1-64: Add purge-safe Tailwind class container
Introduces a generated HTML fragment listing all optimized tw-0tw-59 classes to ensure they are retained during Tailwind's purge process.

🧰 Tools
🪛 HTMLHint (1.5.0)

[error] 4-4: Doctype must be declared before any non-comment content.

(doctype-first)

examples/admin-dashboard/package.json (1)

1-14: Add Playwright test configuration
Defines project metadata and scripts for running and debugging Playwright tests in the admin-dashboard example.

examples/dashboard/views/settings_templ.go (2)

3-3: Generated-code version bump looks fine

No functional impact.


58-60: Path prefix update improves error traces

Switching to the full relative path will make stack traces far easier to follow.

examples/dashboard/views/dashboard_templ.go (2)

3-3: Generated-code version bump acknowledged

Nothing else to flag here.


58-60: Consistent file-path in templ.Error

Good catch; unified paths aid debugging across examples.

examples/realtime-collab/go.mod (1)

3-3: Verify Go toolchain version

go 1.23 is not released yet. Unless you’re intentionally targeting the dev-branch toolchain, bumping prematurely can break CI and downstream consumers.

-go 1.23
+go 1.22
examples/dashboard/views/report_templ.go (1)

55-60: Path prefix update looks good

Generated error wrappers now contain the full relative path, improving stack-traces. No functional impact.

Also applies to: 77-82

examples/admin-dashboard/input.css (1)

25-327: Verify duplicate utility bundles

There are two almost-identical bundles (tw-4 vs tw-58) that differ only in the base translation class (tw-3 vs tw-2). If both variants are required, no action is needed, otherwise consider deduplicating to keep the generated CSS leaner (~5 KB per duplicate).

examples/admin-dashboard/playwright.config.js (1)

22-23: Confirm port alignment

The dashboard server started by go run main.go must serve on 8081 or Playwright navigation will fail. Double-check main.go (and the README) so the example doesn’t 404 in CI.

examples/admin-dashboard/classes/classes.go (1)

6-8: Ensure SetCache() is invoked

The cache is registered only when SetCache() is called. If no other file imports this package and calls the function (e.g. in init()), the template classes will expand to full strings at runtime, defeating the optimisation.

examples/simple/views/view_templ.go (1)

518-519: Missing script asset

/static/js/main.js is referenced but not generated anywhere in this PR. Either remove the tag or commit a stub JS file to avoid a 404.

examples/admin-dashboard/views/dashboard.templ (1)

160-178: String concatenation defeats Twerge deduping

getNavItemClasses(...) + " group" appends a raw utility after Twerge has already generated a short class.
The final string becomes "tw-10 group" (OK) but you lose the chance for Twerge to merge "group" with others and risk duplicates elsewhere.
Prefer passing the full set into a single twerge.It() call.

examples/realtime-collab/input.css (1)

320-333: prefers-contrast: high has near-zero browser support

Only very recent Safari Technology Preview recognises this media query. Shipping it alone gives a false sense of accessibility coverage. At minimum, add a comment and a TODO to revisit when support stabilises, or fall back to a user-controlled “high-contrast” toggle.

examples/realtime-collab/README.md (1)

71-78: Go 1.23 is not released yet

The current stable release is 1.22.x. Depending on an unreleased tool-chain blocks contributors and CI. Please verify the minimum required version and update the docs (or pin to the latest stable).

specs/design-system.md (10)

109-113: Button base classes helper is concise and clear.
No issues found here.


200-218: CardHeader structure is well-defined.
The conditional rendering of subtitle and actions is concise and accessible.


220-223: CardContent wrapper is minimal and to the point.
No concerns.


226-248: CardFooter alignment helper is clear.
The switch covers all justify cases with a sensible default.


251-279: Ensure required imports and typed variants.
You use fmt.Sprintf in the template but don’t show importing fmt. Also, hard-coded strings like "success" could be replaced by a BadgeVariant type to reduce typos.


350-354: Input base classes helper is solid.
Well-structured and clear.


356-371: Confirm size definitions.
Both SizeSM and SizeMD map to text-sm. Verify that MD shouldn’t perhaps use text-base.


555-568: Modal size helper is concise.
No issues.


573-585: ComponentShowcase layout is clear and extensible.
Good use of iteration for demos.


588-595: ComponentDemo struct fields are appropriate.
Props map allows flexibility; consider documenting expected types in comments.

Comment on lines +346 to +352
for _, category := range categories {
@FilterCheckbox(
category,
slices.Contains(selected, category),
len(getProductsInCategory(category))
)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Undefined categories identifier in filter loop
The code for _, category := range categories should iterate over the passed-in slice (e.g., filters.Categories), not an undefined categories variable.

🤖 Prompt for AI Agents
In specs/ecommerce-catalog.md around lines 346 to 352, the loop uses an
undefined variable `categories`. Replace `categories` with the correct slice
variable passed into the function, such as `filters.Categories`, to properly
iterate over the intended category list.

Comment on lines +28 to +33
templ ProductCard(product Product, inCart bool, favorited bool) {
<div class={twerge.It(
"group relative bg-white dark:bg-gray-800 rounded-xl shadow-sm hover:shadow-lg " +
"transition-all duration-300 overflow-hidden border border-gray-200 dark:border-gray-700 " +
"hover:border-gray-300 dark:hover:border-gray-600 " +
twerge.If(product.Featured, "ring-2 ring-blue-500 ring-opacity-50", "") +
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Missing imports in ProductCard snippet
The template references fmt.Sprintf, twerge.If, and getColorClass without showing an import block. Add imports for "fmt" and "github.com/conneroisu/twerge", and document or define getColorClass.

🤖 Prompt for AI Agents
In specs/ecommerce-catalog.md around lines 28 to 33, the ProductCard template
uses fmt.Sprintf, twerge.If, and getColorClass without importing the necessary
packages or defining getColorClass. Add an import block including "fmt" and
"github.com/conneroisu/twerge" at the top of the snippet, and either provide a
definition or documentation for the getColorClass function to clarify its usage.

go 1.24.1

require (
github.com/a-h/templ v0.3.857
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sync templ dependency version
The generated templates target github.com/a-h/templ v0.3.898, but this module requires v0.3.857. Update to match the generated code.

Apply this diff:

-require (
-   github.com/a-h/templ v0.3.857
+require (
+   github.com/a-h/templ v0.3.898

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/admin-dashboard/go.mod at line 6, the templ dependency version is
outdated (v0.3.857) and should be updated to v0.3.898 to match the generated
templates. Change the version number of github.com/a-h/templ from v0.3.857 to
v0.3.898 to ensure compatibility.

Comment on lines +7 to +8
github.com/conneroisu/twerge v0.0.0
github.com/go-chi/chi/v5 v5.1.0
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Pin a real version for github.com/conneroisu/twerge

v0.0.0 is a pseudo placeholder. Use a tagged or commit-hash version to make the example reproducible; the local replace directive remains fine for iterative work.

🤖 Prompt for AI Agents
In examples/realtime-collab/go.mod at lines 7 to 8, the dependency
github.com/conneroisu/twerge is pinned to the placeholder version v0.0.0, which
is not a real version. Replace this with a specific tagged version or a commit
hash to ensure reproducibility of the example, while keeping the local replace
directive for iterative development if needed.

Comment on lines +39 to +42
corePlugins: {
// Ensure group utilities are available
group: true,
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

corePlugins.group is not a valid Tailwind core-plugin

group is a variant that’s always available – it isn’t a core plugin that can be toggled.
Leaving this block in will make Tailwind fail with: “group is not a core plugin”.

-  corePlugins: {
-    // Ensure group utilities are available
-    group: true,
-  },
+  // No need to touch `corePlugins`; `group-hover` / `group-focus` etc. just work.
🤖 Prompt for AI Agents
In examples/admin-dashboard/tailwind.config.js around lines 39 to 42, the
configuration incorrectly sets corePlugins.group to true, but 'group' is not a
valid core plugin in Tailwind CSS. Remove the entire corePlugins block that
references 'group' to prevent Tailwind from failing with an invalid core plugin
error.

Comment on lines +373 to +391
func getInputStateClasses(state ComponentState) string {
switch state {
case StateDefault:
return "border-gray-300 dark:border-gray-600 " +
"focus:border-blue-500 dark:focus:border-blue-400 " +
"focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"
case StateFocus:
return "border-blue-500 dark:border-blue-400 " +
"ring-2 ring-blue-500 ring-opacity-50"
case StateDisabled:
return "border-gray-200 dark:border-gray-700 " +
"bg-gray-50 dark:bg-gray-900 cursor-not-allowed opacity-50"
default:
// Error state
return "border-red-500 dark:border-red-400 " +
"focus:border-red-500 dark:focus:border-red-400 " +
"focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Separate error from default state.
Current default branch returns the error style. Consider making the error state explicit and handling unknown states separately.

🤖 Prompt for AI Agents
In specs/design-system.md around lines 373 to 391, the default case in
getInputStateClasses returns the error state styles, which conflates error with
unknown states. Refactor the function to explicitly handle an error state case
with its own styles, and add a separate default case to handle unknown states,
possibly returning a safe fallback style or an empty string.

Comment on lines +188 to +198
// Card component system with composition
templ Card(variant string, padding bool, shadow bool, children ...templ.Component) {
<div class={twerge.It(
"bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 " +
twerge.If(padding, "p-6", "") +
getCardShadowClasses(shadow) +
getCardVariantClasses(variant)
)}>
{ children... }
</div>
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing helper implementations.
getCardShadowClasses and getCardVariantClasses are referenced but not defined in this spec. Include or document these functions to ensure completeness.

🤖 Prompt for AI Agents
In specs/design-system.md around lines 188 to 198, the functions
getCardShadowClasses and getCardVariantClasses are used but not defined or
documented. To fix this, add the implementations or detailed documentation for
these helper functions within the spec to clarify their behavior and ensure the
Card component is fully understandable and functional.

Comment on lines +700 to +776
//go:build ignore

package main

import (
"github.com/conneroisu/twerge"
"github.com/yourproject/design-system/components"
"github.com/yourproject/design-system/types"
)

func main() {
var demoComponents []templ.Component

// Generate all button combinations
sizes := []types.ComponentSize{types.SizeXS, types.SizeSM, types.SizeMD, types.SizeLG, types.SizeXL}
variants := []types.ComponentVariant{
types.VariantPrimary, types.VariantSecondary,
types.VariantOutline, types.VariantGhost, types.VariantLink,
}
states := []bool{false, true} // disabled states

for _, size := range sizes {
for _, variant := range variants {
for _, disabled := range states {
for _, loading := range states {
demoComponents = append(demoComponents,
components.Button(variant, size, disabled, loading, "", "", "Sample Button"),
)
}
}
}
}

// Generate all input combinations
inputStates := []types.ComponentState{
types.StateDefault, types.StateFocus, types.StateDisabled,
}

for _, size := range sizes {
for _, state := range inputStates {
demoComponents = append(demoComponents,
components.Input("text", "Placeholder", "", size, state, "", "", "", ""),
components.Input("text", "With left icon", "", size, state, "search", "", "", ""),
components.Input("text", "With right icon", "", size, state, "", "check", "", ""),
)
}
}

// Generate toast variations
toastTypes := []types.ToastType{
types.ToastSuccess, types.ToastError, types.ToastWarning, types.ToastInfo,
}

for _, toastType := range toastTypes {
demoComponents = append(demoComponents,
components.Toast(toastType, "Sample Toast", "This is a sample message", true, false, 5),
components.Toast(toastType, "Auto-close Toast", "This will auto-close", true, true, 3),
)
}

// Generate modal variations
for _, size := range []types.ComponentSize{types.SizeSM, types.SizeMD, types.SizeLG, types.SizeXL} {
demoComponents = append(demoComponents,
components.Modal(true, size, true, "Sample Modal", components.Text("Modal content here")),
)
}

if err := twerge.CodeGen(
twerge.Default(),
"design-system/generated.go",
"design-system/input.css",
"design-system/classes.html",
demoComponents...,
); err != nil {
panic(err)
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update placeholder imports and improve error handling.
The script imports github.com/yourproject/...—replace these with the actual module path. Rather than panic, consider returning/logging the error for smoother CI integration.

🤖 Prompt for AI Agents
In specs/design-system.md around lines 700 to 776, replace the placeholder
import paths "github.com/yourproject/..." with the actual module paths used in
your project to ensure correct package resolution. Additionally, modify the
error handling after the twerge.CodeGen call to avoid using panic; instead,
return the error or log it appropriately to allow smoother integration with CI
pipelines and better error management.

Comment on lines +18 to +38
// Design tokens as structured data
type DesignTokens struct {
Colors ColorPalette
Spacing SpacingScale
Typography TypographyScale
Shadows ShadowScale
Borders BorderScale
}

type ColorPalette struct {
Primary ColorScale
Secondary ColorScale
Neutral ColorScale
Success ColorScale
Warning ColorScale
Error ColorScale
}

type ColorScale struct {
50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 string
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Invalid struct field identifiers.
Go struct fields cannot be numeric literals (e.g., 50, 100, …). This will fail to compile. Consider renaming fields (e.g., F50, Level50) or switching to a map-based representation for scales.

🤖 Prompt for AI Agents
In specs/design-system.md around lines 18 to 38, the struct ColorScale uses
numeric literals as field names, which is invalid in Go. Rename these fields to
valid identifiers such as prefixing with a letter (e.g., F50, Level50) or
alternatively change the ColorScale struct to use a map[string]string to
represent the scale levels dynamically.

Comment on lines +492 to +553
templ Modal(
open bool,
size ComponentSize,
closable bool,
title string,
children ...templ.Component,
) {
if open {
<!-- Backdrop -->
<div class={twerge.It(
"fixed inset-0 z-40 bg-black bg-opacity-50 " +
"transition-opacity duration-300 " +
"animate-fade-in"
)}
onclick="closeModal()"
></div>

<!-- Modal -->
<div class={twerge.It(
"fixed inset-0 z-50 flex items-center justify-center p-4 " +
"animate-fade-in"
)}>
<div class={twerge.It(
"relative w-full max-h-full bg-white dark:bg-gray-800 " +
"rounded-lg shadow-xl " +
"transform transition-all duration-300 " +
"animate-scale-in " +
getModalSizeClasses(size)
)}>
<!-- Header -->
if title != "" || closable {
<div class={twerge.It(
"flex items-center justify-between p-6 " +
"border-b border-gray-200 dark:border-gray-700"
)}>
if title != "" {
<h3 class={twerge.It("text-lg font-semibold text-gray-900 dark:text-white")}>
{ title }
</h3>
}
if closable {
<button class={twerge.It(
"text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 " +
"transition-colors duration-200 p-1 rounded-md " +
"hover:bg-gray-100 dark:hover:bg-gray-700"
)}
onclick="closeModal()"
>
@Icon("x", "lg")
</button>
}
</div>
}

<!-- Content -->
<div class={twerge.It("p-6")}>
{ children... }
</div>
</div>
</div>
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define or stub closeModal() and add accessibility roles.
The backdrop and modal reference a closeModal() JS handler that isn’t shown. Also add role="dialog" and aria-modal="true" for screen readers.

🤖 Prompt for AI Agents
In specs/design-system.md around lines 492 to 553, the Modal component uses a
closeModal() function in the backdrop and close button onclick handlers, but
this function is not defined or stubbed. Define or stub a closeModal()
JavaScript handler to handle modal closing. Additionally, add accessibility
attributes role="dialog" and aria-modal="true" to the modal container div to
improve screen reader support.

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.

1 participant