Rework the nav for projects 2.0

This commit is contained in:
Ben Visness 2021-10-20 21:21:24 -05:00
parent 307699af4c
commit ccdbad8978
12 changed files with 357 additions and 270 deletions

3
.gitignore vendored
View File

@ -1,5 +1,6 @@
src/config/config.go src/config/config.go
.vscode .vscode
.idea
vendor/ vendor/
dbclones/ dbclones/
coverage.out coverage.out
@ -11,4 +12,4 @@ annotations/
hmn.conf hmn.conf
adminmailer/config.go adminmailer/config.go
adminmailer/adminmailer adminmailer/adminmailer
local/backups local/backups

View File

@ -1377,7 +1377,7 @@ img, video {
.bw0 { .bw0 {
border-width: 0; } border-width: 0; }
.bw1 { .bw1, header .submenu {
border-width: 0.125rem; } border-width: 0.125rem; }
.bw2 { .bw2 {
@ -4581,7 +4581,7 @@ code, .code {
.pa1 { .pa1 {
padding: 0.25rem; } padding: 0.25rem; }
.pa2, header .menu-bar .items a, .tab { .pa2, .tab, header .root-item > a, header .submenu > a {
padding: 0.5rem; } padding: 0.5rem; }
.pa3, header #login-popup { .pa3, header #login-popup {
@ -4707,7 +4707,7 @@ code, .code {
padding-top: 0.25rem; padding-top: 0.25rem;
padding-bottom: 0.25rem; } padding-bottom: 0.25rem; }
.pv2, header .menu-bar .items a.project-logo, .tab-bar .tab-button, .pv2, .tab-bar .tab-button,
button, button,
.button, .button,
input[type=button], input[type=button],
@ -5053,7 +5053,7 @@ input[type=submit], .notice {
.optionbar .options input[type=submit] { .optionbar .options input[type=submit] {
padding-top: 0.5rem; padding-top: 0.5rem;
padding-bottom: 0.5rem; } padding-bottom: 0.5rem; }
.pv3-ns, header .menu-bar .items a { .pv3-ns {
padding-top: 1rem; padding-top: 1rem;
padding-bottom: 1rem; } padding-bottom: 1rem; }
.pv4-ns { .pv4-ns {
@ -5112,7 +5112,7 @@ input[type=submit], .notice {
margin-left: 0; } margin-left: 0; }
.ml1-ns { .ml1-ns {
margin-left: 0.25rem; } margin-left: 0.25rem; }
.ml2-ns, header .menu-bar .items a:first-child { .ml2-ns {
margin-left: 0.5rem; } margin-left: 0.5rem; }
.ml3-ns { .ml3-ns {
margin-left: 1rem; } margin-left: 1rem; }
@ -5593,7 +5593,7 @@ input[type=submit], .notice {
.ph2-l { .ph2-l {
padding-left: 0.5rem; padding-left: 0.5rem;
padding-right: 0.5rem; } padding-right: 0.5rem; }
.ph3-l, header .menu-bar .items a { .ph3-l, header .root-item > a, header .submenu > a {
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem; } padding-right: 1rem; }
.ph4-l { .ph4-l {
@ -5630,7 +5630,7 @@ input[type=submit], .notice {
margin-left: 0.25rem; } margin-left: 0.25rem; }
.ml2-l { .ml2-l {
margin-left: 0.5rem; } margin-left: 0.5rem; }
.ml3-l, header .menu-bar .items a:first-child { .ml3-l {
margin-left: 1rem; } margin-left: 1rem; }
.ml4-l { .ml4-l {
margin-left: 2rem; } margin-left: 2rem; }
@ -7381,7 +7381,7 @@ article code {
color: #ccc; color: #ccc;
color: var(--theme-color-dimmest); } color: var(--theme-color-dimmest); }
.b--dimmest, header #login-popup, .optionbar, blockquote, .post-content th, .post-content td { .b--dimmest, .optionbar, blockquote, .post-content th, .post-content td, header #login-popup {
border-color: #bbb; border-color: #bbb;
border-color: var(--dimmest-color); } border-color: var(--dimmest-color); }
@ -7578,6 +7578,7 @@ article code {
.svgicon svg { .svgicon svg {
fill: currentColor; fill: currentColor;
stroke: currentColor;
width: 1em; width: 1em;
height: 1em; } height: 1em; }
@ -7588,64 +7589,6 @@ article code {
margin-right: auto; margin-right: auto;
margin-left: auto; } margin-left: auto; }
header .hmn-logo {
height: 3.75rem;
width: 100%;
text-transform: uppercase;
font-family: 'MohaveHMN', sans-serif;
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
color: white !important; }
@media screen and (min-width: 30em) {
header .hmn-logo {
width: 11.25rem; } }
header .menu-bar {
width: 100%;
z-index: 10; }
header .menu-bar .items a {
font-weight: bold; }
header .menu-bar .items a.patreon {
float: right;
height: 30px;
padding-top: 18px;
display: inline-block; }
header .menu-bar .items a h1 {
display: inline; }
header .user-options {
position: relative; }
header .login, header .register {
text-align: center; }
header #login-popup {
background-color: #fbfbfb;
background-color: var(--login-popup-background);
color: black;
color: var(--fg-font-color);
border-width: 1px;
border-style: dashed;
visibility: hidden;
position: absolute;
z-index: 12;
margin-top: 10px;
right: 0px;
top: 20px;
width: 290px;
max-height: 0px;
overflow: hidden;
opacity: 0;
transition: all 0.2s; }
header #login-popup.open {
max-height: 170px;
opacity: 1;
visibility: visible; }
header #login-popup label {
padding-right: 10px; }
@media screen and (min-width: 30em) { @media screen and (min-width: 30em) {
footer .list li:not(:last-child)::after { footer .list li:not(:last-child)::after {
content: ' / '; } } content: ' / '; } }
@ -8762,6 +8705,102 @@ div.mark_as_read_toplevel_blog {
.bbtable tbody tr:nth-child(even) { .bbtable tbody tr:nth-child(even) {
background: rgba(0, 0, 0, 0.05); } background: rgba(0, 0, 0, 0.05); }
header .hmn-logo {
height: 3.75rem;
width: 100%;
text-transform: uppercase;
font-family: 'MohaveHMN', sans-serif;
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
color: white !important; }
@media screen and (min-width: 30em) {
header .hmn-logo {
width: 11.25rem; } }
header .items {
position: relative; }
@media screen and (min-width: 30em) {
header .root-item {
position: relative;
height: 3.75rem; } }
header .root-item:not(:hover):not(.clicked) > .submenu {
display: none; }
header .root-item.clicked .svgicon {
transform: rotate(180deg); }
header .root-item > a {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-weight: bold; }
header .root-item .svgicon {
font-size: 0.7em; }
header .submenu {
background-color: #f8f8f8;
background-color: var(--content-background);
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
z-index: 1;
min-width: 10rem;
border-top-style: solid;
border-bottom-style: solid; }
@media screen and (min-width: 30em) {
header .submenu {
border-top-style: none;
border-left-style: solid;
border-right-style: solid;
left: initial;
right: initial; } }
header .submenu > a {
display: block;
white-space: nowrap;
z-index: 1;
font-weight: bold;
text-align: center; }
@media screen and (min-width: 30em) {
header .submenu > a {
text-align: left; } }
header .menu-bar {
width: 100%;
z-index: 10; }
header #login-popup {
background-color: #fbfbfb;
background-color: var(--login-popup-background);
color: black;
color: var(--fg-font-color);
border-width: 1px;
border-style: dashed;
visibility: hidden;
position: absolute;
z-index: 12;
margin-top: 10px;
right: 0px;
top: 20px;
width: 290px;
max-height: 0px;
overflow: hidden;
opacity: 0;
transition: all 0.2s; }
header #login-popup.open {
max-height: 170px;
opacity: 1;
visibility: visible; }
header #login-popup label {
padding-right: 10px; }
@font-face { @font-face {
font-family: icons; font-family: icons;
src: url("/public/icons.ttf?v=4"); } src: url("/public/icons.ttf?v=4"); }

View File

@ -408,6 +408,7 @@ article code {
.svgicon { .svgicon {
svg { svg {
fill: currentColor; fill: currentColor;
stroke: currentColor;
width: 1em; width: 1em;
height: 1em; height: 1em;
} }
@ -424,100 +425,6 @@ article code {
margin-left: auto; margin-left: auto;
} }
header {
.hmn-logo {
height: px2rem(60px);
width: 100%;
text-transform: uppercase;
font-family: 'MohaveHMN', sans-serif;
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
color: white !important;
@media #{$breakpoint-not-small} {
width: px2rem(180px);
}
}
.menu-bar {
width: 100%;
z-index: 10;
.items a {
@extend .pa2;
@extend .pv3-ns;
@extend .ph3-l;
font-weight: bold;
&:first-child {
@extend .ml2-ns;
@extend .ml3-l;
}
&.patreon {
float:right;
height:30px;
padding-top:18px;
display:inline-block;
}
&.project-logo {
@extend .pv2;
}
h1 {
display: inline;
}
}
}
.user-options {
position: relative;
}
.login, .register {
text-align:center;
}
#login-popup {
@include usevar(background-color, login-popup-background);
@include usevar(color, fg-font-color);
@extend .pa3;
border-width: 1px;
border-style: dashed;
@extend .b--dimmest;
visibility: hidden;
position: absolute;
z-index: 12;
margin-top: 10px;
right: 0px;
top: 20px;
width: 290px;
max-height: 0px;
overflow: hidden;
opacity: 0;
transition: all 0.2s;
&.open {
max-height: 170px;
opacity: 1;
visibility: visible;
}
label {
padding-right:10px;
}
}
}
footer { footer {
.list li:not(:last-child)::after { .list li:not(:last-child)::after {
@extend .c--dimmer; @extend .c--dimmer;

View File

@ -0,0 +1,135 @@
header {
$logo-height: px2rem(60px);
.hmn-logo {
height: $logo-height;
width: 100%;
text-transform: uppercase;
font-family: 'MohaveHMN', sans-serif;
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
color: white !important;
@media #{$breakpoint-not-small} {
width: px2rem(180px);
}
}
.items {
position: relative; // will be used on mobile, when .root-item is not relative
}
.root-item {
@media #{$breakpoint-not-small} {
& {
position: relative; // makes submenus align to this item instead of the screen
height: $logo-height;
}
}
&:not(:hover):not(.clicked) > .submenu {
display: none;
}
&.clicked .svgicon {
transform: rotate(180deg);
}
> a {
@extend .pa2, .ph3-l;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-weight: bold;
}
.svgicon {
font-size: 0.7em;
}
}
.submenu {
@extend .bw1;
@include usevar(background-color, content-background);
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
z-index: 1;
min-width: 10rem;
border-top-style: solid;
border-bottom-style: solid;
@media #{$breakpoint-not-small} {
& {
border-top-style: none;
border-left-style: solid;
border-right-style: solid;
left: initial;
right: initial;
}
}
> a {
@extend .pa2, .ph3-l;
display: block;
white-space: nowrap;
z-index: 1;
font-weight: bold;
text-align: center;
@media #{$breakpoint-not-small} {
& {
text-align: left;
}
}
}
}
.menu-bar {
width: 100%;
z-index: 10;
}
#login-popup {
@include usevar(background-color, login-popup-background);
@include usevar(color, fg-font-color);
@extend .pa3;
border-width: 1px;
border-style: dashed;
@extend .b--dimmest;
visibility: hidden;
position: absolute;
z-index: 12;
margin-top: 10px;
right: 0px;
top: 20px;
width: 290px;
max-height: 0px;
overflow: hidden;
opacity: 0;
transition: all 0.2s;
&.open {
max-height: 170px;
opacity: 1;
visibility: visible;
}
label {
padding-right:10px;
}
}
}

View File

@ -14,6 +14,7 @@
@import 'episodes'; @import 'episodes';
@import 'forms'; @import 'forms';
@import 'forum'; @import 'forum';
@import 'header';
@import 'icons'; @import 'icons';
@import 'irc'; @import 'irc';
@import 'landing'; @import 'landing';

View File

@ -1,4 +1,4 @@
<header class="mb3 bb bw1 b--theme-dark"> <header id="site-header" class="mb3 bb bw1 b--theme-dark">
<div class="user-options flex justify-center justify-end-ns"> <div class="user-options flex justify-center justify-end-ns">
{{ if .User }} {{ if .User }}
{{ if .User.IsStaff }} {{ if .User.IsStaff }}
@ -30,59 +30,81 @@
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark"> <a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark">
Handmade Handmade
</a> </a>
<div class="items flex items-center justify-center justify-start-ns"> <div class="items flex items-center justify-center justify-start-ns ml2-ns ml3-l">
{{ if .IsProjectPage }} <div class="root-item">
<a class="project-logo" href="{{ .Header.ProjectHomepageUrl }}"> <a href="{{ .Header.ProjectIndexUrl }}">Projects</a>
<h1>{{ .Project.Name }}</h1> </div>
</a> <div class="root-item">
{{ end }} <a>Media <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
{{ if not .IsProjectPage }} <div class="submenu b--theme-dark">
<a href="{{ .Header.ProjectIndexUrl }}" class="projects">Projects</a> <a href="{{ .Header.PodcastUrl }}">Podcast</a>
{{ end }} <a href="https://handmadedev.show/" target="_blank">Handmade Dev Show</a>
{{ if .Project.HasBlog }} </div>
<a href="{{ .Header.BlogUrl }}" class="blog">{{ if .IsProjectPage }}Blog{{ else }}News{{ end }}</a> </div>
{{ end }} <div class="root-item">
{{ if .Project.HasForum }} <a href="{{ .Header.ForumsUrl }}">Forums</a>
<a href="{{ .Header.ForumsUrl }}" class="forums">Forums</a> </div>
{{ end }} <div class="root-item">
{{ if .Project.HasLibrary }} <a>Resources <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<a href="{{ .Header.LibraryUrl }}" class="library">Library</a> <div class="submenu b--theme-dark">
{{ end }} <a href="{{ .Header.LibraryUrl }}">Library</a>
{{ if .Project.IsHMN }} </div>
<a href="{{ .Header.ManifestoUrl }}" class="misson">Mission</a> </div>
{{ end }}
{{ if .Header.EpisodeGuideUrl }}
<a href="{{ .Header.EpisodeGuideUrl }}" class="annotations">Episode Guide</a>
{{ end }}
{{ if .Header.EditUrl }}
<a class="edit" href="{{ .Header.EditUrl }}" title="Edit {{ .Project.Name }}"><span class="icon">0</span>&nbsp;Settings</a>
{{ end }}
</div> </div>
</div> </div>
<form onsubmit="this.querySelector('input[name=q]').value = this.querySelector('#searchstring').value + ' site:handmade.network';" class="dn ma0 flex-l flex-column justify-center items-end" method="GET" action="{{ .Header.SearchActionUrl }}" target="_blank">
<input type="hidden" name="q" />
<input class="site-search bn lite pa2 fira" type="text" id="searchstring" value="" placeholder="Search with DuckDuckGo" size="18" />
<input id="search_button_homepage" type="submit" value="Go"/>
</form>
</div> </div>
</header> </header>
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
var loginPopup = document.getElementById("login-popup"); const header = document.querySelector('#site-header');
var loginLink = document.getElementById("login-link");
if (loginPopup !== null) { // set up dropdown stuff for mobile / touch
loginLink.removeAttribute("href"); {
const rootItems = header.querySelectorAll('.root-item');
loginLink.onclick = function() { function clearDropdowns() {
loginPopup.classList.toggle("open"); for (const item of rootItems) {
item.classList.remove('clicked');
}
}
function clickDropdown(el) {
if (el.classList.contains('clicked')) {
clearDropdowns();
} else {
clearDropdowns();
el.classList.add('clicked');
}
}
for (const item of rootItems) {
if (item.querySelector('.submenu')) {
item.addEventListener('click', e => {
clickDropdown(item);
e.stopPropagation();
});
}
} }
} }
for (const time of document.querySelectorAll('time')) { // set up login form
const d = new Date(Date.parse(time.dateTime)); {
time.title = d.toLocaleString(); const loginPopup = document.getElementById("login-popup");
const loginLink = document.getElementById("login-link");
if (loginPopup !== null) {
loginLink.removeAttribute("href");
loginLink.onclick = () => {
loginPopup.classList.toggle("open");
}
}
for (const time of document.querySelectorAll('time')) {
const d = new Date(Date.parse(time.dateTime));
time.title = d.toLocaleString();
}
} }
}); });
</script> </script>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 186 186" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<path d="M16,57L93,129L170,57" style="fill:none;stroke-width:32px;"/>
</svg>

After

Width:  |  Height:  |  Size: 549 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 186 186" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(6.12323e-17,1,-1,6.12323e-17,185.342,0.00025)">
<path d="M51.707,185.343C48.966,185.343 46.214,184.299 44.114,182.194C39.92,178 39.92,171.213 44.114,167.019L118.466,92.672L44.114,18.32C39.92,14.126 39.92,7.333 44.114,3.145C48.308,-1.049 55.101,-1.049 59.294,3.145L141.228,85.079C145.422,89.273 145.422,96.066 141.228,100.254L59.294,182.193C57.201,184.293 54.454,185.343 51.707,185.343Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 910 B

View File

@ -71,32 +71,8 @@ func names(ts []*template.Template) []string {
return result return result
} }
//go:embed svg/close.svg //go:embed svg/*
var SVGClose string var SVGs embed.FS
//go:embed svg/chevron-left.svg
var SVGChevronLeft string
//go:embed svg/chevron-right.svg
var SVGChevronRight string
//go:embed svg/appleinc.svg
var SVGAppleInc string
//go:embed svg/google.svg
var SVGGoogle string
//go:embed svg/spotify.svg
var SVGSpotify string
var SVGMap = map[string]string{
"close": SVGClose,
"chevron-left": SVGChevronLeft,
"chevron-right": SVGChevronRight,
"appleinc": SVGAppleInc,
"google": SVGGoogle,
"spotify": SVGSpotify,
}
var HMNTemplateFuncs = template.FuncMap{ var HMNTemplateFuncs = template.FuncMap{
"add": func(a int, b ...int) int { "add": func(a int, b ...int) int {
@ -185,8 +161,8 @@ var HMNTemplateFuncs = template.FuncMap{
} }
}, },
"svg": func(name string) template.HTML { "svg": func(name string) template.HTML {
contents, found := SVGMap[name] contents, err := SVGs.ReadFile(fmt.Sprintf("svg/%s.svg", name))
if !found { if err != nil {
panic("SVG not found: " + name) panic("SVG not found: " + name)
} }
return template.HTML(contents) return template.HTML(contents)

View File

@ -37,23 +37,19 @@ 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 LoginActionUrl string
LogoutActionUrl string LogoutActionUrl string
ForgotPasswordUrl string ForgotPasswordUrl string
RegisterUrl string RegisterUrl string
HMNHomepageUrl string
ProjectHomepageUrl string HMNHomepageUrl string
ProjectIndexUrl string ProjectIndexUrl string
BlogUrl string PodcastUrl string
ForumsUrl string ForumsUrl string
LibraryUrl string LibraryUrl string
ManifestoUrl string
EpisodeGuideUrl string
EditUrl string
SearchActionUrl string
} }
type Footer struct { type Footer struct {

View File

@ -364,7 +364,8 @@ func ProjectHomepage(c *RequestContext) ResponseData {
projectHomepageData.BaseData = getBaseData(c, project.Name, nil) projectHomepageData.BaseData = getBaseData(c, project.Name, nil)
if canEdit { if canEdit {
projectHomepageData.BaseData.Header.EditUrl = hmnurl.BuildProjectEdit(project.Slug, "") // TODO: Move to project-specific navigation
// projectHomepageData.BaseData.Header.EditURL = hmnurl.BuildProjectEdit(project.Slug, "")
} }
projectHomepageData.BaseData.OpenGraphItems = append(projectHomepageData.BaseData.OpenGraphItems, templates.OpenGraphItem{ projectHomepageData.BaseData.OpenGraphItems = append(projectHomepageData.BaseData.OpenGraphItems, templates.OpenGraphItem{
Property: "og:description", Property: "og:description",

View File

@ -304,11 +304,12 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
} }
} }
episodeGuideUrl := "" // TODO: move to project-specific navigation
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug] // episodeGuideUrl := ""
if hasAnnotations { // defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic) // if hasAnnotations {
} // episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic)
// }
baseData := templates.BaseData{ baseData := templates.BaseData{
Theme: c.Theme, Theme: c.Theme,
@ -330,22 +331,18 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
IsProjectPage: !c.CurrentProject.IsHMN(), IsProjectPage: !c.CurrentProject.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()), LoginActionUrl: hmnurl.BuildLoginAction(c.FullUrl()),
LogoutActionUrl: hmnurl.BuildLogoutAction(c.FullUrl()), LogoutActionUrl: hmnurl.BuildLogoutAction(c.FullUrl()),
ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(), ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(),
RegisterUrl: hmnurl.BuildRegister(), RegisterUrl: hmnurl.BuildRegister(),
HMNHomepageUrl: hmnurl.BuildHomepage(),
ProjectHomepageUrl: hmnurl.BuildProjectHomepage(c.CurrentProject.Slug), HMNHomepageUrl: hmnurl.BuildHomepage(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1), ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
BlogUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, 1), PodcastUrl: hmnurl.BuildPodcast(c.CurrentProject.Slug),
ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1), ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
LibraryUrl: hmnurl.BuildLibrary(c.CurrentProject.Slug), LibraryUrl: hmnurl.BuildLibrary(c.CurrentProject.Slug),
ManifestoUrl: hmnurl.BuildManifesto(),
EpisodeGuideUrl: episodeGuideUrl,
EditUrl: "",
SearchActionUrl: "https://duckduckgo.com",
}, },
Footer: templates.Footer{ Footer: templates.Footer{
HomepageUrl: hmnurl.BuildHomepage(), HomepageUrl: hmnurl.BuildHomepage(),