From a72ce2ef2925c269a76b70cbb9f36c0dc8651d6c Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 27 Jun 2019 17:06:37 -0400 Subject: [PATCH] Make landing page dynamic This enables admins to customize their landing / home page via the Admin dashboard -- including the text at the top of the page and the section below it. It keeps the current default text, falling back to it if the user hasn't overwritten it. Ref T565 --- admin.go | 25 +++++++++++-- app.go | 16 +++++++++ pages.go | 56 +++++++++++++++++++++++++++++ pages/landing.tmpl | 29 +++++++-------- templates/user/admin/pages.tmpl | 3 ++ templates/user/admin/view-page.tmpl | 14 ++++++-- 6 files changed, 122 insertions(+), 21 deletions(-) diff --git a/admin.go b/admin.go index 7d21abd..227d363 100644 --- a/admin.go +++ b/admin.go @@ -299,6 +299,7 @@ func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Reque Config config.AppCfg Message string + Banner *instanceContent Content *instanceContent }{ Config: app.cfg.App, @@ -311,6 +312,13 @@ func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Reque p.Content, err = getAboutPage(app) } else if slug == "privacy" { p.Content, err = getPrivacyPage(app) + } else if slug == "landing" { + p.Banner, err = getLandingBanner(app) + if err != nil { + return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get banner: %v", err)} + } + p.Content, err = getLandingPage(app) + p.Content.ID = "landing" } else { p.Content, err = app.db.GetDynamicContent(slug) } @@ -334,13 +342,24 @@ func handleAdminUpdateSite(app *App, u *User, w http.ResponseWriter, r *http.Req id := vars["page"] // Validate - if id != "about" && id != "privacy" { + if id != "about" && id != "privacy" && id != "landing" { return impart.HTTPError{http.StatusNotFound, "No such page."} } - // Update page + var err error m := "" - err := app.db.UpdateDynamicContent(id, r.FormValue("title"), r.FormValue("content"), "page") + if id == "landing" { + // Handle special landing page + err = app.db.UpdateDynamicContent("landing-banner", "", r.FormValue("banner"), "section") + if err != nil { + m = "?m=" + err.Error() + return impart.HTTPError{http.StatusFound, "/admin/page/" + id + m} + } + err = app.db.UpdateDynamicContent("landing-body", "", r.FormValue("content"), "section") + } else { + // Update page + err = app.db.UpdateDynamicContent(id, r.FormValue("title"), r.FormValue("content"), "page") + } if err != nil { m = "?m=" + err.Error() } diff --git a/app.go b/app.go index 61db4e1..ad2c451 100644 --- a/app.go +++ b/app.go @@ -203,6 +203,8 @@ func handleViewHome(app *App, w http.ResponseWriter, r *http.Request) error { p := struct { page.StaticPage Flashes []template.HTML + Banner template.HTML + Content template.HTML ForcedLanding bool }{ @@ -210,6 +212,20 @@ func handleViewHome(app *App, w http.ResponseWriter, r *http.Request) error { ForcedLanding: forceLanding, } + banner, err := getLandingBanner(app) + if err != nil { + log.Error("unable to get landing banner: %v", err) + return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get banner: %v", err)} + } + p.Banner = template.HTML(applyMarkdown([]byte(banner.Content), "")) + + content, err := getLandingPage(app) + if err != nil { + log.Error("unable to get landing content: %v", err) + return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get content: %v", err)} + } + p.Content = template.HTML(applyMarkdown([]byte(content.Content), "")) + // Get error messages session, err := app.sessionStore.Get(r, cookieName) if err != nil { diff --git a/pages.go b/pages.go index 29ba07a..7ec20df 100644 --- a/pages.go +++ b/pages.go @@ -79,3 +79,59 @@ We store log files, or data about what happens on our servers. We also use cooki Beyond this, it's important that you trust whoever runs **` + cfg.App.SiteName + `**. Software can only do so much to protect you -- your level of privacy protections will ultimately fall on the humans that run this particular service.` } + +func getLandingBanner(app *App) (*instanceContent, error) { + c, err := app.db.GetDynamicContent("landing-banner") + if err != nil { + return nil, err + } + if c == nil { + c = &instanceContent{ + ID: "landing-banner", + Type: "section", + Content: defaultLandingBanner(app.cfg), + Updated: defaultPageUpdatedTime, + } + } + return c, nil +} + +func getLandingPage(app *App) (*instanceContent, error) { + c, err := app.db.GetDynamicContent("landing-body") + if err != nil { + return nil, err + } + if c == nil { + c = &instanceContent{ + ID: "landing-body", + Type: "section", + Content: defaultLandingBody(app.cfg), + Updated: defaultPageUpdatedTime, + } + } + return c, nil +} + +func defaultLandingBanner(cfg *config.Config) string { + if cfg.App.Federation { + return "# Start your blog in the fediverse" + } + return "# Start your blog" +} + +func defaultLandingBody(cfg *config.Config) string { + if cfg.App.Federation { + return `## Join the Fediverse + +The fediverse is a large network of platforms that all speak a common language. Imagine if you could reply to Instagram posts from Twitter, or interact with your favorite Medium blogs from Facebook -- federated alternatives like [PixelFed](https://pixelfed.org), [Mastodon](https://joinmastodon.org), and WriteFreely enable you to do these types of things. + +
+ +
+ +## Write More Socially + +WriteFreely can communicate with other federated platforms like Mastodon, so people can follow your blogs, bookmark their favorite posts, and boost them to their followers. Sign up above to create a blog and join the fediverse.` + } + return "" +} diff --git a/pages/landing.tmpl b/pages/landing.tmpl index fc4be05..d3867a9 100644 --- a/pages/landing.tmpl +++ b/pages/landing.tmpl @@ -53,15 +53,22 @@ tr.subscription { form dd { margin: 0; } +.banner-container { + text-align: left; +} +.banner-container h1 { + margin-top: 0; + max-width: 8em; +} {{end}} {{define "content"}}
-
-

{{if .Federation}}Start your blog in the fediverse{{else}}Start your blog{{end}}

-

Learn more...

+ @@ -101,24 +108,14 @@ form dd {
-{{if .Federation}} +{{if .Content}}
{{end}}
-{{ if .Federation }} +{{ if .Content }}
- -

Join the Fediverse

-

The fediverse is a large network of platforms that all speak a common language. Imagine if you could reply to Instagram posts from Twitter, or interact with your favorite Medium blogs from Facebook — federated alternatives like PixelFed, Mastodon, and WriteFreely enable you to do these types of things.

- -
- -
- -

Write More Socially

-

WriteFreely can communicate with other federated platforms like Mastodon, so people can follow your blogs, bookmark their favorite posts, and boost them to their followers. Sign up above to create a blog and join the fediverse.

- + {{.Content}}
{{ end }} diff --git a/templates/user/admin/pages.tmpl b/templates/user/admin/pages.tmpl index 9842287..25f7984 100644 --- a/templates/user/admin/pages.tmpl +++ b/templates/user/admin/pages.tmpl @@ -17,6 +17,9 @@ table.classy.export .disabled, table.classy.export a { Page Last Modified + + Home + {{range .Pages}} {{if .Title.Valid}}{{.Title.String}}{{else}}{{.ID}}{{end}} diff --git a/templates/user/admin/view-page.tmpl b/templates/user/admin/view-page.tmpl index 3b1acbd..2ed0658 100644 --- a/templates/user/admin/view-page.tmpl +++ b/templates/user/admin/view-page.tmpl @@ -25,23 +25,33 @@ input[type=text] {
{{template "admin-header" .}} -

{{.Content.ID}} page

+

{{if eq .Content.ID "landing"}}Home page{{else}}{{.Content.ID}} page{{end}}

{{if eq .Content.ID "about"}}

Describe what your instance is about.

{{else if eq .Content.ID "privacy"}}

Outline your privacy policy.

+ {{else if eq .Content.ID "landing"}} +

Customize your home page.

{{end}} {{if .Message}}

{{.Message}}

{{end}}
+ {{if eq .Content.Type "section"}} + + +

We suggest a header (e.g. # Welcome), optionally followed by a small bit of text. Accepts Markdown and HTML.

+ {{else}} + {{end}}