[chore] Refactor HTML templates and CSS (#2480)

* [chore] Refactor HTML templates and CSS

* eslint

* ignore "Local"

* rss tests

* fiddle with OG just a tiny bit

* dick around with polls a bit more so SR stops saying "clickable"

* remove break

* oh lord

* don't lazy load avatar

* fix ogmeta tests

* clean up some cruft

* catch remaining calls to c.HTML

* fix error rendering + stack overflow in tag

* allow templating attributes

* fix indent

* set aria-hidden on status complementary content, since it's already present in the label anyway

* tidy up templating calls a little

* try to make styling a bit more consistent + readable

* fix up some remaining CSS issues

* fix up reports
This commit is contained in:
tobi
2023-12-27 11:23:52 +01:00
committed by GitHub
parent 97a1fd9a29
commit 0ff52b71f2
77 changed files with 3262 additions and 1736 deletions

View File

@@ -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" .}}
{{- end }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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" .}}
{{- 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 }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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 }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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">

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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" .}}
{{- end }}

85
web/template/page.tmpl Normal file
View File

@@ -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>

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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>
{{- 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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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" .}}
{{- end }}

View File

@@ -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" .}}
{{- end }}