mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[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:
@@ -1 +1,3 @@
|
||||
node_modules
|
||||
node_modules
|
||||
prism.js
|
||||
prism.css
|
@@ -82,11 +82,11 @@ $button-danger-bg: $error3;
|
||||
$button-danger-fg: $white1;
|
||||
$button-danger-hover-bg: $error2;
|
||||
|
||||
$toot-bg: $gray3;
|
||||
$toot-info-bg: $gray2;
|
||||
$status-bg: $gray3;
|
||||
$status-info-bg: $gray2;
|
||||
|
||||
$toot-focus-bg: $gray5;
|
||||
$toot-focus-info-bg: $gray4;
|
||||
$status-focus-bg: $gray5;
|
||||
$status-focus-info-bg: $gray4;
|
||||
|
||||
$no-img-desc-bg: $orange1;
|
||||
$no-img-desc-fg: $gray1;
|
||||
|
39
web/source/css/about.css
Normal file
39
web/source/css/about.css
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
.about {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
padding: 2rem;
|
||||
|
||||
background: $bg-accent;
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
border-radius: $br;
|
||||
|
||||
.about-section {
|
||||
ul, ol {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,35 +20,52 @@
|
||||
|
||||
/* noto-sans-regular - latin */
|
||||
@font-face {
|
||||
font-family: "Noto Sans";
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
src: url('../fonts/noto-sans-v27-latin-regular.woff2') format('woff2'),
|
||||
url('../fonts/noto-sans-v27-latin-regular.woff') format('woff');
|
||||
font-family: "Noto Sans";
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
src: url('../fonts/noto-sans-v27-latin-regular.woff2') format('woff2'),
|
||||
url('../fonts/noto-sans-v27-latin-regular.woff') format('woff');
|
||||
}
|
||||
|
||||
/* noto-sans-700 - latin */
|
||||
@font-face {
|
||||
font-family: "Noto Sans";
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
src: url('../fonts/noto-sans-v27-latin-700.woff2') format('woff2'),
|
||||
url('../fonts/noto-sans-v27-latin-700.woff') format('woff');
|
||||
font-family: "Noto Sans";
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
src: url('../fonts/noto-sans-v27-latin-700.woff2') format('woff2'),
|
||||
url('../fonts/noto-sans-v27-latin-700.woff') format('woff');
|
||||
}
|
||||
|
||||
/* standard border radius for nice squircles */
|
||||
/*************************************
|
||||
***** SECTION 1: HANDY VARIABLES *****
|
||||
**************************************/
|
||||
|
||||
/*
|
||||
Standard border radius
|
||||
for nice squircles.
|
||||
*/
|
||||
$br: 0.4rem;
|
||||
/* border radius for items that are framed/bordered
|
||||
inside something with $br, eg avatar, header img */
|
||||
|
||||
/*
|
||||
Border radius for items that
|
||||
are framed/bordered inside
|
||||
something with $br, eg avatar,
|
||||
header img, etc.
|
||||
*/
|
||||
$br-inner: 0.2rem;
|
||||
|
||||
/* Fork-Awesome 'fa-fw' fixed icon width
|
||||
keep in sync with https://github.com/ForkAwesome/Fork-Awesome/blob/a99579ae3e735ee70e51ed62dfcee3172b5b2db7/css/fork-awesome.css#L50
|
||||
/*
|
||||
Fork-Awesome 'fa-fw' fixed icon width;
|
||||
keep in sync with https://github.com/ForkAwesome/Fork-Awesome/blob/a99579ae3e735ee70e51ed62dfcee3172b5b2db7/css/fork-awesome.css#L50
|
||||
*/
|
||||
$fa-fw: 1.28571429em;
|
||||
|
||||
/******************************************
|
||||
***** SECTION 2: BASIC GLOBAL STYLING *****
|
||||
*******************************************/
|
||||
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -63,90 +80,28 @@ body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page {
|
||||
display: grid;
|
||||
min-height: 100vh;
|
||||
|
||||
grid-template-columns: 1fr minmax(auto, 50rem) 1fr;
|
||||
grid-template-columns: 1fr min(92%, 50rem) 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
line-height: 2.4rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $link-fg;
|
||||
}
|
||||
|
||||
header, footer {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: 2;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 1.5rem;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
align-self: center;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
flex-grow: 1;
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
|
||||
font-size: 1.5rem;
|
||||
word-wrap: anywhere;
|
||||
color: $fg;
|
||||
}
|
||||
}
|
||||
|
||||
.excerpt-top {
|
||||
margin-bottom: 2rem;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
|
||||
.count {
|
||||
font-weight: bold;
|
||||
color: $fg-accent;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Normalize margins of first and last children.
|
||||
We generally don't want to open a paragraph or
|
||||
paragraph-like element with a top margin or
|
||||
close it with a bottom margin.
|
||||
*/
|
||||
main {
|
||||
p:first-child {
|
||||
p:first-child, ol:first-child, ul:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
p:last-child, ol:last-child, ul:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.button, button {
|
||||
border-radius: 0.2rem;
|
||||
border-radius: $br-inner;
|
||||
color: $button-fg;
|
||||
background: $button-bg;
|
||||
box-shadow: $boxshadow;
|
||||
@@ -184,6 +139,166 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Form styling - used in settings frontend as well.
|
||||
*/
|
||||
input, select, textarea, .input {
|
||||
box-sizing: border-box;
|
||||
border: 0.15rem solid $input-border;
|
||||
border-radius: 0.1rem;
|
||||
color: $fg;
|
||||
background: $input-bg;
|
||||
width: 100%;
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
font-size: 1rem;
|
||||
padding: 0.3rem;
|
||||
|
||||
&:focus, &:active {
|
||||
border-color: $input-focus-border;
|
||||
}
|
||||
|
||||
&:invalid, .invalid & {
|
||||
border-color: $input-error-border;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
opacity: 1;
|
||||
color: $fg-reduced
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Squeeze emojis so they fit inline in text.
|
||||
*/
|
||||
.emoji {
|
||||
width: 1.45em;
|
||||
height: 1.45em;
|
||||
margin: -0.2em 0.02em 0;
|
||||
object-fit: contain;
|
||||
vertical-align: middle;
|
||||
transition: 0.1s;
|
||||
|
||||
/*
|
||||
Enlarge emojis on hover to give
|
||||
viewer a good look at them.
|
||||
*/
|
||||
&:hover, &:active {
|
||||
transform: scale(2);
|
||||
background-color: $bg;
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
border-radius: $br-inner;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Restyle unordered lists; outdent
|
||||
and replace dot with orange dot.
|
||||
*/
|
||||
ul {
|
||||
padding-left: 2.5rem;
|
||||
list-style: none;
|
||||
|
||||
li::before {
|
||||
content: "\2022";
|
||||
color: $border-accent;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 1.5rem;
|
||||
margin-left: -1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Mirror the same styling a little bit
|
||||
for ordered lists by making marker bold.
|
||||
*/
|
||||
ol {
|
||||
padding-left: 2.5rem;
|
||||
|
||||
li::marker {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Outdent block quotes a bit; use
|
||||
orange stripe for left border.
|
||||
*/
|
||||
blockquote {
|
||||
padding: 0.5rem 0 0.5rem 0.5rem;
|
||||
border-left: 0.2rem solid $border-accent;
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/*
|
||||
Nice dashed orange line
|
||||
for horizontal rules.
|
||||
*/
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px dashed $border-accent;
|
||||
}
|
||||
|
||||
/*
|
||||
Don't indent definition
|
||||
lists and definitions.
|
||||
*/
|
||||
dl {
|
||||
margin: 0;
|
||||
|
||||
dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*************************************
|
||||
***** SECTION 3: UTILITY CLASSES *****
|
||||
**************************************/
|
||||
|
||||
/*
|
||||
Column header that appears at the top
|
||||
of threads, at the top of sections of
|
||||
profiles (About, Pinned Posts, etc).
|
||||
*/
|
||||
.col-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 1rem;
|
||||
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
|
||||
margin: 0;
|
||||
background: $profile-bg;
|
||||
border-top-left-radius: $br;
|
||||
border-top-right-radius: $br;
|
||||
padding: 0.75rem;
|
||||
|
||||
a {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.3rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nounderline {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -192,57 +307,37 @@ main {
|
||||
color: $acc1;
|
||||
}
|
||||
|
||||
.logo {
|
||||
justify-self: center;
|
||||
img {
|
||||
height: 30vh;
|
||||
.text-cutoff {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/*
|
||||
Class for lists that don't
|
||||
want the orange dot.
|
||||
*/
|
||||
.nodot {
|
||||
li::before {
|
||||
content: initial;
|
||||
}
|
||||
}
|
||||
|
||||
section.apps {
|
||||
align-self: start;
|
||||
/***********************************
|
||||
***** SECTION 4: SHAMEFUL MESS *****
|
||||
************************************/
|
||||
|
||||
.applist {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 0.5rem;
|
||||
align-content: start;
|
||||
/*
|
||||
EVERYTHING BELOW THIS POINT:
|
||||
Should be moved somewhere else
|
||||
to avoid cluttering up this file.
|
||||
*/
|
||||
|
||||
.entry {
|
||||
display: grid;
|
||||
grid-template-columns: 25% 1fr;
|
||||
gap: 1.5rem;
|
||||
padding: 0.5rem;
|
||||
background: $bg-accent;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
.logo {
|
||||
align-self: center;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.logo.redraw {
|
||||
fill: $fg;
|
||||
stroke: $fg;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div {
|
||||
padding: 0;
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.login {
|
||||
/*
|
||||
Below section stylings are used
|
||||
in transient/error templates.
|
||||
*/
|
||||
section.sign-in {
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -291,98 +386,11 @@ section.oob-token {
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: $error1;
|
||||
background: $error2;
|
||||
border-radius: 0.1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input, select, textarea, .input {
|
||||
box-sizing: border-box;
|
||||
border: 0.15rem solid $input-border;
|
||||
border-radius: 0.1rem;
|
||||
color: $fg;
|
||||
background: $input-bg;
|
||||
width: 100%;
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
font-size: 1rem;
|
||||
padding: 0.3rem;
|
||||
|
||||
&:focus, &:active {
|
||||
border-color: $input-focus-border;
|
||||
}
|
||||
|
||||
&:invalid, .invalid & {
|
||||
border-color: $input-error-border;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
opacity: 1;
|
||||
color: $fg-reduced
|
||||
}
|
||||
|
||||
hr {
|
||||
color: transparent;
|
||||
width: 100%;
|
||||
border-bottom: 0.02rem solid $border-accent;
|
||||
}
|
||||
|
||||
footer {
|
||||
align-self: end;
|
||||
padding: 2rem 0 1rem 0;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
div {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
div {
|
||||
text-align: initial;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
section.apps .applist {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
width: 1.45em;
|
||||
height: 1.45em;
|
||||
margin: -0.2em 0.02em 0;
|
||||
object-fit: contain;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.monospace {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: This is only used in the "finalize"
|
||||
template for new signups; move this elsewhere
|
||||
when that stuff is finished up.
|
||||
*/
|
||||
.callout {
|
||||
margin: 1.5rem 0;
|
||||
border: .05rem solid $border-accent;
|
||||
@@ -397,22 +405,11 @@ footer {
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.fa-spin {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.text-cutoff {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: list and blocklist are only used
|
||||
in settings panel and on blocklist page;
|
||||
consider moving them somewhere else.
|
||||
*/
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -495,21 +492,18 @@ label {
|
||||
}
|
||||
}
|
||||
|
||||
.about {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
h2 {
|
||||
margin: 0.5rem 0;
|
||||
@media screen and (max-width: 30rem) {
|
||||
.domain-blocklist .entry {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: this is only used on About
|
||||
page and in settings application;
|
||||
consider moving it somewhere else.
|
||||
*/
|
||||
.account-card {
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
@@ -541,61 +535,3 @@ label {
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
.instance-rules {
|
||||
list-style-position: inside;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
a.rule {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
color: $fg;
|
||||
text-decoration: none;
|
||||
background: $toot-bg;
|
||||
padding: 1rem;
|
||||
margin: 0.5rem 0;
|
||||
border-radius: $br;
|
||||
line-height: 2rem;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
color: $fg-accent;
|
||||
|
||||
.edit-icon {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
display: none;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 1.75rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
margin-top: 0 !important;
|
||||
display: inline-block;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: $fg-reduced;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 30rem) {
|
||||
.domain-blocklist .entry {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
}
|
@@ -16,26 +16,85 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
header a {
|
||||
margin: 2rem;
|
||||
gap: 2rem;
|
||||
|
||||
img {
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
/*
|
||||
Render instance title a
|
||||
bit bigger on index page.
|
||||
*/
|
||||
.page-header a h1 {
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
main {
|
||||
section {
|
||||
/*
|
||||
Reuse about styling, but rework it
|
||||
to separate sections a bit more.
|
||||
*/
|
||||
.about {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
padding: 0;
|
||||
|
||||
background: initial;
|
||||
box-shadow: initial;
|
||||
border: initial;
|
||||
border-radius: initial;
|
||||
|
||||
.about-section {
|
||||
padding: 2rem;
|
||||
background: $bg-accent;
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
border-radius: $br;
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.apps {
|
||||
align-self: start;
|
||||
|
||||
.applist {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 0.5rem;
|
||||
align-content: start;
|
||||
|
||||
.applist-entry {
|
||||
display: grid;
|
||||
grid-template-columns: 25% 1fr;
|
||||
grid-template-areas: "logo text";
|
||||
gap: 1.5rem;
|
||||
padding: 0.5rem;
|
||||
|
||||
.applist-logo {
|
||||
grid-area: logo;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.applist-logo.redraw {
|
||||
fill: $fg;
|
||||
stroke: $fg;
|
||||
}
|
||||
|
||||
.applist-text {
|
||||
grid-area: text;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.apps .applist {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
107
web/source/css/page.css
Normal file
107
web/source/css/page.css
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
.page {
|
||||
display: grid;
|
||||
min-height: 100vh;
|
||||
|
||||
grid-template-columns: 1fr minmax(auto, 50rem) 1fr;
|
||||
grid-template-columns: 1fr min(92%, 50rem) 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
.page-header, .page-footer {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
grid-column: 2;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 1.5rem;
|
||||
gap: 1rem;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
word-wrap: anywhere;
|
||||
color: $fg;
|
||||
}
|
||||
}
|
||||
|
||||
aside {
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
|
||||
.count {
|
||||
font-weight: bold;
|
||||
color: $fg-accent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
align-self: end;
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
|
||||
/* Override list styling */
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
flex-grow: 1;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.page-header {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
5
web/source/css/prism.css
Normal file
5
web/source/css/prism.css
Normal file
@@ -0,0 +1,5 @@
|
||||
/* PrismJS 1.29.0
|
||||
https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+bash+c+csharp+cpp+docker+elixir+erlang+go+go-module+ini+java+json+kotlin+lua+makefile+markup-templating+nginx+nix+perl+php+promql+python+r+jsx+tsx+ruby+rust+scala+sql+swift+typescript&plugins=show-invisibles+show-language+toolbar+copy-to-clipboard */
|
||||
code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
|
||||
.token.cr,.token.lf,.token.space,.token.tab:not(:empty){position:relative}.token.cr:before,.token.lf:before,.token.space:before,.token.tab:not(:empty):before{color:grey;opacity:.6;position:absolute}.token.tab:not(:empty):before{content:'\21E5'}.token.cr:before{content:'\240D'}.token.crlf:before{content:'\240D\240A'}.token.lf:before{content:'\240A'}.token.space:before{content:'\00B7'}
|
||||
div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
|
@@ -17,28 +17,27 @@
|
||||
*/
|
||||
|
||||
.page {
|
||||
grid-template-columns: 1fr minmax(auto, 60rem) 1fr; /* fallback for lack of min() support */
|
||||
/*
|
||||
Profile page can be a little wider than default
|
||||
page, since we're using a side-by-side column view.
|
||||
*/
|
||||
grid-template-columns: 1fr minmax(auto, 60rem) 1fr;
|
||||
grid-template-columns: 1fr min(92%, 65rem) 1fr;
|
||||
}
|
||||
|
||||
.profile {
|
||||
padding: 0.5rem;
|
||||
border-radius: $br;
|
||||
|
||||
.column-split {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
.profile .column-split {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.profile .header {
|
||||
.profile .profile-header {
|
||||
background: $profile-bg;
|
||||
border-radius: $br;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.header-image {
|
||||
.header-image-wrapper {
|
||||
position: relative;
|
||||
padding-top: 33.33%; /* aspect-ratio 1/3 */
|
||||
|
||||
@@ -55,12 +54,11 @@
|
||||
|
||||
/*
|
||||
Basic info container has the user's avatar, display- and username, and role
|
||||
It's partially overlapped over the header image, by a negative margin-top
|
||||
It's partially overlapped over the header image, by a negative margin-top.
|
||||
*/
|
||||
$avatar-size: 8.5rem;
|
||||
$name-size: 3rem;
|
||||
$username-size: 2rem;
|
||||
|
||||
$overlap: calc($avatar-size - $name-size - $username-size);
|
||||
|
||||
.basic-info {
|
||||
@@ -71,8 +69,8 @@
|
||||
grid-template-rows: $overlap $name-size auto;
|
||||
grid-template-areas:
|
||||
"avatar . ."
|
||||
"avatar displayname displayname"
|
||||
"avatar username role";
|
||||
"avatar namerole namerole"
|
||||
"avatar namerole namerole";
|
||||
|
||||
margin: 1rem;
|
||||
margin-top: calc(-1 * $overlap);
|
||||
@@ -93,131 +91,119 @@
|
||||
}
|
||||
}
|
||||
|
||||
.displayname {
|
||||
grid-area: displayname;
|
||||
line-height: $name-size;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.namerole {
|
||||
grid-area: namerole;
|
||||
|
||||
.username {
|
||||
min-width: 0;
|
||||
grid-area: username;
|
||||
line-height: $username-size;
|
||||
display: grid;
|
||||
gap: 0 1rem;
|
||||
box-sizing: border-box;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: $name-size auto;
|
||||
grid-template-areas:
|
||||
"displayname displayname"
|
||||
"username role";
|
||||
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: $fg-accent;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
.role {
|
||||
background: $bg;
|
||||
color: $fg;
|
||||
border: 0.13rem solid $bg;
|
||||
|
||||
grid-area: role;
|
||||
align-self: center;
|
||||
justify-self: start;
|
||||
border-radius: $br;
|
||||
padding: 0.3rem;
|
||||
|
||||
line-height: 1.1rem;
|
||||
font-size: 0.9rem;
|
||||
font-variant: small-caps;
|
||||
font-weight: bold;
|
||||
|
||||
&.admin {
|
||||
color: $role-admin;
|
||||
border-color: $role-admin;
|
||||
.displayname {
|
||||
grid-area: displayname;
|
||||
line-height: $name-size;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.moderator {
|
||||
color: $role-mod;
|
||||
border-color: $role-mod;
|
||||
|
||||
.username {
|
||||
min-width: 0;
|
||||
grid-area: username;
|
||||
line-height: $username-size;
|
||||
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: $fg-accent;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
.role {
|
||||
background: $bg;
|
||||
color: $fg;
|
||||
border: 0.13rem solid $bg;
|
||||
|
||||
grid-area: role;
|
||||
align-self: center;
|
||||
justify-self: start;
|
||||
border-radius: $br;
|
||||
padding: 0.3rem;
|
||||
|
||||
line-height: 1.1rem;
|
||||
font-size: 0.9rem;
|
||||
font-variant: small-caps;
|
||||
font-weight: bold;
|
||||
|
||||
&.admin {
|
||||
color: $role-admin;
|
||||
border-color: $role-admin;
|
||||
}
|
||||
|
||||
&.moderator {
|
||||
color: $role-mod;
|
||||
border-color: $role-mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
.profile .header {
|
||||
.profile .profile-header {
|
||||
.basic-info {
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: $avatar-size $name-size auto;
|
||||
grid-template-areas:
|
||||
"avatar avatar"
|
||||
"displayname displayname"
|
||||
"username role";
|
||||
|
||||
.displayname {
|
||||
font-size: 1.4rem;
|
||||
"namerole namerole"
|
||||
"namerole namerole";
|
||||
|
||||
.namerole {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: $name-size auto;
|
||||
grid-template-areas:
|
||||
"displayname displayname"
|
||||
"username role";
|
||||
|
||||
.displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile .col-header {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
|
||||
margin: 0;
|
||||
background: $profile-bg;
|
||||
border-top-left-radius: $br;
|
||||
border-top-right-radius: $br;
|
||||
padding: 0.75rem;
|
||||
|
||||
h1, h2 {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.3rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.profile .toots {
|
||||
.profile .statuses-wrapper {
|
||||
flex: 65 25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
min-width: 0%;
|
||||
}
|
||||
|
||||
.col-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 1rem;
|
||||
.profile .statuses {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
|
||||
a {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.rss-icon {
|
||||
display: block;
|
||||
margin: -0.25rem 0;
|
||||
|
||||
.fa {
|
||||
font-size: 2rem;
|
||||
object-fit: contain;
|
||||
vertical-align: middle;
|
||||
color: $orange2;
|
||||
/* can't size a single-color background, so we use a linear-gradient that's effectively white */
|
||||
background: linear-gradient(to right, $white1 100%, transparent 0) no-repeat center center;
|
||||
background-size: 1.2rem 1.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toot {
|
||||
border-radius: 0;
|
||||
|
||||
.info {
|
||||
padding: 0.3rem 0.75rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-left-radius: $br;
|
||||
border-bottom-right-radius: $br;
|
||||
.rss-icon {
|
||||
display: block;
|
||||
margin: -0.25rem 0;
|
||||
|
||||
.fa {
|
||||
font-size: 2rem;
|
||||
object-fit: contain;
|
||||
vertical-align: middle;
|
||||
color: $orange2;
|
||||
/*
|
||||
Can't size a single-color background, so we use
|
||||
a linear-gradient that's effectively white.
|
||||
*/
|
||||
background: linear-gradient(to right, $white1 100%, transparent 0) no-repeat center center;
|
||||
background-size: 1.2rem 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +226,10 @@
|
||||
margin-bottom: -0.25rem;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fields {
|
||||
background: $profile-bg;
|
||||
display: flex;
|
||||
|
@@ -19,25 +19,19 @@
|
||||
@import "photoswipe/dist/photoswipe.css";
|
||||
@import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
|
||||
@import "plyr/dist/plyr.css";
|
||||
@import "./prism.css";
|
||||
|
||||
main {
|
||||
background: transparent;
|
||||
grid-auto-rows: auto;
|
||||
}
|
||||
|
||||
.thread {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: $br;
|
||||
}
|
||||
|
||||
.toot {
|
||||
background: $toot-bg;
|
||||
.status {
|
||||
background: $status-bg;
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
border-radius: $br;
|
||||
position: relative;
|
||||
margin-bottom: $br;
|
||||
padding-top: 0.75rem;
|
||||
|
||||
a {
|
||||
@@ -47,66 +41,75 @@ main {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.author > a {
|
||||
padding: 0 0.75rem;
|
||||
display: grid;
|
||||
grid-template-columns: 3.5rem 1fr auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"avatar display date"
|
||||
"avatar user .";
|
||||
gap: 0 0.5rem;
|
||||
.status-header > address {
|
||||
/*
|
||||
Avoid stretching so wide that user
|
||||
can't click on open thread link that's
|
||||
behind the status header link.
|
||||
*/
|
||||
width: fit-content;
|
||||
|
||||
.avatar {
|
||||
grid-area: avatar;
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
object-fit: cover;
|
||||
|
||||
border: 0.15rem solid $avatar-border;
|
||||
border-radius: $br;
|
||||
overflow: hidden; /* hides corners from img overflowing */
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
background: $bg;
|
||||
}
|
||||
}
|
||||
|
||||
.displayname, .username {
|
||||
justify-self: start;
|
||||
align-self: start;
|
||||
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
> a {
|
||||
padding: 0 0.75rem;
|
||||
display: grid;
|
||||
grid-template-columns: 3.5rem 1fr auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"avatar author-strap author-strap"
|
||||
"avatar author-strap author-strap";
|
||||
gap: 0 0.5rem;
|
||||
font-style: normal;
|
||||
|
||||
.displayname {
|
||||
grid-area: display;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
line-height: 1.3rem;
|
||||
/* margin-top: -0.5rem; */
|
||||
}
|
||||
|
||||
.username {
|
||||
grid-area: user;
|
||||
color: $link-fg;
|
||||
font-size: 1rem;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
grid-area: date;
|
||||
color: $fg-reduced;
|
||||
.avatar {
|
||||
grid-area: avatar;
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
object-fit: cover;
|
||||
|
||||
border: 0.15rem solid $avatar-border;
|
||||
border-radius: $br;
|
||||
overflow: hidden; /* hides corners from img overflowing */
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
background: $bg;
|
||||
}
|
||||
}
|
||||
|
||||
.author-strap {
|
||||
grid-area: author-strap;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas:
|
||||
"display display"
|
||||
"user user";
|
||||
gap: 0 0.5rem;
|
||||
|
||||
.displayname, .username {
|
||||
justify-self: start;
|
||||
align-self: start;
|
||||
max-width: 100%;
|
||||
font-size: 1rem;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
.displayname {
|
||||
grid-area: display;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.username {
|
||||
grid-area: user;
|
||||
color: $link-fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
.status-body {
|
||||
padding: 0.5rem 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -157,6 +160,10 @@ main {
|
||||
line-height: 1.6rem;
|
||||
width: 100%;
|
||||
|
||||
/*
|
||||
Normalize header sizes to fit better
|
||||
with the line-height we use for statuses.
|
||||
*/
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
@@ -187,35 +194,63 @@ main {
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0.5rem 0 0.5rem 0.5rem;
|
||||
border-left: 0.2rem solid $border-accent;
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px dashed $border-accent;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
background-color: $gray2;
|
||||
}
|
||||
|
||||
/*
|
||||
Just code on its own inside status
|
||||
content, ie, `here is some code`.
|
||||
*/
|
||||
code {
|
||||
padding: 0.25rem;
|
||||
border-radius: $br-inner;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
pre {
|
||||
/*
|
||||
Restyle Prism code highlighting toolbar
|
||||
plugin buttons to our own button style.
|
||||
*/
|
||||
.code-toolbar .toolbar {
|
||||
margin-right: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
|
||||
.toolbar-item {
|
||||
span, button {
|
||||
color: $button-fg;
|
||||
background: $button-bg;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.copy-to-clipboard-button, span {
|
||||
box-shadow: $boxshadow;
|
||||
}
|
||||
|
||||
.copy-to-clipboard-button:hover, .copy-to-clipboard-button:hover span {
|
||||
background: $button-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pre, pre[class*="language-"] {
|
||||
border-radius: $br;
|
||||
padding: 0.5rem;
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
|
||||
code {
|
||||
padding: 0.5rem;
|
||||
/*
|
||||
Code inside a pre block, ie.,
|
||||
|
||||
```
|
||||
here is some code
|
||||
```
|
||||
*/
|
||||
code {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border-radius: 0;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
@@ -230,18 +265,6 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
transition: 0.1s;
|
||||
}
|
||||
|
||||
.emoji:hover, .emoji:active {
|
||||
transform: scale(2);
|
||||
background-color: $bg;
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
border-radius: $br-inner;
|
||||
}
|
||||
|
||||
.poll {
|
||||
background-color: $gray2;
|
||||
z-index: 2;
|
||||
@@ -451,41 +474,41 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
background: $toot-info-bg;
|
||||
.status-info {
|
||||
background: $status-info-bg;
|
||||
color: $fg-reduced;
|
||||
border-top: 0.15rem solid $toot-info-border;
|
||||
border-top: 0.15rem solid $status-info-border;
|
||||
padding: 0.5rem 0.75rem;
|
||||
|
||||
time {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: inline-flex;
|
||||
flex: 1;
|
||||
.status-stats {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
|
||||
|
||||
.stats-grouping {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 1rem;
|
||||
}
|
||||
|
||||
.stats-item {
|
||||
span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.stats-item:not(.published-at) {
|
||||
z-index: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.language {
|
||||
margin-left: auto;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
grid-column: span 3;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.toot-link {
|
||||
.status-link {
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@@ -508,15 +531,12 @@ main {
|
||||
/* bottom left, bottom right */
|
||||
border-bottom-left-radius: $br;
|
||||
border-bottom-right-radius: $br;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
background: $toot-focus-bg;
|
||||
padding-bottom: 0;
|
||||
|
||||
.info {
|
||||
background: $toot-focus-info-bg;
|
||||
background: $status-focus-bg;
|
||||
.status-info {
|
||||
background: $status-focus-info-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
web/source/css/thread.css
Normal file
56
web/source/css/thread.css
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
.thread {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
|
||||
/*
|
||||
This column header might contain
|
||||
quite some info, so let it wrap.
|
||||
*/
|
||||
.col-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 1rem;
|
||||
row-gap: 0.5rem;
|
||||
|
||||
box-shadow: $boxshadow;
|
||||
border: $boxshadow-border;
|
||||
|
||||
h2 {
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
border-radius: 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom-left-radius: $br;
|
||||
border-bottom-right-radius: $br;
|
||||
|
||||
.status-info {
|
||||
border-bottom-left-radius: $br;
|
||||
border-bottom-right-radius: $br;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,6 +21,10 @@ const Photoswipe = require("photoswipe/dist/umd/photoswipe.umd.min.js");
|
||||
const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js");
|
||||
const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default;
|
||||
const Plyr = require("plyr");
|
||||
const Prism = require("./prism.js");
|
||||
|
||||
Prism.manual = true;
|
||||
Prism.highlightAll();
|
||||
|
||||
let [_, _user, type, id] = window.location.pathname.split("/");
|
||||
if (type == "statuses") {
|
||||
|
42
web/source/frontend/prism.js
Normal file
42
web/source/frontend/prism.js
Normal file
File diff suppressed because one or more lines are too long
@@ -140,18 +140,23 @@ function ReportedToot({ toot }) {
|
||||
const account = toot.account;
|
||||
|
||||
return (
|
||||
<article className="toot expanded">
|
||||
<section className="author">
|
||||
<a>
|
||||
<img className="avatar" src={account.avatar} alt="" />
|
||||
<span className="displayname">
|
||||
{account.display_name.trim().length > 0 ? account.display_name : account.username}
|
||||
<span className="sr-only">.</span>
|
||||
</span>
|
||||
<span className="username">@{account.username}</span>
|
||||
</a>
|
||||
</section>
|
||||
<section className="body">
|
||||
<article className="status expanded">
|
||||
<header className="status-header">
|
||||
<address>
|
||||
<a style={{margin: 0}}>
|
||||
<img className="avatar" src={account.avatar} alt="" />
|
||||
<dl className="author-strap">
|
||||
<dt className="sr-only">Display name</dt>
|
||||
<dd className="displayname text-cutoff">
|
||||
{account.display_name.trim().length > 0 ? account.display_name : account.username}
|
||||
</dd>
|
||||
<dt className="sr-only">Username</dt>
|
||||
<dd className="username text-cutoff">@{account.username}</dd>
|
||||
</dl>
|
||||
</a>
|
||||
</address>
|
||||
</header>
|
||||
<section className="status-body">
|
||||
<div className="text">
|
||||
<div className="content">
|
||||
{toot.spoiler_text?.length > 0
|
||||
@@ -164,8 +169,17 @@ function ReportedToot({ toot }) {
|
||||
<TootMedia media={toot.media_attachments} sensitive={toot.sensitive} />
|
||||
}
|
||||
</section>
|
||||
<aside className="info">
|
||||
<time dateTime={toot.created_at}>{new Date(toot.created_at).toLocaleString()}</time>
|
||||
<aside className="status-info">
|
||||
<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={toot.created_at}>{new Date(toot.created_at).toLocaleString()}</time>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
</aside>
|
||||
</article>
|
||||
);
|
||||
|
@@ -83,7 +83,7 @@ function ReportEntry({ report }) {
|
||||
<div className="usernames">
|
||||
<Username user={from} link={false} /> reported <Username user={target} link={false} />
|
||||
</div>
|
||||
<h3 className="status">
|
||||
<h3 className="report-status">
|
||||
{report.action_taken ? "Resolved" : "Open"}
|
||||
</h3>
|
||||
</div>
|
||||
|
@@ -22,24 +22,29 @@ const React = require("react");
|
||||
module.exports = function FakeProfile({ avatar, header, display_name, username, role }) {
|
||||
return ( // Keep in sync with web/template/profile.tmpl
|
||||
<div className="profile">
|
||||
<div className="header">
|
||||
<div className="header-image">
|
||||
<div className="profile-header">
|
||||
<div className="header-image-wrapper">
|
||||
<img src={header} alt={header ? `header image for ${username}` : "None set"} />
|
||||
</div>
|
||||
<div className="basic-info" aria-hidden="true">
|
||||
<a className="avatar" href={avatar}>
|
||||
<img src={avatar} alt={avatar ? `avatar image for ${username}` : "None set"} />
|
||||
</a>
|
||||
<span className="displayname text-cutoff">
|
||||
{display_name.trim().length > 0 ? display_name : username}
|
||||
<span className="sr-only">.</span>
|
||||
</span>
|
||||
<span className="username text-cutoff">@{username}</span>
|
||||
{(role && role.name != "user") &&
|
||||
<div className={`role ${role.name}`}>
|
||||
<span className="sr-only">Role: </span>{role.name}
|
||||
</div>
|
||||
}
|
||||
<dl className="namerole">
|
||||
<dt className="sr-only">Display name</dt>
|
||||
<dd className="displayname text-cutoff">{display_name.trim().length > 0 ? display_name : username}</dd>
|
||||
<dt className="sr-only">Username</dt>
|
||||
<dd className="username text-cutoff">@{username}</dd>
|
||||
<dt className="sr-only">Role</dt>
|
||||
{
|
||||
(role && role.name != "user") ?
|
||||
<>
|
||||
<dd className="sr-only">Role</dd>
|
||||
<dt className={`role ${role.name}`}>{role.name}</dt>
|
||||
</>
|
||||
: null
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -29,20 +29,27 @@ module.exports = function FakeToot({ children }) {
|
||||
} } = query.useVerifyCredentialsQuery();
|
||||
|
||||
return (
|
||||
<article className="toot expanded">
|
||||
<section className="author">
|
||||
<a>
|
||||
<img className="avatar" src={account.avatar} alt="" />
|
||||
<span className="displayname">
|
||||
{account.display_name.trim().length > 0 ? account.display_name : account.username}
|
||||
<span className="sr-only">.</span>
|
||||
</span>
|
||||
<span className="username">@{account.username}</span>
|
||||
</a>
|
||||
</section>
|
||||
<section className="body">
|
||||
<article className="status expanded">
|
||||
<header className="status-header">
|
||||
<address>
|
||||
<a style={{margin: 0}}>
|
||||
<img className="avatar" src={account.avatar} alt="" />
|
||||
<dl className="author-strap">
|
||||
<dt className="sr-only">Display name</dt>
|
||||
<dd className="displayname text-cutoff">
|
||||
{account.display_name.trim().length > 0 ? account.display_name : account.username}
|
||||
</dd>
|
||||
<dt className="sr-only">Username</dt>
|
||||
<dd className="username text-cutoff">@{account.username}</dd>
|
||||
</dl>
|
||||
</a>
|
||||
</address>
|
||||
</header>
|
||||
<section className="status-body">
|
||||
<div className="text">
|
||||
{children}
|
||||
<div className="content">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
|
@@ -20,26 +20,14 @@ body {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.content {
|
||||
.page-content {
|
||||
grid-column: 1 / span 3; /* stretch entire width, to fit panel + sidebar nav */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
justify-content: start;
|
||||
|
||||
a {
|
||||
margin: 1.5rem;
|
||||
gap: 1rem;
|
||||
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 3rem;
|
||||
}
|
||||
}
|
||||
/* Don't inherit orange dot from base.css. */
|
||||
ul li::before {
|
||||
content: initial;
|
||||
}
|
||||
|
||||
#root {
|
||||
@@ -1007,7 +995,7 @@ button.with-padding {
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 0.5rem;
|
||||
|
||||
.status {
|
||||
.report-status {
|
||||
color: $border-accent;
|
||||
}
|
||||
}
|
||||
@@ -1029,7 +1017,7 @@ button.with-padding {
|
||||
color: $fg-reduced;
|
||||
border-left: 0.4rem solid $bg;
|
||||
|
||||
.byline .status {
|
||||
.byline .report-status {
|
||||
color: $fg-reduced;
|
||||
}
|
||||
|
||||
@@ -1141,11 +1129,62 @@ button.with-padding {
|
||||
}
|
||||
}
|
||||
|
||||
.instance-rules {
|
||||
list-style-position: inside;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
a.rule {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
color: $fg;
|
||||
text-decoration: none;
|
||||
background: $status-bg;
|
||||
padding: 1rem;
|
||||
margin: 0.5rem 0;
|
||||
border-radius: $br;
|
||||
line-height: 2rem;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
color: $fg-accent;
|
||||
|
||||
.edit-icon {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
display: none;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 1.75rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
margin-top: 0 !important;
|
||||
display: inline-block;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: $fg-reduced;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (orientation: portrait) {
|
||||
.reports .report .byline {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
.status {
|
||||
.report-status {
|
||||
grid-row: 1;
|
||||
}
|
||||
}
|
||||
@@ -1162,4 +1201,14 @@ button.with-padding {
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.fa-spin {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.monospace {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
@@ -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 }}
|
@@ -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
|
||||
{{- .instance.Configuration.Statuses.MaxCharacters }} characters, and
|
||||
{{- .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
|
||||
{{- .instance.Configuration.Polls.MaxOptions }} options, with
|
||||
{{- .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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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">
|
@@ -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 }}
|
115
web/template/index_apps.tmpl
Normal file
115
web/template/index_apps.tmpl
Normal 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 }}
|
@@ -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
85
web/template/page.tmpl
Normal 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>
|
67
web/template/page_footer.tmpl
Normal file
67
web/template/page_footer.tmpl
Normal 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 }}
|
72
web/template/page_header.tmpl
Normal file
72
web/template/page_header.tmpl
Normal 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 }}
|
57
web/template/page_ogmeta.tmpl
Normal file
57
web/template/page_ogmeta.tmpl
Normal 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 }}
|
41
web/template/page_stylesheets.tmpl
Normal file
41
web/template/page_stylesheets.tmpl
Normal 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 }}
|
@@ -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"> {{- .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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 }}
|
@@ -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 -}} {{- $media.RemoteURL -}}"
|
||||
{{- else }}
|
||||
title="Link to external media. {{- $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 -}} {{- $media.RemoteURL -}}"
|
||||
{{- else }}
|
||||
title="Open external media. {{- $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 }}
|
55
web/template/status_attributes.tmpl
Normal file
55
web/template/status_attributes.tmpl
Normal 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 }}
|
56
web/template/status_header.tmpl
Normal file
56
web/template/status_header.tmpl
Normal 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 }}
|
74
web/template/status_info.tmpl
Normal file
74
web/template/status_info.tmpl
Normal 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 }}
|
@@ -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
|
||||
{{- else -}}
|
||||
Poll
|
||||
{{- 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 -}}%</meter>
|
||||
<div class="sr-only">Option {{ increment $index }}: <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 -}}%</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 -}}
|
||||
{{- . -}} vote
|
||||
{{- else -}}
|
||||
{{- . }} votes
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- with . }}
|
||||
<figure class="poll">
|
||||
<figcaption class="poll-info">
|
||||
<span class="poll-expiry">
|
||||
{{- if .Poll.Multiple -}}
|
||||
Multiple-choice poll
|
||||
{{- else -}}
|
||||
Poll
|
||||
{{- 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 -}}
|
||||
{{- 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 -}}%</span>
|
||||
<span class="sr-only">,</span>
|
||||
<span class="poll-vote-count">{{- template "votes" . -}}</span>
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
</div>
|
||||
</li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
</figure>
|
||||
{{- end }}
|
@@ -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 }}
|
@@ -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 }}
|
Reference in New Issue
Block a user