Add back project nav

This commit is contained in:
Ben Visness 2021-10-27 20:35:53 -05:00
parent 5eff3c38b4
commit 4e47c51fa1
11 changed files with 315 additions and 215 deletions

View File

@ -8726,8 +8726,22 @@ header .hmn-logo {
justify-content: center; justify-content: center;
color: white !important; } color: white !important; }
@media screen and (min-width: 30em) { @media screen and (min-width: 30em) {
header .hmn-logo { header .hmn-logo.big {
width: 11.25rem; } } width: 11.25rem; } }
@media screen and (min-width: 30em) {
header .hmn-logo.small {
width: 3.75rem;
padding: 0.8rem;
text-align: justify;
text-justify: inter-character;
flex-direction: column;
font-size: 1rem;
line-height: 1em;
align-items: stretch; }
header .hmn-logo.small div::after {
content: '';
display: inline-block;
width: 100%; } }
header .items { header .items {
position: relative; } position: relative; }
@ -9324,51 +9338,54 @@ span.icon-rss::before {
width: auto; width: auto;
max-height: calc(100vh - 2rem); } } max-height: calc(100vh - 2rem); } }
.carousel-container { .carousel-container .carousel {
width: 50rem; } box-sizing: content-box;
.carousel-container .carousel { position: relative; }
box-sizing: content-box;
position: relative; } .carousel-container .carousel-item {
.carousel-container .carousel-item { position: absolute;
position: absolute; top: 0;
top: 0; left: 0; }
left: 0; } .carousel-container .carousel-item:not(.active) {
.carousel-container .carousel-item:not(.active) { display: none; }
display: none; } .carousel-container .carousel-item br {
.carousel-container .carousel-item br { line-height: 0.6em; }
line-height: 0.6em; }
.carousel-container .carousel-description { .carousel-container .carousel-description {
max-height: 14rem; max-height: 14rem;
overflow: hidden; } overflow: hidden; }
.carousel-container .carousel-fade {
position: absolute; .carousel-container .carousel-fade {
left: 0; position: absolute;
right: 0; left: 0;
bottom: 0; right: 0;
height: 30px; bottom: 0;
background: linear-gradient( rgba(240, 240, 240, 0) , #f0f0f0 ); height: 30px;
background: linear-gradient( var(--dim-background-transparent) , var(--dim-background) ); } background: linear-gradient( rgba(240, 240, 240, 0) , #f0f0f0 );
.carousel-container .carousel-item-small { background: linear-gradient( var(--dim-background-transparent) , var(--dim-background) ); }
position: absolute;
top: 0; .carousel-container .carousel-item-small {
left: 0; } position: absolute;
.carousel-container .carousel-item-small:not(.active) { top: 0;
display: none; } left: 0; }
.carousel-container .carousel-button { .carousel-container .carousel-item-small:not(.active) {
border: 1px solid; display: none; }
border-color: #999;
border-color: var(--dimmer-color); .carousel-container .carousel-button {
cursor: pointer; border: 1px solid;
transition: all 100ms ease-in-out; } border-color: #999;
.carousel-container .carousel-button:hover { border-color: var(--dimmer-color);
background-color: #bbb; cursor: pointer;
background-color: var(--dimmest-color); } transition: all 100ms ease-in-out; }
.carousel-container .carousel-button.active { .carousel-container .carousel-button:hover {
border-color: #666; background-color: #bbb;
border-color: var(--theme-color); } background-color: var(--dimmest-color); }
.carousel-container .carousel-button.active:hover { .carousel-container .carousel-button.active {
background-color: #ccc; border-color: #666;
background-color: var(--theme-color-dimmest); } border-color: var(--theme-color); }
.carousel-container .carousel-button.active:hover {
background-color: #ccc;
background-color: var(--theme-color-dimmest); }
.notice { .notice {
color: #fff; color: #fff;

View File

@ -1,6 +1,4 @@
.carousel-container { .carousel-container {
width: 50rem;
.carousel { .carousel {
box-sizing: content-box; box-sizing: content-box;
position: relative; position: relative;

View File

@ -12,9 +12,30 @@ header {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: white !important; color: white !important;
@media #{$breakpoint-not-small} { &.big {
width: px2rem(180px); @media #{$breakpoint-not-small} {
width: px2rem(180px);
}
}
&.small {
@media #{$breakpoint-not-small} {
width: $logo-height;
padding: 0.8rem;
text-align: justify;
text-justify: inter-character;
flex-direction: column;
font-size: 1rem;
line-height: 1em;
align-items: stretch;
div::after {
content: '';
display: inline-block;
width: 100%;
}
}
} }
} }

View File

@ -26,35 +26,65 @@
{{ end }} {{ end }}
</div> </div>
<div class="menu-bar flex flex-column flex-row-ns justify-between {{ if .IsProjectPage }}project{{ end }}"> <div class="menu-bar flex flex-column flex-row-ns justify-between {{ if .IsProjectPage }}project{{ end }}">
<div class="flex flex-column flex-row-ns"> <div class="flex flex-column flex-row-ns items-center">
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark"> {{ $itemsClass := "items flex items-center justify-center justify-start-ns ml2-ns ml3-l" }}
Handmade {{ if .Header.Project }}
</a> <a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo small bg-theme-dark">
<div class="items flex items-center justify-center justify-start-ns ml2-ns ml3-l"> <div>Hand</div>
<div class="root-item"> <div>made</div>
<a href="{{ .Header.ProjectIndexUrl }}">Projects</a> </a>
</div> <a href="{{ .Project.Url }}">
<div class="root-item"> <h2 class="mb0 mt2 mt0-ns ml3-ns">{{ .Project.Name }}</h2>
<a>Media <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a> </a>
<div class="submenu b--theme-dark"> {{ with .Header.Project }}
<a href="{{ .Header.PodcastUrl }}">Podcast</a> <div class="{{ $itemsClass }}">
<a href="https://handmadedev.show/" target="_blank">Handmade Dev Show</a> {{ if .HasBlog }}
<div class="root-item">
<a href="{{ .BlogUrl }}">Blog</a>
</div>
{{ end }}
{{ if .HasForums }}
<div class="root-item">
<a href="{{ .ForumsUrl }}">Forums</a>
</div>
{{ end }}
{{ if .HasEpisodeGuide }}
<div class="root-item">
<a href="{{ .EpisodeGuideUrl }}">Episode Guide</a>
</div>
{{ end }}
</div>
{{ end }}
{{ else }}
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo big bg-theme-dark">
Handmade
</a>
<div class="{{ $itemsClass }}">
<div class="root-item">
<a href="{{ .Header.ProjectIndexUrl }}">Projects</a>
</div>
<div class="root-item">
<a>Media <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<div class="submenu b--theme-dark">
<a href="{{ .Header.PodcastUrl }}">Podcast</a>
<a href="https://handmadedev.show/" target="_blank">Handmade Dev Show</a>
</div>
</div>
<div class="root-item">
<a href="{{ .Header.ForumsUrl }}">Forums</a>
</div>
<div class="root-item">
<a>Resources <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<div class="submenu b--theme-dark">
<a href="{{ .Header.LibraryUrl }}">Library</a>
</div>
</div> </div>
</div> </div>
<div class="root-item"> {{ end }}
<a href="{{ .Header.ForumsUrl }}">Forums</a>
</div>
<div class="root-item">
<a>Resources <div class="dib svgicon ml1">{{ svg "chevron-down-thick" }}</div></a>
<div class="submenu b--theme-dark">
<a href="{{ .Header.LibraryUrl }}">Library</a>
</div>
</div>
</div>
</div> </div>
<div class="dn flex-ns items-center f3"> <div class="dn flex-ns items-center f3">
<a class="svgicon" href="https://twitter.com/handmade_net/" target="_blank">{{ svg "twitter" }}</a> <a class="svgicon" href="https://twitter.com/handmade_net/" target="_blank">{{ svg "twitter" }}</a>
<a class="svgicon ml2" href="{{ .DiscordUrl }}" target="_blank">{{ svg "discord" }}</a> <a class="svgicon ml2" href="https://discord.gg/hxWxDee" target="_blank">{{ svg "discord" }}</a>
</div> </div>
</div> </div>
</header> </header>

View File

@ -207,7 +207,7 @@
<h2>Community Showcase</h2> <h2>Community Showcase</h2>
<div class="bg--card pa3 br3"> <div class="bg--card pa3 br3">
<div class="mb3"> <div class="mb3">
This is a selection of recent work done by community members. Want to participate? <a href="{{ .DiscordUrl }}" target="_blank">Join us on Discord.</a> This is a selection of recent work done by community members. Want to participate? <a href="https://discord.gg/hxWxDee" target="_blank">Join us on Discord.</a>
</div> </div>
<div id="showcase-container"></div> <div id="showcase-container"></div>
<div> <div>

View File

@ -7,10 +7,32 @@
{{ end }} {{ end }}
{{ define "content" }} {{ define "content" }}
<div class="flex flex-column flex-row-l"> <div class="flex flex-column flex-row-ns">
<div class="flex-grow-1 overflow-hidden"> <div class="sidebar flex-shrink-0 mw5 self-center self-start-ns mh3 ml0-ns overflow-hidden">
<img alt="{{ .Project.Name }}" class="br3" src="{{ .Project.Logo }}" />
<a href="{{ .CurrentProjectUrl }}">
<h2 class="mt3">{{ .Project.Name }}</h2>
</a>
<div class="mt3">
<div class="mb3">
{{ range $i, $owner := .Owners }}
<div class="flex mv3 items-center {{ if eq $i 0 }}mt2{{ end }}">
<img class="avatar-icon mr2" src="{{ $owner.AvatarUrl }}" />
<a class="user-link" href="{{ $owner.ProfileUrl }}">{{ $owner.Name }}</a>
</div>
{{ end }}
</div>
{{ range .ProjectLinks }}
<div class="pair flex">
<div class="key flex-auto flex-shrink-0 mr2">{{ .Name }}</div>
<div class="value projectlink truncate"><a class="external" href="{{ .Url }}" ><span class="icon-{{ .Icon }}"></span> {{ .LinkText }}</a></div>
</div>
{{ end }}
</div>
</div>
<div class="flex-grow-1 overflow-hidden">
{{ with .Screenshots }} {{ with .Screenshots }}
<div class="carousel-container mw-100 mv2 mv3-ns margin-center"> <div class="carousel-container mw-100 mb3">
<div class="carousel aspect-ratio aspect-ratio--16x9 overflow-hidden bg--dim br2-ns"> <div class="carousel aspect-ratio aspect-ratio--16x9 overflow-hidden bg--dim br2-ns">
<div class="dn db-l"> <div class="dn db-l">
{{ range $index, $screenshot := . }} {{ range $index, $screenshot := . }}
@ -48,27 +70,6 @@
</div> </div>
{{ end }} {{ end }}
</div> </div>
<div class="sidebar flex-shrink-0 mw6 w-30-l self-center self-start-l mh3 mh0-ns ml3-l overflow-hidden">
<div class="content-block">
<img alt="{{ .Project.Name }} Logo" class="br3" src="{{ .Project.Logo }}" />
<div class="mv3 relative">
<div class="mb3">
{{ range $i, $owner := .Owners }}
<div class="flex mv3 items-center {{ if eq $i 0 }}mt2{{ end }}">
<img class="avatar-icon mr2" src="{{ $owner.AvatarUrl }}" />
<a class="user-link" href="{{ $owner.ProfileUrl }}">{{ $owner.Name }}</a>
</div>
{{ end }}
</div>
{{ range .ProjectLinks }}
<div class="pair flex flex-wrap">
<div class="key flex-auto mr1">{{ .Name }}</div>
<div class="value projectlink"><a class="external" href="{{ .Url }}" ><span class="icon-{{ .Icon }}"></span> {{ .LinkText }}</a></div>
</div>
{{ end }}
</div>
</div>
</div>
</div> </div>
<script> <script>
const numCarouselItems = {{ len .Screenshots }}; const numCarouselItems = {{ len .Screenshots }};
@ -89,6 +90,10 @@
let carouselTimerCurrent = 0; let carouselTimerCurrent = 0;
const carouselTimer = setInterval(() => { const carouselTimer = setInterval(() => {
if (numCarouselItems === 0) {
return;
}
const next = (carouselTimerCurrent + 1) % numCarouselItems; const next = (carouselTimerCurrent + 1) % numCarouselItems;
activateCarouselItem(next); activateCarouselItem(next);
carouselTimerCurrent = next; carouselTimerCurrent = next;

View File

@ -123,6 +123,10 @@
let carouselTimerCurrent = 0; let carouselTimerCurrent = 0;
const carouselTimer = setInterval(() => { const carouselTimer = setInterval(() => {
if (numCarouselItems === 0) {
return;
}
const next = (carouselTimerCurrent + 1) % numCarouselItems; const next = (carouselTimerCurrent + 1) % numCarouselItems;
activateCarousel(next); activateCarousel(next);
carouselTimerCurrent = next; carouselTimerCurrent = next;

View File

@ -16,9 +16,10 @@ type BaseData struct {
Notices []Notice Notices []Notice
ReportIssueMailto string ReportIssueMailto string
CurrentUrl string CurrentUrl string
LoginPageUrl string CurrentProjectUrl string
ProjectCSSUrl string LoginPageUrl string
ProjectCSSUrl string
Project Project Project Project
User *User User *User
@ -50,6 +51,17 @@ type Header struct {
PodcastUrl string PodcastUrl string
ForumsUrl string ForumsUrl string
LibraryUrl string LibraryUrl string
Project *ProjectHeader
}
type ProjectHeader struct {
HasForums bool
HasBlog bool
HasEpisodeGuide bool
ForumsUrl string
BlogUrl string
EpisodeGuideUrl string
} }
type Footer struct { type Footer struct {

125
src/website/base_data.go Normal file
View File

@ -0,0 +1,125 @@
package website
import (
"git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/hmnurl"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/templates"
)
func getBaseDataAutocrumb(c *RequestContext, title string) templates.BaseData {
return getBaseData(c, title, []templates.Breadcrumb{{Name: title, Url: ""}})
}
// NOTE(asaf): If you set breadcrumbs, the breadcrumb for the current project will automatically be prepended when necessary.
// If you pass nil, no breadcrumbs will be created.
func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadcrumb) templates.BaseData {
var templateUser *templates.User
var templateSession *templates.Session
if c.CurrentUser != nil {
u := templates.UserToTemplate(c.CurrentUser, c.Theme)
s := templates.SessionToTemplate(c.CurrentSession)
templateUser = &u
templateSession = &s
}
notices := getNoticesFromCookie(c)
if len(breadcrumbs) > 0 {
projectUrl := hmnurl.BuildProjectHomepage(c.CurrentProject.Slug)
if breadcrumbs[0].Url != projectUrl {
rootBreadcrumb := templates.Breadcrumb{
Name: c.CurrentProject.Name,
Url: projectUrl,
}
breadcrumbs = append([]templates.Breadcrumb{rootBreadcrumb}, breadcrumbs...)
}
}
baseData := templates.BaseData{
Theme: c.Theme,
Title: title,
Breadcrumbs: breadcrumbs,
CurrentUrl: c.FullUrl(),
CurrentProjectUrl: hmnurl.BuildProjectHomepage(c.CurrentProject.Slug),
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
ProjectCSSUrl: hmnurl.BuildProjectCSS(c.CurrentProject.Color1),
Project: templates.ProjectToTemplate(c.CurrentProject, c.Theme),
User: templateUser,
Session: templateSession,
Notices: notices,
ReportIssueMailto: "team@handmade.network",
OpenGraphItems: buildDefaultOpenGraphItems(c.CurrentProject, title),
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(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
PodcastUrl: hmnurl.BuildPodcast(),
ForumsUrl: hmnurl.BuildForum(models.HMNProjectSlug, nil, 1),
LibraryUrl: hmnurl.BuildLibrary(),
},
Footer: templates.Footer{
HomepageUrl: hmnurl.BuildHomepage(),
AboutUrl: hmnurl.BuildAbout(),
ManifestoUrl: hmnurl.BuildManifesto(),
CodeOfConductUrl: hmnurl.BuildCodeOfConduct(),
CommunicationGuidelinesUrl: hmnurl.BuildCommunicationGuidelines(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
ForumsUrl: hmnurl.BuildForum(models.HMNProjectSlug, nil, 1),
ContactUrl: hmnurl.BuildContactPage(),
},
}
if c.CurrentUser != nil {
baseData.Header.UserProfileUrl = hmnurl.BuildUserProfile(c.CurrentUser.Username)
}
if !c.CurrentProject.IsHMN() {
episodeGuideUrl := ""
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
if hasAnnotations {
episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic)
}
baseData.Header.Project = &templates.ProjectHeader{
HasForums: c.CurrentProject.ForumEnabled,
HasBlog: c.CurrentProject.BlogEnabled,
HasEpisodeGuide: hasAnnotations,
ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
BlogUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, 1),
EpisodeGuideUrl: episodeGuideUrl,
}
}
return baseData
}
func buildDefaultOpenGraphItems(project *models.Project, title string) []templates.OpenGraphItem {
if title == "" {
title = "Handmade Network"
}
image := hmnurl.BuildPublic("logo.png", false)
if !project.IsHMN() {
image = hmnurl.BuildUserFile(project.LogoLight)
}
return []templates.OpenGraphItem{
{Property: "og:title", Value: title},
{Property: "og:site_name", Value: "Handmade Network"},
{Property: "og:type", Value: "website"},
{Property: "og:image", Value: image},
}
}

View File

@ -25,9 +25,6 @@ type LandingTemplateData struct {
FeedUrl string FeedUrl string
PodcastUrl string PodcastUrl string
StreamsUrl string StreamsUrl string
IRCUrl string
DiscordUrl string
ShowUrl string
ShowcaseUrl string ShowcaseUrl string
AtomFeedUrl string AtomFeedUrl string
MarkAllReadUrl string MarkAllReadUrl string
@ -168,9 +165,6 @@ func Index(c *RequestContext) ResponseData {
FeedUrl: hmnurl.BuildFeed(), FeedUrl: hmnurl.BuildFeed(),
PodcastUrl: hmnurl.BuildPodcast(), PodcastUrl: hmnurl.BuildPodcast(),
StreamsUrl: hmnurl.BuildStreams(), StreamsUrl: hmnurl.BuildStreams(),
IRCUrl: hmnurl.BuildBlogThread(models.HMNProjectSlug, 1138, "[Tutorial] Handmade Network IRC"),
DiscordUrl: "https://discord.gg/hxWxDee",
ShowUrl: "https://handmadedev.show/",
ShowcaseUrl: hmnurl.BuildShowcase(), ShowcaseUrl: hmnurl.BuildShowcase(),
AtomFeedUrl: hmnurl.BuildAtomFeed(), AtomFeedUrl: hmnurl.BuildAtomFeed(),
MarkAllReadUrl: hmnurl.BuildForumMarkRead(models.HMNProjectSlug, 0), MarkAllReadUrl: hmnurl.BuildForumMarkRead(models.HMNProjectSlug, 0),

View File

@ -277,112 +277,6 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
return router return router
} }
func getBaseDataAutocrumb(c *RequestContext, title string) templates.BaseData {
return getBaseData(c, title, []templates.Breadcrumb{{Name: title, Url: ""}})
}
// NOTE(asaf): If you set breadcrumbs, the breadcrumb for the current project will automatically be prepended when necessary.
// If you pass nil, no breadcrumbs will be created.
func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadcrumb) templates.BaseData {
var templateUser *templates.User
var templateSession *templates.Session
if c.CurrentUser != nil {
u := templates.UserToTemplate(c.CurrentUser, c.Theme)
s := templates.SessionToTemplate(c.CurrentSession)
templateUser = &u
templateSession = &s
}
notices := getNoticesFromCookie(c)
if len(breadcrumbs) > 0 {
projectUrl := hmnurl.BuildProjectHomepage(c.CurrentProject.Slug)
if breadcrumbs[0].Url != projectUrl {
rootBreadcrumb := templates.Breadcrumb{
Name: c.CurrentProject.Name,
Url: projectUrl,
}
breadcrumbs = append([]templates.Breadcrumb{rootBreadcrumb}, breadcrumbs...)
}
}
// 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,
Title: title,
Breadcrumbs: breadcrumbs,
CurrentUrl: c.FullUrl(),
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
ProjectCSSUrl: hmnurl.BuildProjectCSS(c.CurrentProject.Color1),
Project: templates.ProjectToTemplate(c.CurrentProject, c.Theme),
User: templateUser,
Session: templateSession,
Notices: notices,
ReportIssueMailto: "team@handmade.network",
OpenGraphItems: buildDefaultOpenGraphItems(c.CurrentProject, title),
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(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
PodcastUrl: hmnurl.BuildPodcast(),
ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
LibraryUrl: hmnurl.BuildLibrary(),
},
Footer: templates.Footer{
HomepageUrl: hmnurl.BuildHomepage(),
AboutUrl: hmnurl.BuildAbout(),
ManifestoUrl: hmnurl.BuildManifesto(),
CodeOfConductUrl: hmnurl.BuildCodeOfConduct(),
CommunicationGuidelinesUrl: hmnurl.BuildCommunicationGuidelines(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
ForumsUrl: hmnurl.BuildForum(models.HMNProjectSlug, nil, 1),
ContactUrl: hmnurl.BuildContactPage(),
},
}
if c.CurrentUser != nil {
baseData.Header.UserProfileUrl = hmnurl.BuildUserProfile(c.CurrentUser.Username)
}
return baseData
}
func buildDefaultOpenGraphItems(project *models.Project, title string) []templates.OpenGraphItem {
if title == "" {
title = "Handmade Network"
}
image := hmnurl.BuildPublic("logo.png", false)
if !project.IsHMN() {
image = hmnurl.BuildUserFile(project.LogoLight)
}
return []templates.OpenGraphItem{
{Property: "og:title", Value: title},
{Property: "og:site_name", Value: "Handmade Network"},
{Property: "og:type", Value: "website"},
{Property: "og:image", Value: image},
}
}
func FetchProjectBySlug(ctx context.Context, conn *pgxpool.Pool, slug string) (*models.Project, error) { func FetchProjectBySlug(ctx context.Context, conn *pgxpool.Pool, slug string) (*models.Project, error) {
if len(slug) > 0 && slug != models.HMNProjectSlug { if len(slug) > 0 && slug != models.HMNProjectSlug {
subdomainProjectRow, err := db.QueryOne(ctx, conn, models.Project{}, "SELECT $columns FROM handmade_project WHERE slug = $1", slug) subdomainProjectRow, err := db.QueryOne(ctx, conn, models.Project{}, "SELECT $columns FROM handmade_project WHERE slug = $1", slug)