init(templ): add templated navbar component

This commit is contained in:
2026-01-05 15:39:41 -05:00
parent c6fdbf5084
commit dd299f76e0
2 changed files with 817 additions and 0 deletions

285
components/navbar.templ Normal file
View File

@@ -0,0 +1,285 @@
package components
// Blockchain represents a supported blockchain network
type Blockchain struct {
ID string
Name string
Symbol string
Icon string
Color string
Testnet bool
}
// Account represents a wallet account
type Account struct {
ID string
Name string
Address string
Initials string
Color string
Active bool
}
// NavUser holds user display info
type NavUser struct {
Name string
Address string
}
// NavTab represents a tab in the navigation
type NavTab struct {
ID string
Label string
Icon string
Active bool
}
// NavContext holds navigation state for the header
type NavContext struct {
User NavUser
Blockchains []Blockchain
Accounts []Account
Tabs []NavTab
SelectedChainID string
SelectedAccountID string
ActiveTab string
}
// DefaultBlockchains returns the available blockchain networks
func DefaultBlockchains() []Blockchain {
return []Blockchain{
{ID: "sonr", Name: "Sonr", Symbol: "SNR", Icon: "cube", Color: "var(--wa-color-primary)", Testnet: false},
{ID: "ethereum", Name: "Ethereum", Symbol: "ETH", Icon: "ethereum", Color: "#627eea", Testnet: false},
{ID: "avalanche", Name: "Avalanche", Symbol: "AVAX", Icon: "mountain", Color: "#e84142", Testnet: false},
{ID: "polygon", Name: "Polygon", Symbol: "MATIC", Icon: "hexagon", Color: "#8247e5", Testnet: false},
{ID: "sonr-testnet", Name: "Sonr Testnet", Symbol: "tSNR", Icon: "cube", Color: "var(--wa-color-warning)", Testnet: true},
}
}
// DefaultAccounts returns the user's wallet accounts
func DefaultAccounts() []Account {
return []Account{
{ID: "main", Name: "Main Wallet", Address: "sonr1x9f...7k2m", Initials: "M", Color: "var(--wa-color-primary)", Active: true},
{ID: "trading", Name: "Trading", Address: "sonr1k4m...9p3q", Initials: "T", Color: "var(--wa-color-success)", Active: false},
{ID: "savings", Name: "Savings", Address: "sonr1r7t...2w8x", Initials: "S", Color: "var(--wa-color-warning)", Active: false},
}
}
// DashboardTabs returns the default dashboard tabs
func DashboardTabs(activeTab string) []NavTab {
return []NavTab{
{ID: "overview", Label: "Overview", Icon: "grid-2", Active: activeTab == "overview" || activeTab == ""},
{ID: "transactions", Label: "Transactions", Icon: "arrow-right-arrow-left", Active: activeTab == "transactions"},
{ID: "tokens", Label: "Tokens", Icon: "coins", Active: activeTab == "tokens"},
{ID: "nfts", Label: "NFTs", Icon: "image", Active: activeTab == "nfts"},
{ID: "activity", Label: "Activity", Icon: "chart-line", Active: activeTab == "activity"},
}
}
// DefaultNavContext returns the default navigation context
func DefaultNavContext() NavContext {
return NavContext{
User: NavUser{Name: "Sonr Wallet", Address: "sonr1x9f...7k2m"},
Blockchains: DefaultBlockchains(),
Accounts: DefaultAccounts(),
Tabs: DashboardTabs(""),
SelectedChainID: "sonr",
SelectedAccountID: "main",
ActiveTab: "overview",
}
}
// getSelectedChainName returns the name of the currently selected chain
func getSelectedChainName(chains []Blockchain, id string) string {
for _, c := range chains {
if c.ID == id {
return c.Name
}
}
return "Network"
}
// getSelectedAccountName returns the name of the currently selected account
func getSelectedAccountName(accounts []Account, id string) string {
for _, a := range accounts {
if a.ID == id {
return a.Name
}
}
return "Account"
}
// AppHeader renders the header section for wa-page header slot
templ AppHeader(navCtx NavContext) {
<header slot="header" class="app-header">
<nav class="header-nav">
<!-- Logo -->
<a href="/dashboard" class="nav-logo">
<wa-icon name="cube"></wa-icon>
<span>Sonr</span>
</a>
<span class="nav-sep">/</span>
<!-- Chain Dropdown -->
<wa-dropdown>
<button slot="trigger" class="nav-btn">
{ getSelectedChainName(navCtx.Blockchains, navCtx.SelectedChainID) }
<wa-icon name="chevron-down"></wa-icon>
</button>
<wa-menu>
<small class="menu-label">Mainnets</small>
for _, chain := range navCtx.Blockchains {
if !chain.Testnet {
<wa-menu-item value={ chain.ID }>
<wa-icon slot="prefix" name={ chain.Icon } style={ "color:" + chain.Color }></wa-icon>
{ chain.Name }
</wa-menu-item>
}
}
<wa-divider></wa-divider>
<small class="menu-label">Testnets</small>
for _, chain := range navCtx.Blockchains {
if chain.Testnet {
<wa-menu-item value={ chain.ID }>
<wa-icon slot="prefix" name={ chain.Icon } style={ "color:" + chain.Color }></wa-icon>
{ chain.Name }
</wa-menu-item>
}
}
</wa-menu>
</wa-dropdown>
<span class="nav-sep">/</span>
<!-- Account Dropdown -->
<wa-dropdown>
<button slot="trigger" class="nav-btn">
{ getSelectedAccountName(navCtx.Accounts, navCtx.SelectedAccountID) }
<wa-icon name="chevron-down"></wa-icon>
</button>
<wa-menu>
for _, account := range navCtx.Accounts {
<wa-menu-item value={ account.ID }>
<wa-avatar slot="prefix" initials={ account.Initials } style={ "--size:16px;background:" + account.Color }></wa-avatar>
{ account.Name }
</wa-menu-item>
}
<wa-divider></wa-divider>
<wa-menu-item value="__new__">
<wa-icon slot="prefix" name="plus"></wa-icon>
New Account
</wa-menu-item>
</wa-menu>
</wa-dropdown>
</nav>
<!-- User Avatar -->
<wa-dropdown>
<wa-avatar slot="trigger" initials={ string(navCtx.User.Name[0]) } style="--size:28px;cursor:pointer;"></wa-avatar>
<wa-menu>
<div class="user-info">
<strong>{ navCtx.User.Name }</strong>
<span>{ navCtx.User.Address }</span>
</div>
<wa-divider></wa-divider>
<wa-menu-item value="settings"><wa-icon slot="prefix" name="gear"></wa-icon>Settings</wa-menu-item>
<wa-menu-item value="logout"><wa-icon slot="prefix" name="arrow-right-from-bracket"></wa-icon>Sign Out</wa-menu-item>
</wa-menu>
</wa-dropdown>
</header>
}
// AppSubheader renders the tabs section for wa-page subheader slot
templ AppSubheader(tabs []NavTab) {
<nav slot="subheader" class="tab-bar">
for _, tab := range tabs {
<a href={ templ.SafeURL("/dashboard?tab=" + tab.ID) } class={ "tab", templ.KV("active", tab.Active) }>
<wa-icon name={ tab.Icon }></wa-icon>
{ tab.Label }
</a>
}
</nav>
}
// AppNavStyles renders the CSS styles for the navigation components
templ AppNavStyles() {
<style>
/* Reset wa-page slots */
wa-page::part(header), wa-page::part(subheader) {
background: var(--wa-color-surface);
padding: 0;
}
wa-page::part(header) { border-bottom: 1px solid var(--wa-color-neutral-200); }
wa-page::part(main-content) { background: var(--wa-color-surface-alt); }
/* Header Bar */
.app-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 40px;
padding: 0 12px;
}
.header-nav {
display: flex;
align-items: center;
gap: 2px;
}
.nav-logo {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 6px;
text-decoration: none;
color: var(--wa-color-primary);
font-weight: 600;
font-size: 13px;
border-radius: 4px;
}
.nav-logo:hover { background: var(--wa-color-neutral-100); }
.nav-logo wa-icon { font-size: 16px; }
.nav-sep { color: var(--wa-color-neutral-300); font-size: 14px; padding: 0 2px; }
.nav-btn {
display: flex;
align-items: center;
gap: 3px;
padding: 4px 6px;
border: none;
background: none;
font: inherit;
font-size: 13px;
font-weight: 500;
color: var(--wa-color-neutral-700);
border-radius: 4px;
cursor: pointer;
}
.nav-btn:hover { background: var(--wa-color-neutral-100); }
.nav-btn wa-icon { font-size: 10px; color: var(--wa-color-neutral-400); }
.menu-label { display: block; padding: 6px 12px; font-size: 11px; color: var(--wa-color-neutral-500); }
.user-info { padding: 8px 12px; }
.user-info strong { display: block; font-size: 13px; }
.user-info span { font-size: 11px; color: var(--wa-color-neutral-500); }
/* Tab Bar */
.tab-bar {
display: flex;
gap: 0;
padding: 0 12px;
border-bottom: 1px solid var(--wa-color-neutral-200);
}
.tab {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
font-size: 13px;
font-weight: 500;
color: var(--wa-color-neutral-600);
text-decoration: none;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.tab:hover { color: var(--wa-color-neutral-900); }
.tab.active { color: var(--wa-color-primary); border-bottom-color: var(--wa-color-primary); }
.tab wa-icon { font-size: 14px; }
/* Content */
.content-container { max-width: 1200px; margin: 0 auto; padding: 16px; }
</style>
}

532
components/navbar_templ.go Normal file
View File

@@ -0,0 +1,532 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
// Blockchain represents a supported blockchain network
type Blockchain struct {
ID string
Name string
Symbol string
Icon string
Color string
Testnet bool
}
// Account represents a wallet account
type Account struct {
ID string
Name string
Address string
Initials string
Color string
Active bool
}
// NavUser holds user display info
type NavUser struct {
Name string
Address string
}
// NavTab represents a tab in the navigation
type NavTab struct {
ID string
Label string
Icon string
Active bool
}
// NavContext holds navigation state for the header
type NavContext struct {
User NavUser
Blockchains []Blockchain
Accounts []Account
Tabs []NavTab
SelectedChainID string
SelectedAccountID string
ActiveTab string
}
// DefaultBlockchains returns the available blockchain networks
func DefaultBlockchains() []Blockchain {
return []Blockchain{
{ID: "sonr", Name: "Sonr", Symbol: "SNR", Icon: "cube", Color: "var(--wa-color-primary)", Testnet: false},
{ID: "ethereum", Name: "Ethereum", Symbol: "ETH", Icon: "ethereum", Color: "#627eea", Testnet: false},
{ID: "avalanche", Name: "Avalanche", Symbol: "AVAX", Icon: "mountain", Color: "#e84142", Testnet: false},
{ID: "polygon", Name: "Polygon", Symbol: "MATIC", Icon: "hexagon", Color: "#8247e5", Testnet: false},
{ID: "sonr-testnet", Name: "Sonr Testnet", Symbol: "tSNR", Icon: "cube", Color: "var(--wa-color-warning)", Testnet: true},
}
}
// DefaultAccounts returns the user's wallet accounts
func DefaultAccounts() []Account {
return []Account{
{ID: "main", Name: "Main Wallet", Address: "sonr1x9f...7k2m", Initials: "M", Color: "var(--wa-color-primary)", Active: true},
{ID: "trading", Name: "Trading", Address: "sonr1k4m...9p3q", Initials: "T", Color: "var(--wa-color-success)", Active: false},
{ID: "savings", Name: "Savings", Address: "sonr1r7t...2w8x", Initials: "S", Color: "var(--wa-color-warning)", Active: false},
}
}
// DashboardTabs returns the default dashboard tabs
func DashboardTabs(activeTab string) []NavTab {
return []NavTab{
{ID: "overview", Label: "Overview", Icon: "grid-2", Active: activeTab == "overview" || activeTab == ""},
{ID: "transactions", Label: "Transactions", Icon: "arrow-right-arrow-left", Active: activeTab == "transactions"},
{ID: "tokens", Label: "Tokens", Icon: "coins", Active: activeTab == "tokens"},
{ID: "nfts", Label: "NFTs", Icon: "image", Active: activeTab == "nfts"},
{ID: "activity", Label: "Activity", Icon: "chart-line", Active: activeTab == "activity"},
}
}
// DefaultNavContext returns the default navigation context
func DefaultNavContext() NavContext {
return NavContext{
User: NavUser{Name: "Sonr Wallet", Address: "sonr1x9f...7k2m"},
Blockchains: DefaultBlockchains(),
Accounts: DefaultAccounts(),
Tabs: DashboardTabs(""),
SelectedChainID: "sonr",
SelectedAccountID: "main",
ActiveTab: "overview",
}
}
// getSelectedChainName returns the name of the currently selected chain
func getSelectedChainName(chains []Blockchain, id string) string {
for _, c := range chains {
if c.ID == id {
return c.Name
}
}
return "Network"
}
// getSelectedAccountName returns the name of the currently selected account
func getSelectedAccountName(accounts []Account, id string) string {
for _, a := range accounts {
if a.ID == id {
return a.Name
}
}
return "Account"
}
// AppHeader renders the header section for wa-page header slot
func AppHeader(navCtx NavContext) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<header slot=\"header\" class=\"app-header\"><nav class=\"header-nav\"><!-- Logo --><a href=\"/dashboard\" class=\"nav-logo\"><wa-icon name=\"cube\"></wa-icon> <span>Sonr</span></a> <span class=\"nav-sep\">/</span><!-- Chain Dropdown --><wa-dropdown><button slot=\"trigger\" class=\"nav-btn\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(getSelectedChainName(navCtx.Blockchains, navCtx.SelectedChainID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 125, Col: 71}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " <wa-icon name=\"chevron-down\"></wa-icon></button> <wa-menu><small class=\"menu-label\">Mainnets</small> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, chain := range navCtx.Blockchains {
if !chain.Testnet {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<wa-menu-item value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(chain.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 132, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"><wa-icon slot=\"prefix\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(chain.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 133, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("color:" + chain.Color)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 133, Col: 81}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\"></wa-icon> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(chain.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 134, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</wa-menu-item> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<wa-divider></wa-divider> <small class=\"menu-label\">Testnets</small> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, chain := range navCtx.Blockchains {
if chain.Testnet {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<wa-menu-item value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(chain.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 142, Col: 37}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\"><wa-icon slot=\"prefix\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(chain.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 143, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\" style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("color:" + chain.Color)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 143, Col: 81}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\"></wa-icon> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(chain.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 144, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</wa-menu-item>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</wa-menu></wa-dropdown> <span class=\"nav-sep\">/</span><!-- Account Dropdown --><wa-dropdown><button slot=\"trigger\" class=\"nav-btn\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(getSelectedAccountName(navCtx.Accounts, navCtx.SelectedAccountID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 154, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " <wa-icon name=\"chevron-down\"></wa-icon></button> <wa-menu>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, account := range navCtx.Accounts {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<wa-menu-item value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(account.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 159, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\"><wa-avatar slot=\"prefix\" initials=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(account.Initials)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 160, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\" style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("--size:16px;background:" + account.Color)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 160, Col: 111}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\"></wa-avatar> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(account.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 161, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</wa-menu-item> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<wa-divider></wa-divider> <wa-menu-item value=\"__new__\"><wa-icon slot=\"prefix\" name=\"plus\"></wa-icon> New Account</wa-menu-item></wa-menu></wa-dropdown></nav><!-- User Avatar --><wa-dropdown><wa-avatar slot=\"trigger\" initials=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(string(navCtx.User.Name[0]))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 174, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\" style=\"--size:28px;cursor:pointer;\"></wa-avatar> <wa-menu><div class=\"user-info\"><strong>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(navCtx.User.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 177, Col: 31}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</strong> <span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(navCtx.User.Address)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 178, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</span></div><wa-divider></wa-divider> <wa-menu-item value=\"settings\"><wa-icon slot=\"prefix\" name=\"gear\"></wa-icon>Settings</wa-menu-item> <wa-menu-item value=\"logout\"><wa-icon slot=\"prefix\" name=\"arrow-right-from-bracket\"></wa-icon>Sign Out</wa-menu-item></wa-menu></wa-dropdown></header>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// AppSubheader renders the tabs section for wa-page subheader slot
func AppSubheader(tabs []NavTab) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var19 := templ.GetChildren(ctx)
if templ_7745c5c3_Var19 == nil {
templ_7745c5c3_Var19 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<nav slot=\"subheader\" class=\"tab-bar\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, tab := range tabs {
var templ_7745c5c3_Var20 = []any{"tab", templ.KV("active", tab.Active)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var20...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 templ.SafeURL
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("/dashboard?tab=" + tab.ID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 192, Col: 54}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var20).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\"><wa-icon name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Icon)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 193, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\"></wa-icon> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var24 string
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/navbar.templ`, Line: 194, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</nav>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
// AppNavStyles renders the CSS styles for the navigation components
func AppNavStyles() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var25 := templ.GetChildren(ctx)
if templ_7745c5c3_Var25 == nil {
templ_7745c5c3_Var25 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<style>\n\t\t/* Reset wa-page slots */\n\t\twa-page::part(header), wa-page::part(subheader) {\n\t\t\tbackground: var(--wa-color-surface);\n\t\t\tpadding: 0;\n\t\t}\n\t\twa-page::part(header) { border-bottom: 1px solid var(--wa-color-neutral-200); }\n\t\twa-page::part(main-content) { background: var(--wa-color-surface-alt); }\n\n\t\t/* Header Bar */\n\t\t.app-header {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: space-between;\n\t\t\theight: 40px;\n\t\t\tpadding: 0 12px;\n\t\t}\n\t\t.header-nav {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 2px;\n\t\t}\n\t\t.nav-logo {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 4px;\n\t\t\tpadding: 4px 6px;\n\t\t\ttext-decoration: none;\n\t\t\tcolor: var(--wa-color-primary);\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 13px;\n\t\t\tborder-radius: 4px;\n\t\t}\n\t\t.nav-logo:hover { background: var(--wa-color-neutral-100); }\n\t\t.nav-logo wa-icon { font-size: 16px; }\n\t\t.nav-sep { color: var(--wa-color-neutral-300); font-size: 14px; padding: 0 2px; }\n\t\t.nav-btn {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 3px;\n\t\t\tpadding: 4px 6px;\n\t\t\tborder: none;\n\t\t\tbackground: none;\n\t\t\tfont: inherit;\n\t\t\tfont-size: 13px;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--wa-color-neutral-700);\n\t\t\tborder-radius: 4px;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.nav-btn:hover { background: var(--wa-color-neutral-100); }\n\t\t.nav-btn wa-icon { font-size: 10px; color: var(--wa-color-neutral-400); }\n\t\t.menu-label { display: block; padding: 6px 12px; font-size: 11px; color: var(--wa-color-neutral-500); }\n\t\t.user-info { padding: 8px 12px; }\n\t\t.user-info strong { display: block; font-size: 13px; }\n\t\t.user-info span { font-size: 11px; color: var(--wa-color-neutral-500); }\n\n\t\t/* Tab Bar */\n\t\t.tab-bar {\n\t\t\tdisplay: flex;\n\t\t\tgap: 0;\n\t\t\tpadding: 0 12px;\n\t\t\tborder-bottom: 1px solid var(--wa-color-neutral-200);\n\t\t}\n\t\t.tab {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 6px;\n\t\t\tpadding: 8px 12px;\n\t\t\tfont-size: 13px;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--wa-color-neutral-600);\n\t\t\ttext-decoration: none;\n\t\t\tborder-bottom: 2px solid transparent;\n\t\t\tmargin-bottom: -1px;\n\t\t}\n\t\t.tab:hover { color: var(--wa-color-neutral-900); }\n\t\t.tab.active { color: var(--wa-color-primary); border-bottom-color: var(--wa-color-primary); }\n\t\t.tab wa-icon { font-size: 14px; }\n\n\t\t/* Content */\n\t\t.content-container { max-width: 1200px; margin: 0 auto; padding: 16px; }\n\t</style>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate