feat: bootstrap design kit and vaporwave demo baseline
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# {{ .project_name }} — Instructions for Claude
|
||||
|
||||
Read and follow the project Bible before making any changes:
|
||||
|
||||
**[`bible/README.md`](bible/README.md)**
|
||||
|
||||
The Bible is the single source of truth for architecture, data models, API contracts, and UI
|
||||
pattern conventions.
|
||||
|
||||
Every significant architectural decision must be recorded in the appropriate Bible decision log.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# {{ .project_name }} — Agent Instructions
|
||||
|
||||
Read and follow `bible/README.md` as the architecture source of truth.
|
||||
|
||||
## Rules
|
||||
|
||||
- Keep architecture documentation in English.
|
||||
- Update Bible docs in the same change set as architecture/code contract changes.
|
||||
- Keep README and agent docs minimal; avoid duplicating Bible architecture content.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Architecture Documentation Policy
|
||||
|
||||
This project uses a Bible-style architecture documentation folder as the single source of truth.
|
||||
|
||||
## Mandatory Rules
|
||||
|
||||
- Record architecture decisions before or together with implementation.
|
||||
- Use English for architecture documentation.
|
||||
- Remove or update obsolete architectural guidance in the same change.
|
||||
- Keep non-Bible docs concise and reference the Bible instead of duplicating it.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Project Bible
|
||||
|
||||
The Bible is the single source of truth for this project's architecture.
|
||||
|
||||
## Documentation Rules
|
||||
|
||||
- All architecture decisions must be recorded in this Bible.
|
||||
- The documentation language is English only.
|
||||
- If a decision is superseded, update the Bible immediately and remove or mark obsolete content.
|
||||
- Do not duplicate architecture documentation in `README.md`, `CLAUDE.md`, or other files.
|
||||
|
||||
## Structure
|
||||
|
||||
- `governance/documentation-policy.md` - mandatory rules for maintaining architecture docs.
|
||||
- `architecture/system-overview.md` - current scope, boundaries, and high-level system composition.
|
||||
- `architecture/api-surface.md` - HTTP API and UI route contracts.
|
||||
- `architecture/runtime-flows.md` - critical runtime behavior and failure invariants.
|
||||
- `architecture/ui-information-architecture.md` - required UI structure and semantics.
|
||||
- `decisions/README.md` - how to capture new and updated architecture decisions.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# API Surface
|
||||
|
||||
Document all HTTP endpoints and UI routes that are part of the active contract.
|
||||
|
||||
## Rules
|
||||
|
||||
- Keep request/response shapes explicit.
|
||||
- Record compatibility aliases and deprecations.
|
||||
- Update this file when route behavior changes.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Runtime Flows
|
||||
|
||||
Document the critical runtime flows and failure invariants.
|
||||
|
||||
Recommended sections:
|
||||
|
||||
- Startup flow
|
||||
- Request handling flow
|
||||
- Background tasks
|
||||
- Failure / retry / cancellation behavior
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# System Overview
|
||||
|
||||
## Product
|
||||
|
||||
Describe the product in one paragraph.
|
||||
|
||||
## Active Scope
|
||||
|
||||
- List current in-scope modules/features
|
||||
- List user-visible surfaces
|
||||
- List operational responsibilities
|
||||
|
||||
## Explicitly Removed / Out of Scope
|
||||
|
||||
- List legacy or excluded modules to avoid accidental restoration
|
||||
|
||||
## Runtime Composition
|
||||
|
||||
- HTTP server package(s)
|
||||
- Domain/service orchestration
|
||||
- Persistence layer(s)
|
||||
- Migrations / background workers (if any)
|
||||
|
||||
## Local Execution
|
||||
|
||||
- `make run`
|
||||
- `go run ./cmd/<binary>`
|
||||
|
||||
## Verification
|
||||
|
||||
- `go test ./...`
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# UI Information Architecture
|
||||
|
||||
Document page structure, required section order, UI interaction contracts, and list/filter/
|
||||
pagination behavior.
|
||||
|
||||
Use explicit route names and action contracts so AI agents can implement changes consistently.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Architecture Decision Records
|
||||
|
||||
Use this directory to capture architecture decisions and significant updates.
|
||||
|
||||
## Required
|
||||
|
||||
- Every architecture decision must be recorded in the Bible.
|
||||
- If a decision replaces an older one, update the older document in the same change.
|
||||
- Keep entries short, explicit, and linked to the affected architecture files.
|
||||
|
||||
## Minimal Entry Template
|
||||
|
||||
- Date (`YYYY-MM-DD`)
|
||||
- Decision
|
||||
- Context
|
||||
- Consequences
|
||||
- Supersedes (if any)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Documentation Policy
|
||||
|
||||
## Purpose
|
||||
|
||||
This policy defines how architectural knowledge is captured and maintained.
|
||||
|
||||
## Mandatory Rules
|
||||
|
||||
- Record every architecture decision in the Bible before or together with implementation.
|
||||
- Use English for all architecture documentation.
|
||||
- Keep only current architecture in active sections.
|
||||
- When a solution is replaced, update or remove obsolete guidance in the same change.
|
||||
- Keep architecture details centralized in `bible/`; other top-level docs should only reference it.
|
||||
|
||||
## Change Workflow
|
||||
|
||||
1. Update the relevant file(s) in `bible/architecture/`.
|
||||
2. If behavior changed, add or update a decision note in `bible/decisions/`.
|
||||
3. Remove duplicated or outdated statements from non-Bible docs.
|
||||
4. Validate consistency against current code paths.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Gin Admin App Integration Notes (Example)
|
||||
|
||||
Suggested use:
|
||||
|
||||
- use `ai-rules` templates only if they do not conflict with existing agent instructions
|
||||
- reuse UI pattern bundles for admin tables and modal workflows
|
||||
- keep domain-specific hard rules in project-local Bible docs
|
||||
@@ -0,0 +1,9 @@
|
||||
# Greenfield App Integration Notes (Example)
|
||||
|
||||
Suggested use:
|
||||
|
||||
- apply `ai-rules`
|
||||
- apply `bible-core` (or merge selectively if a Bible already exists)
|
||||
- copy selected UI patterns into new modules/pages
|
||||
|
||||
Keep domain-specific business rules in the host project's own Bible.
|
||||
@@ -0,0 +1,9 @@
|
||||
# net/http Enterprise App Integration Notes (Example)
|
||||
|
||||
This example assumes the host repo already has a mature Bible structure and detailed UI contracts.
|
||||
|
||||
Use this kit primarily for:
|
||||
|
||||
- shared AI instruction wording
|
||||
- pattern bundles that codify existing host UI contracts
|
||||
- future cross-project standardization docs
|
||||
@@ -0,0 +1,13 @@
|
||||
# Controls + Selection Pattern
|
||||
|
||||
Canonical interactive controls for server-rendered admin/list pages:
|
||||
|
||||
- button hierarchy (primary / secondary / danger / quiet / disabled)
|
||||
- segmented filters
|
||||
- row checkboxes + select-all-visible semantics
|
||||
- bulk-action bar with explicit preview/confirm steps
|
||||
- status badges for list rows and workflow state
|
||||
|
||||
This pattern standardizes control language and interaction shape while leaving branding and
|
||||
domain terminology to the host project.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Contract: Controls + Selection
|
||||
|
||||
## Buttons
|
||||
|
||||
- Use a small stable button taxonomy: `primary`, `secondary`, `ghost`, `danger`, `disabled`.
|
||||
- The canonical visual baseline for demo/scaffold examples is the active dual baseline used in the
|
||||
demo/scaffold (`Vapor Soft` / `Vapor Night`, system-selected). A frozen Aqua snapshot bundle may
|
||||
be kept for archival reference, but examples should follow the active baseline.
|
||||
- Destructive actions (`archive`, `delete`, `remove`) must use danger styling and explicit labels.
|
||||
- Button text should describe the action outcome, not implementation detail.
|
||||
- Buttons are text-first; icons are optional and must not replace labels on primary/danger actions.
|
||||
- Base examples must show both `disabled` and `loading` states.
|
||||
|
||||
## Checkbox Selection
|
||||
|
||||
- Row checkboxes support bulk actions from a shared action bar.
|
||||
- Header checkbox semantics must be explicit:
|
||||
- select visible rows only, or
|
||||
- select all rows in query scope (must be clearly labeled)
|
||||
- Selection summary must show count (`N selected`) near bulk actions.
|
||||
- In paginated views, the UI should distinguish selection on the current page from selection across the filtered/query scope.
|
||||
- Selection state should survive pagination/filter navigation via explicit state (query params, server session, or another deterministic mechanism).
|
||||
- Same-page interactions should preserve reading position (module anchor pattern is preferred in canonical server-rendered flows).
|
||||
|
||||
## Segmented Filters
|
||||
|
||||
- Segment/toggle filters are allowed for small enumerations (status, active/archived).
|
||||
- Segmented controls are grouped joined-buttons:
|
||||
- one shared outer shell,
|
||||
- rounded corners only on the first/last segment,
|
||||
- straight internal separators between middle segments.
|
||||
- Active segment color may vary by context (for example blue preset selector vs dark status scope tabs), but geometry must remain consistent.
|
||||
- Segment changes should preserve other active filters where possible.
|
||||
|
||||
## Bulk Action Safety
|
||||
|
||||
- Bulk action click should preview count and target scope before execution.
|
||||
- Destructive bulk actions require confirmation.
|
||||
- Dense bulk action bars may move rare actions into an explicit overflow menu (`More actions`) while keeping primary actions visible.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Forms + Validation Pattern
|
||||
|
||||
Canonical patterns for server-rendered form workflows in Go web applications:
|
||||
|
||||
- tabbed / mode-switched forms
|
||||
- datalist/autocomplete suggestions
|
||||
- inline validation messages
|
||||
- review / confirm step before submit
|
||||
- explicit reset and error handling states
|
||||
|
||||
This pattern standardizes interaction flow and validation UX, not domain-specific field sets.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Contract: Forms + Validation + Suggestions
|
||||
|
||||
## Form Structure
|
||||
|
||||
- Group fields semantically and keep labels explicit.
|
||||
- Inputs requiring suggestions may use `datalist` or equivalent autocomplete UI.
|
||||
- Suggestion sources must represent the full relevant scope (not only visible rows from paginated tables).
|
||||
|
||||
## Validation
|
||||
|
||||
- Surface validation errors inline near fields and in a form-level summary when helpful.
|
||||
- Validation messages must be human-readable and action-oriented.
|
||||
- Do not hide required-field errors behind generic submit failures.
|
||||
|
||||
## Multi-Step Flow
|
||||
|
||||
Recommended stages:
|
||||
|
||||
1. `edit`
|
||||
2. `review`
|
||||
3. `confirm/submit`
|
||||
4. `result`
|
||||
|
||||
Rules:
|
||||
|
||||
- Users must be able to return from review to edit without losing entered values.
|
||||
- Destructive or irreversible actions require explicit confirmation.
|
||||
- Query- or state-driven step transitions should be deterministic and testable.
|
||||
|
||||
## File Inputs in Forms
|
||||
|
||||
- If a workflow includes upload, the file control should be clearly labeled and the supported formats explicit.
|
||||
- Import parsing/preview may be delegated to a dedicated import/export pattern, but the form contract must remain clear.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Import / Export Pattern
|
||||
|
||||
Canonical file transfer UX patterns for Go web applications:
|
||||
|
||||
- file import forms (CSV/JSON and similar)
|
||||
- validation preview tables before confirm
|
||||
- confirm step with human-readable summary
|
||||
- export controls (format + scope + options)
|
||||
- predictable file download behavior and filenames
|
||||
|
||||
This pattern covers UI and UX contracts. Business-specific validation and file schemas remain in
|
||||
the host project's own architecture docs.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Contract: Import / Export Workflows
|
||||
|
||||
## Import Workflow
|
||||
|
||||
Recommended stages:
|
||||
|
||||
1. `Upload`
|
||||
2. `Preview / Validate`
|
||||
3. `Confirm`
|
||||
4. `Execute`
|
||||
5. `Result summary`
|
||||
|
||||
Rules:
|
||||
|
||||
- Validation preview must be human-readable (table/list), not raw JSON only.
|
||||
- Warnings and errors should be shown per row and in aggregate summary.
|
||||
- Confirm step should clearly communicate scope and side effects.
|
||||
|
||||
## Export Workflow
|
||||
|
||||
- User must explicitly choose export scope (`selected`, `filtered`, `all`) when ambiguity exists.
|
||||
- Export format should be explicit (`csv`, `json`, etc.).
|
||||
- Download response should set:
|
||||
- `Content-Type`
|
||||
- `Content-Disposition`
|
||||
- If CSV targets spreadsheet users, document delimiter and BOM policy.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Import errors should map to clear user-facing messages.
|
||||
- Export errors after streaming starts must degrade gracefully (human-readable fallback).
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Modal Workflow Pattern
|
||||
|
||||
This pattern package captures modal-based create/edit/remove workflows for server-rendered Go
|
||||
web UIs.
|
||||
|
||||
Synthesis sources:
|
||||
|
||||
- detailed enterprise UI interaction contracts
|
||||
- operational admin workflows in Go web apps
|
||||
@@ -0,0 +1,9 @@
|
||||
# Contract: Modal Workflows
|
||||
|
||||
## Shared Rules
|
||||
|
||||
- Destructive actions require explicit confirmation.
|
||||
- Validation and backend errors are rendered in human-readable form.
|
||||
- UI state transitions are explicit (`open` / `submit` / `success` / `error` / `cancel`).
|
||||
- API contracts and UI copy should be documented in the host project's Bible.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Operator Tools Pattern
|
||||
|
||||
Universal pattern for complex operator/admin dashboards in Go web applications.
|
||||
|
||||
This pattern standardizes:
|
||||
|
||||
- scope tabs and queue/status filters
|
||||
- operations queue tables with row actions
|
||||
- batch actions with explicit selection
|
||||
- import/export shortcuts near operator workflows
|
||||
- safety checklists and confirmation routing
|
||||
|
||||
See `contract.md` for behavior rules.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Contract: Operator Tools Dashboard
|
||||
|
||||
## Purpose
|
||||
|
||||
Provide a canonical structure for high-density operator/admin screens without encoding
|
||||
domain-specific terminology or business rules.
|
||||
|
||||
## Required UI Regions
|
||||
|
||||
- Scope tabs (or equivalent segmented navigation)
|
||||
- Queue/status filters
|
||||
- Batch action bar with explicit selection count
|
||||
- Primary queue table/list with stable row actions
|
||||
- Safety/guardrail region (checklist, warnings, runbook notes)
|
||||
|
||||
## Selection and Batch Actions
|
||||
|
||||
- Batch actions must require explicit selection; never infer hidden rows by default.
|
||||
- The UI must display selection counts for the current view and, if applicable, outside the current view/filter.
|
||||
- Destructive or high-impact actions must route through an explicit confirmation step (modal or dedicated confirm state).
|
||||
|
||||
## Status and Queue Semantics
|
||||
|
||||
- Queue/status labels must be consistent across filters, row badges, and summaries.
|
||||
- Failed items must remain easy to filter and retry without losing current scope context.
|
||||
- Running/queued states should be visually distinct from done/failed states.
|
||||
|
||||
## Import / Export Placement
|
||||
|
||||
- Import preview and export actions should be discoverable near operator workflows.
|
||||
- Export scope must remain explicit (`selected`, `filtered`, `all`) when ambiguity exists.
|
||||
|
||||
## Reuse Boundary
|
||||
|
||||
- Keep the pattern generic: host projects provide their own tool names, domain fields, and backend execution logic.
|
||||
- This contract standardizes interaction semantics and layout zones, not business workflows.
|
||||
@@ -0,0 +1,4 @@
|
||||
# Status Indicators Pattern (Planned)
|
||||
|
||||
Reserved for health badges, sync status indicators, and severity labels.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Table + Pagination Pattern
|
||||
|
||||
This pattern package captures a shared contract for table-based UI pages with server-side
|
||||
filters and pagination.
|
||||
|
||||
It is derived from mature server-rendered admin UIs and list-page conventions across multiple
|
||||
Go web codebases.
|
||||
@@ -0,0 +1,3 @@
|
||||
// Placeholder template for pagination helpers.
|
||||
// Adapt from existing host codebase conventions (net/http or Gin).
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Contract: Table + Server-Side Filters + Pagination
|
||||
|
||||
## Required Behavior
|
||||
|
||||
- Filters apply to the full query scope before pagination (not page-local filtering).
|
||||
- Pagination state is controlled by URL query parameters.
|
||||
- Changing a filter resets the page parameter to page `1`.
|
||||
- UI shows a summary (`Showing X–Y of N`) and an explicit active page state in pagination controls.
|
||||
- Canonical demo visual style uses a centered dot pager while preserving page semantics via URL parameters and accessible labels.
|
||||
- Demo/base contract includes a `rows per page` control.
|
||||
- Status badge columns should be centered when the column semantics are status-only values.
|
||||
- Small modules (no internal scroll, no more than 2 actions) should place actions in the module header row.
|
||||
- Shared table/filter controls should inherit the repository baseline component theme
|
||||
(currently Vapor Soft / Vapor Night in the canonical demo/scaffold) rather than redefining
|
||||
per-pattern primitives.
|
||||
|
||||
## Recommended Query Parameters
|
||||
|
||||
- `page` for single-list pages
|
||||
- `per_page` when the page-size control is user-visible
|
||||
- section-specific params (for example `active_page`, `chronology_page`) for multi-list pages
|
||||
|
||||
## Interaction Guardrails
|
||||
|
||||
- Same-page filter/pagination interactions should preserve user reading position (for example via module anchors such as `#table-filters` / `#table-list`).
|
||||
- Table status badges should remain readable under the shared theme baseline (including tinted badge variants when a host project opts into a legacy or alternate visual preset).
|
||||
- Dot pager interactions should remain keyboard accessible and expose page meaning via labels/`aria-current`, even if numbers are visually hidden.
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Placeholder styles for table pagination pattern. */
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<!-- Placeholder table + pager partial. -->
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# macOS Aqua Theme Snapshot (Legacy)
|
||||
|
||||
Status: legacy reference only (not active baseline)
|
||||
|
||||
This directory preserves the Aqua-style visual exploration snapshot that was developed during demo
|
||||
refinement. It is stored as a reusable archive bundle so it can be referenced later without
|
||||
driving the active baseline.
|
||||
|
||||
Active visual baseline for the demo/scaffold is Aqua-first. This package is a frozen snapshot for archival/reference use.
|
||||
|
||||
Contents:
|
||||
|
||||
- `demo-aqua-freeze.css` — frozen snapshot of the demo stylesheet at the time of the freeze
|
||||
- `notes.md` — summary of what was explored and how to treat the snapshot
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
# Aqua Legacy Snapshot Notes
|
||||
|
||||
This snapshot is kept for historical reference and selective reuse.
|
||||
|
||||
## What it captures
|
||||
|
||||
- Aqua-style control surfaces and button hierarchy
|
||||
- segmented controls and tab-like grouped buttons
|
||||
- modal window chrome experiments (titlebar + close button)
|
||||
- table/filter visual refinements and dot-pager styling
|
||||
- style-playground Aqua preset refinements
|
||||
|
||||
## What it is not
|
||||
|
||||
- Not a required dependency for host projects
|
||||
- Not the live source of truth for the current Aqua baseline (the live baseline is in demo/scaffold CSS)
|
||||
- Not the target for normal iterative styling work unless explicitly requested
|
||||
|
||||
## Current policy
|
||||
|
||||
- Active baseline styling remains Aqua-first in the live demo/scaffold assets.
|
||||
- Use this snapshot only when explicitly needed for archival comparison or extraction.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Timeline Cards Pattern
|
||||
|
||||
Canonical timeline UX for operational history views:
|
||||
|
||||
- cards grouped by day
|
||||
- summary chips for aggregated actions
|
||||
- source labels (`ingest`, `manual`, `system`, etc.)
|
||||
- single drilldown modal (no nested modals)
|
||||
- in-card search/filtering for event lists
|
||||
|
||||
This pattern is intended for history/audit/timeline surfaces in server-rendered Go web UIs.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Contract: Timeline Cards + Drilldown
|
||||
|
||||
## Card Grouping
|
||||
|
||||
- Render timeline as grouped cards (typically by day), not raw event rows.
|
||||
- Correlated or visually equivalent events may be collapsed into one card with counts.
|
||||
- Card summaries should be human-readable and avoid repeating page-scope identity labels.
|
||||
|
||||
## Filters
|
||||
|
||||
- Timeline filters are server-side when timeline is paginated or large.
|
||||
- Filters should preserve grouping semantics and timezone behavior.
|
||||
- Scope-invariant filters may be hidden on entity detail pages.
|
||||
|
||||
## Drilldown
|
||||
|
||||
- One card opens one drilldown modal/panel.
|
||||
- Drilldown contains:
|
||||
- event list (left/top)
|
||||
- selected event details (right/bottom)
|
||||
- No nested modal inside drilldown.
|
||||
- Card-local search/filter may be applied within the drilldown.
|
||||
|
||||
## UX Rules
|
||||
|
||||
- Use human-readable source labels.
|
||||
- Prefer action-oriented card titles (`Installed N components`, `Removed N components`).
|
||||
- Empty states must explain whether filters removed all results.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
run:
|
||||
go run ./cmd/demo-server
|
||||
|
||||
build:
|
||||
go build ./cmd/demo-server
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
fmt:
|
||||
gofmt -w $$(find . -name '*.go' -type f)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Go net/http Web Skeleton
|
||||
|
||||
Minimal starter skeleton for a Go web app using:
|
||||
|
||||
- `net/http`
|
||||
- `html/template`
|
||||
- embedded templates and static assets
|
||||
|
||||
This scaffold is intended as a starting point that host repositories can adapt.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type IndexViewData struct {
|
||||
Title string
|
||||
}
|
||||
|
||||
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
_ = s.render(w, "base.html", IndexViewData{Title: "Home"})
|
||||
}
|
||||
|
||||
func (s *Server) handleHealthz(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
appweb "{{ .module_path }}/web"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
mux *http.ServeMux
|
||||
tmpl *template.Template
|
||||
}
|
||||
|
||||
func NewServer() (*Server, error) {
|
||||
tmpl, err := parseTemplates()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &Server{
|
||||
mux: http.NewServeMux(),
|
||||
tmpl: tmpl,
|
||||
}
|
||||
s.registerRoutes()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) Handler() http.Handler { return s.mux }
|
||||
|
||||
func (s *Server) registerRoutes() {
|
||||
s.mux.HandleFunc("/", s.handleIndex)
|
||||
s.mux.HandleFunc("/healthz", s.handleHealthz)
|
||||
staticFS, _ := fs.Sub(appweb.Assets, "static")
|
||||
s.mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
appweb "{{ .module_path }}/web"
|
||||
)
|
||||
|
||||
func parseTemplates() (*template.Template, error) {
|
||||
t, err := template.ParseFS(appweb.Assets, "templates/*.html")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse templates: %w", err)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (s *Server) render(w http.ResponseWriter, name string, data any) error {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
if err := s.tmpl.ExecuteTemplate(w, name, data); err != nil {
|
||||
http.Error(w, "template error", http.StatusInternalServerError)
|
||||
return fmt.Errorf("render %s: %w", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package web
|
||||
|
||||
import "embed"
|
||||
|
||||
// Assets contains templates and static files.
|
||||
//
|
||||
//go:embed templates/* static/*
|
||||
var Assets embed.FS
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
:root {
|
||||
--bg: #e6e8ee;
|
||||
--ink: #1f2023;
|
||||
--muted: #5d646f;
|
||||
--card: linear-gradient(180deg, rgba(252,252,253,0.99), rgba(240, 244, 249, 0.97) 44%, rgba(228, 238, 248, 0.96) 78%, rgba(221, 234, 248, 0.96));
|
||||
--line: #b9cbe0;
|
||||
--accent: linear-gradient(180deg, #85b8ef 0%, #93c6fb 26%, #abd8ff 55%, #c7e8ff 82%, #def2ff 100%);
|
||||
--accent-line: #88a4d4;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Lucida Grande", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
background:
|
||||
radial-gradient(760px 360px at 14% 6%, rgba(255,255,255,0.82), transparent 72%),
|
||||
radial-gradient(760px 360px at 88% 8%, rgba(154, 203, 247, 0.16), transparent 74%),
|
||||
repeating-linear-gradient(to bottom, rgba(255,255,255,0.05) 0 1px, rgba(170,182,198,0.03) 1px 3px),
|
||||
linear-gradient(#eef1f6, #dde2ea);
|
||||
color: var(--ink);
|
||||
}
|
||||
.shell {
|
||||
max-width: 880px;
|
||||
margin: 0 auto;
|
||||
padding: 24px 16px 48px;
|
||||
}
|
||||
.hero { margin-bottom: 16px; }
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
color: #5f6772;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: 12px;
|
||||
}
|
||||
h1 { margin: 6px 0 0; font-size: 32px; }
|
||||
.card {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.70), rgba(255,255,255,0.18) 28%, rgba(255,255,255,0.0) 29%),
|
||||
repeating-linear-gradient(to bottom, rgba(255,255,255,0.26) 0 1px, rgba(188,205,223,0.10) 1px 3px),
|
||||
var(--card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 10px 20px rgba(78, 107, 139, 0.09), inset 0 1px 0 rgba(255,255,255,0.96);
|
||||
}
|
||||
code { background: #eef3fb; padding: 1px 5px; border-radius: 6px; }
|
||||
@@ -0,0 +1,2 @@
|
||||
document.documentElement.classList.add("js");
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{{ define "base.html" }}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ .Title }}</title>
|
||||
<link rel="stylesheet" href="/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="shell">
|
||||
<header class="hero">
|
||||
<p class="eyebrow">Go Web Scaffold</p>
|
||||
<h1>{{ .Title }}</h1>
|
||||
</header>
|
||||
{{ template "content" . }}
|
||||
</main>
|
||||
<script src="/static/js/app.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{{ define "content" }}
|
||||
<section class="card">
|
||||
<p>Minimal net/http + html/template scaffold.</p>
|
||||
<ul>
|
||||
<li><code>GET /</code> page</li>
|
||||
<li><code>GET /healthz</code> healthcheck</li>
|
||||
<li><code>/static/*</code> embedded assets</li>
|
||||
</ul>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user