Files
member-console/internal/embeds
cgalo5758 257955c9d3 Add operator list-scale contract and People directory
Governed operator lists (organizations, grants, people, billing×4) gain
server-side search, status filters, and 50-row pages with true totals
from count(*) OVER(); state is URL-addressable, out-of-range pages
clamp,
and no-match is distinct from true-empty.

People is the eighth flat sidebar entry: /operator/persons lists persons
newest-joined first (excluding the reserved system person), rows linking
to the existing detail.

Billing gains an operator invoice detail at
/operator/billing/invoices/{invoiceID} reusing the member projection;
open invoices past due present as Overdue (derived, filterable, stored
status untouched); all four views lead with the linked organization and
mute object IDs.

Grants filter over the derived Live/Superseded/Inactive state, the SQL
HAVING predicate pinned to the Go derivation by test. Embedded lists
(org composite ledger, Tier changes) adopt the shared controls under
namespaced params with sibling-state-preserving URLs and scoped htmx
swaps that hold the viewport.

Review corrections: blocked ladder Delete renders disabled with tooltip
and mutations fire toasts; collapse triggers paint their open state;
sections use outside headings; plan topology drops the orphan-product
check; domains policy collapses behind a disclosure.
2026-08-24 03:58:18 -05:00
..
2025-12-19 15:47:32 -06:00

Embedded Assets

This package provides embedded static files, templates, and configuration using Go's embed directive.

Overview

All assets are embedded at compile time, producing a single binary with no external file dependencies.

package embeds

//go:embed static
var Static embed.FS

//go:embed templates
var Templates embed.FS

//go:embed mc-config.yaml
var Config embed.FS

Directory Structure

internal/embeds/
├── embeds.go           # Embed directives
├── mc-config.yaml      # Default configuration template
├── static/             # Static assets (CSS, JS, images)
│   ├── bootstrap.css
│   ├── bootstrap.bundle.js
│   ├── htmx.min.js
│   └── favicon*.png
└── templates/          # HTML templates
    ├── index.html      # Main page template
    └── partials/       # HTMX partial templates
        ├── fedwiki_sites.html
        ├── fedwiki_create_form.html
        ├── fedwiki_create_success.html
        ├── fedwiki_delete_confirm.html
        └── fedwiki_delete_success.html

Static Assets

Serving Static Files

staticFS, _ := fs.Sub(embeds.Static, "static")
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))

Included Libraries

  • bootstrap.css (5.3.x) - CSS framework
  • bootstrap.bundle.js (5.3.x) - Bootstrap JS (includes Popper)
  • htmx.min.js (2.0.4) - HTMX for dynamic content

Favicons

Standard favicon set for various platforms:

  • favicon.ico - Traditional favicon
  • favicon-16x16.png, favicon-32x32.png - Standard sizes
  • apple-touch-icon.png - iOS home screen
  • android-chrome-*.png - Android home screen
  • site.webmanifest - PWA manifest

Templates

Main Page Template (index.html)

The full HTML page that serves as the application shell:

<!DOCTYPE html>
<html>
<head>
    <!-- Meta, CSS, HTMX -->
</head>
<body>
    <!-- Navigation -->
    
    <!-- Content sections with HTMX triggers -->
    <div hx-get="/partials/fedwiki/sites" 
         hx-trigger="load, refreshSites from:body">
        <!-- Loading spinner -->
    </div>
    
    <!-- Modals -->
    <div class="modal" id="createSiteModal">...</div>
    
    <!-- Scripts -->
</body>
</html>

Partial Templates (partials/)

HTML fragments returned by HTMX handlers. These are not full pages.

Naming Convention

{feature}_{action}.html

Examples:

  • fedwiki_sites.html - Sites list display
  • fedwiki_create_form.html - Site creation form
  • fedwiki_create_success.html - Creation success message
  • fedwiki_delete_confirm.html - Delete confirmation dialog
  • fedwiki_delete_success.html - Deletion success message

Template Data Pattern

Each partial has a corresponding Go struct for its data:

// In fedwiki_partials.go
type SitesData struct {
    Sites        []SiteViewModel
    CurrentCount int64
    Quota        int64
    IsMember     bool
    CanCreate    bool
    Error        string
}

HTMX Patterns in Templates

Loading Content on Page Load

<div hx-get="/partials/fedwiki/sites" 
     hx-trigger="load, refreshSites from:body"
     hx-swap="innerHTML">
    <!-- Initial loading spinner -->
    <div class="spinner-border"></div>
</div>

Form Submission

<form hx-post="/partials/fedwiki/sites" 
      hx-swap="innerHTML" 
      hx-target="#createSiteModalBody">
    <!-- Form fields -->
    <button type="submit">
        <span class="spinner-border d-none" id="spinner"></span>
        Create Site
    </button>
</form>

Loading Button into Modal

<button data-bs-toggle="modal" 
        data-bs-target="#createSiteModal"
        hx-get="/partials/fedwiki/create-form" 
        hx-target="#createSiteModalBody">
    Create Site
</button>

Conditional Button State

<button {{ if .CanCreate }}
          hx-get="/partials/fedwiki/create-form"
        {{ else }}
          disabled title="Site limit reached"
        {{ end }}>
    Create Site
</button>

Spinner Pattern

Spinners are hidden by default and shown during HTMX requests:

<!-- CSS to show spinner during request -->
<style>.htmx-request #createSpinner { display: inline-block !important; }</style>

<!-- Spinner hidden by default -->
<span class="spinner-border d-none" id="createSpinner"></span>

The htmx-request class is automatically added to elements during requests.

Configuration Template

mc-config.yaml provides a default configuration template that can be extracted:

// Extract default config
configData, _ := embeds.Config.ReadFile("mc-config.yaml")

This is used by the init command to create a starter configuration file.

Usage

Accessing Templates

import "git.coopcloud.tech/wiki-cafe/member-console/internal/embeds"

// For full page templates
tmpl, err := template.ParseFS(embeds.Templates, "templates/index.html")

// For partial templates
partialFS, _ := fs.Sub(embeds.Templates, "templates/partials")
tmpl, err := template.ParseFS(partialFS, "*.html")

Accessing Static Files

// Serve static files
staticFS, _ := fs.Sub(embeds.Static, "static")
http.Handle("/static/", http.FileServer(http.FS(staticFS)))