Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ tmp_dir = "tmp"
[build]
args_bin = ["serve", "-p", "3000"]
bin = "./popui"
cmd = "go generate ./... && templ generate && go build ./cmd/popui"
# cmd = "templ generate && go build ./cmd/popui"
# cmd = "go generate ./... && templ generate && go build ./cmd/popui"
cmd = "templ generate && go build ./cmd/popui"
delay = 1000
exclude_dir = ["tmp", "vendor", "testdata", "node_modules", "dist", "svelte", "web-components", "html", "public", "icons", "go/assets"]
exclude_file = ["popui", "assets/popui.css"]
Expand Down
7 changes: 7 additions & 0 deletions .cursor/rules/project-build.mdc
Comment thread
beliolfa marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -
---
description: PopUI project build process, architecture, and development workflow
alwaysApply: true
---

@AGENTS.md
86 changes: 86 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# PopUI Build & Architecture

## Project Overview

Go component library using [templ](https://templ.guide) for HTML templating and Tailwind CSS v4 for styling. The dev server runs via `air` on port 3000.

## Build Pipeline

There are two independent build steps:

### 1. Tailwind CSS (manual)

```bash
tailwindcss -i styles.css -o assets/popui.css --minify
```

Run this whenever you add new Tailwind classes that aren't already in `assets/popui.css`. The CSS is **embedded** into the Go binary via `//go:embed assets/*` in `assets.go`, so a Go rebuild is also needed after regenerating CSS.

After rebuilding CSS, trigger an air rebuild by touching any `.templ` file:

```bash
tailwindcss -i styles.css -o assets/popui.css --minify && touch layout.templ
```

If dynamically constructed class names are needed (e.g. `"shadow-" + name`), add them to the `@source inline(...)` safelist in `styles.css`.

### 2. Go + Templ (automatic via air)

Air watches `.templ`, `.go`, and other source files and runs:

```
templ generate && go build ./cmd/popui
```

Air does **not** rebuild CSS. It excludes `assets/popui.css` from its watch list.

### Prerequisites

The `tailwindcss` CLI must be installed on your system. Install via npm globally:

```bash
npm install -g @tailwindcss/cli
```

There are **no npm dependencies** in this project. The Tailwind plugins (`@tailwindcss/forms`, `@tailwindcss/typography`) and their runtime dependencies are vendored in the `tailwind/` directory. The `styles.css` entry point references them via local paths:

```css
@import "./tailwind/node_modules/tailwindcss" source(none);
@plugin "./tailwind/forms.js";
@plugin "./tailwind/typography/index.js";
```

To update vendored plugins, replace the files in `tailwind/` with newer versions from npm and test with a full CSS rebuild.

## Key Directories

- `*.templ` (root) - Core PopUI components
- `props/` - Go structs for component props
- `icons/` - Auto-generated icon components (via `go generate` from SVG source files)
- `internal/docs/` - Documentation site pages and component examples
- `internal/docs/components/` - Individual component doc pages
- `internal/docs/examples/` - Example usage for each component
- `examples/` - Full application examples (admin, app, console, wizard, etc.)
- `cmd/popui/serve.go` - Dev server routes
- `assets/popui.css` - Compiled CSS (embedded in binary, do not edit directly)
- `styles.css` - Tailwind CSS entry point
- `tailwind.theme.css` - Design tokens (colors, shadows, spacing)
- `tailwind/` - Vendored Tailwind plugins (@tailwindcss/forms, @tailwindcss/typography) and their dependencies
- `components.css` - Custom CSS beyond Tailwind utilities

## Icons

Icons are generated from SVG files. The generator at `icons/generate.go` produces:
- `icons/icons_list.templ` - Icon templ components
- `internal/docs/components/icons_list.templ` - Docs icon gallery page

Run with `go generate ./icons/` (requires the popui SVG source repo at `../../popui/icons/themes`).

When adding icons manually to `icons/icons_list.templ`, they are automatically included in the docs gallery.

## Templ Conventions

- `.templ` files contain the source templates
- `_templ.go` files are auto-generated (never edit manually)
- Components accept props via variadic `...props.Type` pattern
- Use `@popui.ComponentName(props)` syntax to compose components
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
53 changes: 26 additions & 27 deletions app.templ
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package popui
import (
"github.com/invopop/popui.go/classes"
"github.com/invopop/popui.go/htmx"
"github.com/invopop/popui.go/icons"
"github.com/invopop/popui.go/props"
"github.com/invopop/popui.go/tailwind"
)
Expand Down Expand Up @@ -34,9 +35,7 @@ templ App(opts ...props.App) {
{{ p := props.First(opts) }}
if p.HTMX && htmx.IsRequest(ctx) {
// HTMX request, only render the inner contents.
@appBody(p) {
{ children... }
}
{ children... }
} else {
@HTML() {
@Head(props.Head{
Expand All @@ -53,30 +52,29 @@ templ App(opts ...props.App) {
@p.Head
}
}
@Body(props.Body{ID: AppID}) {
@appBody(p) {
@Body() {
// Main app container uses universal ID for HTMX targeting.
<div
id={ AppID }
if p.Data != "" {
x-data={ p.Data }
}
if p.AccentColor != "" {
data-accent-color={ p.AccentColor }
}
class="grid grid-cols-[auto_1fr] grid-rows-[auto_1fr_auto] w-full h-full [&_nav]:col-start-1 [&_nav]:row-span-full"
>
{ children... }
</div>
// Portal for fixed-positioned elements outside the grid
if p.Portal != nil {
@p.Portal
}
}
}
}
}

templ appBody(p props.App) {
// Main app container uses universal ID for HTMX targeting.
<div
if p.Data != "" {
x-data={ p.Data }
}
if p.AccentColor != "" {
data-accent-color={ p.AccentColor }
}
class="grid grid-cols-[auto_1fr] grid-rows-[auto_1fr_auto] w-full h-full [&_nav]:col-start-1 [&_nav]:row-span-full bg-background"
>
{ children... }
</div>
}

// Main provides a wrapper for the main content area of apps.
// This should be used outside the Header, or Footer components.
// For the contents, you may want to use the Article component that provides
Expand All @@ -103,9 +101,6 @@ templ Main(opts ...props.Main) {
p.Class,
),
}
if p.Data != "" {
x-data={ p.Data }
}
{ p.Attributes... }
>
{ children... }
Expand Down Expand Up @@ -177,12 +172,16 @@ templ Header(opts ...props.Header) {
}
{ p.Attributes... }
>
/* TODO: add menu button
<button class="block p-[5px] mr-2 md:hidden">
<div class="flex items-center gap-1">
<button
class="flex items-center justify-center size-7 p-[5px] -ml-1 mr-1 cursor-pointer md:hidden"
x-data
x-show="document.getElementById('popui-sidebar')"
@click="$dispatch('popui-sidebar-toggle')"
aria-label="Toggle sidebar"
>
@icons.Menu()
</button>
*/
<div class="flex items-center gap-1">
if p.Title != nil {
@p.Title
}
Expand Down
Loading