Add a profile dropdown menu
This commit is contained in:
parent
a646dddec0
commit
dffd1c94b5
|
@ -8298,7 +8298,7 @@ header .header-nav > .root-item > a {
|
||||||
display: block;
|
display: block;
|
||||||
padding: var(--spacing-3);
|
padding: var(--spacing-3);
|
||||||
}
|
}
|
||||||
header .header-nav .submenu {
|
header .submenu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -8309,16 +8309,16 @@ header .header-nav .submenu {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-top-width: 0;
|
border-top-width: 0;
|
||||||
}
|
}
|
||||||
header .header-nav .submenu > a {
|
header .submenu > a {
|
||||||
padding: var(--spacing-2) var(--spacing-3);
|
padding: var(--spacing-2) var(--spacing-3);
|
||||||
display: block;
|
display: block;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
header .header-nav .root-item:not(:hover):not(.clicked) > .submenu {
|
header .root-item:not(:hover):not(.clicked) > .submenu {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
header .header-nav .root-item.clicked .svgicon {
|
header .root-item.clicked .svgicon {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
header:not(.clicked) .root-item:not(:hover) > .submenu,
|
header:not(.clicked) .root-item:not(:hover) > .submenu,
|
||||||
|
|
|
@ -67,7 +67,7 @@ func TestLoginWithDiscord(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogoutAction(t *testing.T) {
|
func TestLogoutAction(t *testing.T) {
|
||||||
AssertRegexMatch(t, BuildLogoutAction(""), RegexLogoutAction, nil)
|
AssertRegexMatch(t, BuildLogoutAction(""), RegexLogout, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegister(t *testing.T) {
|
func TestRegister(t *testing.T) {
|
||||||
|
|
|
@ -219,7 +219,7 @@ func BuildLoginWithDiscord(redirectTo string) string {
|
||||||
return Url("/login-with-discord", []Q{{Name: "redirect", Value: redirectTo}})
|
return Url("/login-with-discord", []Q{{Name: "redirect", Value: redirectTo}})
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexLogoutAction = regexp.MustCompile("^/logout$")
|
var RegexLogout = regexp.MustCompile("^/logout$")
|
||||||
|
|
||||||
func BuildLogoutAction(redir string) string {
|
func BuildLogoutAction(redir string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
|
|
|
@ -144,34 +144,34 @@ header {
|
||||||
display: block;
|
display: block;
|
||||||
padding: var(--spacing-3);
|
padding: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.submenu {
|
.submenu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
min-width: 8rem;
|
min-width: 8rem;
|
||||||
background-color: var(--c3);
|
background-color: var(--c3);
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-top-width: 0;
|
border-top-width: 0;
|
||||||
|
|
||||||
>a {
|
>a {
|
||||||
padding: var(--spacing-2) var(--spacing-3);
|
padding: var(--spacing-2) var(--spacing-3);
|
||||||
display: block;
|
display: block;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.root-item {
|
||||||
|
&:not(:hover):not(.clicked)>.submenu {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-item {
|
&.clicked .svgicon {
|
||||||
&:not(:hover):not(.clicked)>.submenu {
|
transform: rotate(180deg);
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.clicked .svgicon {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a class="db {{ if .User }}pv2 ph3{{ else }}pa3{{ end }} lh-solid flex f6 {{ if not .User }}bl{{ end }}" href="{{ or .Header.UserProfileUrl .LoginPageUrl }}">
|
<div class="root-item f6">
|
||||||
{{ with .User }}
|
<a class="db {{ if .User }}pv2 ph3{{ else }}pa3{{ end }} lh-solid flex f6 {{ if not .User }}bl{{ end }}" href="{{ or .Header.UserProfileUrl .LoginPageUrl }}">
|
||||||
<img class="avatar avatar-user" src="{{ .AvatarUrl }}">
|
{{ with .User }}
|
||||||
{{ else }}
|
<img class="avatar avatar-user" src="{{ .AvatarUrl }}">
|
||||||
Log In
|
{{ else }}
|
||||||
|
Log In
|
||||||
|
{{ end }}
|
||||||
|
</a>
|
||||||
|
{{ if .User }}
|
||||||
|
<div class="submenu right-0" id="profile-submenu">
|
||||||
|
<a href="{{ .Header.UserProfileUrl }}">Profile</a>
|
||||||
|
<a href="{{ .Header.UserSettingsUrl }}">Settings</a>
|
||||||
|
<a href="{{ .Header.LogoutUrl }}">Log Out</a>
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</a>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<a class="dib pv2 pl2" href="{{ .Header.UserProfileUrl }}">{{ .User.Username }}</a>
|
<a class="dib pv2 pl2" href="{{ .Header.UserProfileUrl }}">{{ .User.Username }}</a>
|
||||||
<a class="dib pv2 pr2" href="{{ .Header.UserSettingsUrl }}">(settings)</a>
|
<a class="dib pv2 pr2" href="{{ .Header.UserSettingsUrl }}">(settings)</a>
|
||||||
</div>
|
</div>
|
||||||
<a class="pa2" href="{{ .Header.LogoutActionUrl }}"><span class="icon-logout"></span> Log Out</a>
|
<a class="pa2" href="{{ .Header.LogoutUrl }}"><span class="icon-logout"></span> Log Out</a>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<a class="pa2" id="register-link" href="{{ .Header.RegisterUrl }}">Register</a>
|
<a class="pa2" id="register-link" href="{{ .Header.RegisterUrl }}">Register</a>
|
||||||
<a class="pa2" id="login-link" href="{{ .LoginPageUrl }}">Log in</a>
|
<a class="pa2" id="login-link" href="{{ .LoginPageUrl }}">Log in</a>
|
||||||
|
|
|
@ -40,14 +40,12 @@ func (bd *BaseData) AddImmediateNotice(class, content string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Header struct {
|
type Header struct {
|
||||||
AdminUrl string
|
AdminUrl string
|
||||||
UserProfileUrl string
|
UserProfileUrl string
|
||||||
UserSettingsUrl string
|
UserSettingsUrl string
|
||||||
LoginActionUrl string
|
LogoutUrl string
|
||||||
LogoutActionUrl string
|
ForgotPasswordUrl string
|
||||||
ForgotPasswordUrl string
|
RegisterUrl string
|
||||||
RegisterUrl string
|
|
||||||
LoginWithDiscordUrl string
|
|
||||||
|
|
||||||
HMNHomepageUrl string
|
HMNHomepageUrl string
|
||||||
ProjectIndexUrl string
|
ProjectIndexUrl string
|
||||||
|
|
|
@ -64,13 +64,11 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
|
|
||||||
IsProjectPage: !project.IsHMN(),
|
IsProjectPage: !project.IsHMN(),
|
||||||
Header: templates.Header{
|
Header: templates.Header{
|
||||||
AdminUrl: hmnurl.BuildAdminApprovalQueue(), // TODO(asaf): Replace with general-purpose admin page
|
AdminUrl: hmnurl.BuildAdminApprovalQueue(), // TODO(asaf): Replace with general-purpose admin page
|
||||||
UserSettingsUrl: hmnurl.BuildUserSettings(""),
|
UserSettingsUrl: hmnurl.BuildUserSettings(""),
|
||||||
LoginActionUrl: hmnurl.BuildLoginAction(c.FullUrl()),
|
LogoutUrl: hmnurl.BuildLogoutAction(c.FullUrl()),
|
||||||
LogoutActionUrl: hmnurl.BuildLogoutAction(c.FullUrl()),
|
ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(),
|
||||||
ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(),
|
RegisterUrl: hmnurl.BuildRegister(""),
|
||||||
RegisterUrl: hmnurl.BuildRegister(""),
|
|
||||||
LoginWithDiscordUrl: hmnurl.BuildLoginWithDiscord(c.FullUrl()),
|
|
||||||
|
|
||||||
HMNHomepageUrl: hmnurl.BuildHomepage(),
|
HMNHomepageUrl: hmnurl.BuildHomepage(),
|
||||||
ProjectIndexUrl: hmnurl.BuildProjectIndex(),
|
ProjectIndexUrl: hmnurl.BuildProjectIndex(),
|
||||||
|
|
|
@ -137,7 +137,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
||||||
hmnOnly.GET(hmnurl.RegexOldHome, Index)
|
hmnOnly.GET(hmnurl.RegexOldHome, Index)
|
||||||
|
|
||||||
hmnOnly.POST(hmnurl.RegexLoginAction, securityTimerMiddleware(time.Millisecond*100, Login))
|
hmnOnly.POST(hmnurl.RegexLoginAction, securityTimerMiddleware(time.Millisecond*100, Login))
|
||||||
hmnOnly.GET(hmnurl.RegexLogoutAction, Logout)
|
hmnOnly.GET(hmnurl.RegexLogout, Logout)
|
||||||
hmnOnly.GET(hmnurl.RegexLoginPage, LoginPage)
|
hmnOnly.GET(hmnurl.RegexLoginPage, LoginPage)
|
||||||
hmnOnly.GET(hmnurl.RegexLoginWithDiscord, LoginWithDiscord)
|
hmnOnly.GET(hmnurl.RegexLoginWithDiscord, LoginWithDiscord)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue