Page MenuHomeMusing Studio

No OneTemporary

diff --git a/less/pad-theme.less b/less/pad-theme.less
index 94276cd..ee8c041 100644
--- a/less/pad-theme.less
+++ b/less/pad-theme.less
@@ -1,217 +1,368 @@
@lightBG: #ffffff;
@lightTextColor: #000;
@lightLinkColor: #444;
@lightNavBG: #fff;
@lightNavHoverBG: #f6f6f6;
@lightNavBorder: #ccc;
@darkBG: #222222;
@darkTextColor: #ffffff;
@darkLinkColor: #ccc;
@darkNavBG: #393939;
@darkNavHoverBG: #555;
@darkNavBorder: #333;
.pad-theme-transition {
-moz-transition-property: background-color, color;
-webkit-transition-property: background-color, color;
-o-transition-property: background-color, color;
transition-property: background-color, color;
.transition-duration(0.25s);
}
body#pad-sub #posts, .atoms {
h3 {
a {
color: @lightTextColor;
&:hover {
color: darken(@lightTextColor, 10%);
}
}
}
h3, h4 {
a {
color: @lightTextColor;
&:hover {
color: darken(@lightTextColor, 10%);
}
}
}
date, .electron {
color: #999;
}
a.action, a {
color: @lightLinkColor;
&:hover {
color: darken(@lightLinkColor, 10%);
}
}
}
body#pad, body#pad-sub {
.pad-theme-transition;
&.light {
background-color: @lightBG;
color: @lightTextColor;
#tools {
.pad-theme-transition;
background-color: transparent;
h1 {
a {
color: @headerTextColor;
}
}
#belt {
a, button {
color: #000;
}
}
.tool {
&#status {
color: #999;
}
}
.hidden {
&#wc {
color: #777;
}
}
a:hover, a:active {
background-color: transparent;
color: @lightLinkColor;
}
}
.modal {
border-color: @lightNavBorder;
background: @lightNavBG;
}
}
&.dark {
background-color: @darkBG;
color: @darkTextColor;
#tools {
.pad-theme-transition;
background-color: #262626;
h1 {
a {
color: @darkTextColor;
}
}
#belt {
a, button {
color: white;
}
}
.tool {
&#status {
color: #666;
}
}
.hidden {
&#wc {
color: #ececec;
}
}
a:hover, a:active {
background-color: transparent;
color: @darkLinkColor;
}
nav {
&> ul > li a {
color: @darkTextColor;
}
ul {
ul {
background: @darkNavBG;
border-color: @darkNavBorder;
}
li {
&.current-user {
color: #fff;
}
&.selected {
a {
color: #777;
}
}
}
li:hover {
background: @darkNavHoverBG;
}
}
}
}
#posts {
h3 {
a {
color: @darkTextColor;
&:hover {
color: darken(@darkTextColor, 10%);
}
}
}
h3, h4 {
a {
color: @darkTextColor;
&:hover {
color: darken(@darkTextColor, 10%);
}
}
}
a.action, a {
color: @darkLinkColor;
&:hover {
color: darken(@darkLinkColor, 10%);
}
}
}
.modal {
border-color: @darkNavBorder;
background: @darkNavBG;
input {
color: #fff;
}
.form-hint {
color: #ccc;
}
a:link, a:visited {
color: lighten(@primary, 8%);
}
}
}
}
body#pad {
.pad-theme-transition;
textarea, #title {
.pad-theme-transition;
}
&.dark {
textarea, #title, #editor {
background-color: @darkBG;
color: @darkTextColor;
}
}
&.light {
textarea, #title, #editor {
background-color: @lightBG;
color: @lightTextColor;
}
}
}
body {
&.dark {
nav#top-nav {
a {
color: @darkLinkColor;
}
}
}
}
+
+html {
+ &.light {
+ body:not(#pad):not(#pad-sub) {
+ background-color: @lightBG;
+ color: @lightTextColor;
+ }
+ }
+
+ &.dark {
+ body:not(#pad):not(#pad-sub) {
+ background-color: @darkBG;
+ color: @darkTextColor;
+ }
+
+ body:not(#pad):not(#pad-sub) {
+ a {
+ color: @darkLinkColor;
+ &:hover {
+ color: darken(@darkLinkColor, 10%);
+ }
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ color: @darkTextColor;
+ a {
+ color: @darkTextColor;
+ }
+ }
+
+ hr {
+ background: @darkNavBorder;
+ }
+
+ footer nav,
+ .description,
+ .meta-note,
+ .subtitle,
+ .post-title time,
+ .post-title time a:link,
+ .post-title time a:visited,
+ .post-title + .time {
+ color: #999;
+ }
+
+ input, textarea, select {
+ background: @darkNavBG;
+ color: @darkTextColor;
+ border-color: @darkNavBorder;
+ }
+
+ pre, code, blockquote {
+ background-color: #262626;
+ color: @darkTextColor;
+ border-color: @darkNavBorder;
+ }
+
+ .dropdown-nav ul ul,
+ nav#manage ul ul {
+ background: @darkNavBG;
+ border-color: @darkNavBorder;
+ }
+
+ .dropdown-nav ul li,
+ nav#manage ul li {
+ &:hover {
+ background: @darkNavHoverBG;
+ }
+ &.current-user {
+ color: #fff;
+ }
+ &.menu-heading {
+ color: #ccc;
+ }
+ &.selected {
+ a {
+ color: #777;
+ }
+ }
+ }
+
+ .dropdown-nav ul a,
+ nav#manage ul a,
+ header nav a,
+ #user-nav a,
+ #full-nav a {
+ color: @darkTextColor;
+ }
+
+ nav#full-nav a.simple-btn {
+ background: @darkNavBG;
+ color: @darkTextColor;
+ border-color: @darkNavBorder !important;
+ }
+
+ img.ic-18dp,
+ img.ic-24dp {
+ filter: brightness(1.15);
+ }
+
+ .alert {
+ &.info {
+ color: #b9def0;
+ background-color: #24404d;
+ border-color: #35596a;
+ }
+ &.success {
+ color: #cde9c7;
+ background-color: #294232;
+ border-color: #3a6047;
+ }
+ &.danger {
+ color: #f4d999;
+ background-color: #473c1d;
+ border-color: #856404;
+ h3 {
+ color: @darkTextColor !important;
+ }
+ }
+ }
+ }
+ }
+}
+
+.global-theme-toggle {
+ display: inline-block;
+ position: relative;
+ top: -0.15rem;
+ margin-right: 0.85rem;
+ padding: 0;
+ background: transparent;
+ border: 0;
+ box-shadow: none;
+ line-height: 1;
+ vertical-align: middle;
+ &:hover {
+ text-decoration: none;
+ }
+ img {
+ display: block;
+ filter: none !important;
+ }
+}
+
+.global-theme-toggle--floating {
+ position: fixed;
+ top: 1.15rem;
+ right: 1.25rem;
+ z-index: 1000;
+ margin-left: 0;
+}
diff --git a/static/js/theme.js b/static/js/theme.js
new file mode 100644
index 0000000..27a4566
--- /dev/null
+++ b/static/js/theme.js
@@ -0,0 +1,93 @@
+(function () {
+ var STORAGE_KEY = "padTheme";
+ var LIGHT = "light";
+ var DARK = "dark";
+
+ function preferredTheme() {
+ return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? DARK : LIGHT;
+ }
+
+ function storedTheme() {
+ try {
+ return localStorage.getItem(STORAGE_KEY);
+ } catch (e) {
+ return null;
+ }
+ }
+
+ function currentTheme() {
+ return storedTheme() || preferredTheme();
+ }
+
+ function setTheme(theme) {
+ var next = theme === DARK ? DARK : LIGHT;
+ document.documentElement.classList.remove(LIGHT, DARK);
+ document.documentElement.classList.add(next);
+ if (document.body) {
+ document.body.classList.remove(LIGHT, DARK);
+ document.body.classList.add(next);
+ }
+ try {
+ localStorage.setItem(STORAGE_KEY, next);
+ } catch (e) {
+ // ignore storage errors
+ }
+ updateThemeIcons(next);
+ }
+
+ function toggleTheme() {
+ setTheme(document.documentElement.classList.contains(DARK) ? LIGHT : DARK);
+ }
+
+ function updateThemeIcons(theme) {
+ var btns = document.querySelectorAll('#tools a img, [data-theme-toggle] img');
+ for (var i = 0; i < btns.length; i++) {
+ var img = btns[i];
+ if (!img.src) {
+ continue;
+ }
+ if (/ic_brightness(_dark)?@2x\.png$/.test(img.src)) {
+ img.src = theme === LIGHT
+ ? img.src.replace(/ic_brightness(_dark)?@2x\.png$/, 'ic_brightness_dark@2x.png')
+ : img.src.replace(/ic_brightness(_dark)?@2x\.png$/, 'ic_brightness@2x.png');
+ continue;
+ }
+ if (theme === LIGHT) {
+ if (!/_dark@2x\.png$/.test(img.src)) {
+ img.src = img.src.replace(/@2x\.png$/, '_dark@2x.png');
+ }
+ } else {
+ img.src = img.src.replace(/_dark@2x\.png$/, '@2x.png');
+ }
+ }
+ }
+
+ function bindToggle(el) {
+ if (!el || el.dataset.themeBound === "true") {
+ return;
+ }
+ el.dataset.themeBound = "true";
+ el.addEventListener("click", function (e) {
+ e.preventDefault();
+ toggleTheme();
+ });
+ }
+
+ function init() {
+ setTheme(currentTheme());
+ bindToggle(document.getElementById("toggle-theme"));
+ var more = document.querySelectorAll("[data-theme-toggle]");
+ for (var i = 0; i < more.length; i++) {
+ bindToggle(more[i]);
+ }
+ }
+
+ window.toggleTheme = toggleTheme;
+ window.setTheme = setTheme;
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", init);
+ } else {
+ init();
+ }
+})();
diff --git a/templates/base.tmpl b/templates/base.tmpl
index 4440860..4944563 100644
--- a/templates/base.tmpl
+++ b/templates/base.tmpl
@@ -1,95 +1,106 @@
{{define "base"}}<!DOCTYPE HTML>
-<html>
+<html class="light">
<head>
{{ template "head" . }}
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<link rel="stylesheet" type="text/css" href="/css/{{.Theme}}.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="application-name" content="{{.SiteName}}">
<meta name="application-url" content="{{.Host}}">
<meta property="og:site_name" content="{{.SiteName}}" />
</head>
<body {{template "body-attrs" .}}>
<div id="overlay"></div>
<header>
{{ if .Chorus }}<nav id="full-nav">
<div class="left-side">
<h2><a href="/">{{.SiteName}}</a></h2>
</div>
{{ else }}
<h2><a href="/">{{.SiteName}}</a></h2>
{{ end }}
{{if not .SingleUser}}
<nav id="user-nav">
{{if .Username}}
<nav class="dropdown-nav">
<ul><li class="has-submenu"><a>{{.Username}}</a> <img class="ic-18dp" src="/img/ic_down_arrow_dark@2x.png" /><ul>
{{if .IsAdmin}}<li><a href="/admin">Admin dashboard</a></li>{{end}}
<li><a href="/me/settings">Account settings</a></li>
<li><a href="/me/import">Import posts</a></li>
<li><a href="/me/export">Export</a></li>
{{if .CanInvite}}<li><a href="/me/invites">Invite people</a></li>{{end}}
<li class="separator"><hr /></li>
<li><a href="/me/logout">Log out</a></li>
</ul></li>
</ul>
</nav>
{{end}}
<nav class="tabs">
{{ if and .SimpleNav (not .SingleUser) }}
{{if and (and .LocalTimeline .CanViewReader) .Chorus}}<a href="/"{{if eq .Path "/"}} class="selected"{{end}}>Home</a>{{end}}
{{ end }}
{{if or .Chorus (not .Username)}}<a href="/about"{{if eq .Path "/about"}} class="selected"{{end}}>About</a>{{end}}
{{ if not .SingleUser }}
{{ if .Username }}
{{if or (not .Chorus) (gt .MaxBlogs 1)}}<a href="/me/c/"{{if eq .Path "/me/c/"}} class="selected"{{end}}>Blogs</a>{{end}}
{{if and (and .Chorus (eq .MaxBlogs 1)) .Username}}<a href="/{{.Username}}/"{{if eq .Path (printf "/%s/" .Username)}} class="selected"{{end}}>My Posts</a>{{end}}
{{if not .DisableDrafts}}<a href="/me/posts/"{{if eq .Path "/me/posts/"}} class="selected"{{end}}>Drafts</a>{{end}}
{{ end }}
{{if and (and .LocalTimeline .CanViewReader) (not .Chorus)}}<a href="/read"{{if eq .Path "/read"}} class="selected"{{end}}>Reader</a>{{end}}
{{if eq .SignupPath "/signup"}}<a href="/signup"{{if eq .Path "/signup"}} class="selected"{{end}}>Sign up</a>{{end}}
{{if and (not .Username) (not .Private)}}<a href="/login"{{if eq .Path "/login"}} class="selected"{{end}}>Log in</a>{{else if .SimpleNav}}<a href="/me/logout">Log out</a>{{end}}
{{ end }}
</nav>
{{if .Chorus}}{{if .Username}}<div class="right-side" style="font-size: 0.86em;">
<a class="simple-btn" href="/new">New Post</a>
</div>{{end}}
</nav>
{{end}}
</nav>
{{end}}
</header>
<div id="official-writing">
{{ template "content" . }}
</div>
{{ template "footer" . }}
{{if not .JSDisabled}}
+ <script type="text/javascript" src="/js/theme.js"></script>
<script type="text/javascript" src="/js/menu.js"></script>
<script type="text/javascript">
{{if .WebFonts}}
try { // Google Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
{{end}}
</script>
{{else}}
{{if .WebFonts}}<link href="/css/fonts.css" rel="stylesheet" type="text/css" />{{end}}
{{end}}
</body>
</html>{{end}}
{{define "body-attrs"}}{{end}}
diff --git a/templates/chorus-collection-post.tmpl b/templates/chorus-collection-post.tmpl
index 468455c..406b767 100644
--- a/templates/chorus-collection-post.tmpl
+++ b/templates/chorus-collection-post.tmpl
@@ -1,155 +1,167 @@
{{define "post"}}<!DOCTYPE HTML>
-<html {{if .Language.Valid}}lang="{{.Language.String}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language.Valid}}lang="{{.Language.String}}"{{end}} dir="{{.Direction}}">
<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{.Collection.DisplayTitle}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="canonical" href="{{.CanonicalURL .Host}}" />
<meta name="generator" content="WriteFreely">
<meta name="title" content="{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{if .Collection.Title}}{{.Collection.Title}}{{else}}{{.Collection.Alias}}{{end}}">
<meta name="description" content="{{.Summary}}">
{{if gt .Views 1}}<meta name="twitter:label1" value="Views">
<meta name="twitter:data1" value="{{largeNumFmt .Views}}">{{end}}
<meta name="author" content="{{.Collection.Title}}" />
<meta itemprop="description" content="{{.Summary}}">
<meta itemprop="datePublished" content="{{.CreatedDate}}" />
<meta name="twitter:card" content="summary">
<meta name="twitter:description" content="{{.Summary}}">
<meta name="twitter:title" content="{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{if .Collection.Title}}{{.Collection.Title}}{{else}}{{.Collection.Alias}}{{end}}">
{{if gt (len .Images) 0}}<meta name="twitter:image" content="{{index .Images 0}}">{{else}}<meta name="twitter:image" content="{{.Collection.AvatarURL}}">{{end}}
<meta property="og:title" content="{{.PlainDisplayTitle}}" />
<meta property="og:description" content="{{.Summary}}" />
<meta property="og:site_name" content="{{.Collection.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL .Host}}" />
<meta property="og:updated_time" content="{{.Created8601}}" />
{{range .Images}}<meta property="og:image" content="{{.}}" />{{else}}<meta property="og:image" content="{{.Collection.AvatarURL}}">{{end}}
<meta property="article:published_time" content="{{.Created8601}}">
{{template "collection-meta" .}}
{{if .Collection.StyleSheet}}<style type="text/css">{{.Collection.StyleSheetDisplay}}</style>{{end}}
<style type="text/css">
body footer {
max-width: 40rem;
margin: 0 auto;
}
body#post header {
padding: 1em 1rem;
}
</style>
{{if .Collection.RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" . }}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" .}}
</head>
<body id="post">
<div id="overlay"></div>
{{template "user-navigation" .}}
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
<article id="post-body" class="{{.Font}} h-entry">{{if .IsScheduled}}<p class="badge">Scheduled</p>{{end}}{{if .Title.String}}<h2 id="title" class="p-name{{if $.Collection.Format.ShowDates}} dated{{end}}">{{.FormattedDisplayTitle}}</h2>{{end}}{{if and $.Collection.Format.ShowDates (not .IsPinned)}}<time class="dt-published" datetime="{{.Created8601}}" pubdate itemprop="datePublished" content="{{.Created}}">{{.DisplayDate}}</time>{{end}}<div class="e-content">{{.HTMLContent}}</div></article>
{{ if .Collection.ShowFooterBranding }}
<footer dir="ltr">
<p style="text-align: left">Published by <a rel="author" href="{{if .IsTopLevel}}/{{else}}/{{.Collection.Alias}}/{{end}}" class="h-card p-author">{{.Collection.DisplayTitle}}</a>
{{ if .IsOwner }} &middot; <span class="views" dir="ltr"><strong>{{largeNumFmt .Views}}</strong> {{pluralize "view" "views" .Views}}</span>
&middot; <a class="xtra-feature" href="/{{if not .SingleUser}}{{.Collection.Alias}}/{{end}}{{.Slug.String}}/edit" dir="{{.Direction}}">Edit</a>
{{if .IsPinned}} &middot; <a class="xtra-feature unpin" href="/{{.Collection.Alias}}/{{.Slug.String}}/unpin" dir="{{.Direction}}" onclick="unpinPost(event, '{{.ID}}')">Unpin</a>{{end}}
{{ end }}
</p>
<nav>
{{if .PinnedPosts}}
{{range .PinnedPosts}}<a class="pinned{{if eq .Slug.String $.Slug.String}} selected{{end}}" href="{{if not $.SingleUser}}/{{$.Collection.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL $.Host}}{{end}}">{{.PlainDisplayTitle}}</a>{{end}}
{{end}}
</nav>
<hr>
<nav><p style="font-size: 0.9em">{{localhtml "published with write.as" .Language.String}}</p></nav>
</footer>
{{ end }}
</body>
{{if .Collection.CanShowScript}}
{{range .Collection.ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Collection.Script}}<script type="text/javascript">{{.Collection.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/localdate.js"></script>
<script type="text/javascript">
var pinning = false;
function unpinPost(e, postID) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var $footer = document.getElementsByTagName('footer')[0];
var callback = function() {
// Hide current page
var $pinnedNavLink = $footer.getElementsByTagName('nav')[0].querySelector('.pinned.selected');
$pinnedNavLink.style.display = 'none';
};
var $pinBtn = $footer.getElementsByClassName('unpin')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Collection.Alias}}/unpin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
$pinBtn.style.display = 'none';
$pinBtn.innerHTML = 'Pin';
} else if (http.status == 409) {
$pinBtn.innerHTML = 'Unpin';
} else {
$pinBtn.innerHTML = 'Unpin';
alert("Failed to unpin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
try { // Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
{{if and .Monetization (not .IsOwner)}}
<script src="/js/webmonetization.js"></script>
<script>
window.collAlias = '{{.Collection.Alias}}'
window.postSlug = '{{.Slug.String}}'
initMonetization()
</script>
{{end}}
</html>{{end}}
diff --git a/templates/chorus-collection.tmpl b/templates/chorus-collection.tmpl
index 742c544..8bc9a0b 100644
--- a/templates/chorus-collection.tmpl
+++ b/templates/chorus-collection.tmpl
@@ -1,236 +1,248 @@
{{define "collection"}}<!DOCTYPE HTML>
-<html {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
<head>
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.DisplayTitle}}{{if not .SingleUser}} &mdash; {{.SiteName}}{{end}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.CanonicalURL}}">
{{if gt .CurrentPage 1}}<link rel="prev" href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if lt .CurrentPage .TotalPages}}<link rel="next" href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if not .IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.DisplayTitle}} &raquo; Feed" href="{{.CanonicalURL}}feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="WriteFreely">
<meta name="description" content="{{.Description}}">
<meta itemprop="name" content="{{.DisplayTitle}}">
<meta itemprop="description" content="{{.Description}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{.DisplayTitle}}">
<meta name="twitter:image" content="{{.AvatarURL}}">
<meta name="twitter:description" content="{{.Description}}">
<meta property="og:title" content="{{.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}" />
<meta property="og:description" content="{{.Description}}" />
<meta property="og:image" content="{{.AvatarURL}}">
{{template "collection-meta" .}}
{{if .StyleSheet}}<style type="text/css">{{.StyleSheetDisplay}}</style>{{end}}
<style type="text/css">
body#collection header {
max-width: 40em;
margin: 1em auto;
text-align: left;
padding: 0;
}
body#collection header.multiuser {
max-width: 100%;
margin: 1em;
}
body#collection header nav:not(.pinned-posts) {
display: inline;
}
body#collection header nav.dropdown-nav,
body#collection header nav.tabs,
body#collection header nav.tabs a:first-child {
margin: 0 0 0 1em;
}
</style>
{{if .RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" .}}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" . }}
</head>
<body id="collection" itemscope itemtype="http://schema.org/WebPage">
{{template "user-navigation" .}}
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a href="/{{if .IsTopLevel}}{{else}}{{.Prefix}}{{.Alias}}/{{end}}" class="h-card p-author u-url" rel="me author">{{.DisplayTitle}}</a></h1>
{{if .Description}}<p class="description p-note">{{.Description}}</p>{{end}}
{{/*if not .Public/*}}
<!--p class="meta-note"><span>Private collection</span>. Only you can see this page.</p-->
{{/*end*/}}
{{if .PinnedPosts}}<nav class="pinned-posts">
{{range .PinnedPosts}}<a class="pinned" href="{{if not $.SingleUser}}/{{$.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL $.Host}}{{end}}">{{.PlainDisplayTitle}}</a>{{end}}</nav>
{{end}}
</header>
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
{{if .IsWelcome}}
<div id="welcome">
<h2>Welcome, <strong>{{.Username}}</strong>!</h2>
<p>This is your new blog.</p>
<p><a class="simple-cta" href="/#{{.Alias}}">Start writing</a>, or <a class="simple-cta" href="/me/c/{{.Alias}}">customize</a> your blog.</p>
<p>Check out our <a class="simple-cta" href="https://writefreely.org/docs/latest/writer/writing">writing guide</a> to see what else you can do, and <a class="simple-cta" href="/contact">get in touch</a> anytime with questions or feedback.</p>
</div>
{{end}}
{{template "posts" .}}
{{if gt .TotalPages 1}}<nav id="paging" class="content-container clearfix">
{{if or (and .Format.Ascending (le .CurrentPage .TotalPages)) (isRTL .Direction)}}
{{if gt .CurrentPage 1}}<a href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">&#8672; {{if and .Format.Ascending (le .CurrentPage .TotalPages)}}Previous{{else}}Newer{{end}}</a>{{end}}
{{if lt .CurrentPage .TotalPages}}<a style="float:right;" href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Next{{else}}Older{{end}} &#8674;</a>{{end}}
{{else}}
{{if lt .CurrentPage .TotalPages}}<a href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">&#8672; Older</a>{{end}}
{{if gt .CurrentPage 1}}<a style="float:right;" href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">Newer &#8674;</a>{{end}}
{{end}}
</nav>{{end}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{if .ShowFooterBranding }}
<footer>
<hr />
<nav dir="ltr">
{{if not .SingleUser}}<a class="home pubd" href="/">{{.SiteName}}</a> &middot; {{end}}powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a>
</nav>
</footer>
{{ end }}
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/h.js"></script>
<script src="/js/localdate.js"></script>
<script src="/js/postactions.js"></script>
<script type="text/javascript">
var deleting = false;
function delPost(e, id, owned) {
e.preventDefault();
if (deleting) {
return;
}
// TODO: UNDO!
if (window.confirm('Are you sure you want to delete this post?')) {
// AJAX
deletePost(id, "", function() {
// Remove post from list
var $postEl = document.getElementById('post-' + id);
$postEl.parentNode.removeChild($postEl);
// TODO: add next post from this collection at the bottom
});
}
}
var deletePost = function(postID, token, callback) {
deleting = true;
var $delBtn = document.getElementById('post-' + postID).getElementsByClassName('delete action')[0];
$delBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/posts/" + postID;
http.open("DELETE", url, true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
deleting = false;
if (http.status == 204) {
callback();
} else if (http.status == 409) {
$delBtn.innerHTML = 'delete';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$delBtn.innerHTML = 'delete';
alert("Failed to delete." + (http.status>=500?" Please try again.":""));
}
}
}
http.send();
};
var pinning = false;
function pinPost(e, postID, slug, title) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var callback = function() {
// Visibly remove post from collection
var $postEl = document.getElementById('post-' + postID);
$postEl.parentNode.removeChild($postEl);
var $header = document.querySelector('header:not(.multiuser)');
var $pinnedNavs = $header.getElementsByTagName('nav');
// Add link to nav
var link = '<a class="pinned" href="/{{.Alias}}/'+slug+'">'+title+'</a>';
if ($pinnedNavs.length == 0) {
$header.insertAdjacentHTML("beforeend", '<nav>'+link+'</nav>');
} else {
$pinnedNavs[0].insertAdjacentHTML("beforeend", link);
}
};
var $pinBtn = document.getElementById('post-' + postID).getElementsByClassName('pin action')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}/pin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
} else if (http.status == 409) {
$pinBtn.innerHTML = 'pin';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$pinBtn.innerHTML = 'pin';
alert("Failed to pin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
try {
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) {}
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/collection-archive.tmpl b/templates/collection-archive.tmpl
index 5256c58..370a31c 100644
--- a/templates/collection-archive.tmpl
+++ b/templates/collection-archive.tmpl
@@ -1,118 +1,130 @@
{{define "collection"}}<!DOCTYPE HTML>
-<html>
+<html class="light">
<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>Archive &mdash; {{.Collection.DisplayTitle}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.CanonicalURL}}">
{{if gt .CurrentPage 1}}<link rel="prev" href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if lt .CurrentPage .TotalPages}}<link rel="next" href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if not .IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.DisplayTitle}} &raquo; Feed" href="{{.CanonicalURL}}feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="WriteFreely">
<meta name="description" content="{{.PlainDescription}}">
<meta itemprop="name" content="{{.DisplayTitle}}">
<meta itemprop="description" content="{{.PlainDescription}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{.DisplayTitle}}">
<meta name="twitter:image" content="{{.AvatarURL}}">
<meta name="twitter:description" content="{{.PlainDescription}}">
<meta property="og:title" content="{{.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}" />
<meta property="og:description" content="{{.PlainDescription}}" />
<meta property="og:image" content="{{.AvatarURL}}">
{{template "collection-meta" .}}
{{if .StyleSheet}}<style type="text/css">{{.StyleSheetDisplay}}</style>{{end}}
</head>
<body id="subpage">
<div id="overlay"></div>
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a href="{{if .IsTopLevel}}/{{else}}/{{.Collection.Alias}}/{{end}}" class="h-card p-author">{{.Collection.DisplayTitle}}</a></h1>
<nav>
{{if .PinnedPosts}}
{{range .PinnedPosts}}<a class="pinned" href="{{if $.IsOwner}}/{{$.Collection.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL}}{{end}}">{{.DisplayTitle}}</a>{{end}}
{{end}}
</nav>
</header>
{{if .Posts -}}
<section id="wrapper" class="archive" itemscope itemtype="http://schema.org/Blog">
{{- else -}}
<div id="wrapper" class="archive">
{{- end}}
<h1>Archive</h1>
{{if .Flash}}
<div class="alert success flash">
<p>{{.Flash}}</p>
</div>
{{end}}
<ul>
{{ $curYear := 0 }}
{{ range $el := .Posts }}
{{if ne $curYear .Created.Year}}<li class="year">{{.Created.Year}}</li>{{ $curYear = .Created.Year }}{{end}}
<li>
{{if .HasTitleLink -}}
{{.HTMLTitleArrow}}
{{- else -}}
<a href="{{if $.SingleUser}}/{{else}}/{{$.Alias}}/{{end}}{{.Slug.String}}" itemprop="url" class="u-url">
{{- if .DisplayTitle -}}
{{- .DisplayTitle -}}
{{- else -}}
(Untitled)
{{end}}
</a>
{{- end}}
{{if .IsScheduled}}[Scheduled]{{end}}
{{if $.Format.ShowDates -}}
<time class="dt-published" datetime="{{.Created8601}}" pubdate itemprop="datePublished" content="{{.Created}}">
{{- if .HasTitleLink -}}
<a href="{{if $.SingleUser}}/{{else}}/{{$.Alias}}/{{end}}{{.Slug.String}}" itemprop="url">
{{- end -}}
{{.DisplayDate}}
{{- if .HasTitleLink -}}
{{- if .IsPaid}}{{template "paid-badge" (dict "CDNHost" $.CDNHost)}}{{end -}}</a>
{{- end -}}
</time>
{{- else -}}
{{- if .HasTitleLink -}}
<a href="{{if $.SingleUser}}/{{else}}/{{$.Alias}}/{{end}}{{.Slug.String}}" itemprop="url">view</a>
{{- end -}}
{{- end}}
</li>
{{end}}
</ul>
{{template "paging" .}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{if .ShowFooterBranding }}
<footer>
<hr />
<nav dir="ltr">
{{if not .SingleUser}}<a class="home pubd" href="/">{{.SiteName}}</a> &middot; {{end}}powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a>
</nav>
</footer>
{{ end }}
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Collection.Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/localdate.js"></script>
+<script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/collection-post.tmpl b/templates/collection-post.tmpl
index 3d3132d..ec3d187 100644
--- a/templates/collection-post.tmpl
+++ b/templates/collection-post.tmpl
@@ -1,146 +1,158 @@
{{define "post"}}<!DOCTYPE HTML>
-<html {{if .Language.Valid}}lang="{{.Language.String}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language.Valid}}lang="{{.Language.String}}"{{end}} dir="{{.Direction}}">
<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{.Collection.DisplayTitle}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{ if .IsFound }}
<link rel="canonical" href="{{.CanonicalURL .Host}}" />
<meta name="generator" content="WriteFreely">
<meta name="title" content="{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{if .Collection.Title}}{{.Collection.Title}}{{else}}{{.Collection.Alias}}{{end}}">
<meta name="description" content="{{.Summary}}">
{{if gt .Views 1}}<meta name="twitter:label1" value="Views">
<meta name="twitter:data1" value="{{largeNumFmt .Views}}">{{end}}
<meta name="author" content="{{.Collection.Title}}" />
<meta itemprop="description" content="{{.Summary}}">
<meta itemprop="datePublished" content="{{.CreatedDate}}" />
<meta name="twitter:card" content="summary">
<meta name="twitter:description" content="{{.Summary}}">
<meta name="twitter:title" content="{{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{if .Collection.Title}}{{.Collection.Title}}{{else}}{{.Collection.Alias}}{{end}}">
{{if gt (len .Images) 0}}<meta name="twitter:image" content="{{index .Images 0}}">{{else}}<meta name="twitter:image" content="{{.Collection.AvatarURL}}">{{end}}
<meta property="og:title" content="{{.PlainDisplayTitle}}" />
<meta property="og:description" content="{{.Summary}}" />
<meta property="og:site_name" content="{{.Collection.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL .Host}}" />
<meta property="og:updated_time" content="{{.Created8601}}" />
{{range .Images}}<meta property="og:image" content="{{.}}" />{{else}}<meta property="og:image" content="{{.Collection.AvatarURL}}">{{end}}
<meta property="article:published_time" content="{{.Created8601}}">
{{ end }}
{{template "collection-meta" .}}
{{if .Collection.StyleSheet}}<style type="text/css">{{.Collection.StyleSheetDisplay}}</style>{{end}}
{{if .Collection.RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" . }}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" .}}
</head>
<body id="post">
<div id="overlay"></div>
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a rel="author" href="{{if .IsTopLevel}}/{{else}}/{{.Collection.Alias}}/{{end}}" class="h-card p-author">{{.Collection.DisplayTitle}}</a></h1>
<nav>
{{if .PinnedPosts}}
{{range .PinnedPosts}}<a class="pinned{{if eq .Slug.String $.Slug.String}} selected{{end}}" href="{{if not $.SingleUser}}/{{$.Collection.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL $.Host}}{{end}}">{{.PlainDisplayTitle}}</a>{{end}}
{{end}}
{{ if and .IsOwner .IsFound }}<span class="views" dir="ltr"><strong>{{largeNumFmt .Views}}</strong> {{pluralize "view" "views" .Views}}</span>
{{if .Likes}}<span class="views" dir="ltr"><strong>{{largeNumFmt .Likes}}</strong> {{pluralize "like" "likes" .Likes}}</span>{{end}}
<a href="/{{if not .SingleUser}}{{.Collection.Alias}}/{{end}}{{.Slug.String}}/edit" dir="{{.Direction}}">Edit</a>
{{if .IsPinned}}<a class="xtra-feature unpin" href="/{{.Collection.Alias}}/{{.Slug.String}}/unpin" dir="{{.Direction}}" onclick="unpinPost(event, '{{.ID}}')">Unpin</a>{{end}}
{{ end }}
</nav>
</header>
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
<article id="post-body" class="{{.Font}} h-entry {{if not .IsFound}}error-page{{end}}">{{if .IsScheduled}}<p class="badge">Scheduled</p>{{end}}{{if .Title.String}}<h2 id="title" class="p-name{{if and $.Collection.Format.ShowDates (not .IsPinned)}} dated{{end}}">{{.FormattedDisplayTitle}}</h2>{{end}}{{if and $.Collection.Format.ShowDates (not .IsPinned) .IsFound}}<time class="dt-published" datetime="{{.Created8601}}" pubdate itemprop="datePublished" content="{{.Created}}">{{.DisplayDate}}</time>{{end}}<div class="e-content">{{.HTMLContent}}</div></article>
{{ if .Collection.ShowFooterBranding }}
<footer dir="ltr"><hr><nav><p style="font-size: 0.9em">{{localhtml "published with write.as" .Language.String}}</p></nav></footer>
{{ end }}
</body>
{{if .Collection.CanShowScript}}
{{range .Collection.ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Collection.Script}}<script type="text/javascript">{{.Collection.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/localdate.js"></script>
<script type="text/javascript">
var pinning = false;
function unpinPost(e, postID) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var $header = document.getElementsByTagName('header')[0];
var callback = function() {
// Hide current page
var $pinnedNavLink = $header.getElementsByTagName('nav')[0].querySelector('.pinned.selected');
$pinnedNavLink.style.display = 'none';
};
var $pinBtn = $header.getElementsByClassName('unpin')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Collection.Alias}}/unpin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
$pinBtn.style.display = 'none';
$pinBtn.innerHTML = 'Pin';
} else if (http.status == 409) {
$pinBtn.innerHTML = 'Unpin';
} else {
$pinBtn.innerHTML = 'Unpin';
alert("Failed to unpin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
try { // Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
{{if and .Monetization (not .IsOwner)}}
<script src="/js/webmonetization.js"></script>
<script>
window.collAlias = '{{.Collection.Alias}}'
window.postSlug = '{{.Slug.String}}'
initMonetization()
</script>
{{end}}
</html>{{end}}
diff --git a/templates/collection-tags.tmpl b/templates/collection-tags.tmpl
index c8e8a12..0200d60 100644
--- a/templates/collection-tags.tmpl
+++ b/templates/collection-tags.tmpl
@@ -1,211 +1,223 @@
{{define "collection-tags"}}<!DOCTYPE HTML>
-<html>
+<html class="light">
<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.Tag}} &mdash; {{.Collection.DisplayTitle}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
{{if not .Collection.IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.Tag}} posts on {{.DisplayTitle}}" href="{{.CanonicalURL}}tag:{{.Tag}}/feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="canonical" href="{{.CanonicalURL}}tag:{{.Tag | tolower}}" />
<meta name="generator" content="Write.as">
<meta name="title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}">
<meta name="description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="application-name" content="Write.as">
<meta name="application-url" content="https://write.as">
{{if gt .Views 1}}<meta name="twitter:label1" value="Views">
<meta name="twitter:data1" value="{{largeNumFmt .Views}}">{{end}}
<meta itemprop="name" content="{{.Collection.DisplayTitle}}">
<meta itemprop="description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@writeas__">
<meta name="twitter:description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="twitter:title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}">
<meta name="twitter:image" content="{{.Collection.AvatarURL}}">
<meta property="og:title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}tag:{{.Tag}}" />
<meta property="og:image" content="{{.Collection.AvatarURL}}">
{{template "collection-meta" .}}
{{if .Collection.StyleSheet}}<style type="text/css">{{.Collection.StyleSheetDisplay}}</style>{{end}}
{{if .Collection.RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" .}}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" . }}
</head>
<body id="subpage">
<div id="overlay"></div>
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a href="{{if .IsTopLevel}}/{{else}}/{{.Collection.Alias}}/{{end}}" class="h-card p-author">{{.Collection.DisplayTitle}}</a></h1>
<nav>
{{if .PinnedPosts}}
{{range .PinnedPosts}}<a class="pinned" href="{{if not $.SingleUser}}/{{$.Collection.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL $.Host}}{{end}}">{{.DisplayTitle}}</a>{{end}}
{{end}}
</nav>
</header>
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
<h1>{{.Tag}}</h1>
{{template "posts" .}}
{{if gt .TotalPages 1}}<nav id="paging" class="content-container clearfix">
{{if or (and .Format.Ascending (lt .CurrentPage .TotalPages)) (isRTL .Direction)}}
{{if gt .CurrentPage 1}}<a href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">&#8672; {{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Previous{{else}}Newer{{end}}</a>{{end}}
{{if lt .CurrentPage .TotalPages}}<a style="float:right;" href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">{{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Next{{else}}Older{{end}} &#8674;</a>{{end}}
{{else}}
{{if lt .CurrentPage .TotalPages}}<a href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">&#8672; Older</a>{{end}}
{{if gt .CurrentPage 1}}<a style="float:right;" href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">Newer &#8674;</a>{{end}}
{{end}}
</nav>{{end}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{ if .Collection.ShowFooterBranding }}
<footer dir="ltr">
<hr>
<nav>
<p style="font-size: 0.9em"><a class="home pubd" href="/">{{.SiteName}}</a> &middot; powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a></p>
</nav>
</footer>
{{ end }}
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Collection.Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/localdate.js"></script>
{{if .IsOwner}}
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
{{end}}
<script type="text/javascript">
{{if .IsOwner}}
var deleting = false;
function delPost(e, id, owned) {
e.preventDefault();
if (deleting) {
return;
}
// TODO: UNDO!
if (window.confirm('Are you sure you want to delete this post?')) {
// AJAX
deletePost(id, "", function() {
// Remove post from list
var $postEl = document.getElementById('post-' + id);
$postEl.parentNode.removeChild($postEl);
// TODO: add next post from this collection at the bottom
});
}
}
var deletePost = function(postID, token, callback) {
deleting = true;
var $delBtn = document.getElementById('post-' + postID).getElementsByClassName('delete action')[0];
$delBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/posts/" + postID;
http.open("DELETE", url, true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
deleting = false;
if (http.status == 204) {
callback();
} else if (http.status == 409) {
$delBtn.innerHTML = 'delete';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$delBtn.innerHTML = 'delete';
alert("Failed to delete." + (http.status>=500?" Please try again.":""));
}
}
}
http.send();
};
var pinning = false;
function pinPost(e, postID, slug, title) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var callback = function() {
// Visibly remove post from collection
var $postEl = document.getElementById('post-' + postID);
$postEl.parentNode.removeChild($postEl);
var $header = document.getElementsByTagName('header')[0];
var $pinnedNavs = $header.getElementsByTagName('nav');
// Add link to nav
var link = '<a class="pinned" href="{{if not .SingleUser}}/{{.Alias}}/{{end}}'+slug+'">'+title+'</a>';
if ($pinnedNavs.length == 0) {
$header.insertAdjacentHTML("beforeend", '<nav>'+link+'</nav>');
} else {
$pinnedNavs[0].insertAdjacentHTML("beforeend", link);
}
};
var $pinBtn = document.getElementById('post-' + postID).getElementsByClassName('pin action')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}/pin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
} else if (http.status == 409) {
$pinBtn.innerHTML = 'pin';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$pinBtn.innerHTML = 'pin';
alert("Failed to pin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
{{end}}
try { // Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/collection.tmpl b/templates/collection.tmpl
index 269004e..88d7dba 100644
--- a/templates/collection.tmpl
+++ b/templates/collection.tmpl
@@ -1,261 +1,273 @@
{{define "collection"}}<!DOCTYPE HTML>
-<html {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
<head>
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.DisplayTitle}}{{if not .SingleUser}} &mdash; {{.SiteName}}{{end}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.CanonicalURL}}">
{{if gt .CurrentPage 1}}<link rel="prev" href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if lt .CurrentPage .TotalPages}}<link rel="next" href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{end}}
{{if not .IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.DisplayTitle}} &raquo; Feed" href="{{.CanonicalURL}}feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="WriteFreely">
<meta name="description" content="{{.PlainDescription}}">
<meta itemprop="name" content="{{.DisplayTitle}}">
<meta itemprop="description" content="{{.PlainDescription}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{.DisplayTitle}}">
<meta name="twitter:image" content="{{.AvatarURL}}">
<meta name="twitter:description" content="{{.PlainDescription}}">
<meta property="og:title" content="{{.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}" />
<meta property="og:description" content="{{.PlainDescription}}" />
<meta property="og:image" content="{{.AvatarURL}}">
{{template "collection-meta" .}}
{{if .StyleSheet}}<style type="text/css">{{.StyleSheetDisplay}}</style>{{end}}
{{if .RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" .}}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" . }}
</head>
<body id="collection" itemscope itemtype="http://schema.org/WebPage">
{{if or .IsOwner .SingleUser}}
<nav id="manage"><ul>
<li class="has-submenu"><a onclick="void(0)">&#9776; Menu</a>
<ul>
{{ if .IsOwner }}
{{if .SingleUser}}
<li><a href="/me/new">New Post</a></li>
{{else}}
<li><a href="/#{{.Alias}}" class="write">{{.SiteName}}</a></li>
{{end}}
{{if .SimpleNav}}<li><a href="/new#{{.Alias}}">New Post</a></li>{{end}}
<li><a href="/me/c/{{.Alias}}">Customize</a></li>
<li><a href="/me/c/{{.Alias}}/stats">Stats</a></li>
<li><a href="/me/c/{{.Alias}}/subscribers">Subscribers</a></li>
<li class="separator"><hr /></li>
{{if not .SingleUser}}<li><a href="/me/c/"><img class="ic-18dp" src="/img/ic_blogs_dark@2x.png" /> View Blogs</a></li>{{end}}
<li><a href="/me/posts/"><img class="ic-18dp" src="/img/ic_list_dark@2x.png" /> View Drafts</a></li>
{{ else }}
<li><a href="/login">Log in{{if .IsProtected}} to {{.DisplayTitle}}{{end}}</a></li>
{{if .IsProtected}}
<li class="separator"><hr /></li>
<li><a href="/logout">Log out</a></li>
{{end}}
{{ end }}
</ul>
</li>
</ul></nav>
{{else if .IsCollLoggedIn}}
<nav id="manage" class="shiny"><ul>
<li class="has-submenu"><a onclick="void(0)">&#9776; Menu</a>
<ul>
<li class="menu-heading" style="padding: .5rem .75rem; box-sizing: border-box;">{{.DisplayTitle}}</li>
<li><a href="{{.CanonicalURL}}logout">Log out</a></li>
</ul>
</li>
</ul></nav>
{{end}}
<header>
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
<h1 dir="{{.Direction}}" id="blog-title">{{if .Posts}}{{else}}<span class="writeas-prefix"><a href="/">write.as</a></span> {{end}}<a href="/{{if .IsTopLevel}}{{else}}{{.Prefix}}{{.Alias}}/{{end}}" class="h-card p-author u-url" rel="me author">{{.DisplayTitle}}</a></h1>
{{if .Description}}<p class="description p-note">{{.DisplayDescription}}</p>{{end}}
{{/*if not .Public/*}}
<!--p class="meta-note"><span>Private collection</span>. Only you can see this page.</p-->
{{/*end*/}}
{{if .PinnedPosts}}<nav>
{{range .PinnedPosts}}<a class="pinned" href="{{if not $.SingleUser}}/{{$.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL $.Host}}{{end}}">{{.PlainDisplayTitle}}</a>{{end}}</nav>
{{end}}
</header>
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
{{if .IsWelcome}}
<div id="welcome">
<h2>Welcome, <strong>{{.Username}}</strong>!</h2>
<p>This is your new blog.</p>
<p><a class="simple-cta" href="/#{{.Alias}}">Start writing</a>, or <a class="simple-cta" href="/me/c/{{.Alias}}">customize</a> your blog.</p>
<p>Check out our <a class="simple-cta" href="https://writefreely.org/docs/latest/writer/writing">writing guide</a> to see what else you can do, and <a class="simple-cta" href="/contact">get in touch</a> anytime with questions or feedback.</p>
</div>
{{end}}
{{if .Flash}}
<div class="alert success flash">
<p>{{.Flash}}</p>
</div>
{{end}}
{{template "posts" .}}
{{if gt .TotalPages 1}}<nav id="paging" class="content-container clearfix">
{{if or (and .Format.Ascending (le .CurrentPage .TotalPages)) (isRTL .Direction)}}
{{if gt .CurrentPage 1}}<a href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">&#8672; {{if and .Format.Ascending (le .CurrentPage .TotalPages)}}Previous{{else}}Newer{{end}}</a>{{end}}
{{if lt .CurrentPage .TotalPages}}<a style="float:right;" href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">{{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Next{{else}}Older{{end}} &#8674;</a>{{end}}
{{else}}
{{if lt .CurrentPage .TotalPages}}<a href="{{.NextPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">&#8672; Older</a>{{end}}
{{if gt .CurrentPage 1}}<a style="float:right;" href="{{.PrevPageURL .Prefix .NavSuffix .CurrentPage .IsTopLevel}}">Newer &#8674;</a>{{end}}
{{end}}
</nav>{{end}}
{{if not .IsWelcome}}{{template "emailsubscribe" .}}{{end}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{if .ShowFooterBranding }}
<footer>
<hr />
<nav dir="ltr">
{{if not .SingleUser}}<a class="home pubd" href="/">{{.SiteName}}</a> &middot; {{end}}powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a>
</nav>
</footer>
{{ end }}
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
<script src="/js/localdate.js"></script>
<script type="text/javascript" src="/js/menu.js"></script>
<script type="text/javascript">
var deleting = false;
function delPost(e, id, owned) {
e.preventDefault();
if (deleting) {
return;
}
// TODO: UNDO!
if (window.confirm('Are you sure you want to delete this post?')) {
// AJAX
deletePost(id, "", function() {
// Remove post from list
var $postEl = document.getElementById('post-' + id);
$postEl.parentNode.removeChild($postEl);
// TODO: add next post from this collection at the bottom
});
}
}
var deletePost = function(postID, token, callback) {
deleting = true;
var $delBtn = document.getElementById('post-' + postID).getElementsByClassName('delete action')[0];
$delBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/posts/" + postID;
http.open("DELETE", url, true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
deleting = false;
if (http.status == 204) {
callback();
} else if (http.status == 409) {
$delBtn.innerHTML = 'delete';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$delBtn.innerHTML = 'delete';
alert("Failed to delete." + (http.status>=500?" Please try again.":""));
}
}
}
http.send();
};
var pinning = false;
function pinPost(e, postID, slug, title) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var callback = function() {
// Visibly remove post from collection
var $postEl = document.getElementById('post-' + postID);
$postEl.parentNode.removeChild($postEl);
var $header = document.getElementsByTagName('header')[0];
var $pinnedNavs = $header.getElementsByTagName('nav');
// Add link to nav
var link = '<a class="pinned" href="{{if not .SingleUser}}/{{.Alias}}/{{end}}'+slug+'">'+title+'</a>';
if ($pinnedNavs.length == 0) {
$header.insertAdjacentHTML("beforeend", '<nav>'+link+'</nav>');
} else {
$pinnedNavs[0].insertAdjacentHTML("beforeend", link);
}
};
var $pinBtn = document.getElementById('post-' + postID).getElementsByClassName('pin action')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}/pin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
} else if (http.status == 409) {
$pinBtn.innerHTML = 'pin';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$pinBtn.innerHTML = 'pin';
alert("Failed to pin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
try {
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) {}
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/edit-meta.tmpl b/templates/edit-meta.tmpl
index 6c964b6..faddffd 100644
--- a/templates/edit-meta.tmpl
+++ b/templates/edit-meta.tmpl
@@ -1,379 +1,389 @@
{{define "edit-meta"}}<!DOCTYPE HTML>
<html>
<head>
<title>Edit metadata: {{if .Post.Title}}{{.Post.Title}}{{else}}{{.Post.Id}}{{end}} &mdash; {{.SiteName}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
dt {
width: 8em;
}
.error {
display: none;
}
.mono {
font-style: normal;
}
#set-now {
font-style: italic;
margin-left: 0.25rem;
}
.content-container h2 a {
font-size: .6em;
font-weight: normal;
margin-left: 1em;
}
.content-container h2 a:link, .content-container h2 a:visited {
color: blue;
}
+ html.dark .content-container h2 a:link,
+ html.dark .content-container h2 a:visited,
+ html.dark #set-now:link,
+ html.dark #set-now:visited,
+ body.dark .content-container h2 a:link,
+ body.dark .content-container h2 a:visited,
+ body.dark #set-now:link,
+ body.dark #set-now:visited {
+ color: #b9c7ff;
+ }
.content-container h2 a:hover {
text-decoration: underline;
}
</style>
</head>
<body id="pad-sub" class="light">
<header id="tools">
<div id="clip">
<h1><a href="/me/c/" title="View blogs"><img class="ic-24dp" src="/img/ic_blogs_dark@2x.png" /></a></h1>
<nav id="target" class=""><ul>
<li>{{if .EditCollection}}<a href="{{.EditCollection.CanonicalURL}}">{{.EditCollection.Title}}</a>{{else}}<a>Draft</a>{{end}}</li>
</ul></nav>
</div>
<div id="belt">
<div class="tool if-room"><a href="{{if .EditCollection}}{{.EditCollection.CanonicalURL}}{{.Post.Slug}}/edit{{else}}/{{.Post.Id}}/edit{{end}}" title="Edit post" id="edit"><img class="ic-24dp" src="/img/ic_edit_dark@2x.png" /></a></div>
<div class="tool if-room room-2"><a href="#theme" title="Toggle theme" id="toggle-theme"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a></div>
<div class="tool if-room room-1"><a href="/me/posts/" title="View posts" id="view-posts"><img class="ic-24dp" src="/img/ic_list_dark@2x.png" /></a></div>
</div>
</header>
<div class="content-container tight">
<form action="/api/{{if .EditCollection}}collections/{{.EditCollection.Alias}}/{{end}}posts/{{.Post.Id}}" method="post" onsubmit="return updateMeta()">
<h2>Edit metadata: {{if .Post.Title}}{{.Post.Title}}{{else}}{{.Post.Id}}{{end}} <a href="/{{if .EditCollection}}{{if not .SingleUser}}{{.EditCollection.Alias}}/{{end}}{{.Post.Slug}}{{else}}{{if .SingleUser}}d/{{end}}{{.Post.Id}}{{end}}">view post</a></h2>
{{if .Flashes}}<ul class="errors">
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}}
</ul>{{end}}
<dl class="dl-horizontal">
{{if .EditCollection}}
<dt><label for="slug">Slug</label></dt>
<dd><input type="text" id="slug" name="slug" value="{{.Post.Slug}}" /></dd>
{{end}}
<dt><label for="lang">Language</label></dt>
<dd>
<select name="lang" id="lang" dir="auto" class="inputform">
<option value=""></option>
<option value="ab"{{if eq "ab" .Post.Language.String}} selected="selected"{{end}}>аҧсуа бызшәа, аҧсшәа</option>
<option value="aa"{{if eq "aa" .Post.Language.String}} selected="selected"{{end}}>Afaraf</option>
<option value="af"{{if eq "af" .Post.Language.String}} selected="selected"{{end}}>Afrikaans</option>
<option value="ak"{{if eq "ak" .Post.Language.String}} selected="selected"{{end}}>Akan</option>
<option value="sq"{{if eq "sq" .Post.Language.String}} selected="selected"{{end}}>Shqip</option>
<option value="am"{{if eq "am" .Post.Language.String}} selected="selected"{{end}}>አማርኛ</option>
<option dir="rtl" value="ar"{{if eq "ar" .Post.Language.String}} selected="selected"{{end}}>العربية</option>
<option value="an"{{if eq "an" .Post.Language.String}} selected="selected"{{end}}>aragonés</option>
<option value="hy"{{if eq "hy" .Post.Language.String}} selected="selected"{{end}}>Հայերեն</option>
<option value="as"{{if eq "as" .Post.Language.String}} selected="selected"{{end}}>অসমীয়া</option>
<option value="av"{{if eq "av" .Post.Language.String}} selected="selected"{{end}}>авар мацӀ, магӀарул мацӀ</option>
<option value="ae"{{if eq "ae" .Post.Language.String}} selected="selected"{{end}}>avesta</option>
<option value="ay"{{if eq "ay" .Post.Language.String}} selected="selected"{{end}}>aymar aru</option>
<option value="az"{{if eq "az" .Post.Language.String}} selected="selected"{{end}}>azərbaycan dili</option>
<option value="bm"{{if eq "bm" .Post.Language.String}} selected="selected"{{end}}>bamanankan</option>
<option value="ba"{{if eq "ba" .Post.Language.String}} selected="selected"{{end}}>башҡорт теле</option>
<option value="eu"{{if eq "eu" .Post.Language.String}} selected="selected"{{end}}>euskara, euskera</option>
<option value="be"{{if eq "be" .Post.Language.String}} selected="selected"{{end}}>беларуская мова</option>
<option value="bn"{{if eq "bn" .Post.Language.String}} selected="selected"{{end}}>বাংলা</option>
<option value="bh"{{if eq "bh" .Post.Language.String}} selected="selected"{{end}}>भोजपुरी</option>
<option value="bi"{{if eq "bi" .Post.Language.String}} selected="selected"{{end}}>Bislama</option>
<option value="bs"{{if eq "bs" .Post.Language.String}} selected="selected"{{end}}>bosanski jezik</option>
<option value="br"{{if eq "br" .Post.Language.String}} selected="selected"{{end}}>brezhoneg</option>
<option value="bg"{{if eq "bg" .Post.Language.String}} selected="selected"{{end}}>български език</option>
<option value="my"{{if eq "my" .Post.Language.String}} selected="selected"{{end}}>ဗမာစာ</option>
<option value="ca"{{if eq "ca" .Post.Language.String}} selected="selected"{{end}}>català</option>
<option value="ch"{{if eq "ch" .Post.Language.String}} selected="selected"{{end}}>Chamoru</option>
<option value="ce"{{if eq "ce" .Post.Language.String}} selected="selected"{{end}}>нохчийн мотт</option>
<option value="ny"{{if eq "ny" .Post.Language.String}} selected="selected"{{end}}>chiCheŵa, chinyanja</option>
<option value="zh"{{if eq "zh" .Post.Language.String}} selected="selected"{{end}}>中文 (Zhōngwén), 汉语, 漢語</option>
<option value="cv"{{if eq "cv" .Post.Language.String}} selected="selected"{{end}}>чӑваш чӗлхи</option>
<option value="kw"{{if eq "kw" .Post.Language.String}} selected="selected"{{end}}>Kernewek</option>
<option value="co"{{if eq "co" .Post.Language.String}} selected="selected"{{end}}>corsu, lingua corsa</option>
<option value="cr"{{if eq "cr" .Post.Language.String}} selected="selected"{{end}}>ᓀᐦᐃᔭᐍᐏᐣ</option>
<option value="hr"{{if eq "hr" .Post.Language.String}} selected="selected"{{end}}>hrvatski jezik</option>
<option value="cs"{{if eq "cs" .Post.Language.String}} selected="selected"{{end}}>čeština, český jazyk</option>
<option value="da"{{if eq "da" .Post.Language.String}} selected="selected"{{end}}>dansk</option>
<option dir="rtl" value="dv"{{if eq "dv" .Post.Language.String}} selected="selected"{{end}}>ދިވެހި</option>
<option value="nl"{{if eq "nl" .Post.Language.String}} selected="selected"{{end}}>Nederlands, Vlaams</option>
<option value="dz"{{if eq "dz" .Post.Language.String}} selected="selected"{{end}}>རྫོང་ཁ</option>
<option value="en"{{if eq "en" .Post.Language.String}} selected="selected"{{end}}>English</option>
<option value="eo"{{if eq "eo" .Post.Language.String}} selected="selected"{{end}}>Esperanto</option>
<option value="et"{{if eq "et" .Post.Language.String}} selected="selected"{{end}}>eesti, eesti keel</option>
<option value="ee"{{if eq "ee" .Post.Language.String}} selected="selected"{{end}}>Eʋegbe</option>
<option value="fo"{{if eq "fo" .Post.Language.String}} selected="selected"{{end}}>føroyskt</option>
<option value="fj"{{if eq "fj" .Post.Language.String}} selected="selected"{{end}}>vosa Vakaviti</option>
<option value="fi"{{if eq "fi" .Post.Language.String}} selected="selected"{{end}}>suomi, suomen kieli</option>
<option value="fr"{{if eq "fr" .Post.Language.String}} selected="selected"{{end}}>français, langue française</option>
<option value="ff"{{if eq "ff" .Post.Language.String}} selected="selected"{{end}}>Fulfulde, Pulaar, Pular</option>
<option value="gl"{{if eq "gl" .Post.Language.String}} selected="selected"{{end}}>Galego</option>
<option value="ka"{{if eq "ka" .Post.Language.String}} selected="selected"{{end}}>ქართული</option>
<option value="de"{{if eq "de" .Post.Language.String}} selected="selected"{{end}}>Deutsch</option>
<option value="el"{{if eq "el" .Post.Language.String}} selected="selected"{{end}}>ελληνικά</option>
<option value="gn"{{if eq "gn" .Post.Language.String}} selected="selected"{{end}}>Avañe'ẽ</option>
<option value="gu"{{if eq "gu" .Post.Language.String}} selected="selected"{{end}}>ગુજરાતી</option>
<option value="ht"{{if eq "ht" .Post.Language.String}} selected="selected"{{end}}>Kreyòl ayisyen</option>
<option dir="rtl" value="ha"{{if eq "ha" .Post.Language.String}} selected="selected"{{end}}>(Hausa) هَوُسَ</option>
<option dir="rtl" value="he"{{if eq "he" .Post.Language.String}} selected="selected"{{end}}>עברית</option>
<option value="hz"{{if eq "hz" .Post.Language.String}} selected="selected"{{end}}>Otjiherero</option>
<option value="hi"{{if eq "hi" .Post.Language.String}} selected="selected"{{end}}>हिन्दी, हिंदी</option>
<option value="ho"{{if eq "ho" .Post.Language.String}} selected="selected"{{end}}>Hiri Motu</option>
<option value="hu"{{if eq "hu" .Post.Language.String}} selected="selected"{{end}}>magyar</option>
<option value="ia"{{if eq "ia" .Post.Language.String}} selected="selected"{{end}}>Interlingua</option>
<option value="id"{{if eq "id" .Post.Language.String}} selected="selected"{{end}}>Bahasa Indonesia</option>
<option value="ie"{{if eq "ie" .Post.Language.String}} selected="selected"{{end}}>Interlingue</option>
<option value="ga"{{if eq "ga" .Post.Language.String}} selected="selected"{{end}}>Gaeilge</option>
<option value="ig"{{if eq "ig" .Post.Language.String}} selected="selected"{{end}}>Asụsụ Igbo</option>
<option value="ik"{{if eq "ik" .Post.Language.String}} selected="selected"{{end}}>Iñupiaq, Iñupiatun</option>
<option value="io"{{if eq "io" .Post.Language.String}} selected="selected"{{end}}>Ido</option>
<option value="is"{{if eq "is" .Post.Language.String}} selected="selected"{{end}}>Íslenska</option>
<option value="it"{{if eq "it" .Post.Language.String}} selected="selected"{{end}}>Italiano</option>
<option value="iu"{{if eq "iu" .Post.Language.String}} selected="selected"{{end}}>ᐃᓄᒃᑎᑐᑦ</option>
<option value="ja"{{if eq "ja" .Post.Language.String}} selected="selected"{{end}}>日本語 (にほんご)</option>
<option value="jv"{{if eq "jv" .Post.Language.String}} selected="selected"{{end}}>ꦧꦱꦗꦮ, Basa Jawa</option>
<option value="kl"{{if eq "kl" .Post.Language.String}} selected="selected"{{end}}>kalaallisut, kalaallit oqaasii</option>
<option value="kn"{{if eq "kn" .Post.Language.String}} selected="selected"{{end}}>ಕನ್ನಡ</option>
<option value="kr"{{if eq "kr" .Post.Language.String}} selected="selected"{{end}}>Kanuri</option>
<option value="ks"{{if eq "ks" .Post.Language.String}} selected="selected"{{end}}>कश्मीरी, كشميري‎</option>
<option value="kk"{{if eq "kk" .Post.Language.String}} selected="selected"{{end}}>қазақ тілі</option>
<option value="km"{{if eq "km" .Post.Language.String}} selected="selected"{{end}}>ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ</option>
<option value="ki"{{if eq "ki" .Post.Language.String}} selected="selected"{{end}}>Gĩkũyũ</option>
<option value="rw"{{if eq "rw" .Post.Language.String}} selected="selected"{{end}}>Ikinyarwanda</option>
<option value="ky"{{if eq "ky" .Post.Language.String}} selected="selected"{{end}}>Кыргызча, Кыргыз тили</option>
<option value="kv"{{if eq "kv" .Post.Language.String}} selected="selected"{{end}}>коми кыв</option>
<option value="kg"{{if eq "kg" .Post.Language.String}} selected="selected"{{end}}>Kikongo</option>
<option value="ko"{{if eq "ko" .Post.Language.String}} selected="selected"{{end}}>한국어</option>
<option value="ku"{{if eq "ku" .Post.Language.String}} selected="selected"{{end}}>Kurdî, كوردی‎</option>
<option value="kj"{{if eq "kj" .Post.Language.String}} selected="selected"{{end}}>Kuanyama</option>
<option value="la"{{if eq "la" .Post.Language.String}} selected="selected"{{end}}>latine, lingua latina</option>
<option value="lb"{{if eq "lb" .Post.Language.String}} selected="selected"{{end}}>Lëtzebuergesch</option>
<option value="lg"{{if eq "lg" .Post.Language.String}} selected="selected"{{end}}>Luganda</option>
<option value="li"{{if eq "li" .Post.Language.String}} selected="selected"{{end}}>Limburgs</option>
<option value="ln"{{if eq "ln" .Post.Language.String}} selected="selected"{{end}}>Lingála</option>
<option value="lo"{{if eq "lo" .Post.Language.String}} selected="selected"{{end}}>ພາສາລາວ</option>
<option value="lt"{{if eq "lt" .Post.Language.String}} selected="selected"{{end}}>lietuvių kalba</option>
<option value="lu"{{if eq "lu" .Post.Language.String}} selected="selected"{{end}}>Kiluba</option>
<option value="lv"{{if eq "lv" .Post.Language.String}} selected="selected"{{end}}>Latviešu Valoda</option>
<option value="gv"{{if eq "gv" .Post.Language.String}} selected="selected"{{end}}>Gaelg, Gailck</option>
<option value="mk"{{if eq "mk" .Post.Language.String}} selected="selected"{{end}}>македонски јазик</option>
<option value="mg"{{if eq "mg" .Post.Language.String}} selected="selected"{{end}}>fiteny malagasy</option>
<option value="ms"{{if eq "ms" .Post.Language.String}} selected="selected"{{end}}>Bahasa Melayu, بهاس ملايو‎</option>
<option value="ml"{{if eq "ml" .Post.Language.String}} selected="selected"{{end}}>മലയാളം</option>
<option value="mt"{{if eq "mt" .Post.Language.String}} selected="selected"{{end}}>Malti</option>
<option value="mi"{{if eq "mi" .Post.Language.String}} selected="selected"{{end}}>te reo Māori</option>
<option value="mr"{{if eq "mr" .Post.Language.String}} selected="selected"{{end}}>मराठी</option>
<option value="mh"{{if eq "mh" .Post.Language.String}} selected="selected"{{end}}>Kajin M̧ajeļ</option>
<option value="mn"{{if eq "mn" .Post.Language.String}} selected="selected"{{end}}>Монгол хэл</option>
<option value="na"{{if eq "na" .Post.Language.String}} selected="selected"{{end}}>Dorerin Naoero</option>
<option value="nv"{{if eq "nv" .Post.Language.String}} selected="selected"{{end}}>Diné bizaad</option>
<option value="nd"{{if eq "nd" .Post.Language.String}} selected="selected"{{end}}>isiNdebele</option>
<option value="ne"{{if eq "ne" .Post.Language.String}} selected="selected"{{end}}>नेपाली</option>
<option value="ng"{{if eq "ng" .Post.Language.String}} selected="selected"{{end}}>Owambo</option>
<option value="nb"{{if eq "nb" .Post.Language.String}} selected="selected"{{end}}>Norsk Bokmål</option>
<option value="nn"{{if eq "nn" .Post.Language.String}} selected="selected"{{end}}>Norsk Nynorsk</option>
<option value="no"{{if eq "no" .Post.Language.String}} selected="selected"{{end}}>Norsk</option>
<option value="ii"{{if eq "ii" .Post.Language.String}} selected="selected"{{end}}>ꆈꌠ꒿ Nuosuhxop</option>
<option value="nr"{{if eq "nr" .Post.Language.String}} selected="selected"{{end}}>isiNdebele</option>
<option value="oc"{{if eq "oc" .Post.Language.String}} selected="selected"{{end}}>occitan, lenga d'òc</option>
<option value="oj"{{if eq "oj" .Post.Language.String}} selected="selected"{{end}}>ᐊᓂᔑᓈᐯᒧᐎᓐ</option>
<option value="cu"{{if eq "cu" .Post.Language.String}} selected="selected"{{end}}>ѩзыкъ словѣньскъ</option>
<option value="om"{{if eq "om" .Post.Language.String}} selected="selected"{{end}}>Afaan Oromoo</option>
<option value="or"{{if eq "or" .Post.Language.String}} selected="selected"{{end}}>ଓଡ଼ିଆ</option>
<option value="os"{{if eq "os" .Post.Language.String}} selected="selected"{{end}}>ирон æвзаг</option>
<option value="pa"{{if eq "pa" .Post.Language.String}} selected="selected"{{end}}>ਪੰਜਾਬੀ</option>
<option value="pi"{{if eq "pi" .Post.Language.String}} selected="selected"{{end}}>पाऴि</option>
<option dir="rtl" value="fa"{{if eq "fa" .Post.Language.String}} selected="selected"{{end}}>فارسی</option>
<option value="pl"{{if eq "pl" .Post.Language.String}} selected="selected"{{end}}>Język Polski, Polszczyzna</option>
<option dir="rtl" value="ps"{{if eq "ps" .Post.Language.String}} selected="selected"{{end}}>پښتو</option>
<option value="pt"{{if eq "pt" .Post.Language.String}} selected="selected"{{end}}>Português</option>
<option value="qu"{{if eq "qu" .Post.Language.String}} selected="selected"{{end}}>Runa Simi, Kichwa</option>
<option value="rm"{{if eq "rm" .Post.Language.String}} selected="selected"{{end}}>Rumantsch Grischun</option>
<option value="rn"{{if eq "rn" .Post.Language.String}} selected="selected"{{end}}>Ikirundi</option>
<option value="ro"{{if eq "ro" .Post.Language.String}} selected="selected"{{end}}>Română</option>
<option value="ru"{{if eq "ru" .Post.Language.String}} selected="selected"{{end}}>Русский</option>
<option value="sa"{{if eq "sa" .Post.Language.String}} selected="selected"{{end}}>संस्कृतम्</option>
<option value="sc"{{if eq "sc" .Post.Language.String}} selected="selected"{{end}}>sardu</option>
<option value="sd"{{if eq "sd" .Post.Language.String}} selected="selected"{{end}}>सिन्धी, سنڌي، سندھی‎</option>
<option value="se"{{if eq "se" .Post.Language.String}} selected="selected"{{end}}>Davvisámegiella</option>
<option value="sm"{{if eq "sm" .Post.Language.String}} selected="selected"{{end}}>gagana fa'a Samoa</option>
<option value="sg"{{if eq "sg" .Post.Language.String}} selected="selected"{{end}}>yângâ tî sängö</option>
<option value="sr"{{if eq "sr" .Post.Language.String}} selected="selected"{{end}}>српски језик</option>
<option value="gd"{{if eq "gd" .Post.Language.String}} selected="selected"{{end}}>Gàidhlig</option>
<option value="sn"{{if eq "sn" .Post.Language.String}} selected="selected"{{end}}>chiShona</option>
<option value="si"{{if eq "si" .Post.Language.String}} selected="selected"{{end}}>සිංහල</option>
<option value="sk"{{if eq "sk" .Post.Language.String}} selected="selected"{{end}}>Slovenčina, Slovenský Jazyk</option>
<option value="sl"{{if eq "sl" .Post.Language.String}} selected="selected"{{end}}>Slovenski Jezik, Slovenščina</option>
<option value="so"{{if eq "so" .Post.Language.String}} selected="selected"{{end}}>Soomaaliga, af Soomaali</option>
<option value="st"{{if eq "st" .Post.Language.String}} selected="selected"{{end}}>Sesotho</option>
<option value="es"{{if eq "es" .Post.Language.String}} selected="selected"{{end}}>Español</option>
<option value="su"{{if eq "su" .Post.Language.String}} selected="selected"{{end}}>Basa Sunda</option>
<option value="sw"{{if eq "sw" .Post.Language.String}} selected="selected"{{end}}>Kiswahili</option>
<option value="ss"{{if eq "ss" .Post.Language.String}} selected="selected"{{end}}>SiSwati</option>
<option value="sv"{{if eq "sv" .Post.Language.String}} selected="selected"{{end}}>Svenska</option>
<option value="ta"{{if eq "ta" .Post.Language.String}} selected="selected"{{end}}>தமிழ்</option>
<option value="te"{{if eq "te" .Post.Language.String}} selected="selected"{{end}}>తెలుగు</option>
<option value="tg"{{if eq "tg" .Post.Language.String}} selected="selected"{{end}}>тоҷикӣ, toçikī, تاجیکی‎</option>
<option value="th"{{if eq "th" .Post.Language.String}} selected="selected"{{end}}>ไทย</option>
<option value="ti"{{if eq "ti" .Post.Language.String}} selected="selected"{{end}}>ትግርኛ</option>
<option value="bo"{{if eq "bo" .Post.Language.String}} selected="selected"{{end}}>བོད་ཡིག</option>
<option value="tk"{{if eq "tk" .Post.Language.String}} selected="selected"{{end}}>Türkmen, Түркмен</option>
<option value="tl"{{if eq "tl" .Post.Language.String}} selected="selected"{{end}}>Wikang Tagalog</option>
<option value="tn"{{if eq "tn" .Post.Language.String}} selected="selected"{{end}}>Setswana</option>
<option value="to"{{if eq "to" .Post.Language.String}} selected="selected"{{end}}>Faka Tonga</option>
<option value="tr"{{if eq "tr" .Post.Language.String}} selected="selected"{{end}}>Türkçe</option>
<option value="ts"{{if eq "ts" .Post.Language.String}} selected="selected"{{end}}>Xitsonga</option>
<option value="tt"{{if eq "tt" .Post.Language.String}} selected="selected"{{end}}>татар теле, tatar tele</option>
<option value="tw"{{if eq "tw" .Post.Language.String}} selected="selected"{{end}}>Twi</option>
<option value="ty"{{if eq "ty" .Post.Language.String}} selected="selected"{{end}}>Reo Tahiti</option>
<option value="ug"{{if eq "ug" .Post.Language.String}} selected="selected"{{end}}>ئۇيغۇرچە‎, Uyghurche</option>
<option value="uk"{{if eq "uk" .Post.Language.String}} selected="selected"{{end}}>Українська</option>
<option dir="rtl" value="ur"{{if eq "ur" .Post.Language.String}} selected="selected"{{end}}>اردو</option>
<option value="uz"{{if eq "uz" .Post.Language.String}} selected="selected"{{end}}>Oʻzbek, Ўзбек, أۇزبېك‎</option>
<option value="ve"{{if eq "ve" .Post.Language.String}} selected="selected"{{end}}>Tshivenḓa</option>
<option value="vi"{{if eq "vi" .Post.Language.String}} selected="selected"{{end}}>Tiếng Việt</option>
<option value="vo"{{if eq "vo" .Post.Language.String}} selected="selected"{{end}}>Volapük</option>
<option value="wa"{{if eq "wa" .Post.Language.String}} selected="selected"{{end}}>Walon</option>
<option value="cy"{{if eq "cy" .Post.Language.String}} selected="selected"{{end}}>Cymraeg</option>
<option value="wo"{{if eq "wo" .Post.Language.String}} selected="selected"{{end}}>Wollof</option>
<option value="fy"{{if eq "fy" .Post.Language.String}} selected="selected"{{end}}>Frysk</option>
<option value="xh"{{if eq "xh" .Post.Language.String}} selected="selected"{{end}}>isiXhosa</option>
<option dir="rtl" value="yi"{{if eq "yi" .Post.Language.String}} selected="selected"{{end}}>ייִדיש</option>
<option value="yo"{{if eq "yo" .Post.Language.String}} selected="selected"{{end}}>Yorùbá</option>
<option value="za"{{if eq "za" .Post.Language.String}} selected="selected"{{end}}>Saɯ cueŋƅ, Saw cuengh</option>
<option value="zu"{{if eq "zu" .Post.Language.String}} selected="selected"{{end}}>isiZulu</option>
</select>
</dd>
<dt><label for="rtl">Direction</label></dt>
<dd><input type="checkbox" id="rtl" name="rtl" {{if .Post.IsRTL.Bool}}checked="checked"{{end}} /><label for="rtl"> right-to-left</label></dd>
<dt><label for="created">Created</label></dt>
<dd>
<input type="datetime-local" id="created" name="created" value="{{.Post.UserFacingCreated}}" data-time="{{.Post.Created8601}}" step="1" /> <span id="tz">UTC</span> <a href="#" id="set-now">now</a>
<p class="error" id="create-error">Date format should be: <span class="mono"><abbr title="The full year">YYYY</abbr>-<abbr title="The numeric month of the year, where January = 1, with a zero in front if less than 10">MM</abbr>-<abbr title="The day of the month, with a zero in front if less than 10">DD</abbr> <abbr title="The hour (00-23), with a zero in front if less than 10.">HH</abbr>:<abbr title="The minute of the hour (00-59), with a zero in front if less than 10.">MM</abbr>:<abbr title="The seconds (00-59), with a zero in front if less than 10.">SS</abbr></span></p>
</dd>
<dt><label for="lang">Font</label></dt>
<dd>
<select name="font" id="font" dir="auto" class="inputform">
<option value="norm" {{if eq .Post.Font "norm"}}selected="selected"{{end}}>Serif</option>
<option class="sans" value="sans" {{if eq .Post.Font "sans"}}selected="selected"{{end}}>Sans-Serif</option>
<option class="mono" value="wrap" {{if eq .Post.Font "wrap"}}selected="selected"{{end}}>Monospace</option>
<option class="mono" value="mono" {{if eq .Post.Font "mono"}}selected="selected"{{end}}>No-wrap Monospace</option>
<option class="mono" value="code" {{if eq .Post.Font "code"}}selected="selected"{{end}}>Code</option>
</select>
</dd>
<dt>&nbsp;</dt><dd><input type="submit" value="Save changes" /></dd>
</dl>
<input type="hidden" name="web" value="true" />
</form>
</div>
<script src="/js/h.js"></script>
<script>
function updateMeta() {
if ({{.Silenced}}) {
alert("Your account is silenced, so you can't edit posts.");
return
}
document.getElementById('create-error').style.display = 'none';
var $created = document.getElementById('created');
let finalDate = (new Date($created.value)).toISOString().slice(0,-5);
// Change the type to ensure the browser doesn't complain about adding the "Z" for UTC and conforming to our API
$created.type = "text";
$created.value = finalDate+"Z";
var $tz = document.getElementById('tz');
$tz.style.display = "inline";
var $submit = document.querySelector('input[type=submit]');
$submit.value = "Saving...";
$submit.disabled = true;
return true;
}
function dateToStr(d) {
return d.getFullYear() + '-' + ('0' + (d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2)+' '+('0'+d.getHours()).slice(-2)+':'+('0'+d.getMinutes()).slice(-2)+':'+('0'+d.getSeconds()).slice(-2);
}
function setLocalTime() {
var $created = document.getElementById('created');
var d = new Date($created.getAttribute('data-time'));
$created.value = dateToStr(d);
var $tz = document.getElementById('tz');
$tz.style.display = "none";
}
setLocalTime();
function setToNow() {
var $created = document.getElementById('created');
$created.value = dateToStr(new Date());
}
H.getEl('set-now').on('click', function(e) {
e.preventDefault();
setToNow();
});
function toggleTheme() {
var btns = Array.prototype.slice.call(document.getElementById('tools').querySelectorAll('a img'));
if (document.body.className == 'light') {
document.body.className = 'dark';
for (var i=0; i<btns.length; i++) {
btns[i].src = btns[i].src.replace('_dark@2x.png', '@2x.png');
}
} else {
document.body.className = 'light';
for (var i=0; i<btns.length; i++) {
btns[i].src = btns[i].src.replace('@2x.png', '_dark@2x.png');
}
}
H.set('padTheme', document.body.className);
}
if (H.get('padTheme', 'light') != 'light') {
toggleTheme();
}
var setButtonStates = function() {
if (!canPublish) {
$btnPublish.el.className = 'disabled';
return;
}
if ($writer.el.value.length === 0 || (draftDoc != 'lastDoc' && $writer.el.value == origDoc)) {
$btnPublish.el.className = 'disabled';
} else {
$btnPublish.el.className = '';
}
};
H.getEl('toggle-theme').on('click', function(e) {
e.preventDefault();
try {
var newTheme = 'light';
if (document.body.className == 'light') {
newTheme = 'dark';
}
} catch(e) {}
toggleTheme();
});
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
try {
(function() {
var wf=document.createElement('script');
wf.src = '/js/webfont.js';
wf.type='text/javascript';
wf.async='true';
var s=document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) {
// whatevs
}
</script>
<link href="/css/icons.css" rel="stylesheet">
</body>
</html>{{end}}
diff --git a/templates/include/footer.tmpl b/templates/include/footer.tmpl
index 8e3dec9..8c4e73b 100644
--- a/templates/include/footer.tmpl
+++ b/templates/include/footer.tmpl
@@ -1,46 +1,47 @@
{{define "footer"}}
<footer{{if not (or .SingleUser .WFModesty)}} class="contain-me"{{end}}>
<hr />
{{if or .SingleUser .WFModesty}}
<nav>
<a class="home" href="/">{{.SiteName}}</a>
{{if not .SingleUser}}
<a href="/about">about</a>
{{if and .LocalTimeline .CanViewReader}}<a href="/read">reader</a>{{end}}
{{if .Username}}<a href="https://writefreely.org/guide/{{.OfficialVersion}}" target="guide">writer's guide</a>{{end}}
<a href="/contact">contact</a>
<a href="/privacy">privacy</a>
<p style="font-size: 0.9em">powered by <a href="https://writefreely.org">writefreely</a></p>
{{else}}
<a href="https://writefreely.org/guide/{{.OfficialVersion}}" target="guide">writer's guide</a>
<a href="https://developers.write.as/" title="Build on WriteFreely with our open developer API.">developers</a>
<a href="https://github.com/writefreely/writefreely">source code</a>
<a href="https://writefreely.org">writefreely {{.Version}}</a>
{{end}}
</nav>
{{else}}
<div class="marketing-section">
<div class="clearfix blurbs">
<div class="half">
<h3><a class="home" href="/">{{.SiteName}}</a></h3>
<ul>
<li><a href="/about">about</a></li>
{{if and (and (not .SingleUser) .LocalTimeline) .CanViewReader}}<a href="/read">reader</a>{{end}}
<li><a href="/contact">contact</a></li>
<li><a href="/privacy">privacy</a></li>
</ul>
</div>
<div class="half">
<h3><a href="https://writefreely.org" style="color:#444;text-transform:lowercase;">WriteFreely</a></h3>
<ul>
<li><a href="https://writefreely.org/guide/{{.OfficialVersion}}" target="guide">writer's guide</a></li>
<li><a href="https://developers.write.as/" title="Build on WriteFreely with our open developer API.">developers</a></li>
<li><a href="https://github.com/writefreely/writefreely">source code</a></li>
<li style="margin-top:0.8em">{{.Version}}</li>
</ul>
</div>
</div>
</div>
{{end}}
</footer>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
{{end}}
diff --git a/templates/password-collection.tmpl b/templates/password-collection.tmpl
index fde4edc..0aade95 100644
--- a/templates/password-collection.tmpl
+++ b/templates/password-collection.tmpl
@@ -1,88 +1,100 @@
{{define "password-collection"}}<!DOCTYPE HTML>
-<html {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
<head>
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{.DisplayTitle}}{{if not .SingleUser}} &mdash; {{.SiteName}}{{end}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.CanonicalURL}}">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="{{.Description}}">
<meta itemprop="name" content="{{.DisplayTitle}}">
<meta itemprop="description" content="{{.Description}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{.DisplayTitle}}">
<meta name="twitter:description" content="{{.Description}}">
<meta property="og:title" content="{{.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}" />
<meta property="og:description" content="{{.Description}}" />
{{if .StyleSheet}}<style type="text/css">{{.StyleSheetDisplay}}</style>{{end}}
</head>
<body id="collection" itemscope itemtype="http://schema.org/WebPage">
{{if .SingleUser}}
<nav id="manage">
<ul>
<li class="has-submenu"><a onclick="void(0)">&#9776; Menu</a>
<ul>
<li><a href="/login">Log in</a></li>
</ul>
</li>
</ul>
</nav>
{{end}}
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a href="/{{.Alias}}/" class="h-card p-author u-url" rel="me author">{{.DisplayTitle}}</a></h1>
</header>
<div id="wrapper">
<div class="access">
<form method="post" action="/api/auth/read">
{{if .Flashes}}<ul class="errors">
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}}
</ul>{{else}}
<h2>This blog requires a password.</h2>
{{end}}
<input type="hidden" name="alias" value="{{.Alias}}" />
<input type="hidden" name="to" value="{{.Next}}" />
<input type="password" autocomplete="new-password" name="password" tabindex="1" autofocus />
<p><input type="submit" value="Enter" /></p>
</form>
</div>
</div>
<footer>
<hr />
<nav dir="ltr">
<a class="home pubd" href="/">{{.SiteName}}</a> &middot; powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a>
</nav>
</footer>
</body>
{{if and .Script .CanShowScript}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
<script type="text/javascript">
try {
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) {}
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/post.tmpl b/templates/post.tmpl
index ca1c1f9..334333b 100644
--- a/templates/post.tmpl
+++ b/templates/post.tmpl
@@ -1,102 +1,114 @@
{{define "post"}}<!DOCTYPE HTML>
-<html {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
+<html class="light" {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<title>{{if .Title}}{{.Title}}{{else}}{{.GenTitle}}{{end}} {{localhtml "title dash" .Language}} {{.SiteName}}</title>
{{if .IsCode}}
<link rel="stylesheet" href="/css/lib/mono-blue.min.css">
{{end}}
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.Host}}/{{if .SingleUser}}d/{{end}}{{.ID}}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="{{.SiteName}}">
<meta name="title" content="{{if .Title}}{{.Title}}{{else}}{{.GenTitle}}{{end}}">
<meta name="description" content="{{.Description}}">
<meta itemprop="name" content="{{.SiteName}}">
<meta itemprop="description" content="{{.Description}}">
<meta name="twitter:card" content="{{if gt (len .Images) 0}}summary_large_image{{else}}summary{{end}}">
<meta name="twitter:title" content="{{if .Title}}{{.Title}}{{else}}{{.GenTitle}}{{end}}">
<meta name="twitter:description" content="{{.Description}}">
{{if gt .Views 1}}<meta name="twitter:label1" value="Views">
<meta name="twitter:data1" value="{{largeNumFmt .Views}}">{{end}}
{{if gt (len .Images) 0}}<meta name="twitter:image" content="{{index .Images 0}}">{{else}}<meta name="twitter:image" content="{{.Host}}/img/wf-sq.png">{{end}}
<meta property="og:title" content="{{if .Title}}{{.Title}}{{else}}{{.GenTitle}}{{end}}" />
<meta property="og:site_name" content="{{.SiteName}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.Host}}/{{if .SingleUser}}d/{{end}}{{.ID}}" />
<meta property="og:description" content="{{.Description}}" />
{{range .Images}}<meta property="og:image" content="{{.}}" />{{else}}<meta property="og:image" content="{{.Host}}/img/wf-sq.png">{{end}}
{{if .Author}}<meta property="article:author" content="https://{{.Author}}" />{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" .}}
</head>
<body id="post">
<header>
<h1 dir="{{.Direction}}"><a href="/">{{.SiteName}}</a></h1>
<nav>
<span class="views{{if not .IsOwner}} owner-visible{{end}}" dir="ltr"><strong>{{largeNumFmt .Views}}</strong> {{pluralize "view" "views" .Views}}</span>
{{if .IsCode}}<a href="/{{.ID}}.txt" rel="noindex" dir="{{.Direction}}">View raw</a>{{end}}
{{ if .Username }}
{{if .IsOwner}}
<a href="/{{if .SingleUser}}d/{{end}}{{.ID}}/edit" dir="{{.Direction}}">Edit</a>
{{end}}
<a class="xtra-feature dash-nav" href="/me/posts/" dir="{{.Direction}}">Drafts</a>
{{ end }}
</nav>
</header>
{{if .Silenced}}
{{template "user-silenced"}}
{{end}}
<article class="{{.Font}} h-entry">{{if .Title}}<h2 id="title" class="p-name">{{.Title}}</h2>{{end}}{{ if .IsPlainText }}<p id="post-body" class="e-content">{{.Content}}</p>{{ else }}<div id="post-body" class="e-content">{{.HTMLContent}}</div>{{ end }}</article>
<footer dir="ltr"><hr><nav><p style="font-size: 0.9em">{{localhtml "published with write.as" .Language}}</p></nav></footer>
</body>
{{if .IsCode}}
<script src="/js/highlight.min.js"></script>
<script>
hljs.highlightBlock(document.getElementById('post-body'));
</script>
{{else}}
<script src="/js/h.js"></script>
{{if .IsPlainText}}<script src="/js/twitter-text.min.js"></script>{{end}}
{{end}}
<script type="text/javascript">
try {
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin'{{if eq .Font "sans"}}, 'Open+Sans:400,700:latin'{{end}} ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
var posts = localStorage.getItem('posts');
if (posts != null) {
posts = JSON.parse(posts);
var $nav = document.getElementsByTagName('nav')[0];
for (var i=0; i<posts.length; i++) {
if (posts[i].id == "{{.ID}}") {
$nav.innerHTML = $nav.innerHTML + '<a class="xtra-feature" href="/edit/{{.ID}}" dir="{{.Direction}}">Edit</a>';
var $ownerVis = document.querySelectorAll('.owner-visible');
for (var i=0; i<$ownerVis.length; i++) {
$ownerVis[i].classList.remove('owner-visible');
}
break;
}
}
}
</script>
+ <a id="global-theme-toggle" class="global-theme-toggle global-theme-toggle--floating" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
+ <script src="/js/theme.js"></script>
</html>{{end}}
diff --git a/templates/user/include/footer.tmpl b/templates/user/include/footer.tmpl
index 94bb182..5073ffd 100644
--- a/templates/user/include/footer.tmpl
+++ b/templates/user/include/footer.tmpl
@@ -1,42 +1,42 @@
{{define "footer"}}
{{template "foot" .}}
{{template "body-end" .}}
{{end}}
{{define "foot"}}
</div>
<footer>
<hr />
<nav>
<a class="home" href="/">{{.SiteName}}</a>
{{if not .SingleUser}}<a href="/about">about</a>{{end}}
{{if and (not .SingleUser) .LocalTimeline}}<a href="/read">reader</a>{{end}}
<a href="https://writefreely.org/guide/{{.OfficialVersion}}" target="guide">writer's guide</a>
{{if not .SingleUser}}<a href="/contact">contact</a>{{end}}
{{if not .SingleUser}}<a href="/privacy">privacy</a>{{end}}
{{if .WFModesty}}
<p style="font-size: 0.9em">powered by <a href="https://writefreely.org">writefreely</a></p>
{{else}}
<a href="https://writefreely.org">writefreely {{.Version}}</a>
{{end}}
</nav>
</footer>
-
+ <script type="text/javascript" src="/js/theme.js"></script>
<script type="text/javascript" src="/js/menu.js"></script>
<script type="text/javascript">
try { // Google Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
{{end}}
{{define "body-end"}}</body>
</html>{{end}}
diff --git a/templates/user/include/header.tmpl b/templates/user/include/header.tmpl
index 2aeddb5..2e3dfcd 100644
--- a/templates/user/include/header.tmpl
+++ b/templates/user/include/header.tmpl
@@ -1,117 +1,129 @@
{{define "user-navigation"}}
<header class="{{if .SingleUser}}singleuser{{else}}multiuser{{end}}">
<nav id="full-nav">
{{if .SingleUser}}
<nav id="user-nav">
<nav class="dropdown-nav">
<ul><li><a href="/" title="View blog" class="title">{{.SiteName}}</a> <img class="ic-18dp" src="/img/ic_down_arrow_dark@2x.png" />
<ul>
{{if .IsAdmin}}<li><a href="/admin">Admin dashboard</a></li>{{end}}
<li><a href="/me/settings">Account settings</a></li>
<li><a href="/me/import">Import posts</a></li>
<li><a href="/me/export">Export</a></li>
<li class="separator"><hr /></li>
<li><a href="/me/logout">Log out</a></li>
</ul></li>
</ul>
</nav>
<nav class="tabs">
- <a href="/me/c/{{.UserPage.Username}}" {{if and (hasPrefix .Path "/me/c/") (hasSuffix .Path .UserPage.Username)}}class="selected"{{end}}>Customize</a>
- <a href="/me/c/{{.UserPage.Username}}/stats" {{if hasSuffix .Path "/stats"}}class="selected"{{end}}>Stats</a>
- <a href="/me/c/{{.UserPage.Username}}/subscribers" {{if hasSuffix .Path "/subscribers"}}class="selected"{{end}}>Subscribers</a>
+ <a href="/me/c/{{if .CollAlias}}{{.CollAlias}}{{else}}{{.Username}}{{end}}" {{if and (hasPrefix .Path "/me/c/") (or (and .CollAlias (hasSuffix .Path .CollAlias)) (and .Username (hasSuffix .Path .Username)))}}class="selected"{{end}}>Customize</a>
+ <a href="/me/c/{{if .CollAlias}}{{.CollAlias}}{{else}}{{.Username}}{{end}}/stats" {{if hasSuffix .Path "/stats"}}class="selected"{{end}}>Stats</a>
+ <a href="/me/c/{{if .CollAlias}}{{.CollAlias}}{{else}}{{.Username}}{{end}}/subscribers" {{if hasSuffix .Path "/subscribers"}}class="selected"{{end}}>Subscribers</a>
<a href="/me/posts/"{{if eq .Path "/me/posts/"}} class="selected"{{end}}>Drafts</a>
</nav>
</nav>
<div class="right-side">
+ <a class="global-theme-toggle" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
<a class="simple-btn" href="/me/new">New Post</a>
</div>
{{else}}
<div class="left-side">
<h1><a href="/" title="Return to editor">{{.SiteName}}</a></h1>
</div>
<nav id="user-nav">
{{if .UserPage.Username}}
<nav class="dropdown-nav">
<ul><li class="has-submenu"><a>{{.UserPage.Username}}</a> <img class="ic-18dp" src="/img/ic_down_arrow_dark@2x.png" /><ul>
{{if .IsAdmin}}<li><a href="/admin">Admin dashboard</a></li>{{end}}
<li><a href="/me/settings">Account settings</a></li>
<li><a href="/me/import">Import posts</a></li>
<li><a href="/me/export">Export</a></li>
{{if .CanInvite}}<li><a href="/me/invites">Invite people</a></li>{{end}}
<li class="separator"><hr /></li>
<li><a href="/me/logout">Log out</a></li>
</ul></li>
</ul>
</nav>
{{end}}
<nav class="tabs">
{{if .SimpleNav}}
{{ if not .SingleUser }}
{{if and (and .LocalTimeline .CanViewReader) .Chorus}}<a href="/"{{if eq .Path "/"}} class="selected"{{end}}>Home</a>{{end}}
{{ end }}
<a href="/about">About</a>
{{ if not .SingleUser }}
{{ if .UserPage.Username }}
{{if gt .MaxBlogs 1}}<a href="/me/c/"{{if eq .Path "/me/c/"}} class="selected"{{end}}>Blogs</a>{{end}}
{{if and .Chorus (eq .MaxBlogs 1)}}<a href="/{{.UserPage.Username}}/"{{if eq .Path (printf "/%s/" .UserPage.Username)}} class="selected"{{end}}>My Posts</a>{{end}}
{{if not .DisableDrafts}}<a href="/me/posts/"{{if eq .Path "/me/posts/"}} class="selected"{{end}}>Drafts</a>{{end}}
{{ end }}
{{if and (and .LocalTimeline .CanViewReader) (not .Chorus)}}<a href="/read">Reader</a>{{end}}
{{if and (and (and .Chorus .OpenRegistration) (not .UserPage.Username)) (or (not .Private) (ne .Landing ""))}}<a href="/signup"{{if eq .Path "/signup"}} class="selected"{{end}}>Sign up</a>{{end}}
{{if .UserPage.Username}}<a href="/me/logout">Log out</a>{{else}}<a href="/login">Log in</a>{{end}}
{{ end }}
{{else}}
<a href="/me/c/"{{if eq .Path "/me/c/"}} class="selected"{{end}}>Blogs</a>
{{if not .DisableDrafts}}<a href="/me/posts/"{{if eq .Path "/me/posts/"}} class="selected"{{end}}>Drafts</a>{{end}}
{{if and (and .LocalTimeline .CanViewReader) (not .Chorus)}}<a href="/read">Reader</a>{{end}}
{{end}}
</nav>
</nav>
{{if .UserPage.Username}}
<div class="right-side">
+ <a class="global-theme-toggle" href="#theme" title="Toggle theme" data-theme-toggle="true"><img class="ic-24dp" src="/img/ic_brightness_dark@2x.png" /></a>
<a class="simple-btn" href="/{{if .CollAlias}}#{{.CollAlias}}{{end}}">New Post</a>
</div>
{{end}}
{{end}}
</nav>
</header>
{{end}}
{{define "header"}}<!DOCTYPE HTML>
-<html>
+<html class="light">
<head>
<meta charset="utf-8">
<title>{{.PageTitle}} {{if .Separator}}{{.Separator}}{{else}}&mdash;{{end}} {{.SiteName}}</title>
+ <script type="text/javascript">
+ (function () {
+ var theme = localStorage.getItem('padTheme');
+ if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ theme = 'dark';
+ }
+ document.documentElement.classList.remove('light', 'dark');
+ document.documentElement.classList.add(theme || 'light');
+ })();
+ </script>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
{{if .CustomCSS}}<link rel="stylesheet" type="text/css" href="/local/custom.css" />{{end}}
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#888888" />
<meta name="apple-mobile-web-app-title" content="{{.SiteName}}">
<link rel="apple-touch-icon" sizes="152x152" href="/img/touch-icon-152.png">
<link rel="apple-touch-icon" sizes="167x167" href="/img/touch-icon-167.png">
<link rel="apple-touch-icon" sizes="180x180" href="/img/touch-icon-180.png">
</head>
<body id="me">
{{template "user-navigation" .}}
<div id="official-writing">
{{end}}
{{define "admin-header"}}
<header class="admin">
<h1>Admin</h1>
<nav id="admin" class="pager">
<a href="/admin" {{if eq .Path "/admin"}}class="selected"{{end}}>Dashboard</a>
<a href="/admin/settings" {{if eq .Path "/admin/settings"}}class="selected"{{end}}>Settings</a>
{{if not .SingleUser}}
<a href="/admin/users" {{if eq .Path "/admin/users"}}class="selected"{{end}}>Users</a>
<a href="/admin/pages" {{if eq .Path "/admin/pages"}}class="selected"{{end}}>Pages</a>
{{if .UpdateChecks}}<a href="/admin/updates" {{if eq .Path "/admin/updates"}}class="selected"{{end}}>Updates{{if .UpdateAvailable}}<span class="blip">!</span>{{end}}</a>{{end}}
{{end}}
{{if not .Forest}}
<a href="/admin/monitor" {{if eq .Path "/admin/monitor"}}class="selected"{{end}}>Monitor</a>
{{end}}
</nav>
</header>
{{end}}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jul 29, 7:04 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3785082

Event Timeline