summaryrefslogtreecommitdiff
path: root/web/template
diff options
context:
space:
mode:
Diffstat (limited to 'web/template')
-rw-r--r--web/template/404.tmpl40
-rw-r--r--web/template/about.tmpl220
-rw-r--r--web/template/authorize.tmpl44
-rw-r--r--web/template/confirmed.tmpl13
-rw-r--r--web/template/domain-blocklist.tmpl62
-rw-r--r--web/template/error.tmpl22
-rw-r--r--web/template/finalize.tmpl59
-rw-r--r--web/template/frontend.tmpl7
-rw-r--r--web/template/header.tmpl122
-rw-r--r--web/template/index.tmpl74
-rw-r--r--web/template/index_apps.tmpl115
-rw-r--r--web/template/oob.tmpl14
-rw-r--r--web/template/page.tmpl85
-rw-r--r--web/template/page_footer.tmpl67
-rw-r--r--web/template/page_header.tmpl72
-rw-r--r--web/template/page_ogmeta.tmpl57
-rw-r--r--web/template/page_stylesheets.tmpl41
-rw-r--r--web/template/profile.tmpl242
-rw-r--r--web/template/profile_fields.tmpl (renamed from web/template/footer.tmpl)40
-rw-r--r--web/template/sign-in.tmpl10
-rw-r--r--web/template/status.tmpl154
-rw-r--r--web/template/status_attachments.tmpl184
-rw-r--r--web/template/status_attributes.tmpl55
-rw-r--r--web/template/status_header.tmpl56
-rw-r--r--web/template/status_info.tmpl74
-rw-r--r--web/template/status_poll.tmpl105
-rw-r--r--web/template/tag.tmpl16
-rw-r--r--web/template/thread.tmpl59
28 files changed, 1320 insertions, 789 deletions
diff --git a/web/template/404.tmpl b/web/template/404.tmpl
index 2269d667b..cbad36091 100644
--- a/web/template/404.tmpl
+++ b/web/template/404.tmpl
@@ -17,23 +17,27 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section>
- <h1>404: Page Not Found</h1>
- <p>
- GoToSocial only serves Public statuses via the web.
- If you reached this page by clicking on a status link,
- it's possible that the status is not Public, has been
- deleted by the author, you don't have permission to see
- it, or it just doesn't exist at all.
- </p>
- <p>
- If you believe this 404 was an error, you can contact
- the instance admin. Provide them with the following request
- Request ID: <code>{{.requestID}}</code>.
- </p>
- </section>
+ <section>
+ <h1>404: Not Found</h1>
+ <p>
+ GoToSocial only serves Public statuses via the web.
+ </p>
+ <p>
+ If you reached this page by clicking on a status link,
+ it's likely that the status is not Public. You can try
+ entering the status URL in your client's search bar,
+ to view the status from your account. If that doesn't
+ work, it's possible that the status has been deleted by
+ the author, you don't have permission to view it, or it
+ doesn't exist at all.
+ </p>
+ <p>
+ If you believe this 404 was an error, you can contact
+ the instance admin. Provide them with the following
+ request ID: <code>{{- .requestID -}}</code>.
+ </p>
+ </section>
</main>
-
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/about.tmpl b/web/template/about.tmpl
index 6579f492f..a23dfa953 100644
--- a/web/template/about.tmpl
+++ b/web/template/about.tmpl
@@ -17,105 +17,133 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
-<main>
- <section class="about">
- <h1>About</h1>
- <div>
- {{.instance.Description |noescape}}
- </div>
+{{- define "description" -}}
+{{- if .instance.Description }}
+{{ .instance.Description | noescape }}
+{{- else }}
+<p>No description has yet been set for this instance.<p>
+{{- end }}
+{{- end -}}
- <div>
- <h2 id="languages">Languages</h2>
- <p>
- {{ if .languages }}
- This instance prefers the following languages:
- <ol>
- {{range .languages}}
- <li>{{.}}</li>
- {{end}}
- </ol>
- {{ else }}
- This instance does not have any preferred languages.
- {{ end }}
- </p>
- </div>
+{{- define "registrationLimits" -}}
+{{- if .instance.Registrations -}}
+ Registration is enabled; new signups can be submitted to this instance.<br/>
+ {{- if .instance.ApprovalRequired -}}
+ Admin approval is required for new registrations.
+ {{- else -}}
+ Admin approval is not required for registrations; new signups will be automatically approved (pending email confirmation).
+ {{- end -}}
+{{- else -}}
+ Registration is disabled; new signups are currently closed for this instance.
+{{- end -}}
+{{- end -}}
- <div>
- <h2 id="contact">Admin Contact</h2>
- {{if .instance.ContactAccount}}
- <a href="{{.instance.ContactAccount.URL}}" class="account-card">
- <img class="avatar" src="{{.instance.ContactAccount.Avatar}}" alt="" />
- <h3>
- {{if .instance.ContactAccount.DisplayName}}{{emojify .instance.ContactAccount.Emojis (escape .instance.ContactAccount.DisplayName)}}{{else}}{{.instance.ContactAccount.Username}}{{end}}
- </h3>
- <span>@{{.instance.ContactAccount.Username}}</span>
- </a><br />
- {{end}}
- {{if .instance.Email}}
- Email: <a href="mailto:{{.instance.Email}}">{{.instance.Email}}</a>
- {{end}}
- </div>
+{{- define "customCSSLimits" -}}
+{{- if .instance.Configuration.Accounts.AllowCustomCSS -}}
+Users are allowed to set <a href="https://docs.gotosocial.org/en/latest/user_guide/custom_css/" target="_blank" rel="noopener noreferrer">Custom CSS</a> for their profiles.
+{{- else -}}
+<a href="https://docs.gotosocial.org/en/latest/user_guide/custom_css/" target="_blank" rel="noopener noreferrer">Custom CSS</a> is not enabled for user profiles.
+{{- end -}}
+{{- end -}}
- <div>
- <h2 id="rules">Rules</h2>
- <ol>
- {{range .instance.Rules}}
- <li>{{.Text}}</li>
- {{end}}
- </ol>
- </div>
+{{- define "statusLimits" -}}
+Statuses can contain up to&nbsp;
+{{- .instance.Configuration.Statuses.MaxCharacters }} characters, and&nbsp;
+{{- .instance.Configuration.Statuses.MaxMediaAttachments }} media attachments.
+{{- end -}}
- <div>
- <h2 id="features">Features</h2>
- <ul>
- <li>
- Registration is
- {{if .instance.Registrations}}
- enabled{{if .instance.ApprovalRequired}}, but requires admin approval{{end}}.
- {{else}}
- disabled.
- {{end}}
- </li>
- {{if .instance.Configuration.Accounts.AllowCustomCSS}}
- <li>
- Users are allowed to set <a href="https://docs.gotosocial.org/en/latest/user_guide/custom_css/"
- target="_blank" rel="noopener noreferrer">Custom CSS</a> for their profiles.
- </li>
- {{end}}
- <li>
- Toots can contain up to {{.instance.Configuration.Statuses.MaxCharacters}} characters and
- {{.instance.Configuration.Statuses.MaxMediaAttachments}} media attachments.
- </li>
- <li>
- Polls can have up to {{.instance.Configuration.Polls.MaxOptions}} options, with
- {{.instance.Configuration.Polls.MaxCharactersPerOption}} characters each.
- </li>
- </ul>
- </div>
+{{- define "pollLimits" -}}
+Polls can have up to&nbsp;
+{{- .instance.Configuration.Polls.MaxOptions }} options, with&nbsp;
+{{- .instance.Configuration.Polls.MaxCharactersPerOption }} characters per option.
+{{- end -}}
- <div>
- <h2 id="moderated-servers">Moderated servers</h2>
- <p>
- ActivityPub instances exchange (federate) data with other instances, including accounts and toots.
- This can be prevented for specific domains by suspending them. None of their content is stored,
- and interaction with their users is blocked both ways.</br>
- {{if .blocklistExposed}}
- <a href="/about/suspended">View the list of suspended domains</a>
- {{else}}
- This instance does not publically share this list.
- {{end}}
- </p>
- </div>
-
- <div>
- <h2 id="stats">Instance Statistics</h2>
- <ul>
- <li>Users: <span class="count">{{.instance.Stats.user_count}}</span></li>
- <li>Posts: <span class="count">{{.instance.Stats.status_count}}</span></li>
- <li>Federates with: <span class="count">{{.instance.Stats.domain_count}}</span> instances</li>
- </ul>
- </div>
- </section>
+{{- with . }}
+<main class="about">
+ <section class="about-section" role="region" aria-labelledby="about">
+ <h3 id="about">About {{ .instance.Title -}}</h3>
+ {{- with . }}
+ {{- include "description" . | indent 2 }}
+ {{- end }}
+ </section>
+ <section class="about-section" role="region" aria-labelledby="contact">
+ <h3 id="contact">Admin Contact</h3>
+ {{- if .instance.ContactAccount }}
+ <a href="{{- .instance.ContactAccount.URL -}}" class="account-card">
+ <img class="avatar" src="{{- .instance.ContactAccount.Avatar -}}" alt=""/>
+ <h3>
+ {{- if .instance.ContactAccount.DisplayName -}}
+ {{- emojify .instance.ContactAccount.Emojis (escape .instance.ContactAccount.DisplayName) -}}
+ {{- else -}}
+ {{- .instance.ContactAccount.Username -}}
+ {{- end -}}
+ </h3>
+ <span>@{{- .instance.ContactAccount.Username -}}</span>
+ </a>
+ {{- else }}
+ <p>This instance has not yet set a contact account.</p>
+ {{- end }}
+ {{- if .instance.Email }}
+ <p>Email: <a href="mailto:{{- .instance.Email -}}">{{- .instance.Email -}}</a></p>
+ {{- else }}
+ <p>This instance has not yet set a contact email address.</p>
+ {{- end }}
+ </section>
+ <section class="about-section" role="region" aria-labelledby="languages">
+ <h3 id="languages">Languages</h3>
+ {{- if .languages }}
+ <p>This instance prefers the following languages:</p>
+ <ol>
+ {{- range .languages }}
+ <li>{{- . -}}</li>
+ {{- end }}
+ </ol>
+ {{- else }}
+ <p>This instance does not have any preferred languages.</p>
+ {{- end }}
+ </section>
+ <section class="about-section" role="region" aria-labelledby="rules">
+ <h3 id="rules">Instance Rules</h3>
+ <p>This instance has the following rules:</p>
+ {{- if .instance.Rules }}
+ <ol>
+ {{- range .instance.Rules }}
+ <li>{{- .Text -}}</li>
+ {{- end }}
+ </ol>
+ {{- else }}
+ <p>This instance has not yet set any rules.</p>
+ {{- end }}
+ </section>
+ <section class="about-section" role="region" aria-labelledby="features">
+ <h3 id="features">Instance Features</h3>
+ <ul>
+ <li>{{- template "registrationLimits" . -}}</li>
+ <li>{{- template "customCSSLimits" . -}}</li>
+ <li>{{- template "statusLimits" . -}}</li>
+ <li>{{- template "pollLimits" . -}}</li>
+ </ul>
+ </section>
+ <section class="about-section" role="region" aria-labelledby="moderated-servers">
+ <h3 id="moderated-servers">Moderated servers</h3>
+ <p>
+ ActivityPub instances federate with other instances by exchanging data with them over the network.
+ Exchanged data includes things like accounts, statuses, likes, boosts, and media attachments.
+ This exchange of data can prevented for instances on specific domains via a domain block created
+ by an instance admin. When an instance is domain blocked by another instance:
+ </p>
+ <ul>
+ <li>Any existing data from the blocked instance is deleted from the storage of the instance doing the blocking.</li>
+ <li>Interaction between the two instances is cut off in both directions; neither instance can interact with the other.</li>
+ <li>No new data from the blocked instance will be created on the instance that blocks it.</li>
+ </ul>
+ <p>
+ {{- if .blocklistExposed }}
+ <a href="/about/suspended">View the list of domains blocked by this instance</a>
+ {{- else }}
+ This instance does not publically share their list of blocked domains.
+ {{- end }}
+ </p>
+ </section>
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/authorize.tmpl b/web/template/authorize.tmpl
index ada078968..9be094137 100644
--- a/web/template/authorize.tmpl
+++ b/web/template/authorize.tmpl
@@ -17,26 +17,24 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
- <main>
- <form action="/oauth/authorize" method="POST">
- <h1>Hi {{.user}}!</h1>
- <p>
- Application <b>{{.appname}}</b>
- {{if len .appwebsite | eq 0 | not}}
- ({{.appwebsite}})
- {{end}}
- would like to perform actions on your behalf, with scope <em>{{.scope}}</em>.
- </p>
- <p>The application will redirect to {{.redirect}} to continue.</p>
- <p>
- <button
- type="submit"
- style="width:200px;"
- >
- Allow
- </button>
- </p>
- </form>
- </main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- with . }}
+<main>
+ <form action="/oauth/authorize" method="POST">
+ <h1>Hi {{ .user -}}!</h1>
+ <p>
+ Application
+ {{- if .appwebsite }}
+ <a href="{{- .appwebsite -}}" rel="nofollow noreferrer noopener" target="_blank">{{- .appname -}}</a>
+ {{- else }}
+ <b>{{- .appname -}}</b>
+ {{- end }}
+ would like to perform actions on your behalf, with scope
+ <em>{{- .scope -}}</em>.
+ </p>
+ <p>
+ To continue, the application will redirect to: <code>{{- .redirect -}}</code>
+ </p>
+ <button type="submit" style="width:200px;">Allow</button>
+ </form>
+</main>
+{{- end }} \ No newline at end of file
diff --git a/web/template/confirmed.tmpl b/web/template/confirmed.tmpl
index 3cf5b7ac9..c1633a8fb 100644
--- a/web/template/confirmed.tmpl
+++ b/web/template/confirmed.tmpl
@@ -17,12 +17,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section>
- <h1>Email Address Confirmed</h1>
- <p>Thanks {{.username}}! Your email address <b>{{.email}}</b> has been confirmed.<p>
- </section>
+ <section>
+ <h1>Email Address Confirmed</h1>
+ <p>Thanks {{ .username -}}! Your email address <b>{{- .email -}}</b> has been confirmed.<p>
+ </section>
</main>
-
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/domain-blocklist.tmpl b/web/template/domain-blocklist.tmpl
index def1b990e..9a21796f9 100644
--- a/web/template/domain-blocklist.tmpl
+++ b/web/template/domain-blocklist.tmpl
@@ -17,36 +17,36 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section>
- <h1>Suspended Instances</h1>
- <p>
- The following list of domains have been suspended by the administrator(s) of this server.
- </p>
- <p>
- All current and future accounts on these instances are blocked, and no more data is federated to the remote
- servers.
- This extends to subdomains, so an entry for 'example.com' includes 'social.example.com' as well.
- </p>
- <div class="list domain-blocklist">
- <div class="header entry">
- <div class="domain">Domain</div>
- <div class="public_comment">Public comment</div>
- </div>
- {{range .blocklist}}
- <div class="entry" id="{{.Domain}}">
- <div class="domain">
- <a class="text-cutoff" href="#{{.Domain}}" title="{{.Domain}}">{{.Domain}}</a>
- </div>
- <div class="public_comment">
- <p>
- {{.PublicComment}}
- </p>
- </div>
- </div>
- {{end}}
- </div>
- </section>
+ <section>
+ <h1>Suspended Instances</h1>
+ <p>
+ The following list of domains have been suspended
+ by the administrator(s) of this server.
+ </p>
+ <p>
+ All current and future accounts on these instances are
+ blocked, and no more data is federated to the remote servers.
+ This extends to subdomains, so an entry for 'example.com'
+ includes 'social.example.com' as well.
+ </p>
+ <div class="list domain-blocklist">
+ <div class="header entry">
+ <div class="domain">Domain</div>
+ <div class="public_comment">Public comment</div>
+ </div>
+ {{- range .blocklist }}
+ <div class="entry" id="{{- .Domain -}}">
+ <div class="domain">
+ <a class="text-cutoff" href="#{{- .Domain -}}" title="{{- .Domain -}}">{{- .Domain -}}</a>
+ </div>
+ <div class="public_comment">
+ <p>{{- .PublicComment -}}</p>
+ </div>
+ </div>
+ {{- end }}
+ </div>
+ </section>
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/error.tmpl b/web/template/error.tmpl
index dc0713e43..816062e27 100644
--- a/web/template/error.tmpl
+++ b/web/template/error.tmpl
@@ -17,16 +17,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section class="error">
- <h1>An error occured:</h1>
- <pre>{{.error}}</pre>
- {{if .requestID}}
- <div>
- <span>Request ID:</span> <code>{{.requestID}}</code>
- </div>
- {{end}}
- </section>
+ <section class="error">
+ <h1>An error occured:</h1>
+ <pre>{{- .error -}}</pre>
+ {{- if .requestID }}
+ <div>
+ <span>Request ID:</span> <code>{{- .requestID -}}</code>
+ </div>
+ {{- end }}
+ </section>
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/finalize.tmpl b/web/template/finalize.tmpl
index e0d880db7..56ab677e5 100644
--- a/web/template/finalize.tmpl
+++ b/web/template/finalize.tmpl
@@ -17,34 +17,31 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
- <main>
- <form action="/oauth/finalize" method="POST">
- <h1>Hi {{.name}}!</h1>
- <p>
- You are about to sign-up to {{ .instance.Title }} (<code>{{ .instance.URI }}</code>)
- <br>
- To ensure the best experience for you, we need you to provide some additional details.
- </p>
- {{if .error}}
- <section class="error">
- <span>❌</span> <pre>{{.error}}</pre>
- </section>
- {{end}}
- <div class="callout">
- <p class="callout-title">Important</p>
- <p>Due to the way the ActivityPub standard works, you <strong>cannot</strong> change your username after it has been set.</p>
- </div>
- <div class="labelinput">
- <label for="username">Username <small>(must contain only lowercase letters, numbers, and underscores)</small></label>
- <input type="text"
- class="form-control"
- name="username"
- required
- placeholder="Please enter your desired username" value="{{ .preferredUsername }}">
- </div>
- <input type="hidden" name="name" value="{{ .name }}">
- <button type="submit" style="width: 100%; margin-top: 1rem;" class="btn btn-success">Submit</button>
- </form>
- </main>
-{{ template "footer.tmpl" .}}
+{{- with . }}
+<main>
+ <form action="/oauth/finalize" method="POST">
+ <h1>Hi {{ .name -}}!</h1>
+ <p>
+ You are about to sign-up to {{ .instance.Title -}}.
+ To ensure the best experience for you, we need you to provide some additional details.
+ </p>
+ <div class="callout">
+ <p class="callout-title">Important</p>
+ <p>Due to the way the ActivityPub standard works, you <strong>cannot</strong> change your username after it has been set.</p>
+ </div>
+ <div class="labelinput">
+ <label for="username">Username <small>(must contain only lowercase letters, numbers, and underscores)</small></label>
+ <input
+ type="text"
+ class="form-control"
+ name="username"
+ required
+ placeholder="Please enter your desired username"
+ value="{{- .preferredUsername -}}"
+ >
+ </div>
+ <input type="hidden" name="name" value="{{- .name -}}">
+ <button type="submit" style="width: 100%; margin-top: 1rem;" class="btn btn-success">Submit</button>
+ </form>
+</main>
+{{- end }} \ No newline at end of file
diff --git a/web/template/frontend.tmpl b/web/template/frontend.tmpl
index 977a7fab4..8e5267f4a 100644
--- a/web/template/frontend.tmpl
+++ b/web/template/frontend.tmpl
@@ -17,9 +17,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main class="lightgray">
- <div id="root">
- </div>
+ <div id="root"></div>
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/header.tmpl b/web/template/header.tmpl
deleted file mode 100644
index 2759ab804..000000000
--- a/web/template/header.tmpl
+++ /dev/null
@@ -1,122 +0,0 @@
-{{- /*
-// GoToSocial
-// Copyright (C) GoToSocial Authors admin@gotosocial.org
-// SPDX-License-Identifier: AGPL-3.0-or-later
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/ -}}
-
-
-{{- /*
- NESTED TEMPLATE DECLARATIONS
- If some if/else macro is used multiple times, declare it once here instead.
- When invoking these nested templates, remember to pass in the values passed
- to the executing template, ie., use '{{ template "example" . }}' not
- '{{ template "example" }}', otherwise you'll end up with empty variables.
-*/ -}}
-{{ define "thumbnailType" }}{{ if .instance.ThumbnailType }}{{ .instance.ThumbnailType }}{{ else }}image/png{{ end }}{{ end }}
-{{ define "instanceTitle" }}{{ if .ogMeta }}{{ .ogMeta.Title }}{{ else }}{{ .instance.Title }} - GoToSocial{{ end }}{{ end }}
-
-{{- /*
- BOILERPLATE GOES HERE
-*/ -}}
-<!DOCTYPE html>
-<!-- header.tmpl -->
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
-
- {{- /*
- ROBOTS META TAGS
- If this template was provided with a specific robots meta policy, use that.
- Otherwise, fall back to a default restrictive policy.
- See: https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
- */ -}}
- <meta name="robots" content="{{ if .robotsMeta }}{{ .robotsMeta }}{{ else }}noindex, nofollow{{ end }}">
-
- {{- /*
- OPEN GRAPH META TAGS
- To enable fancy previews of links to GtS posts/profiles shared via instant
- messaging, or other social media, parse out provided Open Graph meta tags.
- */ -}}
- {{ if .ogMeta -}}
- {{ if .ogMeta.Locale }}<meta name="og:locale" content="{{ .ogMeta.Locale }}">{{ end }}
- <meta property="og:type" content="{{ .ogMeta.Type }}">
- <meta property="og:title" content="{{ .ogMeta.Title }}">
- <meta property="og:url" content="{{ .ogMeta.URL }}">
- <meta property="og:site_name" content="{{ .ogMeta.SiteName }}">
- <meta property="og:description" {{ .ogMeta.Description | noescapeAttr }}>
- {{ if .ogMeta.ArticlePublisher }}
- <meta property="og:article:publisher" content="{{ .ogMeta.ArticlePublisher }}">
- <meta property="og:article:author" content="{{ .ogMeta.ArticleAuthor }}">
- <meta property="og:article:modified_time" content="{{ .ogMeta.ArticleModifiedTime }}">
- <meta property="og:article:published_time" content="{{ .ogMeta.ArticlePublishedTime }}">
- {{ end }}
- {{ if .ogMeta.ProfileUsername }}<meta property="og:profile:username" content="{{ .ogMeta.ProfileUsername }}">{{ end }}
- <meta property="og:image" content="{{ .ogMeta.Image }}">
- {{ if .ogMeta.ImageAlt }}<meta property="og:image:alt" content="{{ .ogMeta.ImageAlt }}">{{ end }}
- {{ if .ogMeta.ImageWidth }}
- <meta property="og:image:width" content="{{ .ogMeta.ImageWidth }}">
- <meta property="og:image:height" content="{{ .ogMeta.ImageHeight }}">
- {{ end }}
- {{- end }}
-
- {{- /*
- ICON
- For icon, provide a link to the instance thumbnail. If the instance admin has
- set a custom thumbnail, use the type they uploaded, else assume image/png.
- See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel#icon
- */ -}}
- <link rel="icon" href="{{ .instance.Thumbnail }}" type="{{ template "thumbnailType" . }}">
- <link rel="apple-touch-icon" href="{{ .instance.Thumbnail }}" type="{{ template "thumbnailType" . }}">
- <link rel="apple-touch-startup-image" href="{{ .instance.Thumbnail }}" type="{{ template "thumbnailType" . }}">
-
- {{- /*
- RSS FEED
- To enable automatic rss feed discovery for feed readers, provide the 'alternate'
- link only if rss is enabled.
- See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel#alternate
- */ -}}
- {{ if .rssFeed -}}
- <link rel="alternate" type="application/rss+xml" href="{{ .rssFeed }}" title="{{ template "instanceTitle" . }}">
- {{- end }}
-
- {{- /*
- STYLESHEET STUFF
- To try to speed up rendering a little bit, offer a preload for each stylesheet.
- See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload.
- */ -}}
- <link rel="preload" href="/assets/dist/_colors.css" as="style">
- <link rel="preload" href="/assets/dist/base.css" as="style">
- {{ range .stylesheets }}<link rel="preload" href="{{ . }}" as="style">{{ end }}
- <link rel="stylesheet" href="/assets/dist/_colors.css">
- <link rel="stylesheet" href="/assets/dist/base.css">
- {{ range .stylesheets }}<link rel="stylesheet" href="{{ . }}">{{ end }}
- <title>{{ template "instanceTitle" . }}</title>
-</head>
-
-<body>
- <div class="page">
- <header>
- <a aria-label="{{ .instance.Title }}. Go to instance homepage" href="/" class="nounderline header">
- <img src="{{ .instance.Thumbnail }}"
- alt="{{ if .instance.ThumbnailDescription }}{{ .instance.ThumbnailDescription }}{{ else }}Instance Logo{{ end }}" />
- <h1>
- {{ .instance.Title }}
- </h1>
- </a>
- </header>
- <div class="content"> \ No newline at end of file
diff --git a/web/template/index.tmpl b/web/template/index.tmpl
index 665ce7a7e..f27cf8570 100644
--- a/web/template/index.tmpl
+++ b/web/template/index.tmpl
@@ -17,61 +17,21 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
-<section class="excerpt-top">
- home to <span class="count">{{.instance.Stats.user_count}}</span> users
- who posted <span class="count">{{.instance.Stats.status_count}}</span> statuses,
- federating with <span class="count">{{.instance.Stats.domain_count}}</span> other instances.
-</section>
-<main class="lightgray">
- <section>
- <div className="short-description">
- {{.instance.ShortDescription |noescape}}
- </div>
- </section>
- <section class="apps">
- <p>
- GoToSocial does not provide its own webclient, but implements the Mastodon client API.
- You can use this server through a variety of other clients:
- </p>
- <div class="applist">
- <div class="entry">
- <svg role="img" aria-labelledby="semaphoreTitle semaphoreDesc" class="logo redraw" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 146 120">
- <title id="semaphoreTitle">The Semaphore logo</title>
- <desc id="semaphoreDesc">A waving flag</desc>
- <path d="M68.13 0C53.94 0 42.81 20 13.9 27.1l-2.23-5.29a6.5 6.5 0 0 0-5.17-10.4 6.5 6.5 0 0 0-.81 12.95L46.2 120l5.99-2.5-14.42-33.33c22.8-6.86 32.51-22.16 49.83-20.58 9.9.9 4.87 19.56 8.11 17.93 16.22-8.15 32.44-11.41 50.29-11.41-7.96-9.78-17.38-20.55-22.71-31.74L120.8 32c-2.32-7.33-2.56-14.75.87-22.22-9.74-3.26-21.1 0-32.45 4.9C82.2 9.77 79.5 0 68.13 0zM15.26 30.42c8.95 6.63 13.63 13.86 16.07 20.94l1.62 6.32c1.24 6.58 1.07 12.8 1.27 18.03z"></path>
- </svg>
- <div>
- <h2>Semaphore</h2>
- <p>Semaphore is a web client designed for speed and simplicity.</p>
- <a href="https://semaphore.social/" target="_blank" rel="noopener">Use Semaphore</a>
- </div>
- </div>
- <div class="entry">
- <img class="logo" src="/assets/tusky.svg" alt="The Tusky mascot, a cartoon elephant tooting happily"/>
- <div>
- <h2>Tusky</h2>
- <p>Tusky is a lightweight mobile client for Android.</p>
- <a href="https://tusky.app" target="_blank" rel="noopener">Get Tusky</a>
- </div>
- </div>
- <div class="entry">
- <img class="logo" src="/assets/feditext.svg" alt="The Feditext logo, the characters ft at a slight angle">
- <div>
- <h2>Feditext</h2>
- <p>Feditext (beta) is a beautiful client for iOS, iPadOS and macOS.</p>
- <a href="https://fedi.software/@Feditext" target="_blank" rel="noopener">Get Feditext</a>
- </div>
- </div>
- <div class="entry">
- <img class="logo" src="/assets/mastodon.svg" alt="The Mastodon logo, the character M in a speech bubble">
- <div>
- <h2>More clients</h2>
- <p>Or try one of the clients listed on the official Mastodon page.</p>
- <a href="https://joinmastodon.org/apps" target="_blank" rel="noopener">Get Mastodon apps</a>
- </div>
- </div>
- </div>
- </section>
+{{- define "shortDescription" -}}
+{{- if .instance.ShortDescription }}
+{{ .instance.ShortDescription | noescape }}
+{{- else }}
+<p>No short description has yet been set for this instance.<p>
+{{- end }}
+{{- end -}}
+
+{{- with . }}
+<main class="about">
+ <section class="about-section" role="region" aria-labelledby="about">
+ <h3 id="about">About this instance</h3>
+ {{- include "shortDescription" . | indent 2 }}
+ <a href="/about">See more details</a>
+ </section>
+ {{- include "index_apps.tmpl" . | indent 1 }}
</main>
-{{ template "footer.tmpl" .}}
+{{- end }} \ No newline at end of file
diff --git a/web/template/index_apps.tmpl b/web/template/index_apps.tmpl
new file mode 100644
index 000000000..05a4a9517
--- /dev/null
+++ b/web/template/index_apps.tmpl
@@ -0,0 +1,115 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- with . }}
+<section role="region" class="about-section apps" aria-labelledby="apps">
+ <h3 id="apps">Client applications</h3>
+ <p>
+ GoToSocial does not provide its own webclient, but implements the Mastodon client API.
+ You can use this server through a variety of other clients:
+ </p>
+ <ul class="applist nodot" role="group">
+ <li class="applist-entry">
+ <div class="applist-text">
+ <p><strong>Semaphore</strong> is a web client designed for speed and simplicity.</p>
+ <a
+ href="https://semaphore.social/"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ Use Semaphore
+ </a>
+ </div>
+ <svg
+ role="img"
+ aria-labelledby="semaphore-title semaphore-desc"
+ class="applist-logo redraw"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 146 120"
+ width="100"
+ height="100"
+ >
+ <title id="semaphore-title">The Semaphore logo</title>
+ <desc id="semaphore-desc">A waving flag</desc>
+ <path d="M68.13 0C53.94 0 42.81 20 13.9 27.1l-2.23-5.29a6.5 6.5 0 0 0-5.17-10.4 6.5 6.5 0 0 0-.81 12.95L46.2 120l5.99-2.5-14.42-33.33c22.8-6.86 32.51-22.16 49.83-20.58 9.9.9 4.87 19.56 8.11 17.93 16.22-8.15 32.44-11.41 50.29-11.41-7.96-9.78-17.38-20.55-22.71-31.74L120.8 32c-2.32-7.33-2.56-14.75.87-22.22-9.74-3.26-21.1 0-32.45 4.9C82.2 9.77 79.5 0 68.13 0zM15.26 30.42c8.95 6.63 13.63 13.86 16.07 20.94l1.62 6.32c1.24 6.58 1.07 12.8 1.27 18.03z"></path>
+ </svg>
+ </li>
+ <li class="applist-entry">
+ <div class="applist-text">
+ <p><strong>Tusky</strong> is a lightweight mobile client for Android.</p>
+ <a
+ href="https://tusky.app"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ Get Tusky
+ </a>
+ </div>
+ <img
+ class="applist-logo"
+ src="/assets/tusky.svg"
+ alt="The Tusky mascot, a cartoon elephant tooting happily"
+ title="The Tusky mascot, a cartoon elephant tooting happily"
+ width="100"
+ height="100"
+ />
+ </li>
+ <li class="applist-entry">
+ <div class="applist-text">
+ <p><strong>Feditext</strong> (beta) is a beautiful client for iOS, iPadOS and macOS.</p>
+ <a
+ href="https://fedi.software/@Feditext"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ Get Feditext
+ </a>
+ </div>
+ <img
+ class="applist-logo"
+ src="/assets/feditext.svg"
+ alt="The Feditext logo, the characters 'ft' at a slight angle"
+ title="The Feditext logo, the characters 'ft' at a slight angle"
+ width="100"
+ height="100"
+ />
+ </li>
+ <li class="applist-entry">
+ <div class="applist-text">
+ <p>Or try one of the <strong>Mastodon clients</strong> listed on the official Mastodon page.</p>
+ <a
+ href="https://joinmastodon.org/apps"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ Get Mastodon apps
+ </a>
+ </div>
+ <img
+ class="applist-logo"
+ src="/assets/mastodon.svg"
+ alt="The Mastodon logo, the character 'M' in a speech bubble"
+ title="The Mastodon logo, the character 'M' in a speech bubble"
+ width="100"
+ height="100"
+ />
+ </li>
+ </ul>
+</section>
+{{- end }} \ No newline at end of file
diff --git a/web/template/oob.tmpl b/web/template/oob.tmpl
index 0f183c350..ff36582e7 100644
--- a/web/template/oob.tmpl
+++ b/web/template/oob.tmpl
@@ -17,12 +17,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section class="oob-token">
- <h1>Hi {{ .user }}!</h1>
- <p>Here's your out-of-band token with scope "<em>{{.scope}}</em>", use it wisely:</p>
- <code>{{ .oobToken }}</code>
- </section>
+ <section class="oob-token">
+ <h1>Hi {{ .user -}}!</h1>
+ <p>Here's your out-of-band token with scope "<em>{{- .scope -}}</em>", use it wisely:</p>
+ <code>{{- .oobToken -}}</code>
+ </section>
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/page.tmpl b/web/template/page.tmpl
new file mode 100644
index 000000000..347caf33e
--- /dev/null
+++ b/web/template/page.tmpl
@@ -0,0 +1,85 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- /*
+ NESTED TEMPLATE DECLARATIONS
+ If some if/else macro is used multiple times, declare it once here instead.
+ When invoking these nested templates, remember to pass in the values passed
+ to the executing template, ie., use '{{ template "example" . }}' not
+ '{{ template "example" }}', otherwise you'll end up with empty variables.
+*/ -}}
+
+{{- define "thumbnailType" -}}
+{{- if .instance.ThumbnailType -}}
+{{- .instance.ThumbnailType -}}
+{{- else -}}
+image/png
+{{- end -}}
+{{- end -}}
+
+{{- define "instanceTitle" -}}
+{{- if .ogMeta -}}
+{{- demojify .ogMeta.Title | noescape -}}
+{{- else -}}
+{{- .instance.Title }} - GoToSocial
+{{- end -}}
+{{- end -}}
+
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="robots" content="{{- if .robotsMeta -}}{{- .robotsMeta -}}{{- else -}}noindex, nofollow{{- end -}}">
+ {{- if .ogMeta }}
+ {{- include "page_ogmeta.tmpl" . | indent 2 }}
+ {{- else }}
+ {{- end }}
+ {{- if .rssFeed }}
+ <link rel="alternate" type="application/rss+xml" href="{{- .rssFeed -}}" title="{{- template "instanceTitle" . -}}">
+ {{- else }}
+ {{- end }}
+ {{- if .account }}
+ <link rel="alternate" type="application/activity+json" href="/users/{{- .account.Username -}}">
+ {{- else if .status }}
+ <link rel="alternate" type="application/activity+json" href="/users/{{- .status.Account.Username -}}/statuses/{{- .status.ID -}}">
+ {{- else }}
+ {{- end }}
+ <link rel="icon" href="{{- .instance.Thumbnail -}}" type="{{- template "thumbnailType" . -}}">
+ <link rel="apple-touch-icon" href="{{- .instance.Thumbnail -}}" type="{{- template "thumbnailType" . -}}">
+ <link rel="apple-touch-startup-image" href="{{- .instance.Thumbnail -}}" type="{{- template "thumbnailType" . -}}">
+ {{- include "page_stylesheets.tmpl" . | indent 2 }}
+ {{- range .javascript }}
+ <script type="text/javascript" src="{{- . -}}" async="" defer=""></script>
+ {{- end }}
+ <title>{{- template "instanceTitle" . -}}</title>
+ </head>
+ <body class="page">
+ <header class="page-header">
+ {{- include "page_header.tmpl" . | indent 3 }}
+ </header>
+ <div class="page-content">
+ {{- include .pageContent . | indent 3 | outdentPre }}
+ </div>
+ <footer class="page-footer">
+ {{- include "page_footer.tmpl" . | indent 3 }}
+ </footer>
+ </body>
+</html> \ No newline at end of file
diff --git a/web/template/page_footer.tmpl b/web/template/page_footer.tmpl
new file mode 100644
index 000000000..a00f4dfde
--- /dev/null
+++ b/web/template/page_footer.tmpl
@@ -0,0 +1,67 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- with . }}
+<nav>
+ <ul class="nodot">
+ <li id="about">
+ <a
+ href="/about"
+ class="nounderline"
+ >
+ About {{ .instance.Title }}
+ </a>
+ </li>
+ <li id="version">
+ <a
+ href="https://github.com/superseriousbusiness/gotosocial"
+ class="nounderline"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ <span aria-hidden="true">🦥</span>
+ Source - GoToSocial {{ .instance.Version }}
+ <span aria-hidden="true">🦥</span>
+ </a>
+ </li>
+ {{- if .instance.ContactAccount }}
+ <li id="contact">
+ <a
+ href="/@{{- .instance.ContactAccount.Username -}}"
+ class="nounderline"
+ >
+ Contact account - {{ .instance.ContactAccount.Username }}
+ </a>
+ </li>
+ {{- end }}
+ {{- if .instance.Email }}
+ <li id="email">
+ <a
+ href="mailto:{{- .instance.Email -}}"
+ class="nounderline"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ >
+ Email - {{ .instance.Email }}
+ </a>
+ </li>
+ {{- end }}
+ </ul>
+</nav>
+{{- end }} \ No newline at end of file
diff --git a/web/template/page_header.tmpl b/web/template/page_header.tmpl
new file mode 100644
index 000000000..dc727d144
--- /dev/null
+++ b/web/template/page_header.tmpl
@@ -0,0 +1,72 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- define "thumbnailDescription" -}}
+{{- if .instance.ThumbnailDescription -}}
+{{- .instance.ThumbnailDescription -}}
+{{- else -}}
+Instance Logo
+{{- end -}}
+{{- end -}}
+
+{{- define "strapUsers" -}}
+{{- with .instance.Stats.user_count -}}
+ {{- if eq . 1 -}}
+ <span class="count">{{- . -}}</span> user
+ {{- else -}}
+ <span class="count">{{- . -}}</span> users
+ {{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "strapPosts" -}}
+{{- with .instance.Stats.status_count -}}
+ {{- if eq . 1 -}}
+ <span class="count">{{- . -}}</span> post
+ {{- else -}}
+ <span class="count">{{- . -}}</span> posts
+ {{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "strapInstances" -}}
+{{- with .instance.Stats.domain_count -}}
+ {{- if eq . 1 -}}
+ <span class="count">{{- . -}}</span> other instance
+ {{- else -}}
+ <span class="count">{{- . -}}</span> other instances
+ {{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- with . }}
+<a aria-label="{{- .instance.Title -}}. Go to instance homepage" href="/" class="nounderline">
+ <img
+ src="{{- .instance.Thumbnail -}}"
+ alt="{{- template "thumbnailDescription" . -}}"
+ title="{{- template "thumbnailDescription" . -}}"
+ width="100"
+ height="100"
+ />
+ <h1>{{- .instance.Title -}}</h1>
+</a>
+{{- if .showStrap }}
+<aside>home to {{ template "strapUsers" . }} who wrote {{ template "strapPosts" . }}, federating with {{ template "strapInstances" . }}</aside>
+{{- end }}
+{{- end }} \ No newline at end of file
diff --git a/web/template/page_ogmeta.tmpl b/web/template/page_ogmeta.tmpl
new file mode 100644
index 000000000..82bb4bbfb
--- /dev/null
+++ b/web/template/page_ogmeta.tmpl
@@ -0,0 +1,57 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- /*
+ OPEN GRAPH META TAGS
+ To enable fancy previews of links to GtS posts/profiles shared via instant
+ messaging, or other social media, parse out provided Open Graph meta tags.
+*/ -}}
+
+{{- with .ogMeta }}
+{{- if .Locale }}
+<meta name="og:locale" content="{{- .Locale -}}">
+{{- else }}
+{{- end }}
+<meta property="og:type" content="{{- .Type -}}">
+<meta property="og:title" content="{{- demojify .Title | noescape -}}">
+<meta property="og:url" content="{{- .URL -}}">
+<meta property="og:site_name" content="{{- .SiteName -}}">
+<meta property="og:description" {{ demojify .Description | noescapeAttr -}}>
+{{- if .ArticlePublisher }}
+<meta property="og:article:publisher" content="{{ .ArticlePublisher }}">
+<meta property="og:article:author" content="{{ .ArticleAuthor }}">
+<meta property="og:article:modified_time" content="{{ .ArticleModifiedTime }}">
+<meta property="og:article:published_time" content="{{ .ArticlePublishedTime }}">
+{{- else }}
+{{- end }}
+{{- if .ProfileUsername }}
+<meta property="og:profile:username" content="{{- .ProfileUsername -}}">
+{{- else }}
+{{- end }}
+<meta property="og:image" content="{{- .Image -}}">
+{{- if .ImageAlt }}
+<meta property="og:image:alt" content="{{- .ImageAlt -}}">
+{{- else }}
+{{- end }}
+{{- if .ImageWidth }}
+<meta property="og:image:width" content="{{ .ImageWidth }}">
+<meta property="og:image:height" content="{{ .ImageHeight }}">
+{{- else }}
+{{- end }}
+{{- end }} \ No newline at end of file
diff --git a/web/template/page_stylesheets.tmpl b/web/template/page_stylesheets.tmpl
new file mode 100644
index 000000000..9234607f8
--- /dev/null
+++ b/web/template/page_stylesheets.tmpl
@@ -0,0 +1,41 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- /*
+ Order of stylesheet loading is important: _colors and base should always be loaded
+ before any other provided sheets, since the latter cascade from the former.
+
+ To try to speed up rendering a little bit, offer a preload for each stylesheet.
+ See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload.
+*/ -}}
+
+{{- with . }}
+<link rel="preload" href="/assets/dist/_colors.css" as="style">
+<link rel="preload" href="/assets/dist/base.css" as="style">
+<link rel="preload" href="/assets/dist/page.css" as="style">
+{{- range .stylesheets }}
+<link rel="preload" href="{{- . -}}" as="style">
+{{- end }}
+<link rel="stylesheet" href="/assets/dist/_colors.css">
+<link rel="stylesheet" href="/assets/dist/base.css">
+<link rel="stylesheet" href="/assets/dist/page.css">
+{{- range .stylesheets }}
+<link rel="stylesheet" href="{{- . -}}">
+{{- end }}
+{{- end }} \ No newline at end of file
diff --git a/web/template/profile.tmpl b/web/template/profile.tmpl
index 4207b39e8..0b079db10 100644
--- a/web/template/profile.tmpl
+++ b/web/template/profile.tmpl
@@ -17,129 +17,123 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
-
+{{- with . }}
<main class="profile">
- <div class="header">
- <div class="header-image">
- {{ if .account.Header }}
- <img src="{{.account.Header}}" alt="" />
- {{ end }}
- </div>
- <div class="basic-info" aria-hidden="true">
- <a class="avatar" href="{{.account.Avatar}}">
- <img src="{{.account.Avatar}}" alt="">
- </a>
- <span class="displayname text-cutoff">
- {{if .account.DisplayName}}
- {{emojify .account.Emojis (escape .account.DisplayName)}}
- {{else}}
- {{.account.Username}}
- {{end}}
- </span>
- <span class="username text-cutoff">@{{.account.Username}}@{{.instance.AccountDomain}}</span>
- {{- /* Only render account role if 1. it's present and 2. it's not equal to the standard 'user' role */ -}}
- {{ if and (.account.Role) (ne .account.Role.Name "user") }}
- <div class="role {{ .account.Role.Name }}">
- {{ .account.Role.Name }}
- </div>
- {{ end }}
- </div>
- <div class="sr-only">
- Profile for
- {{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}.
- Username @{{.account.Username}}, {{.instance.AccountDomain}}.
- {{ if and (.account.Role) (ne .account.Role.Name "user") }}
- Role: {{ .account.Role.Name }}
- {{ end }}
- </div>
- </div>
-
- <div class="column-split">
-
- <section class="about-user">
- <div class="col-header">
- <h1>About</h1>
- </div>
-
- <div class="fields">
- {{ range .account.Fields }}
- <div class="field">
- <b>{{emojify $.account.Emojis (noescape .Name)}}</b>
- <span>{{emojify $.account.Emojis (noescape .Value)}}</span>
- </div>
- {{ end }}
- </div>
-
- <div class="bio">
- {{ if .account.Note }}
- {{emojify .account.Emojis (noescape .account.Note)}}
- {{else}}
- This GoToSocial user hasn't written a bio yet!
- {{end}}
- </div>
-
- <div class="sr-only" role="group">
- <span>Joined on {{.account.CreatedAt | timestampVague}}.</span>
- <span>{{.account.StatusesCount}} post{{if .account.StatusesCount | eq 1 | not}}s{{end}}.</span>
- <span>Followed by {{.account.FollowersCount}}.</span>
- <span>Following {{.account.FollowingCount}}.</span>
- </div>
-
- <div class="accountstats" aria-hidden="true">
- <b>Joined</b><time datetime="{{.account.CreatedAt}}">{{.account.CreatedAt | timestampVague}}</time>
- <b>Posts</b><span>{{.account.StatusesCount}}</span>
- <b>Followed by</b><span>{{.account.FollowersCount}}</span>
- <b>Following</b><span>{{.account.FollowingCount}}</span>
- </div>
- </section>
-
- <section class="toots">
- {{ if .pinned_statuses }}
- <div class="col-header">
- <h2>Pinned posts</h2>
- <a href="#recent">jump to recent</a>
- </div>
- <section class="thread">
- {{ range .pinned_statuses }}
- <article class="toot expanded" id="{{.ID}}">
- {{ template "status.tmpl" .}}
- </article>
- {{ end }}
- </section>
- {{ end }}
-
- <div class="col-header">
- <h2 id="recent" tabindex="-1">Recent posts</h2>
- {{ if .rssFeed }}
- <a href="{{ .rssFeed }}" class="rss-icon" aria-label="RSS feed">
- <i class="fa fa-rss-square" aria-hidden="true"></i>
- </a>
- {{ end }}
- </div>
-
- <section class="thread">
- {{ if not .statuses }}
- <div data-nosnippet class="nothinghere">Nothing here!</div>
- {{ else }}
- {{ range .statuses }}
- <article class="toot expanded" id="{{.ID}}">
- {{ template "status.tmpl" .}}
- </article>
- {{ end }}
- {{ end }}
- </section>
-
- <div class="backnextlinks">
- {{ if .show_back_to_top }}
- <a href="/@{{ .account.Username }}">Back to top</a>
- {{ end }}
- {{ if .statuses_next }}
- <a href="{{ .statuses_next }}" class="next">Show older</a>
- {{ end }}
- </div>
- </section>
- </div>
+ <h2 class="sr-only">Profile for {{ .account.Username -}}</h2>
+ <section class="profile-header" role="region" aria-label="Basic info">
+ <div class="header-image-wrapper">
+ <img
+ src="{{- .account.Header -}}"
+ alt="Header for {{ .account.Username -}}"
+ title="Header for {{ .account.Username -}}"
+ />
+ </div>
+ <div class="basic-info">
+ <a class="avatar" href="{{- .account.Avatar -}}">
+ <img
+ src="{{- .account.Avatar -}}"
+ alt="Avatar for {{ .account.Username -}}"
+ title="Avatar for {{ .account.Username -}}"
+ />
+ </a>
+ <dl class="namerole">
+ <dt class="sr-only">Display name</dt>
+ <dd class="displayname text-cutoff">
+ {{- if .account.DisplayName -}}
+ {{- emojify .account.Emojis (escape .account.DisplayName) -}}
+ {{- else -}}
+ {{- .account.Username -}}
+ {{- end -}}
+ </dd>
+ <dt class="sr-only">Username</dt>
+ <dd class="username text-cutoff">@{{- .account.Username -}}@{{- .instance.AccountDomain -}}</dd>
+ {{- if and (.account.Role) (ne .account.Role.Name "user") }}
+ <dt class="sr-only">Role</dt>
+ <dd class="role {{ .account.Role.Name -}}">{{- .account.Role.Name -}}</dd>
+ {{- end }}
+ </dl>
+ </div>
+ </section>
+ <div class="column-split">
+ <section class="about-user" role="region" aria-labelledby="about-header">
+ <div class="col-header">
+ <h3 id="about-header">About<span class="sr-only">&nbsp;{{- .account.Username -}}</span></h3>
+ </div>
+ {{- if .account.Fields }}
+ {{- include "profile_fields.tmpl" . | indent 3 }}
+ {{- end }}
+ <h4 class="sr-only">Bio</h4>
+ <div class="bio">
+ {{- if .account.Note }}
+ {{ emojify .account.Emojis (noescape .account.Note) }}
+ {{- else }}
+ <p>This GoToSocial user hasn't written a bio yet!</p>
+ {{- end }}
+ </div>
+ <h4 class="sr-only">Stats</h4>
+ <dl class="accountstats">
+ <dt>Joined</dt>
+ <dd><time datetime="{{- .account.CreatedAt -}}">{{- .account.CreatedAt | timestampVague -}}</time></dd>
+ <dt>Posts</dt>
+ <dd>{{- .account.StatusesCount -}}</dd>
+ <dt>Followed by</dt>
+ <dd>{{- .account.FollowersCount -}}</dd>
+ <dt>Following</dt>
+ <dd>{{- .account.FollowingCount -}}</dd>
+ </dl>
+ </section>
+ <div class="statuses-wrapper" role="region" aria-label="Posts by {{ .account.Username -}}">
+ {{- if .pinned_statuses }}
+ <section class="pinned statuses" aria-labelledby="pinned">
+ <div class="col-header">
+ <h3 id="pinned">Pinned posts</h3>
+ <a href="#recent">jump to recent</a>
+ </div>
+ <div class="thread">
+ {{- range .pinned_statuses }}
+ <article
+ class="status expanded"
+ {{- includeAttr "status_attributes.tmpl" . | indentAttr 6 }}
+ >
+ {{- include "status.tmpl" . | indent 6 }}
+ </article>
+ {{- end }}
+ </div>
+ </section>
+ {{- end }}
+ <section class="recent statuses" aria-labelledby="recent">
+ <div class="col-header">
+ <h3 id="recent" tabindex="-1">Recent posts</h3>
+ {{- if .rssFeed }}
+ <a href="{{- .rssFeed -}}" class="rss-icon" aria-label="RSS feed">
+ <i class="fa fa-rss-square" aria-hidden="true"></i>
+ </a>
+ {{- end }}
+ </div>
+ <div class="thread">
+ {{- if not .statuses }}
+ <div data-nosnippet class="nothinghere">Nothing here!</div>
+ {{- else }}
+ {{- range .statuses }}
+ <article
+ class="status expanded"
+ {{- includeAttr "status_attributes.tmpl" . | indentAttr 6 }}
+ >
+ {{- include "status.tmpl" . | indent 6 }}
+ </article>
+ {{- end }}
+ {{- end }}
+ </div>
+ <nav class="backnextlinks">
+ {{- if .show_back_to_top }}
+ <a href="/@{{- .account.Username -}}">Back to top</a>
+ {{- end }}
+ {{- if .statuses_next }}
+ <a href="{{- .statuses_next -}}" class="next">Show older</a>
+ {{- end }}
+ </nav>
+ </section>
+ </div>
+ </div>
</main>
-
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/footer.tmpl b/web/template/profile_fields.tmpl
index 028a27ffb..e9005d4c9 100644
--- a/web/template/footer.tmpl
+++ b/web/template/profile_fields.tmpl
@@ -17,30 +17,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
- <!-- footer.tmpl -->
- </div>
- <footer>
- <div id="version">
- <a name="Source code" href="https://github.com/superseriousbusiness/gotosocial">
- GoToSocial <span class="accent">{{.instance.Version}}</span>
- </a>
- </div>
- {{ if .instance.ContactAccount }}
- <div id="contact">
- Contact: <a href="{{.instance.ContactAccount.URL}}" class="nounderline">{{.instance.ContactAccount.Username}}</a><br>
- </div>
- {{ end }}
- {{ if .instance.Email }}
- <div id="email">
- Email: <a href="mailto:{{.instance.Email}}" class="nounderline">{{.instance.Email}}</a><br>
- </div>
- {{ end }}
- </footer>
- </div>
- {{ if .javascript }}
- {{ range .javascript }}
- <script src="{{.}}"></script>
- {{ end }}
- {{ end }}
-</body>
-</html> \ No newline at end of file
+{{- with . }}
+<div class="fields">
+ <h4 class="sr-only">Fields</h4>
+ <dl>
+ {{- range .account.Fields }}
+ <div class="field">
+ <dt>{{- emojify $.account.Emojis (noescape .Name) -}}</dt>
+ <dd>{{- emojify $.account.Emojis (noescape .Value) -}}</dd>
+ </div>
+ {{- end }}
+ </dl>
+</div>
+{{- end }} \ No newline at end of file
diff --git a/web/template/sign-in.tmpl b/web/template/sign-in.tmpl
index e2a985b9c..916d6942f 100644
--- a/web/template/sign-in.tmpl
+++ b/web/template/sign-in.tmpl
@@ -17,10 +17,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
+{{- with . }}
<main>
- <section class="login">
- <h1>Login</h1>
+ <section class="sign-in" aria-labelledby="sign-in">
+ <h2 id="sign-in">Sign in</h2>
<form action="/auth/sign_in" method="POST">
<div class="labelinput">
<label for="email">Email</label>
@@ -30,8 +30,8 @@
<label for="password">Password</label>
<input type="password" class="form-control" name="password" required placeholder="Please enter your password">
</div>
- <button type="submit" class="btn btn-success">Login</button>
+ <button type="submit" class="btn btn-success">Sign in</button>
</form>
</section>
</main>
-{{ template "footer.tmpl" .}}
+{{- end }} \ No newline at end of file
diff --git a/web/template/status.tmpl b/web/template/status.tmpl
index eb6c6a6c6..de2167d88 100644
--- a/web/template/status.tmpl
+++ b/web/template/status.tmpl
@@ -17,88 +17,74 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-<a data-nosnippet href="{{- .URL -}}" class="toot-link">Open thread</a>
-<section class="author">
- <a href="{{- .Account.URL -}}">
- <img class="avatar" src="{{- .Account.Avatar -}}" alt="">
- <span aria-hidden="true" class="displayname">
- {{- if .Account.DisplayName -}}
- {{- emojify .Account.Emojis (escape .Account.DisplayName) -}}
- {{- else -}}
- {{- .Account.Username -}}
- {{- end -}}
- </span>
- <span aria-hidden="true" class="username">@{{- .Account.Username -}}</span>
- <span class="sr-only">
- {{- if .Account.DisplayName -}}
- {{- emojify .Account.Emojis (escape .Account.DisplayName) -}}. Username: @{{ .Account.Acct -}}.
- {{- else -}}
- @{{- .Account.Acct -}}.
- {{- end -}}
- </span>
- </a>
-</section>
-<section class="body">
- {{- if .SpoilerText }}
- <details class="text-spoiler">
- <summary>
- <span class="spoiler-text" lang="{{- .LanguageTag.TagStr -}}">{{- emojify .Emojis (escape .SpoilerText) -}}</span>
- <span class="button" role="button" tabindex="0">Toggle visibility</span>
- </summary>
- <div class="text">
- <div class="content" lang="{{- .LanguageTag.TagStr -}}">
- {{ emojify .Emojis (noescape .Content) }}
- </div>
- {{- if .Poll }}
- {{ template "status_poll.tmpl" . }}
- {{- end }}
- </div>
- </details>
- {{- else }}
- <div class="text">
- <div class="content" lang="{{- .LanguageTag.TagStr -}}">
- {{ emojify .Emojis (noescape .Content) }}
- </div>
- {{- if .Poll }}
- {{ template "status_poll.tmpl" . }}
- {{- end }}
- </div>
- {{- end }}
- {{- if .MediaAttachments }}
- {{ template "status_attachments.tmpl" . }}
- {{- end }}
-</section>
-<aside class="info">
- <dl class="sr-only">
- <dt>Published<dt>
- <dd>{{- .CreatedAt | timestampPrecise -}}</dd>
- {{- if .LanguageTag.DisplayStr }}
- <dt>Language</dt>
- <dd>{{ .LanguageTag.DisplayStr }}</dd>
- {{- end }}
- </dl>
- <time aria-hidden="true" datetime="{{- .CreatedAt -}}">{{- .CreatedAt | timestampPrecise -}}</time>
- <div class="stats" role="group">
- <div class="stats-item">
- <span aria-hidden="true"><i class="fa fa-reply-all"></i> {{ .RepliesCount -}}</span>
- <span class="sr-only">{{- .RepliesCount }} {{ if .RepliesCount | eq 1 }}reply{{ else }}replies{{ end -}}</span>
- </div>
- <div class="stats-item">
- <span aria-hidden="true"><i class="fa fa-star"></i> {{ .FavouritesCount -}}</span>
- <span class="sr-only">{{- .FavouritesCount }} {{ if .FavouritesCount | eq 1 }}favourite{{ else }}favourites{{ end -}}</span>
- </div>
- <div class="stats-item">
- <span aria-hidden="true"><i class="fa fa-retweet"></i> {{ .ReblogsCount -}}</span>
- <span class="sr-only">{{- .ReblogsCount }} {{ if .ReblogsCount | eq 1 }}boost{{ else }}boosts{{ end -}}</span>
- </div>
- {{- if .Pinned }}
- <div class="stats-item">
- <i class="fa fa-thumb-tack" aria-hidden="true"></i>
- <span class="sr-only">pinned</span>
- </div>
- {{- end }}
- {{- if .LanguageTag.DisplayStr }}
- <div aria-hidden="true" class="stats-item language" title="Language: {{ .LanguageTag.DisplayStr }}">{{ .LanguageTag.TagStr }}</div>
- {{- end }}
- </div>
+{{- define "statusContent" -}}
+{{- with .Content }}
+<div class="content" lang="{{- $.LanguageTag.TagStr -}}">
+ {{ noescape . | emojify $.Emojis }}
+</div>
+{{- end }}
+{{- end -}}
+
+{{- /*
+ When including this template, always wrap
+ it in an appropriate <article></article>!
+*/ -}}
+
+{{- with . }}
+<header class="status-header">
+ {{- include "status_header.tmpl" . | indent 1 }}
+</header>
+<div class="status-body">
+ {{- if .SpoilerText }}
+ <details class="text-spoiler">
+ <summary>
+ <span class="spoiler-text" lang="{{- .LanguageTag.TagStr -}}">{{- emojify .Emojis (escape .SpoilerText) -}}</span>
+ <span class="button" role="button" tabindex="0">Toggle visibility</span>
+ </summary>
+ <div class="text">
+ {{- with . }}
+ {{- include "statusContent" . | indent 3 }}
+ {{- end }}
+ {{- if .Poll }}
+ {{- include "status_poll.tmpl" . | indent 3 }}
+ {{- end }}
+ </div>
+ </details>
+ {{- else }}
+ <div class="text">
+ {{- with . }}
+ {{- include "statusContent" . | indent 2 }}
+ {{- end }}
+ {{- if .Poll }}
+ {{- include "status_poll.tmpl" . | indent 2 }}
+ {{- end }}
+ </div>
+ {{- end }}
+ {{- if .MediaAttachments }}
+ {{- include "status_attachments.tmpl" . | indent 1 }}
+ {{- end }}
+</div>
+<aside class="status-info" aria-hidden="true">
+ {{- include "status_info.tmpl" . | indent 1 }}
</aside>
+{{- if .Local }}
+<a
+ href="{{- .URL -}}"
+ class="status-link"
+ data-nosnippet
+ title="Open thread at this post"
+>
+ Open thread at this post
+</a>
+{{- else }}
+<a
+ href="{{- .URL -}}"
+ class="status-link"
+ data-nosnippet
+ rel="nofollow noreferrer noopener" target="_blank"
+ title="Open remote post (opens in a new window)"
+>
+ Open remote post (opens in a new window)
+</a>
+{{- end }}
+{{- end }} \ No newline at end of file
diff --git a/web/template/status_attachments.tmpl b/web/template/status_attachments.tmpl
index bd26c82a6..b257f2211 100644
--- a/web/template/status_attachments.tmpl
+++ b/web/template/status_attachments.tmpl
@@ -18,77 +18,119 @@
*/ -}}
{{- /*
- Template for rendering a gallery of status media attachments.
- To use this template, pass a web view status into it.
+ Template for rendering a gallery of status media attachments.
+ To use this template, pass a web view status into it.
*/ -}}
-{{ with .MediaAttachments }}
- <div class="media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{ else if eq (len .) 2 }}double{{- end -}}">
- {{- range $index, $media := . }}
- <div class="media-wrapper">
- <details class="{{- $media.Type -}}-spoiler media-spoiler" {{- if not $media.Sensitive }} open{{ end -}}>
- <summary>
- <div class="show sensitive button" aria-hidden="true">Show sensitive media</div>
- <span class="eye button" role="button" tabindex="0" aria-label="Toggle media">
- <i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i>
- <i class="show fa fa-fw fa-eye" aria-hidden="true"></i>
- </span>
- {{- if eq .Type "video" }}
- <video {{- if .Description }} title="{{- $media.Description -}}" {{- end -}}>
- <source type="video/mp4" src="{{- $media.URL -}}"/>
- </video>
- {{- else if eq .Type "image" }}
- <img src="{{- $media.PreviewURL -}}" {{- if .Description }} title="{{- $media.Description -}}" {{- end }}/>
- {{- end }}
- </summary>
- {{- if eq .Type "video" }}
- <video
- class="plyr-video photoswipe-slide"
- controls
- data-pswp-index="{{- $index -}}"
- data-pswp-width="{{- $media.Meta.Original.Width -}}px"
- data-pswp-height="{{- $media.Meta.Original.Height -}}px"
- {{- if .Description }}
- alt="{{- $media.Description -}}"
- title="{{- $media.Description -}}"
- {{- end }}
- >
- <source type="video/mp4" src="{{- $media.URL -}}"/>
- </video>
- {{- else if eq .Type "image" }}
- <a
- class="photoswipe-slide"
- href="{{- $media.URL -}}"
- target="_blank"
- data-pswp-width="{{- $media.Meta.Original.Width -}}px"
- data-pswp-height="{{- $media.Meta.Original.Height -}}px"
- data-cropped="true"
- {{- if .Description }}
- title="{{- $media.Description -}}"
- {{- end }}
- >
- <img src="{{$media.PreviewURL}}" {{if .Description}}alt="{{$media.Description}}" {{end}} />
- </a>
- {{- else }}
- <a
- class="unknown-attachment"
- href="{{- $media.RemoteURL -}}"
- target="_blank"
- {{- if .Description }}
- title="Link to external media: {{ $media.Description -}}&#10;&#13;{{- $media.RemoteURL -}}"
- {{- else }}
- title="Link to external media.&#10;&#13;{{- $media.RemoteURL -}}"
- {{- end }}
- >
- <div class="placeholder" aria-hidden="true">
- <i class="placeholder-external-link fa fa-external-link"></i>
- <i class="placeholder-icon fa fa-file-text"></i>
- <div class="placeholder-link-to">External media</div>
- </div>
- </a>
- {{- end }}
- </details>
- </div>
- {{- end }}
- </div>
+{{- define "imagePreview" }}
+<img
+ src="{{- .PreviewURL -}}"
+ loading="lazy"
+ {{- if .Description }}
+ alt="{{- .Description -}}"
+ title="{{- .Description -}}"
+ {{- end }}
+ width="{{- .Meta.Original.Width -}}"
+ height="{{- .Meta.Original.Height -}}"
+/>
{{- end }}
+
+{{- define "videoPreview" }}
+<video
+ {{- if .Description }}
+ alt="{{- .Description -}}"
+ title="{{- .Description -}}"
+ {{- end }}
+ width="{{- .Meta.Original.Width -}}"
+ height="{{- .Meta.Original.Height -}}"
+>
+ <source type="video/mp4" src="{{- .URL -}}"/>
+</video>
+{{- end }}
+
+{{- /* Produces something like "1 attachment", "2 attachments", etc */ -}}
+{{- define "attachmentsLength" -}}
+{{- (len .) }}{{- if eq (len .) 1 }} attachment{{- else }} attachments{{- end -}}
+{{- end -}}
+
+{{- /* Produces something like "media photoswipe-gallery odd single" */ -}}
+{{- define "galleryClass" -}}
+media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{ else if eq (len .) 2 }}double{{ end }}
+{{- end -}}
+
+{{- with .MediaAttachments }}
+<div
+ class="{{- template "galleryClass" . -}}"
+ role="group"
+ aria-label="{{- template "attachmentsLength" . -}}"
+>
+ {{- range $index, $media := . }}
+ <div class="media-wrapper">
+ <details class="{{- $media.Type -}}-spoiler media-spoiler" {{- if not $media.Sensitive }} open{{- end -}}>
+ <summary>
+ <div class="show sensitive button" aria-hidden="true">Show sensitive media</div>
+ <span class="eye button" role="button" tabindex="0" aria-label="Toggle media">
+ <i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i>
+ <i class="show fa fa-fw fa-eye" aria-hidden="true"></i>
+ </span>
+ {{- if eq .Type "video" }}
+ {{- include "videoPreview" $media | indent 4 }}
+ {{- else if eq .Type "image" }}
+ {{- include "imagePreview" $media | indent 4 }}
+ {{- end }}
+ </summary>
+ {{- if eq .Type "video" }}
+ <video
+ class="plyr-video photoswipe-slide"
+ controls
+ data-pswp-index="{{- $index -}}"
+ data-pswp-width="{{- $media.Meta.Original.Width -}}px"
+ data-pswp-height="{{- $media.Meta.Original.Height -}}px"
+ {{- if .Description }}
+ alt="{{- $media.Description -}}"
+ title="{{- $media.Description -}}"
+ {{- end }}
+ >
+ <source type="video/mp4" src="{{- $media.URL -}}"/>
+ </video>
+ {{- else if eq .Type "image" }}
+ <a
+ class="photoswipe-slide"
+ href="{{- $media.URL -}}"
+ target="_blank"
+ data-pswp-width="{{- $media.Meta.Original.Width -}}px"
+ data-pswp-height="{{- $media.Meta.Original.Height -}}px"
+ data-cropped="true"
+ {{- if .Description }}
+ alt="{{- $media.Description -}}"
+ title="{{- $media.Description -}}"
+ {{- end }}
+ >
+ {{- with $media }}
+ {{- include "imagePreview" . | indent 4 }}
+ {{- end }}
+ </a>
+ {{- else }}
+ <a
+ class="unknown-attachment"
+ href="{{- $media.RemoteURL -}}"
+ rel="nofollow noreferrer noopener"
+ target="_blank"
+ {{- if .Description }}
+ title="Open external media: {{ $media.Description -}}&#10;&#13;{{- $media.RemoteURL -}}"
+ {{- else }}
+ title="Open external media.&#10;&#13;{{- $media.RemoteURL -}}"
+ {{- end }}
+ >
+ <div class="placeholder" aria-hidden="true">
+ <i class="placeholder-external-link fa fa-external-link"></i>
+ <i class="placeholder-icon fa fa-file-text"></i>
+ <div class="placeholder-link-to">External media</div>
+ </div>
+ </a>
+ {{- end }}
+ </details>
+ </div>
+ {{- end }}
+</div>
+{{- end }} \ No newline at end of file
diff --git a/web/template/status_attributes.tmpl b/web/template/status_attributes.tmpl
new file mode 100644
index 000000000..92659b6b2
--- /dev/null
+++ b/web/template/status_attributes.tmpl
@@ -0,0 +1,55 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- define "ariaLabel" -}}
+@{{ .Account.Acct -}}, {{ timestamp .CreatedAt -}}
+{{- if .LanguageTag -}}
+ , language {{ .LanguageTag.DisplayStr -}}
+{{- end -}}
+{{- if .MediaAttachments -}}
+ , has media
+{{- end -}}
+{{- if .RepliesCount -}}
+ {{- if eq .RepliesCount 1 -}}
+ , 1 reply
+ {{- else -}}
+ , {{ .RepliesCount }} replies
+ {{- end -}}
+{{- end -}}
+{{- if .FavouritesCount -}}
+ {{- if eq .FavouritesCount 1 -}}
+ , 1 favourite
+ {{- else -}}
+ , {{ .FavouritesCount }} favourites
+ {{- end -}}
+{{- end -}}
+{{- if .ReblogsCount -}}
+ {{- if eq .ReblogsCount 1 -}}
+ , 1 boost
+ {{- else -}}
+ , {{ .ReblogsCount }} boosts
+ {{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- with . }}
+id="{{- .ID -}}{{- if .Pinned -}}-pinned{{- end -}}"
+role="region"
+aria-label="{{- template "ariaLabel" . -}}"
+{{- end }} \ No newline at end of file
diff --git a/web/template/status_header.tmpl b/web/template/status_header.tmpl
new file mode 100644
index 000000000..8946a1030
--- /dev/null
+++ b/web/template/status_header.tmpl
@@ -0,0 +1,56 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- with .Account }}
+<address>
+ {{- if $.Local }}
+ <a
+ href="{{- .URL -}}"
+ rel="author"
+ title="Open profile"
+ >
+ {{- else }}
+ <a
+ href="{{- .URL -}}"
+ rel="author nofollow noreferrer noopener" target="_blank"
+ title="Open remote profile (opens in a new window)"
+ >
+ {{- end }}
+ <img
+ class="avatar"
+ aria-hidden="true"
+ src="{{- .Avatar -}}"
+ alt="Avatar for {{ .Username -}}"
+ title="Avatar for {{ .Username -}}"
+ >
+ <div class="author-strap">
+ <span class="displayname text-cutoff">
+ {{- if .DisplayName -}}
+ {{- emojify .Emojis (escape .DisplayName) -}}
+ {{- else -}}
+ {{- .Username -}}
+ {{- end -}}
+ </span>
+ <span class="sr-only">,</span>
+ <span class="username text-cutoff">@{{- .Acct -}}</span>
+ </div>
+ <span class="sr-only">(open profile)</span>
+ </a>
+</address>
+{{- end }} \ No newline at end of file
diff --git a/web/template/status_info.tmpl b/web/template/status_info.tmpl
new file mode 100644
index 000000000..c5ba3ef35
--- /dev/null
+++ b/web/template/status_info.tmpl
@@ -0,0 +1,74 @@
+{{- /*
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/ -}}
+
+{{- with . }}
+<dl class="status-stats">
+ <div class="stats-grouping">
+ <div class="stats-item published-at text-cutoff">
+ <dt class="sr-only">Published</dt>
+ <dd>
+ <time datetime="{{- .CreatedAt -}}">{{- .CreatedAt | timestampPrecise -}}</time>
+ </dd>
+ </div>
+ <div class="stats-grouping">
+ <div class="stats-item" title="Replies">
+ <dt>
+ <span class="sr-only">Replies</span>
+ <i class="fa fa-reply-all" aria-hidden="true"></i>
+ </dt>
+ <dd>{{- .RepliesCount -}}</dd>
+ </div>
+ <div class="stats-item" title="Faves">
+ <dt>
+ <span class="sr-only">Favourites</span>
+ <i class="fa fa-star" aria-hidden="true"></i>
+ </dt>
+ <dd>{{- .FavouritesCount -}}</dd>
+ </div>
+ <div class="stats-item" title="Boosts">
+ <dt>
+ <span class="sr-only">Reblogs</span>
+ <i class="fa fa-retweet" aria-hidden="true"></i>
+ </dt>
+ <dd>{{- .ReblogsCount -}}</dd>
+ </div>
+ {{- if .Pinned }}
+ <div class="stats-item" title="Pinned">
+ <dt>
+ <span class="sr-only">Pinned</span>
+ <i class="fa fa-thumb-tack" aria-hidden="true"></i>
+ </dt>
+ <dd class="sr-only">{{- .Pinned -}}</dd>
+ </div>
+ {{- else }}
+ {{- end }}
+ </div>
+ </div>
+ {{- if .LanguageTag.DisplayStr }}
+ <div class="stats-item language" title="{{ .LanguageTag.DisplayStr }}">
+ <dt class="sr-only">Language</dt>
+ <dd>
+ <span class="sr-only">{{ .LanguageTag.DisplayStr }}</span>
+ <span aria-hidden="true">{{- .LanguageTag.TagStr -}}</span>
+ </dd>
+ </div>
+ {{- else }}
+ {{- end }}
+</dl>
+{{- end }} \ No newline at end of file
diff --git a/web/template/status_poll.tmpl b/web/template/status_poll.tmpl
index a900f5e74..8cb5dde8f 100644
--- a/web/template/status_poll.tmpl
+++ b/web/template/status_poll.tmpl
@@ -18,51 +18,64 @@
*/ -}}
{{- /*
- Template for rendering a web view of a poll.
- To use this template, pass a web view status into it.
+ Template for rendering a web view of a poll.
+ To use this template, pass a web view status into it.
*/ -}}
- <figure class="poll">
- <figcaption class="poll-info">
- <span class="poll-expiry">
- {{- if .Poll.Multiple -}}
- Multiple-choice poll&nbsp;
- {{- else -}}
- Poll&nbsp;
- {{- end -}}
- {{- if .Poll.Expired -}}
- closed {{ .Poll.ExpiresAt | timestampPrecise -}}
- {{- else if .Poll.ExpiresAt -}}
- open until {{ .Poll.ExpiresAt | timestampPrecise -}}
- {{- else -}}
- open forever
- {{- end -}}
- </span>
- <span class="total-votes">Total votes: {{ .Poll.VotesCount }}</span>
- </figcaption>
- <ul class="poll-options">
- {{- range $index, $pollOption := .WebPollOptions }}
- <li class="poll-option">
- <label aria-hidden="true" for="poll-{{- $pollOption.PollID -}}-option-{{- increment $index -}}" lang="{{- .LanguageTag.TagStr -}}">{{- emojify .Emojis (noescape $pollOption.Title) -}}</label>
- <meter aria-hidden="true" id="poll-{{- $pollOption.PollID -}}-option-{{- increment $index -}}" min="0" max="100" value="{{- $pollOption.VoteShare -}}">{{- $pollOption.VoteShare -}}&#37;</meter>
- <div class="sr-only">Option {{ increment $index }}:&nbsp;<span lang="{{ .LanguageTag.TagStr }}">{{ emojify .Emojis (noescape $pollOption.Title) -}}</span></div>
- <div class="poll-vote-summary">
- {{- if isNil $pollOption.VotesCount }}
- Results not yet published.
- {{- else -}}
- {{- with deref $pollOption.VotesCount }}
- <span class="poll-vote-share">{{- $pollOption.VoteShareStr -}}&#37;</span>
- <span class="poll-vote-count">
- {{- if eq . 1 -}}
- {{- . }} vote
- {{- else -}}
- {{- . }} votes
- {{- end -}}
- </span>
- {{- end -}}
- {{- end }}
- </div>
- </li>
- {{- end }}
- </ul>
- </figure>
+{{- define "votes" -}}
+ {{- if eq . 1 -}}
+ {{- . -}}&nbsp;vote
+ {{- else -}}
+ {{- . }}&nbsp;votes
+ {{- end -}}
+{{- end -}}
+
+{{- with . }}
+<figure class="poll">
+ <figcaption class="poll-info">
+ <span class="poll-expiry">
+ {{- if .Poll.Multiple -}}
+ Multiple-choice poll&nbsp;
+ {{- else -}}
+ Poll&nbsp;
+ {{- end -}}
+ {{- if .Poll.Expired -}}
+ closed <time datetime="{{- .Poll.ExpiresAt -}}">{{- .Poll.ExpiresAt | timestampPrecise -}}</time>
+ {{- else if .Poll.ExpiresAt -}}
+ open until <time datetime="{{- .Poll.ExpiresAt -}}">{{- .Poll.ExpiresAt | timestampPrecise -}}</time>
+ {{- else -}}
+ open forever
+ {{- end -}}
+ </span>
+ <span class="sr-only">,</span>
+ <span class="total-votes">
+ {{- template "votes" .Poll.VotesCount -}}&nbsp;
+ {{- if .Poll.Expired -}}
+ total
+ {{- else -}}
+ so far
+ {{- end -}}
+ </span>
+ </figcaption>
+ <ul class="poll-options nodot">
+ {{- range $index, $pollOption := .WebPollOptions }}
+ <li class="poll-option">
+ <span class="sr-only">Option {{ increment $index }},</span>
+ <span lang="{{- .LanguageTag.TagStr -}}">{{ emojify .Emojis (noescape $pollOption.Title) }}</span>
+ <meter aria-hidden="true" min="0" max="100" value="{{- $pollOption.VoteShare -}}"></meter>
+ <div class="poll-vote-summary">
+ {{- if isNil $pollOption.VotesCount }}
+ Results not yet published.
+ {{- else }}
+ {{- with deref $pollOption.VotesCount }}
+ <span class="poll-vote-share">{{- $pollOption.VoteShareStr -}}&#37;</span>
+ <span class="sr-only">,</span>
+ <span class="poll-vote-count">{{- template "votes" . -}}</span>
+ {{- end }}
+ {{- end }}
+ </div>
+ </li>
+ {{- end }}
+ </ul>
+</figure>
+{{- end }} \ No newline at end of file
diff --git a/web/template/tag.tmpl b/web/template/tag.tmpl
index c84d7a1a4..c1bba0720 100644
--- a/web/template/tag.tmpl
+++ b/web/template/tag.tmpl
@@ -17,11 +17,13 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
-
-<main class="thread">
- <h2 id="tag-name" tabindex="-1">#{{.tagName}}</h2>
- <p>There's nothing here yet!</p>
+{{- with . }}
+<main>
+ <h2 id="tag-name" tabindex="-1">#{{- .tagName -}}</h2>
+ <p>There's nothing here!</p>
+ <p>
+ For privacy reasons, GoToSocial doesn't (yet) implement public web views of tag timelines.
+ To soften the blow, here's a tongue twister: "I squeeze the soft sloth often in the mothy loft" 🦥
+ </p>
</main>
-
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file
diff --git a/web/template/thread.tmpl b/web/template/thread.tmpl
index f2b61019d..2231a5ab8 100644
--- a/web/template/thread.tmpl
+++ b/web/template/thread.tmpl
@@ -17,22 +17,45 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
-{{ template "header.tmpl" .}}
-<main>
- <section data-nosnippet class="thread">
- {{range .context.Ancestors}}
- <article class="toot" id="{{.ID}}">
- {{ template "status.tmpl" .}}
- </article>
- {{end}}
- <article class="toot expanded" id="{{.status.ID}}">
- {{ template "status.tmpl" .status}}
- </article>
- {{range .context.Descendants}}
- <article class="toot" id="{{.ID}}">
- {{ template "status.tmpl" .}}
- </article>
- {{end}}
- </section>
+{{- define "threadLength" -}}
+ {{- with $length := add (len $.context.Ancestors) (len $.context.Descendants) | increment -}}
+ {{- if eq $length 1 -}}
+ {{- $length }} post
+ {{- else -}}
+ {{- $length }} posts
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- with . }}
+<main data-nosnippet class="thread" aria-labelledby="thread-summary">
+ <div class="col-header">
+ <h2 id="thread-summary">Thread with {{ template "threadLength" . -}}</h2>
+ <a href="#{{- .status.ID -}}">jump to expanded post</a>
+ </div>
+ {{- range .context.Ancestors }}
+ <article
+ class="status"
+ {{- includeAttr "status_attributes.tmpl" . | indentAttr 2 }}
+ >
+ {{- include "status.tmpl" . | indent 2 }}
+ </article>
+ {{- end }}
+ {{- with .status }}
+ <article
+ class="status expanded"
+ {{- includeAttr "status_attributes.tmpl" . | indentAttr 2 }}
+ >
+ {{- include "status.tmpl" . | indent 2 }}
+ </article>
+ {{- end }}
+ {{- range .context.Descendants }}
+ <article
+ class="status"
+ {{- includeAttr "status_attributes.tmpl" . | indentAttr 2 }}
+ >
+ {{- include "status.tmpl" . | indent 2 }}
+ </article>
+ {{- end }}
</main>
-{{ template "footer.tmpl" .}} \ No newline at end of file
+{{- end }} \ No newline at end of file