feat(layouts): add app header with blockchain and account selectors
This commit is contained in:
@@ -5,6 +5,66 @@ type WalletUser struct {
|
||||
Address string
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// AppContext holds navigation state for the header
|
||||
type AppContext struct {
|
||||
User WalletUser
|
||||
Blockchains []Blockchain
|
||||
Accounts []Account
|
||||
SelectedChainID string
|
||||
SelectedAccountID 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},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultAppContext returns the default navigation context
|
||||
func DefaultAppContext() AppContext {
|
||||
return AppContext{
|
||||
User: WalletUser{Name: "Sonr Wallet", Address: "sonr1x9f...7k2m"},
|
||||
Blockchains: DefaultBlockchains(),
|
||||
Accounts: DefaultAccounts(),
|
||||
SelectedChainID: "sonr",
|
||||
SelectedAccountID: "main",
|
||||
}
|
||||
}
|
||||
|
||||
templ AppLayout(title string, user WalletUser) {
|
||||
@Base(title) {
|
||||
@appStyles()
|
||||
@@ -22,19 +82,71 @@ templ AppLayout(title string, user WalletUser) {
|
||||
}
|
||||
|
||||
templ AppHeader(user WalletUser) {
|
||||
@AppHeaderWithContext(DefaultAppContext())
|
||||
}
|
||||
|
||||
templ AppHeaderWithContext(ctx AppContext) {
|
||||
<div class="header-wrapper">
|
||||
<header class="app-header">
|
||||
<div class="header-left">
|
||||
<wa-icon name="cube" style="font-size: 24px; color: var(--wa-color-primary);"></wa-icon>
|
||||
<span class="logo-text">Sonr Wallet</span>
|
||||
<wa-breadcrumb>
|
||||
<span slot="separator">/</span>
|
||||
<!-- Sonr Logo -->
|
||||
<wa-breadcrumb-item>
|
||||
<a href="/dashboard" class="breadcrumb-logo">
|
||||
<wa-icon name="cube" style="font-size: 20px; color: var(--wa-color-primary);"></wa-icon>
|
||||
<span>Sonr</span>
|
||||
</a>
|
||||
</wa-breadcrumb-item>
|
||||
<!-- Blockchain Selector -->
|
||||
<wa-breadcrumb-item>
|
||||
<wa-combobox placeholder="Network" value={ ctx.SelectedChainID } size="small" class="nav-combobox">
|
||||
<small>Mainnets</small>
|
||||
for _, chain := range ctx.Blockchains {
|
||||
if !chain.Testnet {
|
||||
<wa-option value={ chain.ID }>
|
||||
<wa-icon slot="prefix" name={ chain.Icon } style={ "color: " + chain.Color + ";" }></wa-icon>
|
||||
{ chain.Name }
|
||||
</wa-option>
|
||||
}
|
||||
}
|
||||
<wa-divider></wa-divider>
|
||||
<small>Testnets</small>
|
||||
for _, chain := range ctx.Blockchains {
|
||||
if chain.Testnet {
|
||||
<wa-option value={ chain.ID }>
|
||||
<wa-icon slot="prefix" name={ chain.Icon } style={ "color: " + chain.Color + ";" }></wa-icon>
|
||||
{ chain.Name }
|
||||
</wa-option>
|
||||
}
|
||||
}
|
||||
</wa-combobox>
|
||||
</wa-breadcrumb-item>
|
||||
<!-- Account Selector -->
|
||||
<wa-breadcrumb-item>
|
||||
<wa-combobox placeholder="Account" value={ ctx.SelectedAccountID } size="small" class="nav-combobox">
|
||||
for _, account := range ctx.Accounts {
|
||||
<wa-option value={ account.ID }>
|
||||
<wa-avatar slot="prefix" initials={ account.Initials } style={ "--size: 20px; background: " + account.Color + ";" }></wa-avatar>
|
||||
{ account.Name }
|
||||
</wa-option>
|
||||
}
|
||||
<wa-divider></wa-divider>
|
||||
<wa-option value="__create__">
|
||||
<wa-icon slot="prefix" name="plus"></wa-icon>
|
||||
Create Account
|
||||
</wa-option>
|
||||
</wa-combobox>
|
||||
</wa-breadcrumb-item>
|
||||
</wa-breadcrumb>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<wa-dropdown>
|
||||
<wa-avatar slot="trigger" initials="S" style="--size: 36px; background: var(--wa-color-primary); cursor: pointer;"></wa-avatar>
|
||||
<div style="padding: var(--wa-space-m); border-bottom: 1px solid var(--wa-color-neutral-200);">
|
||||
<div class="wa-stack wa-gap-0">
|
||||
<span class="wa-heading-s">{ user.Name }</span>
|
||||
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">{ user.Address }</span>
|
||||
<span class="wa-heading-s">{ ctx.User.Name }</span>
|
||||
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">{ ctx.User.Address }</span>
|
||||
</div>
|
||||
</div>
|
||||
<wa-dropdown-item href="/connections">
|
||||
@@ -95,11 +207,6 @@ templ appStyles() {
|
||||
align-items: center;
|
||||
gap: var(--wa-space-m);
|
||||
}
|
||||
.logo-text {
|
||||
font-weight: 600;
|
||||
font-size: var(--wa-font-size-l);
|
||||
color: var(--wa-color-neutral-900);
|
||||
}
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
@@ -109,5 +216,39 @@ templ appStyles() {
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--wa-space-l);
|
||||
}
|
||||
/* Breadcrumb Navigation */
|
||||
.header-left wa-breadcrumb {
|
||||
--separator-color: var(--wa-color-neutral-400);
|
||||
}
|
||||
.header-left wa-breadcrumb::part(base) {
|
||||
align-items: center;
|
||||
}
|
||||
.breadcrumb-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--wa-space-xs);
|
||||
text-decoration: none;
|
||||
color: var(--wa-color-neutral-900);
|
||||
font-weight: 600;
|
||||
font-size: var(--wa-font-size-m);
|
||||
}
|
||||
.breadcrumb-logo:hover {
|
||||
color: var(--wa-color-primary);
|
||||
}
|
||||
.nav-combobox {
|
||||
--wa-input-border-color: transparent;
|
||||
--wa-input-background-color: var(--wa-color-surface-alt);
|
||||
min-width: 140px;
|
||||
}
|
||||
.nav-combobox::part(combobox) {
|
||||
border-radius: var(--wa-radius-m);
|
||||
padding: var(--wa-space-2xs) var(--wa-space-s);
|
||||
}
|
||||
.nav-combobox:hover::part(combobox) {
|
||||
background: var(--wa-color-neutral-100);
|
||||
}
|
||||
.nav-combobox::part(display-input) {
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ templ Base(title string) {
|
||||
<title>{ title } - Sonr Motr Wallet</title>
|
||||
<script src="https://kit.webawesome.com/47c7425b971f443c.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0-alpha5/dist/htmx.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
|
||||
<style>
|
||||
:root {
|
||||
--wa-color-primary: #17c2ff;
|
||||
|
||||
@@ -43,7 +43,7 @@ func Base(title string) templ.Component {
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " - Sonr Motr Wallet</title><script src=\"https://kit.webawesome.com/47c7425b971f443c.js\" crossorigin=\"anonymous\"></script><script src=\"https://cdn.jsdelivr.net/npm/htmx.org@4.0.0-alpha5/dist/htmx.min.js\"></script><style>\n\t\t\t\t:root {\n\t\t\t\t\t--wa-color-primary: #17c2ff;\n\t\t\t\t}\n\t\t\t\thtml, body {\n\t\t\t\t\tmin-height: 100%;\n\t\t\t\t\tpadding: 0;\n\t\t\t\t\tmargin: 0;\n\t\t\t\t\tcursor: default;\n\t\t\t\t}\n\t\t\t\twa-button, a, [onclick], [hx-get], [hx-post] {\n\t\t\t\t\tcursor: pointer;\n\t\t\t\t}\n\t\t\t</style></head><body>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " - Sonr Motr Wallet</title><script src=\"https://kit.webawesome.com/47c7425b971f443c.js\" crossorigin=\"anonymous\"></script><script src=\"https://cdn.jsdelivr.net/npm/htmx.org@4.0.0-alpha5/dist/htmx.min.js\"></script><script src=\"https://cdn.jsdelivr.net/npm/d3@7\"></script><style>\n\t\t\t\t:root {\n\t\t\t\t\t--wa-color-primary: #17c2ff;\n\t\t\t\t}\n\t\t\t\thtml, body {\n\t\t\t\t\tmin-height: 100%;\n\t\t\t\t\tpadding: 0;\n\t\t\t\t\tmargin: 0;\n\t\t\t\t\tcursor: default;\n\t\t\t\t}\n\t\t\t\twa-button, a, [onclick], [hx-get], [hx-post] {\n\t\t\t\t\tcursor: pointer;\n\t\t\t\t}\n\t\t\t</style></head><body>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user