diff options
Diffstat (limited to 'internal/web/templates')
| -rw-r--r-- | internal/web/templates/dashboard/design.html | 54 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/layout.html | 113 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/module_form.html | 34 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/overview.html | 2 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/pages.html | 6 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/section_form.html | 14 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/sections.html | 2 | ||||
| -rw-r--r-- | internal/web/templates/layouts/blog.html | 84 | ||||
| -rw-r--r-- | internal/web/templates/partials/dashnav.html | 1 |
9 files changed, 244 insertions, 66 deletions
diff --git a/internal/web/templates/dashboard/design.html b/internal/web/templates/dashboard/design.html index af482fe..342cabe 100644 --- a/internal/web/templates/dashboard/design.html +++ b/internal/web/templates/dashboard/design.html @@ -5,7 +5,8 @@ <h1>Design</h1> <p class="lead muted">Changes are live as soon as you save; refresh <a href="{{.BlogURL}}" target="_blank">your blog ↗</a> to see them.</p> </div> -<p class="jumps"><a href="#schemes">Schemes</a><a href="#background">Background</a><a href="#text">Text</a><a href="#header">Header</a><a href="#menu">Menu</a><a href="#posts">Posts</a><a href="#footer">Footer</a><a href="#icon">Icon</a></p> +<p class="jumps"><a href="#schemes">Schemes</a><a href="#background">Background</a><a href="#text">Text</a><a href="#header">Header</a><a href="#menu">Menu</a><a href="#posts">Posts</a><a href="#footer">Footer</a><a href="#logo">Logo & icon</a></p> +<p class="muted small">What appears where — header, columns, footer and their modules — is arranged on the <a href="/b/{{.Blog.Subdomain}}/layout">Layout</a> tab.</p> <div class="card" id="schemes"> <h2>Colour schemes</h2> @@ -81,12 +82,13 @@ <option value="card"{{if eq $t.ContentStyle "card"}} selected{{end}}>Card (shadow, rounded corners)</option> <option value="flat"{{if eq $t.ContentStyle "flat"}} selected{{end}}>Flat</option> </select></label> - <label>Padding<br><select name="content_padding"> + <label>Padding <span class="muted">(inside the box)</span><br><select name="content_padding"> <option value="compact"{{if eq $t.ContentPadding "compact"}} selected{{end}}>Compact</option> <option value="normal"{{if eq $t.ContentPadding "normal"}} selected{{end}}>Normal</option> <option value="roomy"{{if eq $t.ContentPadding "roomy"}} selected{{end}}>Roomy</option> </select></label> </div> + <p class="muted small">Width only applies while there are no side columns; with a left or right column the blog uses the whole page.</p> </div> <div class="card" id="header"> @@ -104,43 +106,24 @@ <option value="tall"{{if eq $t.HeaderImageHeight "tall"}} selected{{end}}>Tall</option> </select></label> </div> - <label class="check"><input type="checkbox" name="header_show_title"{{if $t.HeaderShowTitle}} checked{{end}}> Show blog title and tagline in the header</label> + <p class="muted small">The title, logo and menu are header modules — add, remove and order them on the <a href="/b/{{.Blog.Subdomain}}/layout#header">Layout</a> tab. The banner below is shown across the top of the header whenever one is chosen.</p> {{template "imagepick" (dict "name" "header_image" "current" $t.HeaderImage "images" .Data.images "label" "Header image (banner)")}} </div> <div class="card" id="menu"> <h2>Menu</h2> - <p class="muted small">The menu lists the pages you marked "show in menu". Pick where it goes; the options underneath follow your choice.</p> - <div class="navpos"> - <input type="radio" name="nav_position" value="below-header" id="np-below"{{if eq $t.NavPosition "below-header"}} checked{{end}}> - <label for="np-below" class="tile"><svg viewBox="0 0 80 56" width="80" height="56" aria-hidden="true"><rect x="0" y="0" width="80" height="56" fill="#f4efe4"/><rect x="0" y="0" width="80" height="14" fill="#1d1a17"/><rect x="0" y="16" width="80" height="6" fill="#c8541a"/><rect x="10" y="28" width="60" height="24" fill="#fffdf8" stroke="#1d1a17"/></svg><span>Below the header</span></label> - <input type="radio" name="nav_position" value="top-bar" id="np-top"{{if eq $t.NavPosition "top-bar"}} checked{{end}}> - <label for="np-top" class="tile"><svg viewBox="0 0 80 56" width="80" height="56" aria-hidden="true"><rect x="0" y="0" width="80" height="56" fill="#f4efe4"/><rect x="0" y="0" width="80" height="6" fill="#c8541a"/><rect x="0" y="8" width="80" height="14" fill="#1d1a17"/><rect x="10" y="28" width="60" height="24" fill="#fffdf8" stroke="#1d1a17"/></svg><span>Bar at the very top</span></label> - <input type="radio" name="nav_position" value="left-sidebar" id="np-side"{{if eq $t.NavPosition "left-sidebar"}} checked{{end}}> - <label for="np-side" class="tile"><svg viewBox="0 0 80 56" width="80" height="56" aria-hidden="true"><rect x="0" y="0" width="80" height="56" fill="#f4efe4"/><rect x="0" y="0" width="80" height="14" fill="#1d1a17"/><rect x="8" y="20" width="18" height="32" fill="#c8541a"/><rect x="30" y="20" width="42" height="32" fill="#fffdf8" stroke="#1d1a17"/></svg><span>Sidebar on the left</span></label> - <div class="row only-horizontal"> - <label>Alignment<br><select name="nav_align"> - <option value="left"{{if eq $t.NavAlign "left"}} selected{{end}}>Left</option> - <option value="center"{{if eq $t.NavAlign "center"}} selected{{end}}>Centred</option> - <option value="right"{{if eq $t.NavAlign "right"}} selected{{end}}>Right</option> - </select></label> - </div> - <div class="row only-sidebar"> - <label>Sidebar width<br><select name="nav_sidebar_width"> - <option value="narrow"{{if eq $t.NavSidebarWidth "narrow"}} selected{{end}}>Narrow</option> - <option value="normal"{{if eq $t.NavSidebarWidth "normal"}} selected{{end}}>Normal</option> - <option value="wide"{{if eq $t.NavSidebarWidth "wide"}} selected{{end}}>Wide</option> - </select></label> - </div> - <p class="muted small only-sidebar">Links stack under each other; announcements placed "in the sidebar" appear beneath them. On phones the sidebar turns into a row of links above the content.</p> - </div> + <p class="muted small">Which links the menu shows, and where it sits, is set on the <a href="/b/{{.Blog.Subdomain}}/layout#menu">Layout</a> tab. Here you choose how it looks.</p> <div class="row"> + <label>Alignment <span class="muted">(menu in the header)</span><br><select name="nav_align"> + <option value="left"{{if eq $t.NavAlign "left"}} selected{{end}}>Left</option> + <option value="center"{{if eq $t.NavAlign "center"}} selected{{end}}>Centred</option> + <option value="right"{{if eq $t.NavAlign "right"}} selected{{end}}>Right</option> + </select></label> <label>Link style<br><select name="nav_style"> <option value="normal"{{if eq $t.NavStyle "normal"}} selected{{end}}>Normal</option> <option value="uppercase"{{if eq $t.NavStyle "uppercase"}} selected{{end}}>Uppercase, spaced</option> </select></label> </div> - <label class="check"><input type="checkbox" name="nav_show_home"{{if $t.NavShowHome}} checked{{end}}> Include the home page in the menu</label> <h3>Menu colours</h3> <div class="row"> <label>Background<br><input type="color" name="nav_bg" value="{{$t.NavBg}}"></label> @@ -167,16 +150,23 @@ <div class="card" id="footer"> <h2>Footer</h2> - <label>Footer text<br><input name="footer_text" value="{{$t.FooterText}}" maxlength="2000" placeholder="© 2026 Me"></label> + <p class="muted small">The footer text, RSS link and other footer modules live on the <a href="/b/{{.Blog.Subdomain}}/layout#footer">Layout</a> tab.</p> <div class="row"> <label>Background<br><input type="color" name="footer_bg" value="{{$t.FooterBg}}"></label> <label>Text colour<br><input type="color" name="footer_color" value="{{$t.FooterColor}}"></label> </div> - <label class="check"><input type="checkbox" name="footer_show_rss"{{if $t.FooterShowRSS}} checked{{end}}> Show the RSS link in the footer</label> </div> -<div class="card" id="icon"> - <h2>Site icon</h2> +<div class="card" id="logo"> + <h2>Logo & site icon</h2> + <div class="row"> + <label>Logo size<br><select name="logo_size"> + <option value="small"{{if eq $t.LogoSize "small"}} selected{{end}}>Small (48 px tall)</option> + <option value="medium"{{if eq $t.LogoSize "medium"}} selected{{end}}>Medium (80 px)</option> + <option value="large"{{if eq $t.LogoSize "large"}} selected{{end}}>Large (140 px)</option> + </select></label> + </div> + {{template "imagepick" (dict "name" "logo" "current" $t.Logo "images" .Data.images "label" "Logo" "hint" "Shown wherever you place a Logo module (Layout tab); it links to your front page.")}} {{template "imagepick" (dict "name" "favicon" "current" $t.Favicon "images" .Data.images "label" "Favicon" "hint" "The small icon browsers show in the tab. A square PNG or ICO of 32–64 px works best; pick None for the Blogspace icon." "accept" "image/png,image/x-icon,image/gif,image/webp,image/jpeg,.ico")}} </div> diff --git a/internal/web/templates/dashboard/layout.html b/internal/web/templates/dashboard/layout.html new file mode 100644 index 0000000..7691b1e --- /dev/null +++ b/internal/web/templates/dashboard/layout.html @@ -0,0 +1,113 @@ +{{define "title"}}Layout · {{.Blog.Title}}{{end}} +{{define "content"}} +{{$t := .Data.theme}} +{{$u := print "/b/" .Blog.Subdomain "/layout"}} +<div class="pagehead"> + <h1>Layout</h1> + <p class="lead muted">Decide what goes where on your blog. Every change here is saved straight away; refresh <a href="{{.BlogURL}}" target="_blank">your blog ↗</a> to see it. Colours and fonts are on the <a href="/b/{{.Blog.Subdomain}}/design">Design</a> tab.</p> +</div> +<p class="jumps"><a href="#columns">Columns</a><a href="#header">Header</a><a href="#left">Left column</a><a href="#main">Main content</a><a href="#right">Right column</a><a href="#footer">Footer</a><a href="#menu">Menu</a></p> + +<div class="card" id="columns"> + <h2>Columns</h2> + <div class="lay"> + <div class="lay-row lay-header{{if not $t.HeaderOn}} off{{end}}">Header{{if not $t.HeaderOn}} (hidden){{end}}</div> + <div class="lay-cols"> + <div class="lay-col lay-side{{if not $t.LeftOn}} off{{end}}{{if not (index .Data.areas "left")}} empty{{end}}" style="width:{{$t.LeftWidth}}%">Left {{$t.LeftWidth}}%</div> + <div class="lay-col lay-main" style="width:{{$t.MainWidth}}%">Main content {{$t.MainWidth}}%</div> + <div class="lay-col lay-side{{if not $t.RightOn}} off{{end}}{{if not (index .Data.areas "right")}} empty{{end}}" style="width:{{$t.RightWidth}}%">Right {{$t.RightWidth}}%</div> + </div> + <div class="lay-row lay-footer{{if not $t.FooterOn}} off{{end}}">Footer{{if not $t.FooterOn}} (hidden){{end}}</div> + </div> + <form method="post" action="{{$u}}/widths"> + <input type="hidden" name="_csrf" value="{{.CSRF}}"> + <div class="row"> + <label>Left column width<br><input type="number" name="left_width" value="{{$t.LeftWidth}}" min="15" max="40" step="5"> %</label> + <label>Right column width<br><input type="number" name="right_width" value="{{$t.RightWidth}}" min="15" max="40" step="5"> %</label> + </div> + <p class="muted small">Between 15% and 40% each; the main content takes the rest. A column only appears when it has at least one module; as soon as one does, the blog spreads over the whole page. On phones the columns stack: main content first, then the left and right columns, then the footer.</p> + <label class="check"><input type="checkbox" name="keep_columns"{{if $t.KeepColumns}} checked{{end}}> Always keep the columns' space, even when a column is empty or hidden <span class="muted">(the main content then has the same width on every page)</span></label> + <p class="actionrow"><button type="submit">Save columns</button></p> + </form> +</div> + +{{template "area" (dict "area" "header" "root" . "hint" "The top of every page. Stack the title, a logo and the menu in the order you like. A banner image can be chosen on the Design tab.")}} +{{template "area" (dict "area" "left" "root" . "hint" "A narrow column beside your posts. Good for the menu, an archive or recent posts.")}} + +<div class="card" id="main"> + <div class="cardhead"><h2>Main content</h2></div> + <p class="muted small">Your posts and pages always show here. You can add your own HTML before and after them — an intro box, a newsletter form, a badge…</p> + <table class="modules"> + {{range $area := .Data.areaOrder}}{{$mods := index $.Data.areas $area}} + <tr><th>{{index $.Data.areaNames $area}}</th> + {{if $mods}}{{$m := index $mods 0}} + <td>{{index $.Data.names $m.Kind}}{{with modsummary $m}} <span class="muted">— {{.}}</span>{{end}}</td> + <td class="nowrap actions"><a href="{{$u}}/modules/{{$m.ID}}/edit">edit</a> <a class="danger" href="{{$u}}/modules/{{$m.ID}}/delete">remove</a></td> + {{else}} + <td class="muted">Nothing extra.</td> + <td class="nowrap actions"><form method="post" action="{{$u}}/areas/{{$area}}/add" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="kind" value="html"><button class="mini">+ Add custom HTML</button></form></td> + {{end}} + </tr>{{end}} + </table> +</div> + +{{template "area" (dict "area" "right" "root" . "hint" "A narrow column on the other side of your posts. Same choices as the left one.")}} +{{template "area" (dict "area" "footer" "root" . "hint" "The bottom of every page: a copyright line, the RSS link, a list of your pages.")}} + +<div class="card" id="menu"> + <h2>Menu</h2> + <p class="muted small">The links the Menu module shows, wherever you place it. Pages and outside links can be mixed in any order. Ticking "Show in menu" on a page does the same as adding it here.</p> + {{if .Data.menu}}<table class="modules"> + {{range .Data.menu}}<tr> + <td class="nowrap order"> + <form method="post" action="{{$u}}/menu/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="dir" value="up"><button class="mini" title="Move up">▲</button></form> + <form method="post" action="{{$u}}/menu/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="dir" value="down"><button class="mini" title="Move down">▼</button></form> + </td> + <td>{{.Text}} {{if .PageID}}<span class="tag">page</span>{{else}}<span class="tag">link</span> <span class="muted small">{{.URL}}</span>{{end}}</td> + <td class="nowrap actions"><form method="post" action="{{$u}}/menu/{{.ID}}/delete" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><button class="mini danger">Remove</button></form></td> + </tr>{{end}} + </table>{{else}}<p class="muted">The menu is empty.</p>{{end}} + <div class="cols addrow"> + <form method="post" action="{{$u}}/menu/add-page" class="add"> + <input type="hidden" name="_csrf" value="{{.CSRF}}"> + <h3>Add a page</h3> + {{if .Data.freePages}}<label>Page<br><select name="page">{{range .Data.freePages}}<option value="{{.ID}}">{{.Title}}</option>{{end}}</select></label> + <button type="submit" class="secondary">Add page</button> + {{else}}<p class="muted small">Every page is already in the menu.</p>{{end}} + </form> + <form method="post" action="{{$u}}/menu/add-link" class="add"> + <input type="hidden" name="_csrf" value="{{.CSRF}}"> + <h3>Add a link</h3> + <label>Text<br><input name="label" maxlength="60" placeholder="My photos"></label> + <label>Address<br><input name="url" maxlength="500" placeholder="https://example.org"></label> + <button type="submit" class="secondary">Add link</button> + </form> + </div> +</div> +{{end}} + +{{/* One area card: on/off switch, its modules in order, and an "add" form. */}} +{{define "area"}}{{$r := .root}}{{$area := .area}}{{$u := print "/b/" $r.Blog.Subdomain "/layout"}}{{$on := $r.Data.theme.AreaOn $area}}{{$mods := index $r.Data.areas $area}} +<div class="card{{if not $on}} area-off{{end}}" id="{{$area}}"> + <div class="cardhead"> + <h2>{{index $r.Data.areaNames $area}}{{if not $on}} <span class="tag off">hidden</span>{{end}}</h2> + <form method="post" action="{{$u}}/areas/{{$area}}/toggle" class="inline switch"><input type="hidden" name="_csrf" value="{{$r.CSRF}}"><button class="mini">{{if $on}}Hide this area{{else}}Show this area{{end}}</button></form> + </div> + <p class="muted small">{{.hint}}</p> + {{if $mods}}<table class="modules"> + {{range $mods}}<tr> + <td class="nowrap order"> + <form method="post" action="{{$u}}/modules/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$r.CSRF}}"><input type="hidden" name="dir" value="up"><button class="mini" title="Move up">▲</button></form> + <form method="post" action="{{$u}}/modules/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$r.CSRF}}"><input type="hidden" name="dir" value="down"><button class="mini" title="Move down">▼</button></form> + </td> + <td>{{index $r.Data.names .Kind}}{{with modsummary .}} <span class="muted">— {{.}}</span>{{end}} + {{if and (eq .Kind "logo") (not $r.Data.theme.Logo)}}<span class="tag off">no logo chosen</span> <span class="muted small">pick one on the <a href="/b/{{$r.Blog.Subdomain}}/design#logo">Design</a> tab</span>{{end}}</td> + <td class="nowrap actions">{{if modsettings .Kind}}<a href="{{$u}}/modules/{{.ID}}/edit">edit</a> {{end}}<a class="danger" href="{{$u}}/modules/{{.ID}}/delete">remove</a></td> + </tr>{{end}} + </table>{{else}}<p class="muted">Nothing here yet{{if ne $area "header"}} — this area is not shown until you add a module{{end}}.</p>{{end}} + <form method="post" action="{{$u}}/areas/{{$area}}/add" class="addmod"> + <input type="hidden" name="_csrf" value="{{$r.CSRF}}"> + <label>Add a module<br><select name="kind">{{range index $r.Data.kinds $area}}<option value="{{.}}">{{index $r.Data.names .}}</option>{{end}}</select></label> + <button type="submit" class="secondary">Add</button> + </form> +</div>{{end}} diff --git a/internal/web/templates/dashboard/module_form.html b/internal/web/templates/dashboard/module_form.html new file mode 100644 index 0000000..b63b405 --- /dev/null +++ b/internal/web/templates/dashboard/module_form.html @@ -0,0 +1,34 @@ +{{define "title"}}{{.Data.name}} · {{.Blog.Title}}{{end}} +{{define "content"}} +{{$m := .Data.module}} +<div class="card"> + <h1>{{.Data.name}} <span class="muted small">in the {{lower .Data.area}}</span></h1> + <form method="post"> + <input type="hidden" name="_csrf" value="{{.CSRF}}"> + {{if or (eq $m.Kind "recent") (eq $m.Kind "archive") (eq $m.Kind "sitemap") (and (eq $m.Kind "html") (or (eq $m.Area "left") (eq $m.Area "right") (eq $m.Area "footer")))}} + <label>Heading <span class="muted">(optional)</span><br><input name="title" value="{{$m.Title}}" maxlength="120" placeholder="{{if eq $m.Kind "recent"}}Recent posts{{else if eq $m.Kind "archive"}}Archive{{else if eq $m.Kind "sitemap"}}Pages{{end}}"></label> + {{end}} + {{if eq $m.Kind "recent"}} + <div class="row"><label>How many posts<br><select name="count">{{range $n := .Data.counts}}<option value="{{$n}}"{{if eq $n $m.Count}} selected{{end}}>{{$n}}</option>{{end}}</select></label></div> + <p class="muted small">The newest published posts from every page of your blog, newest first.</p> + {{else if eq $m.Kind "archive"}} + <p class="muted small">Every published post grouped by year and month, newest first. Years and months fold open and shut; the latest year starts open.</p> + {{else if eq $m.Kind "sitemap"}} + <p class="muted small">Links to every page of your blog.</p> + {{else if eq $m.Kind "html"}} + <label for="mod-body">HTML</label> + <textarea id="mod-body" name="body" rows="14" class="mono" spellcheck="false" placeholder="<p>Hello!</p>">{{$m.Body}}</textarea> + <p class="muted small">Put into your page exactly as written — embeds, badges and scripts all work. Anything broken here (an unclosed tag, say) can break the page around it, so check your blog after saving. 20 KB at most.</p> + {{else if eq $m.Kind "text"}} + <label for="mod-body">Text</label> + <textarea id="mod-body" name="body" rows="4" placeholder="© 2026 Me">{{$m.Body}}</textarea> + <p class="muted small">Plain text; each line becomes its own paragraph.</p> + {{end}} + <p class="actionrow"> + <button type="submit">Save</button> + <a class="btn secondary" href="{{.BlogURL}}" target="_blank">View blog ↗</a> + <a href="/b/{{.Blog.Subdomain}}/layout#{{if or (eq $m.Area "above") (eq $m.Area "below")}}main{{else}}{{$m.Area}}{{end}}">Back to layout</a> + </p> + </form> +</div> +{{end}} diff --git a/internal/web/templates/dashboard/overview.html b/internal/web/templates/dashboard/overview.html index fbe49f9..acd539d 100644 --- a/internal/web/templates/dashboard/overview.html +++ b/internal/web/templates/dashboard/overview.html @@ -7,7 +7,7 @@ <div class="card"> <h2>Quick actions</h2> <p><a class="btn" href="/b/{{.Blog.Subdomain}}/posts/new">Write a new post</a></p> - <p><a href="/b/{{.Blog.Subdomain}}/pages/new">Add a page</a> · <a href="/b/{{.Blog.Subdomain}}/announcements/new">Post an announcement</a> · <a href="/b/{{.Blog.Subdomain}}/design">Change the look</a> · <a href="/b/{{.Blog.Subdomain}}/images">Upload images</a></p> + <p><a href="/b/{{.Blog.Subdomain}}/pages/new">Add a page</a> · <a href="/b/{{.Blog.Subdomain}}/announcements/new">Post an announcement</a> · <a href="/b/{{.Blog.Subdomain}}/layout">Arrange the layout</a> · <a href="/b/{{.Blog.Subdomain}}/design">Change the look</a> · <a href="/b/{{.Blog.Subdomain}}/images">Upload images</a></p> </div> <div class="card"> <h2>Pages</h2> diff --git a/internal/web/templates/dashboard/pages.html b/internal/web/templates/dashboard/pages.html index 5e9aca5..eeb09c5 100644 --- a/internal/web/templates/dashboard/pages.html +++ b/internal/web/templates/dashboard/pages.html @@ -3,18 +3,18 @@ <div class="pagehead"> <h1>Pages</h1> <div class="actions"><a class="btn" href="/b/{{.Blog.Subdomain}}/pages/new">+ New page</a></div> - <p class="lead muted">Pages appear in your blog's menu in this order. Each page holds its own list of posts.</p> + <p class="lead muted">Each page holds its own list of posts. Which pages are in the menu, and in what order, is set on the <a href="/b/{{.Blog.Subdomain}}/layout#menu">Layout</a> tab.</p> </div> <div class="card"> <table> - <tr><th>Menu order</th><th>Title</th><th>Address</th><th>Posts</th><th></th></tr> + <tr><th>Order</th><th>Title</th><th>Address</th><th>Posts</th><th></th></tr> {{range .Data.pages}}<tr> <td class="nowrap"> <form method="post" action="/b/{{$.Blog.Subdomain}}/pages/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="dir" value="up"><button class="mini" title="Move up">▲</button></form> <form method="post" action="/b/{{$.Blog.Subdomain}}/pages/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="dir" value="down"><button class="mini" title="Move down">▼</button></form> </td> <td><a href="/b/{{$.Blog.Subdomain}}/pages/{{.ID}}/edit">{{.Title}}</a> - {{if .IsHome}}<span class="tag">home</span>{{end}}{{if not .ShowInNav}}<span class="tag">hidden</span>{{end}}</td> + {{if .IsHome}}<span class="tag">home</span>{{end}}{{if not .ShowInNav}}<span class="tag off">not in menu</span>{{end}}</td> <td><a href="{{$.BlogURL}}{{if .IsHome}}/{{else}}/{{.Slug}}{{end}}" target="_blank">{{if .IsHome}}/{{else}}/{{.Slug}}{{end}} ↗</a></td> <td><a href="/b/{{$.Blog.Subdomain}}/posts?page={{.ID}}">{{.PostCount}}</a></td> <td class="nowrap"> diff --git a/internal/web/templates/dashboard/section_form.html b/internal/web/templates/dashboard/section_form.html index 9d4529c..7eeaf7c 100644 --- a/internal/web/templates/dashboard/section_form.html +++ b/internal/web/templates/dashboard/section_form.html @@ -7,10 +7,14 @@ <input type="hidden" name="_csrf" value="{{.CSRF}}"> <label>Title <span class="muted">(optional)</span><br><input name="title" value="{{$s.Title}}" maxlength="120" autofocus placeholder="Next meeting"></label> <div class="row"> - <label>Where<br><select name="placement"> - <option value="above"{{if eq $s.Placement "above"}} selected{{end}}>Above the posts</option> - <option value="below"{{if eq $s.Placement "below"}} selected{{end}}>Below the posts</option> - <option value="sidebar"{{if eq $s.Placement "sidebar"}} selected{{end}}>Sidebar, under the menu</option> + <label>Where<br><select name="column"> + <option value="main"{{if eq $s.Column "main"}} selected{{end}}>Main content (with the posts)</option> + <option value="left"{{if eq $s.Column "left"}} selected{{end}}>Left column</option> + <option value="right"{{if eq $s.Column "right"}} selected{{end}}>Right column</option> + </select></label> + <label>Position<br><select name="position"> + <option value="top"{{if eq $s.Position "top"}} selected{{end}}>At the top</option> + <option value="bottom"{{if eq $s.Position "bottom"}} selected{{end}}>At the bottom</option> </select></label> <label>Look<br><select name="style"> <option value="note"{{if eq $s.Style "note"}} selected{{end}}>Highlighted</option> @@ -18,7 +22,7 @@ <option value="plain"{{if eq $s.Style "plain"}} selected{{end}}>Plain</option> </select></label> </div> - <p class="muted small">The sidebar spot only exists when the menu is a sidebar (see <a href="/b/{{.Blog.Subdomain}}/design">Design</a>); otherwise a sidebar announcement is shown above the posts.</p> + <p class="muted small">"Top" of a side column means above its modules, "bottom" below them. If that column is not shown on your blog (see <a href="/b/{{.Blog.Subdomain}}/layout">Layout</a>) the announcement moves to the main content instead.</p> <label for="ed-body">Text <span class="muted">(Markdown)</span></label> {{template "editor" (dict "name" "body" "value" $s.BodyMD "rows" 10 "tall" false "upload" (print "/b/" .Blog.Subdomain "/images/upload") "csrf" .CSRF)}} <label class="check"><input type="checkbox" name="enabled"{{if $s.Enabled}} checked{{end}}> Shown on the blog</label> diff --git a/internal/web/templates/dashboard/sections.html b/internal/web/templates/dashboard/sections.html index d2fade7..1834229 100644 --- a/internal/web/templates/dashboard/sections.html +++ b/internal/web/templates/dashboard/sections.html @@ -16,7 +16,7 @@ <form method="post" action="{{$u}}/{{.ID}}/move" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><input type="hidden" name="dir" value="down"><button class="mini" title="Move down">▼</button></form> </td> <td><a href="{{$u}}/{{.ID}}/edit">{{if .Title}}{{.Title}}{{else}}(untitled){{end}}</a>{{if not .Enabled}}<span class="tag off">hidden</span>{{end}}</td> - <td>{{if eq .Placement "above"}}Above the posts{{else if eq .Placement "below"}}Below the posts{{else}}Sidebar{{end}}</td> + <td>{{if eq .Column "main"}}Main content{{else if eq .Column "left"}}Left column{{else}}Right column{{end}}, {{.Position}}</td> <td>{{if eq .Style "note"}}Highlighted{{else if eq .Style "warning"}}Warning{{else}}Plain{{end}}</td> <td class="nowrap"> <form method="post" action="{{$u}}/{{.ID}}/toggle" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><button class="mini">{{if .Enabled}}Hide{{else}}Show{{end}}</button></form> diff --git a/internal/web/templates/layouts/blog.html b/internal/web/templates/layouts/blog.html index 3447e1f..deaaa75 100644 --- a/internal/web/templates/layouts/blog.html +++ b/internal/web/templates/layouts/blog.html @@ -11,30 +11,35 @@ {{end}}<link rel="stylesheet" href="/static/blog.css"> <style>{{css .Data.css}}</style> </head> -<body class="nav-{{.Data.theme.NavPosition}}"> -{{if eq .Data.theme.NavPosition "top-bar"}}{{template "blognav" .}}{{end}} -<div class="site-header"> +{{$l := .Data.layout}} +<body class="{{if $l.HasLeft}}has-left {{end}}{{if $l.HasRight}}has-right{{end}}"> +{{if or $l.Header .Data.theme.HeaderImage}}{{if .Data.theme.HeaderOn}}<div class="site-header"> {{if .Data.theme.HeaderImage}}<div class="header-image"><a href="/"><img src="/media/{{.Data.theme.HeaderImage}}" alt=""></a></div>{{end}} - {{if .Data.theme.HeaderShowTitle}}<div class="wrap header-text"> - <h1 class="site-title"><a href="/">{{.Blog.Title}}</a></h1> - {{if .Blog.Tagline}}<p class="tagline">{{.Blog.Tagline}}</p>{{end}} - </div>{{end}} -</div> -{{if eq .Data.theme.NavPosition "below-header"}}{{template "blognav" .}}{{end}} -<div class="wrap body-wrap"> - {{if eq .Data.theme.NavPosition "left-sidebar"}}{{template "blognav" .}}{{if .Data.sidebar}}<div class="sidebar-notices">{{template "notices" .Data.sidebar}}</div>{{end}}{{end}} - <div class="content"> - {{template "notices" .Data.above}} + {{range $l.Header}}{{template "module" (dict "m" . "root" $)}}{{end}} +</div>{{end}}{{end}} +<div class="wrap body-wrap cols"> + {{$n := .Data.notices}} + <div class="col col-main"><div class="content"> + {{template "notices" (index $n "main-top")}} + {{range $l.Above}}{{template "module" (dict "m" . "root" $)}}{{end}} {{template "content" .}} - {{template "notices" .Data.below}} - </div> -</div> -<div class="site-footer"> - <div class="wrap footer-inner"> - {{if .Data.theme.FooterText}}<p>{{.Data.theme.FooterText}}</p>{{end}} - <p class="small">{{if .Data.theme.FooterShowRSS}}<a href="/feed.xml">RSS</a> · {{end}}{{.Blog.Title}}</p> - </div> + {{range $l.Below}}{{template "module" (dict "m" . "root" $)}}{{end}} + {{template "notices" (index $n "main-bottom")}} + </div></div> + {{if $l.HasLeft}}<div class="col col-left{{if and (not $l.Left) (not (index $n "left-top")) (not (index $n "left-bottom"))}} col-empty{{end}}"> + {{template "notices" (index $n "left-top")}} + {{range $l.Left}}{{template "module" (dict "m" . "root" $)}}{{end}} + {{template "notices" (index $n "left-bottom")}} + </div>{{end}} + {{if $l.HasRight}}<div class="col col-right{{if and (not $l.Right) (not (index $n "right-top")) (not (index $n "right-bottom"))}} col-empty{{end}}"> + {{template "notices" (index $n "right-top")}} + {{range $l.Right}}{{template "module" (dict "m" . "root" $)}}{{end}} + {{template "notices" (index $n "right-bottom")}} + </div>{{end}} </div> +{{if $l.Footer}}<div class="site-footer"><div class="wrap footer-inner"> + {{range $l.Footer}}{{template "module" (dict "m" . "root" $)}}{{end}} +</div></div>{{end}} </body> </html>{{end}} @@ -44,6 +49,37 @@ </aside> {{end}}{{end}} -{{define "blognav"}}<div class="site-nav"><div class="wrap nav-inner"> -{{range .Data.nav}}<a href="{{if .IsHome}}/{{else}}/{{.Slug}}{{end}}"{{if and $.Data.page (eq $.Data.page.ID .ID)}} class="active"{{end}}>{{.Title}}</a> -{{end}}</div></div>{{end}} +{{/* One layout module. .m is the store.Module, .root the page data; the same + kind renders differently in the header (big blocks) and elsewhere (boxes). */}} +{{define "module"}}{{$m := .m}}{{$r := .root}}{{$t := $r.Data.theme}} +{{- if eq $m.Kind "title"}}<div class="wrap header-text"> + <h1 class="site-title"><a href="/">{{$r.Blog.Title}}</a></h1> + {{if $r.Blog.Tagline}}<p class="tagline">{{$r.Blog.Tagline}}</p>{{end}} +</div> +{{- else if eq $m.Kind "logo"}}{{if $t.Logo}}{{if eq $m.Area "header"}}<div class="wrap header-logo"><a href="/"><img class="logo" src="/media/{{$t.Logo}}" alt="{{$r.Blog.Title}}"></a></div> +{{else}}<div class="mod mod-logo"><a href="/"><img class="logo" src="/media/{{$t.Logo}}" alt="{{$r.Blog.Title}}"></a></div>{{end}}{{end}} +{{- else if eq $m.Kind "menu"}}{{if eq $m.Area "header"}}<div class="site-nav"><div class="wrap nav-inner">{{template "menulinks" $r}}</div></div> +{{else}}<div class="mod site-nav mod-menu">{{template "modtitle" $m}}<div class="nav-inner">{{template "menulinks" $r}}</div></div>{{end}} +{{- else if eq $m.Kind "recent"}}<div class="mod mod-recent">{{template "modtitle" $m}} + <ul>{{range $i, $p := $r.Data.recent}}{{if lt $i $m.Count}}<li><a href="/{{$p.PageSlug}}/{{$p.Slug}}">{{$p.Title}}</a></li>{{end}}{{end}}</ul> +</div> +{{- else if eq $m.Kind "archive"}}<div class="mod mod-archive">{{template "modtitle" $m}} + {{range $i, $y := $r.Data.archive}}<details{{if eq $i 0}} open{{end}}><summary>{{$y.Year}} <span class="muted">({{$y.Count}})</span></summary> + {{range $y.Months}}<details><summary>{{.Name}} <span class="muted">({{len .Posts}})</span></summary> + <ul>{{range .Posts}}<li><a href="/{{.PageSlug}}/{{.Slug}}">{{.Title}}</a></li>{{end}}</ul> + </details>{{end}} + </details>{{else}}<p class="muted">No posts yet.</p>{{end}} +</div> +{{- else if eq $m.Kind "html"}}{{if not $m.Body}}{{else if or (eq $m.Area "above") (eq $m.Area "below")}}<div class="custom-html custom-html-{{$m.Area}}">{{html $m.Body}}</div> +{{else}}<div class="mod mod-html">{{template "modtitle" $m}}{{html $m.Body}}</div>{{end}} +{{- else if eq $m.Kind "rss"}}<p class="mod mod-rss small"><a href="/feed.xml">RSS feed</a></p> +{{- else if eq $m.Kind "text"}}{{if $m.Body}}<div class="mod mod-text">{{range split $m.Body "\n"}}{{if .}}<p>{{.}}</p>{{end}}{{end}}</div>{{end}} +{{- else if eq $m.Kind "sitemap"}}<div class="mod mod-sitemap">{{template "modtitle" $m}} + <ul>{{range $r.Data.pages}}<li><a href="{{if .IsHome}}/{{else}}/{{.Slug}}{{end}}">{{.Title}}</a></li>{{end}}</ul> +</div> +{{- end}}{{end}} + +{{define "modtitle"}}{{if .Title}}<h3 class="mod-title">{{.Title}}</h3>{{end}}{{end}} + +{{define "menulinks"}}{{range .Data.menu}}<a href="{{.Href}}"{{if and .PageID $.Data.page (eq $.Data.page.ID (deref64 .PageID))}} class="active"{{end}}>{{.Text}}</a> +{{end}}{{end}} diff --git a/internal/web/templates/partials/dashnav.html b/internal/web/templates/partials/dashnav.html index f54cb2d..e46d7c3 100644 --- a/internal/web/templates/partials/dashnav.html +++ b/internal/web/templates/partials/dashnav.html @@ -21,6 +21,7 @@ <a href="{{$b}}posts"{{if hasPrefix .Path (print $b "posts")}} class="active"{{end}}>Posts</a> <a href="{{$b}}pages"{{if hasPrefix .Path (print $b "pages")}} class="active"{{end}}>Pages</a> <a href="{{$b}}announcements"{{if hasPrefix .Path (print $b "announcements")}} class="active"{{end}}>Announcements</a> + <a href="{{$b}}layout"{{if hasPrefix .Path (print $b "layout")}} class="active"{{end}}>Layout</a> <a href="{{$b}}design"{{if hasPrefix .Path (print $b "design")}} class="active"{{end}}>Design</a> <a href="{{$b}}images"{{if hasPrefix .Path (print $b "images")}} class="active"{{end}}>Images</a> <a href="{{$b}}settings"{{if hasPrefix .Path (print $b "settings")}} class="active"{{end}}>Settings</a> |
