webx

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 12 Imported by: 0

README

webx

Beautiful, accessible UI components built with Go, Templ, Tailwind CSS, DaisyUI, and Datastar.

Philosophy

webx is inspired by daisyui. Like daisyui, this is a component library you install as a dependency. Fork it and own it.

  • You own the code. Need to change something? Just edit it.
  • No versioning conflicts or breaking changes to worry about.
  • Zero configuration complexity. Customize by changing the code.
  • Server-side rendering with Go/templ — no Node.js build step for components.
  • ~15KB of JavaScript total (the Datastar library) for all frontend interactivity.

Component structure

Each component lives in its own directory under ui/ and follows a consistent pattern:

ui/button/
  button.templ       # Component template (Props struct, variants, rendering)
  button_templ.go    # Generated Go code (do not edit)

Interactive components that need a server-side handler add extra files:

ui/form/
  form.templ         # Component template
  form_templ.go      # Generated Go code
  handler.go         # SSE handler for Datastar interactivity

Components use DaisyUI classes for styling and Datastar attributes for interactivity:

package button

type Props struct {
    ID         string
    Class      string
    Attributes templ.Attributes
    Variant    Variant           // btn-primary, btn-secondary, etc.
    Size       Size              // btn-lg, btn-sm, btn-xs
    Disabled   bool
    OnClick    string            // Datastar action expression
}

templ Button(props ...Props) {
    // Optional variadic props — sensible zero-value defaults
    // DaisyUI classes merged with utils.TwMerge()
    // Datastar attributes spread via ds.* helpers
}

Import and use in your templ files:

import "github.com/plaenen/webx/ui/button"

@button.Button(button.Props{Variant: button.VariantPrimary}) {
    Click me
}

Prerequisites

  • Go 1.24+

Getting started

# Install dependencies (downloads DaisyUI, Datastar, tidies modules)
go tool task install:all

# Generate templ + build Tailwind
go tool templ generate
go tool gotailwind

# Run the showcase (uses open-source Datastar)
go run ./cmd/showcase serve

The showcase starts at http://localhost:3000.

Datastar Pro (optional)

The showcase supports both open-source Datastar and Datastar Pro. Open-source is the default and requires no license.

To use Datastar Pro, purchase a license from data-star.dev and place the files in the byol/ directory (gitignored):

byol/
  datastar/
    datastar-pro.js
    datastar-inspector.js
    datastar-pro-rocket.js    # optional

Then start the showcase with the --pro flag:

go run ./cmd/showcase serve --pro

Pro mode enables the Datastar inspector and loads from your local BYOL files.

Documentation

Overview

Provides context for webx templates

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrWorkspaceLimitReached is returned when a user has reached the
	// maximum number of workspaces allowed by their plan.
	ErrWorkspaceLimitReached = errors.New("workspace limit reached for current plan")

	// ErrMemberLimitReached is returned when a workspace has reached the
	// maximum number of members allowed by its plan.
	ErrMemberLimitReached = errors.New("member limit reached for current plan")
)
View Source
var Byol embed.FS
View Source
var Static embed.FS

Functions

func Post

func Post(url string) string

Post returns a Datastar expression that performs a POST request to the given URL.

func RequireCapability

func RequireCapability(required string) func(http.Handler) http.Handler

RequireCapability returns middleware that checks the user has the required capability in the current workspace context. Returns 403 if not.

func SecurityHeadersMiddleware

func SecurityHeadersMiddleware() func(http.Handler) http.Handler

SecurityHeadersMiddleware sets common security response headers.

func SessionMiddleware

func SessionMiddleware(store SessionStore) func(http.Handler) http.Handler

SessionMiddleware reads or creates a session cookie, then populates WebXContext with the session ID and CSRF token from the store.

func WithWorkspaceContext

func WithWorkspaceContext(ctx context.Context, wsc *WorkspaceContext) context.Context

WithWorkspaceContext returns a new context with the WorkspaceContext attached.

func WorkspaceMiddleware

func WorkspaceMiddleware(
	workspaces WorkspaceStore,
	memberships MembershipStore,
	roles RoleStore,
	getUserID func(r *http.Request) string,
) func(http.Handler) http.Handler

WorkspaceMiddleware resolves the workspace from the URL parameter "wsID", verifies the user is a member, derives capabilities from the role, and attaches a WorkspaceContext to the request context.

getUserID extracts the current user's ID from the request. This decouples the middleware from any specific session implementation.

Types

type AddMemberInput

type AddMemberInput struct {
	WorkspaceID string
	UserID      string
	RoleID      string
	Limits      *PlanLimits // if non-nil, enforce MaxMembers before adding
}

AddMemberInput is the input for adding a member to a workspace.

type BillingProvider

type BillingProvider interface {
	// CreateCustomer creates a billing customer for a workspace.
	CreateCustomer(workspaceID, email string) (customerID string, err error)
	// CreateSubscription starts a subscription for the given tier.
	CreateSubscription(customerID string, tier PlanTier) (subscriptionID string, err error)
	// CancelSubscription cancels the workspace's subscription.
	CancelSubscription(subscriptionID string) error
	// GetPortalURL returns a URL where the user can manage billing.
	GetPortalURL(customerID string) (string, error)
	// ChangePlan upgrades or downgrades to a new tier.
	ChangePlan(subscriptionID string, tier PlanTier) error
}

BillingProvider abstracts a billing/payment backend (e.g. Stripe).

type CreateWorkspaceInput

type CreateWorkspaceInput struct {
	Name       string
	OwnerID    string
	Tier       PlanTier    // stored on the workspace
	Limits     *PlanLimits // if non-nil, enforce MaxWorkspaces before creation
	ProviderID string
	RegionID   string
}

CreateWorkspaceInput is the input for creating a new workspace.

type CreateWorkspaceResult

type CreateWorkspaceResult struct {
	Workspace  Workspace
	OwnerRole  Role
	Membership Membership
}

CreateWorkspaceResult is the output of workspace creation.

func CreateWorkspace

func CreateWorkspace(
	workspaces WorkspaceStore,
	roles RoleStore,
	memberships MembershipStore,
	input CreateWorkspaceInput,
) (*CreateWorkspaceResult, error)

CreateWorkspace creates a workspace with a system "owner" role and assigns the creating user as owner. This enforces the invariant that every workspace always has at least one owner. When Limits is provided, it checks that the user has not exceeded the workspace cap before creating.

type LimitStatus

type LimitStatus struct {
	Limit     int // 0 = unlimited
	Used      int
	Remaining int // -1 = unlimited
}

LimitStatus reports usage against a limit.

func CheckMemberLimit

func CheckMemberLimit(memberships MembershipStore, workspaceID string, limits PlanLimits) (*LimitStatus, error)

CheckMemberLimit returns how many members a workspace has vs. the given limits.

func CheckWorkspaceLimit

func CheckWorkspaceLimit(memberships MembershipStore, userID string, limits PlanLimits) (*LimitStatus, error)

CheckWorkspaceLimit returns how many workspaces a user has vs. the given limits.

type Membership

type Membership struct {
	ID          string
	WorkspaceID string
	UserID      string
	RoleID      string
	CreatedAt   time.Time
}

Membership binds a user to a workspace with a specific role.

func AddMember

func AddMember(
	memberships MembershipStore,
	input AddMemberInput,
) (*Membership, error)

AddMember adds a user to a workspace with the given role. When Limits is provided, it checks that the workspace has not exceeded the member cap.

type MembershipStore

type MembershipStore interface {
	Create(m Membership) error
	Get(id string) (*Membership, error)
	GetByUserAndWorkspace(userID, workspaceID string) (*Membership, error)
	ListByWorkspace(workspaceID string) ([]Membership, error)
	ListByUser(userID string) ([]Membership, error)
	Delete(id string) error
}

MembershipStore persists workspace memberships.

type NoopBillingProvider

type NoopBillingProvider struct{}

NoopBillingProvider is a no-op implementation for dev/testing.

func (NoopBillingProvider) CancelSubscription

func (NoopBillingProvider) CancelSubscription(_ string) error

func (NoopBillingProvider) ChangePlan

func (NoopBillingProvider) ChangePlan(_ string, _ PlanTier) error

func (NoopBillingProvider) CreateCustomer

func (NoopBillingProvider) CreateCustomer(_, _ string) (string, error)

func (NoopBillingProvider) CreateSubscription

func (NoopBillingProvider) CreateSubscription(_ string, _ PlanTier) (string, error)

func (NoopBillingProvider) GetPortalURL

func (NoopBillingProvider) GetPortalURL(_ string) (string, error)

type Plan

type Plan struct {
	ID        string
	Tier      PlanTier
	Name      string // display name, e.g. "Pro Plan"
	Limits    PlanLimits
	CreatedAt time.Time
}

Plan is a named plan with limits.

type PlanLimits

type PlanLimits struct {
	MaxWorkspaces   int      // per user, 0 = unlimited
	MaxMembers      int      // per workspace, 0 = unlimited
	MaxStorageBytes int64    // per workspace, 0 = unlimited
	MaxTokens       int      // per workspace, 0 = unlimited
	AllowSelfHost   bool     // whether self-hosted providers are available
	AllowedRegions  []string // region IDs available; empty = all
}

PlanLimits defines the resource limits for a plan tier. A zero value means unlimited for numeric fields.

type PlanTier

type PlanTier string

PlanTier identifies a pricing tier. Apps define their own tier constants.

type Provider

type Provider struct {
	ID          string
	Name        string       // e.g. "AWS", "Google Cloud", "My Home Server"
	Type        ProviderType // app-defined, e.g. "managed" or "selfhosted"
	OwnerID     string       // self-hosted: user who created it (empty for managed)
	PairingCode string       // self-hosted: short code for pairing
	PairedAt    *time.Time   // self-hosted: nil = pending pairing
	CreatedAt   time.Time
}

Provider represents a deployment target for workspaces.

type ProviderStore

type ProviderStore interface {
	Create(p Provider) error
	Get(id string) (*Provider, error)
	List() ([]Provider, error)
	ListByType(t ProviderType) ([]Provider, error)
	ListByOwner(ownerID string) ([]Provider, error)
	Update(p Provider) error
	Delete(id string) error
}

ProviderStore persists providers.

type ProviderType

type ProviderType string

ProviderType distinguishes managed cloud providers from self-hosted. Apps define their own constants (e.g. "managed", "selfhosted").

type Region

type Region struct {
	ID         string
	ProviderID string
	Name       string // e.g. "us-east-1"
	Label      string // e.g. "US East (Virginia)"
	CreatedAt  time.Time
}

Region represents a deployment region within a provider.

type RegionStore

type RegionStore interface {
	Create(r Region) error
	Get(id string) (*Region, error)
	ListByProvider(providerID string) ([]Region, error)
	Delete(id string) error
}

RegionStore persists regions.

type Role

type Role struct {
	ID           string
	WorkspaceID  string   // empty = global/system role
	Name         string   // e.g. "owner", "editor", "viewer"
	Capabilities []string // e.g. ["invoices:read", "invoices:write"]
	System       bool     // built-in, cannot be deleted
	CreatedAt    time.Time
}

Role defines a named set of capabilities within a workspace.

type RoleStore

type RoleStore interface {
	Create(r Role) error
	Get(id string) (*Role, error)
	GetByNameAndWorkspace(name, workspaceID string) (*Role, error)
	ListByWorkspace(workspaceID string) ([]Role, error)
	Update(r Role) error
	Delete(id string) error
}

RoleStore persists roles.

type SessionStore

type SessionStore interface {
	Get(sessionID string, key string) (string, error)
	Set(sessionID string, key string, value string) error
	Delete(sessionID string) error
}

SessionStore provides session-scoped key/value storage. Implementations can back this with memory, NATS KV, Redis, etc.

type Subscription

type Subscription struct {
	ID             string
	WorkspaceID    string
	CustomerID     string // billing provider customer ID
	SubscriptionID string // billing provider subscription ID
	Tier           PlanTier
	Active         bool
	CreatedAt      time.Time
}

Subscription tracks a workspace's billing subscription.

type SubscriptionStore

type SubscriptionStore interface {
	Create(s Subscription) error
	Get(id string) (*Subscription, error)
	GetByWorkspace(workspaceID string) (*Subscription, error)
	Update(s Subscription) error
	Delete(id string) error
}

SubscriptionStore persists subscriptions.

type Token

type Token struct {
	Value     string
	Email     string
	Verified  bool
	ExpiresAt time.Time
	CreatedAt time.Time
}

func (*Token) Expired

func (t *Token) Expired() bool

type TokenStore

type TokenStore interface {
	Create(email string) (*Token, error)
	Get(value string) (*Token, error)
	MarkVerified(value string) bool
	Delete(value string)
	ListAll() ([]*Token, error)
}

type WebXContext

type WebXContext struct {
	ShowDatastarInspector bool
	DatastarPro           bool
	CSRFToken             string
	DevMode               bool
	SessionID             string
	BasePath              string // prefix for all SSE handler routes (e.g. "/showcase")
}

func FromContext

func FromContext(ctx context.Context) *WebXContext

func NewContext

func NewContext(ctx context.Context) *WebXContext

func (*WebXContext) APIPath

func (wctx *WebXContext) APIPath(path string) string

APIPath returns the full path for a component SSE handler by prepending the BasePath. For example, with BasePath "/showcase" and path "/api/calendar/navigate", it returns "/showcase/api/calendar/navigate".

func (*WebXContext) WithContext

func (wctx *WebXContext) WithContext(ctx context.Context) context.Context

type Workspace

type Workspace struct {
	ID         string
	Name       string
	PlanTier   PlanTier
	ProviderID string
	RegionID   string
	CreatedAt  time.Time
}

Workspace represents a logical tenant.

type WorkspaceContext

type WorkspaceContext struct {
	Workspace    *Workspace
	Membership   *Membership
	Role         *Role
	Capabilities capability.Set
}

WorkspaceContext holds the resolved workspace, membership, role, and capabilities for the current request.

func GetWorkspaceContext

func GetWorkspaceContext(ctx context.Context) *WorkspaceContext

GetWorkspaceContext returns the WorkspaceContext from the context, or nil.

type WorkspaceStore

type WorkspaceStore interface {
	Create(ws Workspace) error
	Get(id string) (*Workspace, error)
	List() ([]Workspace, error)
	Update(ws Workspace) error
	Delete(id string) error
}

WorkspaceStore persists workspaces.

Directories

Path Synopsis
cmd
dashboard command
dashboard/internal/fragments/login
templ: version: v0.3.977
templ: version: v0.3.977
dashboard/internal/pages/auth/templates
templ: version: v0.3.977
templ: version: v0.3.977
templ: version: v0.3.977
icongen command
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
showcase command
showcase/internal/layouts
templ: version: v0.3.977
templ: version: v0.3.977
showcase/internal/pages
templ: version: v0.3.977
templ: version: v0.3.977
Package ds provides typed helpers for Datastar HTML attributes.
Package ds provides typed helpers for Datastar HTML attributes.
templ: version: v0.3.977
templ: version: v0.3.977
providers
ui
accordion
templ: version: v0.3.977
templ: version: v0.3.977
alert
templ: version: v0.3.977
templ: version: v0.3.977
avatar
templ: version: v0.3.977
templ: version: v0.3.977
badge
templ: version: v0.3.977
templ: version: v0.3.977
breadcrumbs
templ: version: v0.3.977
templ: version: v0.3.977
button
templ: version: v0.3.977
templ: version: v0.3.977
calendar
templ: version: v0.3.977
templ: version: v0.3.977
card
templ: version: v0.3.977
templ: version: v0.3.977
carousel
templ: version: v0.3.977
templ: version: v0.3.977
chat
templ: version: v0.3.977
templ: version: v0.3.977
dock
templ: version: v0.3.977
templ: version: v0.3.977
drawer
templ: version: v0.3.977
templ: version: v0.3.977
dropdown
templ: version: v0.3.977
templ: version: v0.3.977
fab
templ: version: v0.3.977
templ: version: v0.3.977
fieldset
templ: version: v0.3.977
templ: version: v0.3.977
fileinput
templ: version: v0.3.977
templ: version: v0.3.977
fileupload
templ: version: v0.3.977
templ: version: v0.3.977
filter
templ: version: v0.3.977
templ: version: v0.3.977
footer
templ: version: v0.3.977
templ: version: v0.3.977
form
templ: version: v0.3.977
templ: version: v0.3.977
hovergallery
templ: version: v0.3.977
templ: version: v0.3.977
indicator
templ: version: v0.3.977
templ: version: v0.3.977
join
templ: version: v0.3.977
templ: version: v0.3.977
kbd
templ: version: v0.3.977
templ: version: v0.3.977
label
templ: version: v0.3.977
templ: version: v0.3.977
link
templ: version: v0.3.977
templ: version: v0.3.977
list
templ: version: v0.3.977
templ: version: v0.3.977
loading
templ: version: v0.3.977
templ: version: v0.3.977
markdown
templ: version: v0.3.977
templ: version: v0.3.977
menu
templ: version: v0.3.977
templ: version: v0.3.977
mockupcode
templ: version: v0.3.977
templ: version: v0.3.977
modal
templ: version: v0.3.977
templ: version: v0.3.977
money
templ: version: v0.3.977
templ: version: v0.3.977
moneyinput
templ: version: v0.3.977
templ: version: v0.3.977
navbar
templ: version: v0.3.977
templ: version: v0.3.977
pagination
templ: version: v0.3.977
templ: version: v0.3.977
progress
templ: version: v0.3.977
templ: version: v0.3.977
radialprogress
templ: version: v0.3.977
templ: version: v0.3.977
radio
templ: version: v0.3.977
templ: version: v0.3.977
rangeinput
templ: version: v0.3.977
templ: version: v0.3.977
rating
templ: version: v0.3.977
templ: version: v0.3.977
selectinput
templ: version: v0.3.977
templ: version: v0.3.977
separator
templ: version: v0.3.977
templ: version: v0.3.977
skeleton
templ: version: v0.3.977
templ: version: v0.3.977
stack
templ: version: v0.3.977
templ: version: v0.3.977
stat
templ: version: v0.3.977
templ: version: v0.3.977
status
templ: version: v0.3.977
templ: version: v0.3.977
steps
templ: version: v0.3.977
templ: version: v0.3.977
tab
templ: version: v0.3.977
templ: version: v0.3.977
table
templ: version: v0.3.977
templ: version: v0.3.977
textarea
templ: version: v0.3.977
templ: version: v0.3.977
textrotate
templ: version: v0.3.977
templ: version: v0.3.977
themecontroller
templ: version: v0.3.977
templ: version: v0.3.977
timeline
templ: version: v0.3.977
templ: version: v0.3.977
toast
templ: version: v0.3.977
templ: version: v0.3.977
toggle
templ: version: v0.3.977
templ: version: v0.3.977
tooltip
templ: version: v0.3.977
templ: version: v0.3.977
validator
templ: version: v0.3.977
templ: version: v0.3.977

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL