From ccdbad89789f790a0f28679c254e434818b97549 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Wed, 20 Oct 2021 21:21:24 -0500 Subject: [PATCH] Rework the nav for projects 2.0 --- .gitignore | 3 +- public/style.css | 171 ++++++++++++++--------- src/rawdata/scss/_core.scss | 95 +------------ src/rawdata/scss/_header.scss | 135 ++++++++++++++++++ src/rawdata/scss/style.scss | 1 + src/templates/src/include/header.html | 106 ++++++++------ src/templates/svg/chevron-down-thick.svg | 5 + src/templates/svg/chevron-down.svg | 7 + src/templates/templates.go | 32 +---- src/templates/types.go | 30 ++-- src/website/projects.go | 3 +- src/website/routes.go | 39 +++--- 12 files changed, 357 insertions(+), 270 deletions(-) create mode 100644 src/rawdata/scss/_header.scss create mode 100644 src/templates/svg/chevron-down-thick.svg create mode 100644 src/templates/svg/chevron-down.svg diff --git a/.gitignore b/.gitignore index 383ab59..ffcf48e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ src/config/config.go .vscode +.idea vendor/ dbclones/ coverage.out @@ -11,4 +12,4 @@ annotations/ hmn.conf adminmailer/config.go adminmailer/adminmailer -local/backups \ No newline at end of file +local/backups diff --git a/public/style.css b/public/style.css index 5fa0228..befa431 100644 --- a/public/style.css +++ b/public/style.css @@ -1377,7 +1377,7 @@ img, video { .bw0 { border-width: 0; } -.bw1 { +.bw1, header .submenu { border-width: 0.125rem; } .bw2 { @@ -4581,7 +4581,7 @@ code, .code { .pa1 { padding: 0.25rem; } -.pa2, header .menu-bar .items a, .tab { +.pa2, .tab, header .root-item > a, header .submenu > a { padding: 0.5rem; } .pa3, header #login-popup { @@ -4707,7 +4707,7 @@ code, .code { padding-top: 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, input[type=button], @@ -5053,7 +5053,7 @@ input[type=submit], .notice { .optionbar .options input[type=submit] { padding-top: 0.5rem; padding-bottom: 0.5rem; } - .pv3-ns, header .menu-bar .items a { + .pv3-ns { padding-top: 1rem; padding-bottom: 1rem; } .pv4-ns { @@ -5112,7 +5112,7 @@ input[type=submit], .notice { margin-left: 0; } .ml1-ns { margin-left: 0.25rem; } - .ml2-ns, header .menu-bar .items a:first-child { + .ml2-ns { margin-left: 0.5rem; } .ml3-ns { margin-left: 1rem; } @@ -5593,7 +5593,7 @@ input[type=submit], .notice { .ph2-l { padding-left: 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-right: 1rem; } .ph4-l { @@ -5630,7 +5630,7 @@ input[type=submit], .notice { margin-left: 0.25rem; } .ml2-l { margin-left: 0.5rem; } - .ml3-l, header .menu-bar .items a:first-child { + .ml3-l { margin-left: 1rem; } .ml4-l { margin-left: 2rem; } @@ -7381,7 +7381,7 @@ article code { color: #ccc; 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: var(--dimmest-color); } @@ -7578,6 +7578,7 @@ article code { .svgicon svg { fill: currentColor; + stroke: currentColor; width: 1em; height: 1em; } @@ -7588,64 +7589,6 @@ article code { margin-right: 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) { footer .list li:not(:last-child)::after { content: ' / '; } } @@ -8762,6 +8705,102 @@ div.mark_as_read_toplevel_blog { .bbtable tbody tr:nth-child(even) { 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-family: icons; src: url("/public/icons.ttf?v=4"); } diff --git a/src/rawdata/scss/_core.scss b/src/rawdata/scss/_core.scss index 20dceaa..246b3e3 100644 --- a/src/rawdata/scss/_core.scss +++ b/src/rawdata/scss/_core.scss @@ -408,6 +408,7 @@ article code { .svgicon { svg { fill: currentColor; + stroke: currentColor; width: 1em; height: 1em; } @@ -424,100 +425,6 @@ article code { 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 { .list li:not(:last-child)::after { @extend .c--dimmer; diff --git a/src/rawdata/scss/_header.scss b/src/rawdata/scss/_header.scss new file mode 100644 index 0000000..15dd3d9 --- /dev/null +++ b/src/rawdata/scss/_header.scss @@ -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; + } + } +} diff --git a/src/rawdata/scss/style.scss b/src/rawdata/scss/style.scss index 0aa6480..461ec3a 100644 --- a/src/rawdata/scss/style.scss +++ b/src/rawdata/scss/style.scss @@ -14,6 +14,7 @@ @import 'episodes'; @import 'forms'; @import 'forum'; +@import 'header'; @import 'icons'; @import 'irc'; @import 'landing'; diff --git a/src/templates/src/include/header.html b/src/templates/src/include/header.html index 34e8fe5..bede63b 100644 --- a/src/templates/src/include/header.html +++ b/src/templates/src/include/header.html @@ -1,4 +1,4 @@ -
+ diff --git a/src/templates/svg/chevron-down-thick.svg b/src/templates/svg/chevron-down-thick.svg new file mode 100644 index 0000000..4fa11a5 --- /dev/null +++ b/src/templates/svg/chevron-down-thick.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/templates/svg/chevron-down.svg b/src/templates/svg/chevron-down.svg new file mode 100644 index 0000000..744ded6 --- /dev/null +++ b/src/templates/svg/chevron-down.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/templates/templates.go b/src/templates/templates.go index 9e6f1e4..fbc22f2 100644 --- a/src/templates/templates.go +++ b/src/templates/templates.go @@ -71,32 +71,8 @@ func names(ts []*template.Template) []string { return result } -//go:embed svg/close.svg -var SVGClose string - -//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, -} +//go:embed svg/* +var SVGs embed.FS var HMNTemplateFuncs = template.FuncMap{ "add": func(a int, b ...int) int { @@ -185,8 +161,8 @@ var HMNTemplateFuncs = template.FuncMap{ } }, "svg": func(name string) template.HTML { - contents, found := SVGMap[name] - if !found { + contents, err := SVGs.ReadFile(fmt.Sprintf("svg/%s.svg", name)) + if err != nil { panic("SVG not found: " + name) } return template.HTML(contents) diff --git a/src/templates/types.go b/src/templates/types.go index 3fba22f..bc8b24d 100644 --- a/src/templates/types.go +++ b/src/templates/types.go @@ -37,23 +37,19 @@ func (bd *BaseData) AddImmediateNotice(class, content string) { } type Header struct { - AdminUrl string - UserProfileUrl string - UserSettingsUrl string - LoginActionUrl string - LogoutActionUrl string - ForgotPasswordUrl string - RegisterUrl string - HMNHomepageUrl string - ProjectHomepageUrl string - ProjectIndexUrl string - BlogUrl string - ForumsUrl string - LibraryUrl string - ManifestoUrl string - EpisodeGuideUrl string - EditUrl string - SearchActionUrl string + AdminUrl string + UserProfileUrl string + UserSettingsUrl string + LoginActionUrl string + LogoutActionUrl string + ForgotPasswordUrl string + RegisterUrl string + + HMNHomepageUrl string + ProjectIndexUrl string + PodcastUrl string + ForumsUrl string + LibraryUrl string } type Footer struct { diff --git a/src/website/projects.go b/src/website/projects.go index de55395..7daf700 100644 --- a/src/website/projects.go +++ b/src/website/projects.go @@ -364,7 +364,8 @@ func ProjectHomepage(c *RequestContext) ResponseData { projectHomepageData.BaseData = getBaseData(c, project.Name, nil) 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{ Property: "og:description", diff --git a/src/website/routes.go b/src/website/routes.go index d5cc14f..1c0e365 100644 --- a/src/website/routes.go +++ b/src/website/routes.go @@ -304,11 +304,12 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc } } - episodeGuideUrl := "" - defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug] - if hasAnnotations { - episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic) - } + // TODO: move to project-specific navigation + // episodeGuideUrl := "" + // defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug] + // if hasAnnotations { + // episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic) + // } baseData := templates.BaseData{ Theme: c.Theme, @@ -330,22 +331,18 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc IsProjectPage: !c.CurrentProject.IsHMN(), Header: templates.Header{ - AdminUrl: hmnurl.BuildAdminApprovalQueue(), // TODO(asaf): Replace with general-purpose admin page - UserSettingsUrl: hmnurl.BuildUserSettings(""), - LoginActionUrl: hmnurl.BuildLoginAction(c.FullUrl()), - LogoutActionUrl: hmnurl.BuildLogoutAction(c.FullUrl()), - ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(), - RegisterUrl: hmnurl.BuildRegister(), - HMNHomepageUrl: hmnurl.BuildHomepage(), - ProjectHomepageUrl: hmnurl.BuildProjectHomepage(c.CurrentProject.Slug), - ProjectIndexUrl: hmnurl.BuildProjectIndex(1), - BlogUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, 1), - ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1), - LibraryUrl: hmnurl.BuildLibrary(c.CurrentProject.Slug), - ManifestoUrl: hmnurl.BuildManifesto(), - EpisodeGuideUrl: episodeGuideUrl, - EditUrl: "", - SearchActionUrl: "https://duckduckgo.com", + AdminUrl: hmnurl.BuildAdminApprovalQueue(), // TODO(asaf): Replace with general-purpose admin page + UserSettingsUrl: hmnurl.BuildUserSettings(""), + LoginActionUrl: hmnurl.BuildLoginAction(c.FullUrl()), + LogoutActionUrl: hmnurl.BuildLogoutAction(c.FullUrl()), + ForgotPasswordUrl: hmnurl.BuildRequestPasswordReset(), + RegisterUrl: hmnurl.BuildRegister(), + + HMNHomepageUrl: hmnurl.BuildHomepage(), + ProjectIndexUrl: hmnurl.BuildProjectIndex(1), + PodcastUrl: hmnurl.BuildPodcast(c.CurrentProject.Slug), + ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1), + LibraryUrl: hmnurl.BuildLibrary(c.CurrentProject.Slug), }, Footer: templates.Footer{ HomepageUrl: hmnurl.BuildHomepage(),