Thread views on the web (#207)

* Webviews for status threads

* fix up templates

* add ForkAwesome and gotosocial-styling into repo

* clean up gotosocial-styling, old styling

* update CONTRIBUTING with new css building, and nodemon recommendation

* update Dockerfile with new css bundling

* those weren't supposed to make it in

* upgrade gotosocial-styling deps

* update authorize template with main wrapper

* update css pipeline

* abstract status from thread to avoid copy-pasting

* basic CW implementation

* fix PR review suggestions

* fix no-image-desc icon alignment

* remove template loading println

* remove println

* remove changes to testmodels

* reset changes to testmodels
This commit is contained in:
f0x52
2021-09-13 14:45:33 +02:00
committed by GitHub
parent 635281f133
commit 026674bc2c
29 changed files with 1742 additions and 190 deletions

View File

@@ -1,11 +1,9 @@
{{ template "header.tmpl" .}}
<aside class="left logo">
<img src="/assets/sloth.png" alt="Clipart styled sloth logo">
</aside>
<section>
<h1>404: Page Not Found</h1>
If you believe this was an error, you can <a href="{{.instance.ContactAccount.URL}}">contact an admin</a>
</section>
<main>
<section>
<h1>404: Page Not Found</h1>
If you believe this was an error, you can <a href="{{.instance.ContactAccount.URL}}">contact an admin</a>
</section>
</main>
{{ template "footer.tmpl" .}}

View File

@@ -1,15 +1,17 @@
{{ template "header.tmpl" .}}
<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>
<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" .}}

View File

@@ -1,19 +1,26 @@
<!DOCTYPE html>
<!-- header.tmpl -->
<!-- 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">
<meta name="og:title" content="{{.instance.Title}}">
<meta name="og:description" content="{{.instance.Description}}">
<link rel="stylesheet" href="/assets/bundle.css">
<link rel="shortcut icon" href="/assets/sloth.png" type="image/png">
<meta name="og:title" content="GoToSocial Testing Instance">
<meta name="og:description" content="">
<link rel="stylesheet" href="/assets/base.css">
{{range .stylesheets}}<link rel="stylesheet" href="{{.}}">
{{end}}
<link rel="shortcut icon" href="/assets/logo.png" type="image/png">
<title>{{.instance.Title}} - GoToSocial</title>
</head>
<body>
<header>
<h1>
{{.instance.Title}}
</h1>
<img src="/assets/logo.png" alt="Instance Logo"/>
<div>
<h1>
{{.instance.Title}}
</h1>
</div>
<div></div>
</header>

View File

@@ -1,40 +1,40 @@
{{ template "header.tmpl" .}}
<div class="left logo">
<img src="/assets/sloth.png" alt="Clipart styled sloth logo">
</div>
<section>
<h1>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.</h1>
<div className="short-description">
{{.instance.ShortDescription |noescape}}
</div>
</section>
<main class="lightgray">
<section class="apps">
<p>
GoToSocial does not provide its own frontend, but implements the Mastodon client API.
You can use this server through a variety of clients:
</p>
<div class="applist">
<div class="entry">
<svg class="logo redraw" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10000 10000">
<path d="M9212 5993H5987V823c1053 667 2747 2177 3225 5170zM3100 2690A12240 12240 0 01939 6035h2161zm676 7210h2448a3067 3067 0 003067-3067H5052V627a527 527 0 00-1052 0v6206H709a3067 3067 0 003067 3067z"></path>
</svg>
<div>
<h2>Pinafore</h2>
<p>Pinafore is a web client designed for speed and simplicity.</p>
<a class="button" href="https://pinafore.social/settings/instances/add">Use Pinafore</a>
<section>
<h1>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.</h1>
<div className="short-description">
{{.instance.ShortDescription |noescape}}
</div>
</section>
<section class="apps">
<p>
GoToSocial does not provide its own frontend, but implements the Mastodon client API.
You can use this server through a variety of clients:
</p>
<div class="applist">
<div class="entry">
<svg class="logo redraw" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10000 10000">
<path d="M9212 5993H5987V823c1053 667 2747 2177 3225 5170zM3100 2690A12240 12240 0 01939 6035h2161zm676 7210h2448a3067 3067 0 003067-3067H5052V627a527 527 0 00-1052 0v6206H709a3067 3067 0 003067 3067z"></path>
</svg>
<div>
<h2>Pinafore</h2>
<p>Pinafore is a web client designed for speed and simplicity.</p>
<a class="button" href="https://pinafore.social/settings/instances/add">Use Pinafore</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 class="button" href="https://tusky.app">Get Tusky</a>
</div>
</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 class="button" href="https://tusky.app">Get Tusky</a>
</div>
</div>
</div>
</section>
</section>
</main>
{{ template "footer.tmpl" .}}

View File

@@ -1,13 +1,15 @@
{{ template "header.tmpl" .}}
<section class="login">
<h1>Login</h1>
<form action="/auth/sign_in" method="POST">
<label for="email">Email</label>
<input type="text" class="form-control" name="username" required placeholder="Please enter your email address">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" required placeholder="Please enter your password">
<button type="submit" class="btn btn-success">Login</button>
</form>
</section>
<main>
<section class="login">
<h1>Login</h1>
<form action="/auth/sign_in" method="POST">
<label for="email">Email</label>
<input type="text" class="form-control" name="username" required placeholder="Please enter your email address">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" required placeholder="Please enter your password">
<button type="submit" class="btn btn-success">Login</button>
</form>
</section>
</main>
{{ template "footer.tmpl" .}}

36
web/template/status.tmpl Normal file
View File

@@ -0,0 +1,36 @@
<a href="{{.Account.URL}}" class="avatar"><img src="{{.Account.Avatar}}"></a>
<a href="{{.Account.URL}}" class="displayname">{{if .Account.DisplayName}}{{.Account.DisplayName}}{{else}}{{.Account.Username}}{{end}}</a>
<a href="{{.Account.URL}}" class="username">@{{.Account.Username}}</a>
<div class="text">
{{if .SpoilerText}}
<input class="spoiler" id="hideSpoiler-{{.ID}}" type="checkbox" style="display: none" aria-hidden="true" checked="true" />
<div class="spoiler">
<span>{{.SpoilerText}}</span><label class="spoiler-label" for="hideSpoiler-{{.ID}}">Toggle visibility</label>
</div>
{{end}}
<div class="content">
{{.Content |noescape}}
</div>
</div>
{{with .MediaAttachments}}
<div class="media {{(len .) | oddOrEven }}{{if eq (len .) 1}} single{{end}}{{if eq (len .) 2}} double{{end}}">
{{range .}}
<a href="{{.URL}}" target="_blank" title="{{.Description}}">
{{if not .Description}}
<div class="no-image-desc" aria-hidden="true" ><i class="fa fa-info-circle"></i><span>Missing image description</span></div>
{{end}}
<img src="{{.PreviewURL}}" alt="{{.Description}}"/>
</a>
{{end}}
</div>
{{end}}
<div class="info">
<div id="date">{{.CreatedAt | timestamp}}</div>
<div class="stats">
<div id="visibility">{{.Visibility | visibilityIcon}}</div>
<div id="replies"><i aria-label="Replies" class="fa fa-reply-all"></i> {{.RepliesCount}}</div>
<div id="boosts"><i aria-label="Boosts" class="fa fa-retweet"></i> {{.ReblogsCount}}</div>
<div id="favorites"><i aria-label="Favorites" class="fa fa-star"></i> {{.FavouritesCount}}</div>
</div>
</div>
<a href="{{.URL}}" class="toot-link">View toot</a>

34
web/template/thread.tmpl Normal file
View File

@@ -0,0 +1,34 @@
{{ template "header.tmpl" .}}
<main>
<div class="thread">
{{range .context.Ancestors}}
<div class="toot">
{{ template "status.tmpl" .}}
</div>
{{end}}
<div class="toot expanded">
{{ template "status.tmpl" .status}}
</div>
{{range .context.Descendants}}
<div class="toot">
{{ template "status.tmpl" .}}
</div>
{{end}}
</div>
</main>
<script>
Array.from(document.getElementsByClassName("spoiler-label")).forEach((label) => {
let checkbox = document.getElementById(label.htmlFor);
function update() {
if(checkbox.checked) {
label.innerHTML = "Show more";
} else {
label.innerHTML = "Show less";
}
}
update();
label.addEventListener("click", () => {setTimeout(update, 1)});
});
</script>
{{ template "footer.tmpl" .}}