mirror of
https://github.com/writeas/writefreely
synced 2025-02-03 13:47:51 +01:00
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
This commit is contained in:
parent
aedb05080c
commit
a72ce2ef29
25
admin.go
25
admin.go
@ -299,6 +299,7 @@ func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Reque
|
|||||||
Config config.AppCfg
|
Config config.AppCfg
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
|
Banner *instanceContent
|
||||||
Content *instanceContent
|
Content *instanceContent
|
||||||
}{
|
}{
|
||||||
Config: app.cfg.App,
|
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)
|
p.Content, err = getAboutPage(app)
|
||||||
} else if slug == "privacy" {
|
} else if slug == "privacy" {
|
||||||
p.Content, err = getPrivacyPage(app)
|
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 {
|
} else {
|
||||||
p.Content, err = app.db.GetDynamicContent(slug)
|
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"]
|
id := vars["page"]
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if id != "about" && id != "privacy" {
|
if id != "about" && id != "privacy" && id != "landing" {
|
||||||
return impart.HTTPError{http.StatusNotFound, "No such page."}
|
return impart.HTTPError{http.StatusNotFound, "No such page."}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update page
|
var err error
|
||||||
m := ""
|
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 {
|
if err != nil {
|
||||||
m = "?m=" + err.Error()
|
m = "?m=" + err.Error()
|
||||||
}
|
}
|
||||||
|
16
app.go
16
app.go
@ -203,6 +203,8 @@ func handleViewHome(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||||||
p := struct {
|
p := struct {
|
||||||
page.StaticPage
|
page.StaticPage
|
||||||
Flashes []template.HTML
|
Flashes []template.HTML
|
||||||
|
Banner template.HTML
|
||||||
|
Content template.HTML
|
||||||
|
|
||||||
ForcedLanding bool
|
ForcedLanding bool
|
||||||
}{
|
}{
|
||||||
@ -210,6 +212,20 @@ func handleViewHome(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||||||
ForcedLanding: forceLanding,
|
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
|
// Get error messages
|
||||||
session, err := app.sessionStore.Get(r, cookieName)
|
session, err := app.sessionStore.Get(r, cookieName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
56
pages.go
56
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.`
|
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.
|
||||||
|
|
||||||
|
<div style="text-align:center">
|
||||||
|
<iframe style="width: 560px; height: 315px; max-width: 100%;" sandbox="allow-same-origin allow-scripts" src="https://video.writeas.org/videos/embed/cc55e615-d204-417c-9575-7b57674cc6f3" frameborder="0" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 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 ""
|
||||||
|
}
|
||||||
|
@ -53,15 +53,22 @@ tr.subscription {
|
|||||||
form dd {
|
form dd {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.banner-container {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.banner-container h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
max-width: 8em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
<div id="pricing" class="content-container wide-form">
|
<div id="pricing" class="content-container wide-form">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div style="text-align:left">
|
<div class="banner-container">
|
||||||
<h1 style="margin-top:0;max-width:8em;">{{if .Federation}}Start your blog in the fediverse{{else}}Start your blog{{end}}</h1>
|
{{.Banner}}
|
||||||
<p><a href="{{if .Federation}}#more{{else}}/about{{end}}">Learn more...</a></p>
|
<p><a href="{{if .Content}}#more{{else}}/about{{end}}">Learn more...</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div{{if not .OpenRegistration}} style="padding: 2em 0;"{{end}}>
|
<div{{if not .OpenRegistration}} style="padding: 2em 0;"{{end}}>
|
||||||
@ -101,24 +108,14 @@ form dd {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if .Federation}}
|
{{if .Content}}
|
||||||
<a name="more"></a><hr style="margin: 1em auto 3em;" />
|
<a name="more"></a><hr style="margin: 1em auto 3em;" />
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ if .Federation }}
|
{{ if .Content }}
|
||||||
<div class="content-container snug">
|
<div class="content-container snug">
|
||||||
|
{{.Content}}
|
||||||
<h2>Join the Fediverse</h2>
|
|
||||||
<p>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 <a href="https://pixelfed.org/" target="pixel">PixelFed</a>, <a href="https://joinmastodon.org/" target="masto">Mastodon</a>, and WriteFreely enable you to do these types of things.</p>
|
|
||||||
|
|
||||||
<div style="text-align:center">
|
|
||||||
<iframe style="width: 560px; height: 315px; max-width: 100%;" sandbox="allow-same-origin allow-scripts" src="https://video.writeas.org/videos/embed/cc55e615-d204-417c-9575-7b57674cc6f3" frameborder="0" allowfullscreen></iframe>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Write More Socially</h2>
|
|
||||||
<p>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.</p>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@ table.classy.export .disabled, table.classy.export a {
|
|||||||
<th>Page</th>
|
<th>Page</th>
|
||||||
<th>Last Modified</th>
|
<th>Last Modified</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><a href="/admin/page/landing">Home</a></td>
|
||||||
|
</tr>
|
||||||
{{range .Pages}}
|
{{range .Pages}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/admin/page/{{.ID}}">{{if .Title.Valid}}{{.Title.String}}{{else}}{{.ID}}{{end}}</a></td>
|
<td><a href="/admin/page/{{.ID}}">{{if .Title.Valid}}{{.Title.String}}{{else}}{{.ID}}{{end}}</a></td>
|
||||||
|
@ -25,23 +25,33 @@ input[type=text] {
|
|||||||
<div class="snug content-container">
|
<div class="snug content-container">
|
||||||
{{template "admin-header" .}}
|
{{template "admin-header" .}}
|
||||||
|
|
||||||
<h2 id="posts-header">{{.Content.ID}} page</h2>
|
<h2 id="posts-header">{{if eq .Content.ID "landing"}}Home page{{else}}{{.Content.ID}} page{{end}}</h2>
|
||||||
|
|
||||||
{{if eq .Content.ID "about"}}
|
{{if eq .Content.ID "about"}}
|
||||||
<p class="page-desc content-desc">Describe what your instance is <a href="/about" target="page">about</a>.</p>
|
<p class="page-desc content-desc">Describe what your instance is <a href="/about" target="page">about</a>.</p>
|
||||||
{{else if eq .Content.ID "privacy"}}
|
{{else if eq .Content.ID "privacy"}}
|
||||||
<p class="page-desc content-desc">Outline your <a href="/privacy" target="page">privacy policy</a>.</p>
|
<p class="page-desc content-desc">Outline your <a href="/privacy" target="page">privacy policy</a>.</p>
|
||||||
|
{{else if eq .Content.ID "landing"}}
|
||||||
|
<p class="page-desc content-desc">Customize your <a href="/?landing=1">home page</a>.</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Message}}<p>{{.Message}}</p>{{end}}
|
{{if .Message}}<p>{{.Message}}</p>{{end}}
|
||||||
|
|
||||||
<form method="post" action="/admin/update/{{.Content.ID}}" onsubmit="savePage(this)">
|
<form method="post" action="/admin/update/{{.Content.ID}}" onsubmit="savePage(this)">
|
||||||
|
{{if eq .Content.Type "section"}}
|
||||||
|
<label for="banner">
|
||||||
|
Banner
|
||||||
|
</label>
|
||||||
|
<textarea id="banner" class="section codable norm edit-page" style="min-height: 5em; height: 5em;" name="banner">{{.Banner.Content}}</textarea>
|
||||||
|
<p class="content-desc">We suggest a header (e.g. <code># Welcome</code>), optionally followed by a small bit of text. Accepts Markdown and HTML.</p>
|
||||||
|
{{else}}
|
||||||
<label for="title">
|
<label for="title">
|
||||||
Title
|
Title
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="title" id="title" value="{{.Content.Title.String}}" />
|
<input type="text" name="title" id="title" value="{{.Content.Title.String}}" />
|
||||||
|
{{end}}
|
||||||
<label for="content">
|
<label for="content">
|
||||||
Content
|
{{if .Banner}}Body{{else}}Content{{end}}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<textarea id="content" class="section codable norm edit-page" name="content">{{.Content.Content}}</textarea>
|
<textarea id="content" class="section codable norm edit-page" name="content">{{.Content.Content}}</textarea>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user