init - add project files
This commit is contained in:
175
ui/app_layout.go
Normal file
175
ui/app_layout.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"maxwarden/auth"
|
||||
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
const (
|
||||
LAYOUT_SECTION_VAULT = iota
|
||||
LAYOUT_SECTION_TOOLS = iota
|
||||
LAYOUT_SECTION_ACCOUNT = iota
|
||||
LAYOUT_SECTION_API = iota
|
||||
)
|
||||
|
||||
type NavGroup struct {
|
||||
SectionId int
|
||||
Title string
|
||||
URL string
|
||||
SubGroup []NavGroup
|
||||
NewTab bool
|
||||
}
|
||||
|
||||
var NavGroups = []NavGroup{
|
||||
{SectionId: LAYOUT_SECTION_VAULT, Title: "Vault", URL: "/app", SubGroup: nil},
|
||||
{
|
||||
Title: "Tools",
|
||||
SubGroup: []NavGroup{
|
||||
{SectionId: LAYOUT_SECTION_TOOLS, Title: "Password Generator", URL: "/app/examples/forms"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func AppLayout(title string, identity auth.Identity, session map[string]interface{}, children ...Node) Node {
|
||||
navbarDropdown := func(dropdownHeader Node, dropdownItems Node) Node {
|
||||
return Div(
|
||||
InlineStyle("$me{cursor: pointer; position: relative; margin-left: $3;}"),
|
||||
Div(
|
||||
Class("button"),
|
||||
InlineStyle(`
|
||||
$me {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
position: relative;
|
||||
padding-top: $2;
|
||||
padding-bottom: $2;
|
||||
padding-left: $3;
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--text-sm--line-height);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: $color(white);
|
||||
}
|
||||
|
||||
$me:hover{color: $color(white);}
|
||||
`),
|
||||
Button(
|
||||
Div(InlineStyle("$me{cursor: pointer; display: flex; align-items: center;}"),
|
||||
dropdownHeader, Span(Text(" ")),
|
||||
Icon(ICON_CHEVRON_DOWN, 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(
|
||||
Class("dropdown"),
|
||||
InlineStyle(`$me{display: none; position: absolute; right: 0; z-index: 10; padding-top: $1; padding-bottom: $1; margin-top: $2; width: $48; background-color: $color(white); transform-origin: top right; box-shadow: var(--shadow-lg);}`),
|
||||
TabIndex("-1"),
|
||||
dropdownItems,
|
||||
),
|
||||
InlineScript(`
|
||||
let button = me(".button", me());
|
||||
let dropdown = me(".dropdown", me());
|
||||
|
||||
button.on("click", ev => { toggleShowHide(dropdown) });
|
||||
onClickOutsideOrEscape(me(), () => { hide(dropdown) });
|
||||
`),
|
||||
)
|
||||
}
|
||||
|
||||
navbarDropdownItem := func(name string, url string, newPage bool) Node {
|
||||
return A(InlineStyle(`$me{display: block; padding-top: $2; padding-bottom: $2; padding-left: $4; padding-right: $4; font-size: var(--text-sm); line-height: $5; color: $color(neutral-700); } $me:hover{background: $color(neutral-100);}`), Href(url), TabIndex("-1"), Text(name), If(newPage, Target("_blank")))
|
||||
}
|
||||
|
||||
navbarLink := func(name string, url string, newPage bool) Node {
|
||||
return A(
|
||||
InlineStyle(`$me{ padding-left: $3; padding-right: $3; padding-top: $2; padding-bottom: $2; font-size: var(--text-sm); font-weight: var(--font-weight-medium); color: $color(white);}`),
|
||||
InlineStyle("$me:hover{color: $color(white);}"),
|
||||
Href(url),
|
||||
Text(name),
|
||||
If(newPage, Target("_blank")),
|
||||
)
|
||||
}
|
||||
|
||||
return RootLayout(title+" | MaxWarden",
|
||||
Body(InlineStyle("$me{background-color: $color(light-grey); height: 100%;}"),
|
||||
Div(InlineStyle("$me{min-height: 100%}"),
|
||||
Nav(InlineStyle("$me{background-color: $color(deep-blue);}"),
|
||||
Div(InlineStyle("$me{margin-left: auto; margin-right: auto; max-width: var(--container-7xl);}"),
|
||||
Div(InlineStyle("$me{display: flex; height: $16; align-items: center; justify-content: space-between;}"),
|
||||
Div(InlineStyle("$me{align-items: center; display: flex;}"),
|
||||
Div(InlineStyle("@media $lg-{ $me{display: block;}}"),
|
||||
Div(InlineStyle(`$me{margin-left: $1; display: flex; align-items: baseline;} $me:not(:last-child){ margin-left: $4; }`),
|
||||
Map(NavGroups, func(nav NavGroup) Node {
|
||||
if len(nav.SubGroup) > 0 {
|
||||
return navbarDropdown(
|
||||
Text(nav.Title),
|
||||
Map(nav.SubGroup, func(sub NavGroup) Node {
|
||||
return navbarDropdownItem(sub.Title, sub.URL, sub.NewTab)
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
return navbarLink(nav.Title, nav.URL, nav.NewTab)
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(InlineStyle("$me{display: none;} @media $md { $me{ display: block; }}"),
|
||||
Div(InlineStyle("$me{ margin-left: $4; display: flex; align-items: center;} @media $md { $me{ margin-left: $6;}}"),
|
||||
Div(InlineStyle("$me{position: relative; margin-left: $3;}"),
|
||||
navbarDropdown(
|
||||
Icon(ICON_USERS, 24),
|
||||
Group{
|
||||
navbarDropdownItem("My Profile", "/app/account", false),
|
||||
navbarDropdownItem("Logout", "/auth/logout", false),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(InlineStyle("$me{margin-right: $2; display: flex;} @media $md{ $me{display: none;}}"),
|
||||
Button(
|
||||
InlineStyle("$me{position: relative; display: inline-flex; justify-items: center; padding: $2; color: $color(neutral-400)}"),
|
||||
InlineStyle("$me:hover{color: $color(white); background-color: $color(neutral-900);}"),
|
||||
Type("button"),
|
||||
Span(InlineStyle("$me{position: absolute;}")),
|
||||
Icon(ICON_MENU, 24),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(InlineStyle("@media $md { $me {display: none; }}"),
|
||||
Div(Class("space-y-1 px-2 pb-3 pt-2 sm:px-3"),
|
||||
A(Href("/app/dashboard"), Class("block hover:bg-neutral-900 px-3 py-2 text-base font-medium text-white"), Text("Dashboard")),
|
||||
),
|
||||
Div(Class("border-t border-neutral-700 pb-3 pt-4"),
|
||||
Div(Class("flex items-center px-5"),
|
||||
Div(Class("flex-shrink-0"),
|
||||
Img(Class("h-10 w-10 rounded-full"), Src(""), Alt("profile picture")),
|
||||
),
|
||||
Div(Class("ml-3"),
|
||||
// Div(Class("text-base/5 font-medium text-white"), Text(identity.User.Firstname+" "+identity.User.Lastname)),
|
||||
// Div(Class("text-sm font-medium text-neutral-400"), Text(identity.User.Email)),
|
||||
),
|
||||
),
|
||||
Div(Class("mt-3 space-y-1 px-2"),
|
||||
A(Href("/auth/logout"), Class("block px-3 py-2 text-base font-medium text-neutral-200 hover:bg-neutral-900 hover:text-white"), Text("Log out")),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Header(InlineStyle("$me{background-color: $color(white); box-shadow: var(--shadow-sm);}"),
|
||||
Div(InlineStyle("$me{margin-left: auto; margin-right: auto; max-width: var(--container-7xl); padding: $4;} @media $lg { $me{ padding-left: $8; padding-right: $8;}}"),
|
||||
H1(InlineStyle("$me{font-size: var(--text-3xl); font-weight: var(--font-weight-bold); color: $color(neutral-950); letter-spacing: var(--tracking-tight);}"), Text(title)),
|
||||
),
|
||||
),
|
||||
Main(
|
||||
Div(InlineStyle("$me{margin-left: auto; margin-right: auto; max-width: var(--container-7xl); padding: $6 $4;} @media $sm { $me{padding-left: $6; padding-right: $6; }} @media $lg { $me{padding-left: $8; padding-right: $8;}}"),
|
||||
Group(children),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user