mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 20:12:26 -05:00 
			
		
		
		
	[frontend] Profiles with fields & more (#1764)
* redesign status template
* separate index page styling
* redesign profile template
* fix header styling/wrapping
* remove old spoiler js
* fix status cw button wrapping
* fix status info variables
* profile responsiveness, accessibility tweaks
* fix variable use, mobile
* remove duplicate id's
* rss icon, fix indent
* fix toot border-radius
* fix toot spacing
* emojify and html profile fields
* refactor (sensitive) media rendering
* plaintext profile fields
* bundle plyr icon svg
* only pause video when switching photoswipe slides
* yarn upgrade
* profile fields formatting
* replace uglifyify with @browserify updated fork
* fix profile field templating (yet again)
* fix React classes
* testrig: add testing profile field for admin user
* fix sensitive media interactions
* Revert "testrig: add testing profile field for admin user"
This reverts commit 80490c183e.
* settings interface wrapping
* fix reported toot styling
* add role to profile sr-only text
* comment fallback rule
* remove currently unused image description lacking indicator
	
	
This commit is contained in:
		
					parent
					
						
							
								6392e00653
							
						
					
				
			
			
				commit
				
					
						9cc9ffc5a7
					
				
			
		
					 21 changed files with 1754 additions and 1382 deletions
				
			
		|  | @ -22,6 +22,7 @@ import ( | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | @ -158,6 +159,15 @@ func emojify(emojis []apimodel.Emoji, inputText template.HTML) template.HTML { | ||||||
| 	return template.HTML(out) | 	return template.HTML(out) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func acctInstance(acct string) string { | ||||||
|  | 	parts := strings.Split(acct, "@") | ||||||
|  | 	if len(parts) > 1 { | ||||||
|  | 		return "@" + parts[1] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func LoadTemplateFunctions(engine *gin.Engine) { | func LoadTemplateFunctions(engine *gin.Engine) { | ||||||
| 	engine.SetFuncMap(template.FuncMap{ | 	engine.SetFuncMap(template.FuncMap{ | ||||||
| 		"escape":           escape, | 		"escape":           escape, | ||||||
|  | @ -169,5 +179,6 @@ func LoadTemplateFunctions(engine *gin.Engine) { | ||||||
| 		"timestampVague":   timestampVague, | 		"timestampVague":   timestampVague, | ||||||
| 		"timestampPrecise": timestampPrecise, | 		"timestampPrecise": timestampPrecise, | ||||||
| 		"emojify":          emojify, | 		"emojify":          emojify, | ||||||
|  | 		"acctInstance":     acctInstance, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,5 +43,8 @@ func (m *Module) baseHandler(c *gin.Context) { | ||||||
| 	c.HTML(http.StatusOK, "index.tmpl", gin.H{ | 	c.HTML(http.StatusOK, "index.tmpl", gin.H{ | ||||||
| 		"instance": instance, | 		"instance": instance, | ||||||
| 		"ogMeta":   ogBase(instance), | 		"ogMeta":   ogBase(instance), | ||||||
|  | 		"stylesheets": []string{ | ||||||
|  | 			distPathPrefix + "/index.css", | ||||||
|  | 		}, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,3 +5,5 @@ The following files and subdirectories in this directory are licensed under the | ||||||
| - ./default_avatars/* (all default avatars) | - ./default_avatars/* (all default avatars) | ||||||
| 
 | 
 | ||||||
| To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. | To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. | ||||||
|  | 
 | ||||||
|  | The plyr.svg file is MIT licensed, and can be found at https://github.com/sampotts/plyr | ||||||
							
								
								
									
										1
									
								
								web/assets/plyr.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/assets/plyr.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 5.6 KiB | 
|  | @ -69,8 +69,10 @@ $border-accent: $orange2; | ||||||
| 
 | 
 | ||||||
| $link-fg: $fg-accent; | $link-fg: $fg-accent; | ||||||
| 
 | 
 | ||||||
| $role-moderator: $orange1; | $role-admin: $orange2; | ||||||
| $role-admin: $blue2; | $role-mod: $blue2; | ||||||
|  | 
 | ||||||
|  | $profile-bg: $gray4; | ||||||
| 
 | 
 | ||||||
| $button-bg: $blue2; | $button-bg: $blue2; | ||||||
| $button-fg: $gray1; | $button-fg: $gray1; | ||||||
|  | @ -80,10 +82,11 @@ $button-danger-bg: $error3; | ||||||
| $button-danger-fg: $white1; | $button-danger-fg: $white1; | ||||||
| $button-danger-hover-bg: $error2; | $button-danger-hover-bg: $error2; | ||||||
| 
 | 
 | ||||||
| $toot-focus-bg: $gray5; | $toot-bg: $gray3; | ||||||
| $toot-unfocus-bg: $gray2; | $toot-info-bg: $gray2; | ||||||
| 
 | 
 | ||||||
| $toot-info-bg: $gray4; | $toot-focus-bg: $gray5; | ||||||
|  | $toot-focus-info-bg: $gray4; | ||||||
| 
 | 
 | ||||||
| $no-img-desc-bg: $orange1; | $no-img-desc-bg: $orange1; | ||||||
| $no-img-desc-fg: $gray1; | $no-img-desc-fg: $gray1; | ||||||
|  | @ -117,3 +120,12 @@ $error-bg: $error2; | ||||||
| $list-entry-bg: $gray2; | $list-entry-bg: $gray2; | ||||||
| $list-entry-alternate-bg: $gray3; | $list-entry-alternate-bg: $gray3; | ||||||
| $list-entry-hover-bg: $gray4; | $list-entry-hover-bg: $gray4; | ||||||
|  | 
 | ||||||
|  | /* Plyr video player */ | ||||||
|  | $plyr-color-main: $orange2; | ||||||
|  | $plyr-video-background: $bg-accent; | ||||||
|  | $plyr-badge-background: $bg-accent; | ||||||
|  | $plyr-video-controls-background: $bg-accent; | ||||||
|  | $plyr-badge-text-color: $fg; | ||||||
|  | $plyr-badge-border-radius: $br; | ||||||
|  | $plyr-video-progress-buffered-background: $gray8; | ||||||
|  | @ -44,6 +44,11 @@ $br: 0.4rem; | ||||||
|    inside something with $br, eg avatar, header img */ |    inside something with $br, eg avatar, header img */ | ||||||
| $br-inner: 0.2rem;  | $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 | ||||||
|  | */ | ||||||
|  | $fa-fw: 1.28571429em; | ||||||
|  | 
 | ||||||
| html, body { | html, body { | ||||||
| 	padding: 0; | 	padding: 0; | ||||||
| 	margin: 0; | 	margin: 0; | ||||||
|  | @ -95,27 +100,26 @@ header { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| header a { | header a { | ||||||
| 	margin: 2rem; |  | ||||||
| 	display: flex; | 	display: flex; | ||||||
| 	flex-wrap: wrap; | 	flex-wrap: wrap; | ||||||
| 	gap: 2rem; | 	margin: 1.5rem; | ||||||
|  | 	gap: 1rem; | ||||||
|  | 	justify-content: center; | ||||||
| 
 | 
 | ||||||
| 	img { | 	img { | ||||||
| 		align-self: center; | 		align-self: center; | ||||||
| 		height: 6rem; | 		height: 3rem; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	div { |  | ||||||
| 		flex-grow: 1; |  | ||||||
| 		align-self: center; |  | ||||||
| 		display: flex; |  | ||||||
| 
 |  | ||||||
| 	h1 { | 	h1 { | ||||||
| 			word-wrap: anywhere; | 		flex-grow: 1; | ||||||
| 		align-self: center; | 		align-self: center; | ||||||
|  | 		text-align: center; | ||||||
|  | 
 | ||||||
|  | 		font-size: 1.5rem; | ||||||
|  | 		word-wrap: anywhere; | ||||||
| 		color: $fg; | 		color: $fg; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .excerpt-top { | .excerpt-top { | ||||||
|  | @ -132,15 +136,6 @@ header a { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| main { | main { | ||||||
| 	section { |  | ||||||
| 		background: $bg-accent; |  | ||||||
| 		box-shadow: $boxshadow; |  | ||||||
| 		border: $boxshadow-border; |  | ||||||
| 		border-radius: $br; |  | ||||||
| 		padding: 2rem; |  | ||||||
| 		margin-bottom: 2rem; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	p:first-child { | 	p:first-child { | ||||||
| 		margin-top: 0; | 		margin-top: 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								web/source/css/index.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								web/source/css/index.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | /* | ||||||
|  | 	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/>. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | header a { | ||||||
|  | 	margin: 2rem; | ||||||
|  | 	gap: 2rem; | ||||||
|  | 
 | ||||||
|  | 	img { | ||||||
|  | 		height: 6rem; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	h1 { | ||||||
|  | 		font-size: 2rem; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main { | ||||||
|  | 	section { | ||||||
|  | 		background: $bg-accent; | ||||||
|  | 		box-shadow: $boxshadow; | ||||||
|  | 		border: $boxshadow-border; | ||||||
|  | 		border-radius: $br; | ||||||
|  | 		padding: 2rem; | ||||||
|  | 		margin-bottom: 2rem; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -16,269 +16,187 @@ | ||||||
| 	along with this program.  If not, see <http://www.gnu.org/licenses/>. | 	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| header { | .page { | ||||||
| 	a img { | 	grid-template-columns: 1fr minmax(auto, 60rem) 1fr; /* fallback for lack of min() support */ | ||||||
| 		height: 5rem; | 	grid-template-columns: 1fr min(92%, 65rem) 1fr; | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| main { |  | ||||||
| 	background: transparent; |  | ||||||
| 	padding-top: 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .profile { | .profile { | ||||||
| 	background: $bg-accent; | 	padding: 0.5rem; | ||||||
| 	display: grid; |  | ||||||
| 	grid-template-columns: 100%; |  | ||||||
| 	gap: 0.5rem; |  | ||||||
| 	margin-bottom: 0.2rem; |  | ||||||
| 	overflow-x: hidden; |  | ||||||
| 	position: relative; |  | ||||||
| 
 |  | ||||||
| 	border-radius: $br; | 	border-radius: $br; | ||||||
| 	box-shadow: $boxshadow; |  | ||||||
| 	border: $boxshadow-border; |  | ||||||
| 
 | 
 | ||||||
| 	.headerimage { | 	.column-split { | ||||||
| 		width: 100%; | 		display: flex; | ||||||
| 		aspect-ratio: 3 / 1; | 		flex-wrap: wrap; | ||||||
| 		max-height: 16rem; | 		gap: 1rem; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .profile .header { | ||||||
|  | 	background: $profile-bg; | ||||||
|  | 	border-radius: $br; | ||||||
| 	overflow: hidden; | 	overflow: hidden; | ||||||
| 		box-shadow: $boxshadow; | 	margin-bottom: 1rem; | ||||||
|  | 
 | ||||||
|  | 	.header-image { | ||||||
|  | 		position: relative; | ||||||
|  | 		padding-top: 33.33%; /* aspect-ratio 1/3 */ | ||||||
| 
 | 
 | ||||||
| 		img { | 		img { | ||||||
|  | 			position: absolute; | ||||||
|  | 			top: 0; | ||||||
|  | 			left: 0; | ||||||
|  | 			right: 0; | ||||||
| 			width: 100%; | 			width: 100%; | ||||||
| 			height: 100%; | 			height: 100%; | ||||||
| 			object-fit: cover; | 			object-fit: cover; | ||||||
| 			border-radius: $br-inner $br-inner 0 0; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.basic { | 	/*  | ||||||
| 		height: 8.5rem; | 		Basic info container has the user's avatar, display- and username, and role | ||||||
| 		margin-top: -6.5rem; | 		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 { | ||||||
|  | 		position: relative; | ||||||
| 		display: grid; | 		display: grid; | ||||||
| 		grid-template-columns: 1rem 8.5rem 1fr; | 		box-sizing: border-box; | ||||||
| 		grid-template-rows: 3rem 3rem 2.5rem; | 		grid-template-columns: $avatar-size auto 1fr; | ||||||
| 
 | 		grid-template-rows: $overlap $name-size auto; | ||||||
| 		grid-template-areas: | 		grid-template-areas: | ||||||
| 			".       avatar ." | 			"avatar . ." | ||||||
| 			"filler2 avatar displayname" | 			"avatar displayname displayname" | ||||||
| 			".       avatar username"; | 			"avatar username role"; | ||||||
| 
 | 
 | ||||||
| 		#profile-basic-filler2 { | 		margin: 1rem; | ||||||
| 			grid-area: filler2; | 		margin-top: calc(-1 * $overlap); | ||||||
| 			background: $bg-trans; | 		gap: 0 1rem; | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		.avatar { | 		.avatar { | ||||||
| 			align-self: end; |  | ||||||
| 			box-sizing: border-box; |  | ||||||
| 			height: 8.5rem; |  | ||||||
| 			width: 8.5rem; |  | ||||||
| 			grid-area: avatar; | 			grid-area: avatar; | ||||||
| 			background: $bg; | 			height: $avatar-size; | ||||||
|  | 			width: $avatar-size; | ||||||
| 			border: 0.2rem solid $avatar-border; | 			border: 0.2rem solid $avatar-border; | ||||||
| 			padding: 0; |  | ||||||
| 			border-radius: $br; | 			border-radius: $br; | ||||||
| 			position: relative; | 			overflow: hidden; /* prevents image extending beyond rounded borders */ | ||||||
| 
 | 
 | ||||||
| 			box-shadow: $boxshadow; |  | ||||||
| 			img { | 			img { | ||||||
| 				object-fit: cover; |  | ||||||
| 				border-radius: $br-inner; |  | ||||||
| 				width: 100%; |  | ||||||
| 				height: 100%; | 				height: 100%; | ||||||
|  | 				width: 100%; | ||||||
|  | 				object-fit: cover; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		a, div { |  | ||||||
| 			color: inherit; |  | ||||||
| 			text-decoration: none; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.displayname { | 		.displayname { | ||||||
| 			grid-area: displayname; | 			grid-area: displayname; | ||||||
|  | 			line-height: $name-size; | ||||||
|  | 			font-size: 1.5rem; | ||||||
| 			font-weight: bold; | 			font-weight: bold; | ||||||
| 			font-size: 2rem; |  | ||||||
| 			line-height: 3rem; |  | ||||||
| 			background: $bg-trans; |  | ||||||
| 			word-break: break-all; |  | ||||||
| 			white-space: nowrap; |  | ||||||
| 			text-overflow: ellipsis; |  | ||||||
| 			overflow: hidden; |  | ||||||
| 			max-height: 6rem; |  | ||||||
| 			padding: 0 0.5rem; |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.usernamecontainer { |  | ||||||
| 			height: 2.5rem; |  | ||||||
| 			display: grid; |  | ||||||
| 			grid-template-columns: auto 1fr; |  | ||||||
| 			grid-area: username; |  | ||||||
| 			/* justify-content: space-between; */ |  | ||||||
| 			padding: 0; |  | ||||||
| 			gap: 0.5rem; |  | ||||||
| 			position: relative; |  | ||||||
| 			 |  | ||||||
| 			color: $fg-accent; |  | ||||||
| 			font-weight: bold; |  | ||||||
| 
 |  | ||||||
| 		.username { | 		.username { | ||||||
| 				white-space: nowrap; | 			min-width: 0; | ||||||
| 				text-overflow: ellipsis; | 			grid-area: username; | ||||||
| 				overflow: hidden; | 			line-height: $username-size; | ||||||
| 				user-select: all; |  | ||||||
| 
 | 
 | ||||||
| 				line-height: 2.5rem; | 			font-size: 1rem; | ||||||
| 				padding-left: 0; | 			font-weight: bold; | ||||||
| 				margin-left: 0.5rem; | 			color: $fg-accent; | ||||||
|  | 			user-select: all; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.role { | 		.role { | ||||||
| 				justify-self: start; | 			background: $bg; | ||||||
|  | 			color: $fg; | ||||||
|  | 			border: 0.13rem solid $bg; | ||||||
|  | 
 | ||||||
|  | 			grid-area: role; | ||||||
| 			align-self: center; | 			align-self: center; | ||||||
|  | 			justify-self: start; | ||||||
|  | 			border-radius: $br; | ||||||
|  | 			padding: 0.3rem; | ||||||
|  | 			 | ||||||
| 			line-height: 1.1rem; | 			line-height: 1.1rem; | ||||||
| 			font-size: 0.9rem; | 			font-size: 0.9rem; | ||||||
| 				margin-right: 0.2rem; |  | ||||||
| 				padding: 0.2rem; |  | ||||||
| 				margin-top: 0.1rem; |  | ||||||
| 				padding-top: 0.1rem; |  | ||||||
| 				border: 0.1rem solid $gray1; |  | ||||||
| 				border-radius: $br; |  | ||||||
| 			font-variant: small-caps; | 			font-variant: small-caps; | ||||||
|  | 			font-weight: bold; | ||||||
|  | 
 | ||||||
|  | 			&.admin { | ||||||
|  | 				color: $role-admin; | ||||||
|  | 				border-color: $role-admin; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			.role.admin { | 			&.moderator { | ||||||
| 				background: $gray1; | 				color: $role-mod; | ||||||
| 				color: $orange2; | 				border-color: $role-mod; | ||||||
| 				border-color: $orange2; |  | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 			.role.moderator { | @media screen and (max-width: 750px) { | ||||||
| 				background: $gray1; | 	.profile .header { | ||||||
| 				color: $blue2; | 		.basic-info { | ||||||
| 				border-color: $blue1; | 			grid-template-columns: auto 1fr; | ||||||
| 			} | 			grid-template-rows: $avatar-size $name-size auto; | ||||||
| 		} | 			grid-template-areas: | ||||||
| 	} | 				"avatar avatar" | ||||||
| 
 | 				"displayname displayname" | ||||||
| 	@media screen and (max-width: 600px) { | 				"username role"; | ||||||
| 		& { |  | ||||||
| 			gap: 0.1rem; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.basic { |  | ||||||
| 			margin-top: calc(-22vw + 1rem); |  | ||||||
| 			height: initial; |  | ||||||
| 			display: flex; |  | ||||||
| 			flex-direction: column; |  | ||||||
| 
 |  | ||||||
| 			#profile-basic-filler2 { |  | ||||||
| 				display: none; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			.avatar { |  | ||||||
| 				align-self: flex-start; |  | ||||||
| 				margin-left: 1rem; |  | ||||||
| 				height: 22vw; |  | ||||||
| 				width: 22vw; |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			.displayname { | 			.displayname { | ||||||
| 				padding-left: 1rem; | 				font-size: 1.4rem; | ||||||
| 				font-size: 1.5rem; |  | ||||||
| 				line-height: 2rem; |  | ||||||
| 				margin-top: 0.5rem; |  | ||||||
| 				align-self: stretch; |  | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 			.usernamecontainer { | .profile .col-header { | ||||||
| 				padding-left: 1rem; | 	display: flex; | ||||||
|  | 	justify-content: start; | ||||||
|  | 	gap: 2rem; | ||||||
|  | 	align-items: center;  | ||||||
| 
 | 
 | ||||||
| 				.username { | 	margin: 0; | ||||||
| 					margin-left: 0; | 	background: $profile-bg; | ||||||
| 				} | 	border-top-left-radius: $br; | ||||||
| 			} | 	border-top-right-radius: $br; | ||||||
| 		} | 	padding: 0.75rem; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	.detailed { | 	h3 { | ||||||
|  | 		font-size: 1.2rem; | ||||||
|  | 		line-height: 1.3rem; | ||||||
|  | 		margin: 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .profile .toots { | ||||||
|  | 	flex: 65 25rem;  | ||||||
| 	display: flex; | 	display: flex; | ||||||
| 	flex-direction: column; | 	flex-direction: column; | ||||||
| 		flex: 1 1 25em; | 	gap: 0.4rem; | ||||||
| 
 | 
 | ||||||
| 		h2 { | 	.col-header { | ||||||
| 			margin-top: 0; | 		display: grid; | ||||||
| 		} | 		grid-template-columns: auto 1fr; | ||||||
| 
 | 		gap: 1rem; | ||||||
| 		.bio { |  | ||||||
| 			margin-top: 0; |  | ||||||
| 			margin-bottom: 0.5rem; |  | ||||||
| 			margin-left: 1rem; |  | ||||||
| 			margin-right: 1rem; |  | ||||||
| 			word-break: break-word; |  | ||||||
| 
 | 
 | ||||||
| 		a { | 		a { | ||||||
| 				color: $acc1; | 			justify-self: end; | ||||||
| 				text-decoration: underline; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .accountstats { |  | ||||||
| 	display: flex; |  | ||||||
| 	flex-wrap: wrap; |  | ||||||
| 	border-radius: 0 0 $br $br; |  | ||||||
| 	border-top: 0.1rem solid $bg; |  | ||||||
| 
 |  | ||||||
| 	.entry-group { |  | ||||||
| 		flex: 1 1 auto; |  | ||||||
| 		min-width: 50%; |  | ||||||
| 		display: flex; |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	.entry { |  | ||||||
| 		white-space: nowrap; |  | ||||||
| 		width: 50%; |  | ||||||
| 		margin: 1.2rem 0.5rem; |  | ||||||
| 		text-align: center; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .nothinghere { |  | ||||||
| 	margin-left: 1rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .backnextlinks { |  | ||||||
| 	display: flex; |  | ||||||
| 	flex-wrap: wrap; |  | ||||||
| 	justify-content: space-between; |  | ||||||
| 
 |  | ||||||
| 	a { |  | ||||||
| 		padding: 1rem; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	.next { |  | ||||||
| 		margin-left: auto; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .toot, .toot:last-child { |  | ||||||
| 	box-shadow: $boxshadow; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #recent, #pinned { |  | ||||||
| 	display: flex; |  | ||||||
| 	flex-direction: row; |  | ||||||
| 	align-items: center; |  | ||||||
| 	justify-content: space-between; |  | ||||||
| 	margin: 1rem; |  | ||||||
| 		.rss-icon { | 		.rss-icon { | ||||||
| 		font-size: 1.45em; | 			display: block; | ||||||
|  | 			margin: -0.25rem 0; | ||||||
|  | 			 | ||||||
|  | 			.fa { | ||||||
|  | 				font-size: 2rem; | ||||||
| 				object-fit: contain; | 				object-fit: contain; | ||||||
| 				vertical-align: middle; | 				vertical-align: middle; | ||||||
| 				color: $orange2; | 				color: $orange2; | ||||||
|  | @ -286,4 +204,64 @@ main { | ||||||
| 				background: linear-gradient(to right, $white1 100%, transparent 0) no-repeat center center; | 				background: linear-gradient(to right, $white1 100%, transparent 0) no-repeat center center; | ||||||
| 				background-size: 1.2rem 1.4rem; | 				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; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .profile .about-user { | ||||||
|  | 	flex: 35 14rem; | ||||||
|  | 	border-radius: $br; | ||||||
|  | 	overflow: hidden; | ||||||
|  | 
 | ||||||
|  | 	.col-header { | ||||||
|  | 		margin-bottom: -0.25rem; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.fields { | ||||||
|  | 		background: $profile-bg; | ||||||
|  | 		display: flex; | ||||||
|  | 		flex-direction: column; | ||||||
|  | 		padding: 0 0.5rem; | ||||||
|  | 		padding-top: 0.25rem; | ||||||
|  | 
 | ||||||
|  | 		.field { | ||||||
|  | 			padding: 0.25rem; | ||||||
|  | 			display: flex; | ||||||
|  | 			flex-direction: column; | ||||||
|  | 			border-bottom: 0.1rem solid $gray2; | ||||||
|  | 			word-break: break-all; | ||||||
|  | 
 | ||||||
|  | 			&:first-child { | ||||||
|  | 				border-top: 0.1rem solid $gray2; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.bio { | ||||||
|  | 		background: $profile-bg; | ||||||
|  | 		padding: 1rem 0.75rem; | ||||||
|  | 		padding-bottom: 1.25rem; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.accountstats { | ||||||
|  | 		background: $bg-accent; | ||||||
|  | 		padding: 0.75rem; | ||||||
|  | 		 | ||||||
|  | 		display: grid; | ||||||
|  | 		grid-template-columns: auto 1fr; | ||||||
|  | 		gap: 0.25rem 1rem; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| 
 | 
 | ||||||
| @import "photoswipe/dist/photoswipe.css"; | @import "photoswipe/dist/photoswipe.css"; | ||||||
| @import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css"; | @import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css"; | ||||||
|  | @import "plyr/dist/plyr.css"; | ||||||
| 
 | 
 | ||||||
| main { | main { | ||||||
| 	background: transparent; | 	background: transparent; | ||||||
|  | @ -31,13 +32,13 @@ main { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .toot { | .toot { | ||||||
| 	background: $toot-unfocus-bg; | 	background: $toot-bg; | ||||||
| 	box-shadow: $boxshadow; | 	box-shadow: $boxshadow; | ||||||
| 	border: $boxshadow-border; | 	border: $boxshadow-border; | ||||||
|  | 	border-radius: $br; | ||||||
| 	position: relative; | 	position: relative; | ||||||
| 	margin-bottom: $br; | 	margin-bottom: $br; | ||||||
| 	padding-top: 1.5rem; | 	padding-top: 0.75rem; | ||||||
| 	padding-bottom: 0.7rem; |  | ||||||
| 
 | 
 | ||||||
| 	a { | 	a { | ||||||
| 		position: relative; | 		position: relative; | ||||||
|  | @ -46,26 +47,24 @@ main { | ||||||
| 		text-decoration: none; | 		text-decoration: none; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.contentgrid { | 	.author > a { | ||||||
| 		padding: 0 1.5rem; | 		padding: 0 0.75rem; | ||||||
| 		display: grid; | 		display: grid; | ||||||
| 		grid-template-columns: 4rem 1fr auto; | 		grid-template-columns: 3.5rem 1fr auto; | ||||||
| 		grid-template-rows: 1.5rem auto auto auto; | 		grid-template-rows: auto auto; | ||||||
| 		column-gap: 0.5rem; | 		grid-template-areas: | ||||||
| 	} | 			"avatar display date" | ||||||
| 
 | 			"avatar user ."; | ||||||
| 	.not-expanded { | 		gap: 0 0.5rem; | ||||||
| 		color: $fg-reduced; |  | ||||||
| 		grid-column: 3; |  | ||||||
| 		grid-row: 1; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 		.avatar { | 		.avatar { | ||||||
| 		grid-row: span 3; | 			grid-area: avatar; | ||||||
| 		aspect-ratio: 1/1; | 			height: 3.5rem; | ||||||
| 		display: flex; | 			width: 3.5rem; | ||||||
| 		border: 0.2rem solid $avatar-border; | 			object-fit: cover; | ||||||
| 		border-radius: 0.4rem; | 
 | ||||||
|  | 			border: 0.15rem solid $avatar-border; | ||||||
|  | 			border-radius: $br; | ||||||
| 			overflow: hidden; /* hides corners from img overflowing */ | 			overflow: hidden; /* hides corners from img overflowing */ | ||||||
| 
 | 
 | ||||||
| 			img { | 			img { | ||||||
|  | @ -87,46 +86,49 @@ main { | ||||||
| 		} | 		} | ||||||
| 	 | 	 | ||||||
| 		.displayname { | 		.displayname { | ||||||
|  | 			grid-area: display; | ||||||
| 			font-weight: bold; | 			font-weight: bold; | ||||||
| 		font-size: 1.5rem; | 			font-size: 1rem; | ||||||
| 		line-height: 2rem; | 			line-height: 1.3rem; | ||||||
| 		margin-top: -0.5rem; | 			/* margin-top: -0.5rem; */ | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.username { | 		.username { | ||||||
|  | 			grid-area: user; | ||||||
| 			color: $link-fg; | 			color: $link-fg; | ||||||
| 			font-size: 1rem; | 			font-size: 1rem; | ||||||
| 			line-height: 1.3rem; | 			line-height: 1.3rem; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	input.spoiler:checked ~ .content { | 		.timestamp { | ||||||
| 		display: none; | 			grid-area: date; | ||||||
|  | 			color: $fg-reduced; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.spoiler { | 	.body { | ||||||
| 		padding-bottom: 0.5rem; | 		padding: 0.5rem 0.75rem; | ||||||
| 		 |  | ||||||
| 		display: flex; | 		display: flex; | ||||||
| 		align-items: center; | 		flex-direction: column; | ||||||
| 		flex-wrap: wrap; | 		gap: 0.5rem; | ||||||
| 		gap: 0.4rem; |  | ||||||
| 
 |  | ||||||
| 		.spoiler-text { |  | ||||||
| 			word-break: break-word; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 		label { | 	details > summary { | ||||||
| 			padding: 0.2rem 0.3rem; | 		display: inline-block; | ||||||
|  | 		list-style: none; | ||||||
|  | 
 | ||||||
|  | 		&::-webkit-details-marker { | ||||||
|  | 			display: none; /* Safari */ | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		.button { | ||||||
|  | 			white-space: nowrap; | ||||||
| 			cursor: pointer; | 			cursor: pointer; | ||||||
| 			font-size: 1rem; |  | ||||||
| 		} |  | ||||||
| 		label:hover { |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.text { | 	.text { | ||||||
| 		margin: 0; | 		margin: 0; | ||||||
| 		padding-top: 0.5rem; |  | ||||||
| 		grid-row: span 1; | 		grid-row: span 1; | ||||||
| 		grid-column: 1 / span 3; | 		grid-column: 1 / span 3; | ||||||
| 
 | 
 | ||||||
|  | @ -135,14 +137,21 @@ main { | ||||||
| 
 | 
 | ||||||
| 		width: 100%; | 		width: 100%; | ||||||
| 
 | 
 | ||||||
|  | 		details > summary { | ||||||
|  | 			padding-bottom: 0.5rem; | ||||||
|  | 
 | ||||||
|  | 			.button { | ||||||
|  | 				padding: 0.2rem 0.3rem; | ||||||
|  | 				font-size: 1rem; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		a { | 		a { | ||||||
| 			color: $link-fg; | 			color: $link-fg; | ||||||
| 			text-decoration: underline; | 			text-decoration: underline; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.content { | 		.content { | ||||||
| 			padding-bottom: 0.5rem; |  | ||||||
| 
 |  | ||||||
| 			word-break: break-word; | 			word-break: break-word; | ||||||
| 
 | 
 | ||||||
| 			blockquote { | 			blockquote { | ||||||
|  | @ -202,17 +211,104 @@ main { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.media { | 	.media { | ||||||
| 		margin-top: 0.5rem; |  | ||||||
| 		border-radius: $br; |  | ||||||
| 		grid-column: span 3; | 		grid-column: span 3; | ||||||
| 		display: grid; | 		display: grid; | ||||||
| 		grid-template-columns: 50% 50%; | 		grid-template-columns: 50% 50%; | ||||||
| 		grid-auto-rows: 10rem; | 		grid-auto-rows: 10rem; | ||||||
| 		overflow: hidden; | 		overflow: hidden; | ||||||
| 		gap: 0.3rem; |  | ||||||
| 
 | 
 | ||||||
| 		.media-wrapper { | 		.media-wrapper { | ||||||
|  | 			height: 100%; | ||||||
|  | 			width: 100%; | ||||||
|  | 			box-sizing: border-box; | ||||||
|  | 			border: 0.15rem solid $gray1; | ||||||
|  | 			border-radius: $br; | ||||||
| 			position: relative; | 			position: relative; | ||||||
|  | 			overflow: hidden; | ||||||
|  | 			z-index: 2; | ||||||
|  | 
 | ||||||
|  | 			details { | ||||||
|  | 				position: absolute; | ||||||
|  | 				height: 100%; | ||||||
|  | 				width: 100%; | ||||||
|  | 
 | ||||||
|  | 				&[open] summary { | ||||||
|  | 					height: auto; | ||||||
|  | 					width: auto; | ||||||
|  | 					margin: 1rem; | ||||||
|  | 					padding: 0; | ||||||
|  | 
 | ||||||
|  | 					.show, video, img { | ||||||
|  | 						display: none; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					.eye.button .hide { | ||||||
|  | 						display: inline-block; | ||||||
|  | 						grid-column: 1 / span 3; | ||||||
|  | 						grid-row: 1 / span 2; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				summary { | ||||||
|  | 					position: absolute; | ||||||
|  | 					height: 100%; | ||||||
|  | 					width: 100%; | ||||||
|  | 					z-index: 3; | ||||||
|  | 					overflow: hidden; | ||||||
|  | 					 | ||||||
|  | 					display: grid; | ||||||
|  | 					padding: 1rem; | ||||||
|  | 					grid-template-columns: 1fr auto 1fr; | ||||||
|  | 					grid-template-rows: 1fr 1fr; | ||||||
|  | 					grid-template-areas:  | ||||||
|  | 						"eye sensitive ." | ||||||
|  | 						".   sensitive  ."; | ||||||
|  | 
 | ||||||
|  | 					.eye.button { | ||||||
|  | 						grid-area: eye; | ||||||
|  | 						align-self: start; | ||||||
|  | 						justify-self: start; | ||||||
|  | 						margin: 0; | ||||||
|  | 						padding: 0.4rem; | ||||||
|  | 
 | ||||||
|  | 						.fa-fw { | ||||||
|  | 							line-height: $fa-fw; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						.hide { | ||||||
|  | 							display: none; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					.show.sensitive { | ||||||
|  | 						grid-area: sensitive; | ||||||
|  | 						align-self: center; | ||||||
|  | 
 | ||||||
|  | 						.button { | ||||||
|  | 							cursor: pointer; | ||||||
|  | 							align-self: center; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					video, img { | ||||||
|  | 						z-index: -1; | ||||||
|  | 						position: absolute; | ||||||
|  | 						height: calc(100% + 1.2rem); | ||||||
|  | 						width: calc(100% + 1.2rem); | ||||||
|  | 						top: -0.6rem; | ||||||
|  | 						left: -0.6rem; | ||||||
|  | 						filter: blur(1.2rem); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				video.plyr-video, .plyr { | ||||||
|  | 					position: absolute; | ||||||
|  | 					height: 100%; | ||||||
|  | 					width: 100%; | ||||||
|  | 					object-fit: contain; | ||||||
|  | 					background: $gray1; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		&.single .media-wrapper { | 		&.single .media-wrapper { | ||||||
|  | @ -223,133 +319,6 @@ main { | ||||||
| 			grid-row: span 2; | 			grid-row: span 2; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.open, .open .button { |  | ||||||
| 			display: none; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.closed { |  | ||||||
| 			z-index: 2; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		input.sensitive-checkbox:checked { /* Media is shown */ |  | ||||||
| 			& ~ .video-play { |  | ||||||
| 				display: flex; |  | ||||||
| 			} |  | ||||||
| 			& ~ .sensitive { |  | ||||||
| 				.closed { |  | ||||||
| 					transition: 0.8s; |  | ||||||
| 					pointer-events: none; |  | ||||||
| 					opacity: 0; |  | ||||||
| 
 |  | ||||||
| 					& > * { |  | ||||||
| 						display: none; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				.open { |  | ||||||
| 					display: flex; |  | ||||||
| 					justify-content: flex-start; |  | ||||||
| 
 |  | ||||||
| 					.button { |  | ||||||
| 						align-self: flex-start; |  | ||||||
| 						display: initial; |  | ||||||
| 						z-index: 4; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.video-play { |  | ||||||
| 			.icon-span { |  | ||||||
| 				align-self: center; |  | ||||||
| 				display: initial; |  | ||||||
| 				z-index: 4; |  | ||||||
| 
 |  | ||||||
| 				.icon { |  | ||||||
| 					color: $white1; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				.icon-bg { |  | ||||||
| 					color: $gray1; |  | ||||||
| 					font-size: 1.1em; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			display: none; |  | ||||||
| 			position: absolute; |  | ||||||
| 			height: 100%; |  | ||||||
| 			width: 100%; |  | ||||||
| 			justify-content: center; |  | ||||||
| 			align-items: center; |  | ||||||
| 			font-size: 7em; |  | ||||||
| 			pointer-events: none; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.sensitive { |  | ||||||
| 			position: absolute; |  | ||||||
| 			height: 100%; |  | ||||||
| 			width: 100%; |  | ||||||
| 
 |  | ||||||
| 			.open, .closed { |  | ||||||
| 				display: flex; |  | ||||||
| 				position: absolute; |  | ||||||
| 				height: 100%; |  | ||||||
| 				width: 100%; |  | ||||||
| 				justify-content: center; |  | ||||||
| 				padding: 1rem; |  | ||||||
| 
 |  | ||||||
| 				label { |  | ||||||
| 					z-index: 3; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			.closed { |  | ||||||
| 				transition: 0.3s; |  | ||||||
| 				background: $bg-sensitive; |  | ||||||
| 				@supports (backdrop-filter: blur(2rem)) { |  | ||||||
| 					background: transparent; |  | ||||||
| 					backdrop-filter: blur(2rem); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				.button { |  | ||||||
| 					align-self: center; |  | ||||||
| 					justify-self: center; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.no-image-desc { |  | ||||||
| 			color: $no-img-desc-fg; |  | ||||||
| 			background: $no-img-desc-bg; |  | ||||||
| 			display: flex; |  | ||||||
| 			position: absolute; |  | ||||||
| 			bottom: 0.1rem; |  | ||||||
| 			right: 0.4rem; |  | ||||||
| 			margin-bottom: 0.4rem; |  | ||||||
| 			margin-right: 0.4rem; |  | ||||||
| 			padding: 0.1rem 0.45rem; |  | ||||||
| 			border-radius: 100%; |  | ||||||
| 			border: 0.2rem solid $button-fg; |  | ||||||
| 			z-index: 3; |  | ||||||
| 
 |  | ||||||
| 			i.fa { |  | ||||||
| 				display: block; |  | ||||||
| 				line-height: 1.6rem; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			span { |  | ||||||
| 				margin-left: 0.3rem; |  | ||||||
| 				display: none; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			&:hover { |  | ||||||
| 				span { |  | ||||||
| 					display: block; |  | ||||||
| 				} |  | ||||||
| 				border-radius: 0.2rem; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		img { | 		img { | ||||||
| 			width: 100%; | 			width: 100%; | ||||||
| 			height: 100%; | 			height: 100%; | ||||||
|  | @ -358,14 +327,14 @@ main { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.info { | 	.info { | ||||||
|  | 		display: flex; | ||||||
| 		background: $toot-info-bg; | 		background: $toot-info-bg; | ||||||
| 		color: $fg-reduced; | 		color: $fg-reduced; | ||||||
| 		display: none; |  | ||||||
| 		border-top: 0.15rem solid $toot-info-border; | 		border-top: 0.15rem solid $toot-info-border; | ||||||
| 		padding: 0.5rem 1.5rem; | 		padding: 0.5rem 0.75rem; | ||||||
| 
 | 
 | ||||||
| 		div { | 		div, time { | ||||||
| 			padding-right: 1.3rem; | 			padding-right: 1rem; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		.stats { | 		.stats { | ||||||
|  | @ -406,39 +375,39 @@ main { | ||||||
| 		background: $toot-focus-bg; | 		background: $toot-focus-bg; | ||||||
| 		padding-bottom: 0; | 		padding-bottom: 0; | ||||||
| 
 | 
 | ||||||
| 		.contentgrid { |  | ||||||
| 			.displayname { |  | ||||||
| 				grid-column: span 2; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			.not-expanded { |  | ||||||
| 				display: none; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.info { | 		.info { | ||||||
| 			display: flex; | 			background: $toot-focus-info-bg; | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		.media { |  | ||||||
| 			margin-bottom: 0.5rem; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| footer + div { /* something weird from the devstack.. */ | .plyr--video { | ||||||
| 	display: none; | 	flex-direction: column-reverse; | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| @media screen and (max-width: 89ch) { | 	.plyr__video-wrapper { | ||||||
| 	.toot { | 		position: relative; | ||||||
| 		.contentgrid { |  | ||||||
| 			grid-template-rows: 1.5rem 1.3rem 1.3rem auto; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 		.username, .not-expanded { | 	.plyr__controls { | ||||||
| 			grid-column: 2; | 		align-self: stretch; | ||||||
| 			grid-row: auto; | 		position: initial; | ||||||
|  | 		padding: 0.1rem; | ||||||
|  | 		padding-top: 0.2rem; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	.plyr__control { | ||||||
|  | 		box-shadow: none; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.plyr__control--overlaid { | ||||||
|  | 		top: calc(50% - 18px); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .pswp__content { | ||||||
|  | 	padding: 2rem; | ||||||
|  | 
 | ||||||
|  | 	.plyr { | ||||||
|  | 		max-height: 100%; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -22,7 +22,7 @@ | ||||||
| const Photoswipe = require("photoswipe/dist/umd/photoswipe.umd.min.js"); | const Photoswipe = require("photoswipe/dist/umd/photoswipe.umd.min.js"); | ||||||
| const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js"); | const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js"); | ||||||
| const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default; | const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default; | ||||||
| const PhotoswipeVideoPlugin = require("photoswipe-video-plugin").default; | const Plyr = require("plyr"); | ||||||
| 
 | 
 | ||||||
| let [_, _user, type, id] = window.location.pathname.split("/"); | let [_, _user, type, id] = window.location.pathname.split("/"); | ||||||
| if (type == "statuses") { | if (type == "statuses") { | ||||||
|  | @ -34,29 +34,128 @@ if (type == "statuses") { | ||||||
| 
 | 
 | ||||||
| const lightbox = new PhotoswipeLightbox({ | const lightbox = new PhotoswipeLightbox({ | ||||||
| 	gallery: '.photoswipe-gallery', | 	gallery: '.photoswipe-gallery', | ||||||
| 	children: 'a', | 	children: '.photoswipe-slide', | ||||||
| 	pswpModule: Photoswipe, | 	pswpModule: Photoswipe, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| new PhotoswipeCaptionPlugin(lightbox, { | new PhotoswipeCaptionPlugin(lightbox, { | ||||||
| 	type: 'auto', | 	type: 'auto', | ||||||
|  | 	captionContent(slide) { | ||||||
|  | 		return slide.data.alt; | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | lightbox.addFilter('itemData', (item) => { | ||||||
|  | 	const el = item.element; | ||||||
|  | 	if (el && el.classList.contains("plyr-video")) { | ||||||
|  | 		const parentNode = el._plyrContainer.parentNode; | ||||||
|  | 
 | ||||||
|  | 		return { | ||||||
|  | 			alt: el.getAttribute("alt"), | ||||||
|  | 			_video: { | ||||||
|  | 				open(c) { | ||||||
|  | 					c.appendChild(el._plyrContainer); | ||||||
|  | 				}, | ||||||
|  | 				close() { | ||||||
|  | 					parentNode.appendChild(el._plyrContainer); | ||||||
|  | 				}, | ||||||
|  | 				pause() { | ||||||
|  | 					el._player.pause(); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			width: parseInt(el.dataset.pswpWidth), | ||||||
|  | 			height: parseInt(el.dataset.pswpHeight) | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | 	return item; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | lightbox.on("contentActivate", (e) => { | ||||||
|  | 	const { content } = e; | ||||||
|  | 	if (content.data._video != undefined) { | ||||||
|  | 		content.data._video.open(content.element); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | lightbox.on("contentDeactivate", (e) => { | ||||||
|  | 	const { content } = e; | ||||||
|  | 	if (content.data._video != undefined) { | ||||||
|  | 		content.data._video.pause(); | ||||||
|  | 		content.data._video.close(); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | lightbox.on("close", function () { | ||||||
|  | 	if (lightbox.pswp.currSlide.data._video != undefined) { | ||||||
|  | 		lightbox.pswp.currSlide.data._video.close(); | ||||||
|  | 	} | ||||||
| }); | }); | ||||||
| new PhotoswipeVideoPlugin(lightbox, {}); |  | ||||||
| 
 | 
 | ||||||
| lightbox.init(); | lightbox.init(); | ||||||
| 
 | 
 | ||||||
| Array.from(document.getElementsByClassName("spoiler-label")).forEach((label) => { | function dynamicSpoiler(className, updateFunc) { | ||||||
| 	let checkbox = document.getElementById(label.htmlFor); | 	Array.from(document.getElementsByClassName(className)).forEach((spoiler) => { | ||||||
| 	if (checkbox != undefined) { | 		const update = updateFunc(spoiler); | ||||||
| 		function update() { | 		if (update) { | ||||||
| 			if (checkbox.checked) { |  | ||||||
| 				label.innerHTML = "Show more"; |  | ||||||
| 			} else { |  | ||||||
| 				label.innerHTML = "Show less"; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 			update(); | 			update(); | ||||||
|  | 			spoiler.addEventListener("toggle", update); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 		label.addEventListener("click", () => { setTimeout(update, 1); }); | dynamicSpoiler("text-spoiler", (spoiler) => { | ||||||
|  | 	const button = spoiler.querySelector("button"); | ||||||
|  | 
 | ||||||
|  | 	if (button != undefined) { | ||||||
|  | 		return () => { | ||||||
|  | 			button.textContent = spoiler.open | ||||||
|  | 				? "Show less" | ||||||
|  | 				: "Show more"; | ||||||
|  | 		}; | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | dynamicSpoiler("video-spoiler", (spoiler) => { | ||||||
|  | 	const video = spoiler.querySelector(".plyr-video"); | ||||||
|  | 	const eye = spoiler.querySelector(".eye.button"); | ||||||
|  | 
 | ||||||
|  | 	if (video != undefined) { | ||||||
|  | 		return () => { | ||||||
|  | 			if (spoiler.open) { | ||||||
|  | 				eye.setAttribute("aria-label", "Hide media"); | ||||||
|  | 			} else { | ||||||
|  | 				eye.setAttribute("aria-label", "Show media"); | ||||||
|  | 				video.pause(); | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => { | ||||||
|  | 	let player = new Plyr(video, { | ||||||
|  | 		title: video.title, | ||||||
|  | 		settings: ["loop"], | ||||||
|  | 		disableContextMenu: false, | ||||||
|  | 		hideControls: false, | ||||||
|  | 		tooltips: { contrors: true, seek: true }, | ||||||
|  | 		iconUrl: "/assets/plyr.svg", | ||||||
|  | 		listeners: { | ||||||
|  | 			fullscreen: () => { | ||||||
|  | 				if (player.playing) { | ||||||
|  | 					setTimeout(() => { | ||||||
|  | 						player.play(); | ||||||
|  | 					}, 1); | ||||||
|  | 				} | ||||||
|  | 				lightbox.loadAndOpen(parseInt(video.dataset.pswpIndex), { | ||||||
|  | 					gallery: video.closest(".photoswipe-gallery") | ||||||
|  | 				}); | ||||||
|  | 
 | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	player.elements.container.title = video.title; | ||||||
|  | 	video._player = player; | ||||||
|  | 	video._plyrContainer = player.elements.container; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ let cssEntryFiles = fs.readdirSync(path.join(__dirname, "./css")).map((file) => | ||||||
| 
 | 
 | ||||||
| const prodCfg = { | const prodCfg = { | ||||||
| 	transform: [ | 	transform: [ | ||||||
| 		["uglifyify", { | 		["@browserify/uglifyify", { | ||||||
| 			global: true, | 			global: true, | ||||||
| 			exts: ".js" | 			exts: ".js" | ||||||
| 		}], | 		}], | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ | ||||||
|     "papaparse": "^5.3.2", |     "papaparse": "^5.3.2", | ||||||
|     "photoswipe": "^5.3.3", |     "photoswipe": "^5.3.3", | ||||||
|     "photoswipe-dynamic-caption-plugin": "^1.2.7", |     "photoswipe-dynamic-caption-plugin": "^1.2.7", | ||||||
|     "photoswipe-video-plugin": "^1.0.2", |     "plyr": "^3.7.8", | ||||||
|     "psl": "^1.9.0", |     "psl": "^1.9.0", | ||||||
|     "react": "^18.2.0", |     "react": "^18.2.0", | ||||||
|     "react-dom": "^18.2.0", |     "react-dom": "^18.2.0", | ||||||
|  | @ -42,6 +42,7 @@ | ||||||
|     "@babel/preset-env": "^7.19.4", |     "@babel/preset-env": "^7.19.4", | ||||||
|     "@babel/preset-react": "^7.18.6", |     "@babel/preset-react": "^7.18.6", | ||||||
|     "@browserify/envify": "^6.0.0", |     "@browserify/envify": "^6.0.0", | ||||||
|  |     "@browserify/uglifyify": "^6.0.0", | ||||||
|     "@joepie91/eslint-config": "^1.1.1", |     "@joepie91/eslint-config": "^1.1.1", | ||||||
|     "autoprefixer": "^10.4.13", |     "autoprefixer": "^10.4.13", | ||||||
|     "babelify": "^10.0.0", |     "babelify": "^10.0.0", | ||||||
|  | @ -55,7 +56,6 @@ | ||||||
|     "postcss": "^8.4.18", |     "postcss": "^8.4.18", | ||||||
|     "postcss-custom-prop-vars": "^0.0.5", |     "postcss-custom-prop-vars": "^0.0.5", | ||||||
|     "postcss-import": "^15.0.0", |     "postcss-import": "^15.0.0", | ||||||
|     "postcss-nested": "^6.0.0", |     "postcss-nested": "^6.0.0" | ||||||
|     "uglifyify": "^5.0.2" |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -140,13 +140,18 @@ function ReportedToot({ toot }) { | ||||||
| 	const account = toot.account; | 	const account = toot.account; | ||||||
| 
 | 
 | ||||||
| 	return ( | 	return ( | ||||||
| 		<div className="toot expanded"> | 		<article className="toot expanded"> | ||||||
| 			<div className="contentgrid"> | 			<section className="author"> | ||||||
| 				<span className="avatar"> | 				<a> | ||||||
| 					<img src={account.avatar} alt="" /> | 					<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> | ||||||
| 				<span className="displayname">{account.display_name.trim().length > 0 ? account.display_name : account.username}</span> |  | ||||||
| 					<span className="username">@{account.username}</span> | 					<span className="username">@{account.username}</span> | ||||||
|  | 				</a> | ||||||
|  | 			</section> | ||||||
|  | 			<section className="body"> | ||||||
| 				<div className="text"> | 				<div className="text"> | ||||||
| 					<div className="content"> | 					<div className="content"> | ||||||
| 						{toot.spoiler_text?.length > 0 | 						{toot.spoiler_text?.length > 0 | ||||||
|  | @ -158,15 +163,11 @@ function ReportedToot({ toot }) { | ||||||
| 				{toot.media_attachments?.length > 0 && | 				{toot.media_attachments?.length > 0 && | ||||||
| 					<TootMedia media={toot.media_attachments} sensitive={toot.sensitive} /> | 					<TootMedia media={toot.media_attachments} sensitive={toot.sensitive} /> | ||||||
| 				} | 				} | ||||||
| 			</div> | 			</section> | ||||||
| 			<div className="toot-info"> | 			<aside className="info"> | ||||||
| 				<a | 				<time datetime={toot.created_at}>{new Date(toot.created_at).toLocaleString()}</time> | ||||||
| 					href={toot.url} | 			</aside> | ||||||
| 					target="_blank" | 		</article> | ||||||
| 					rel="noreferrer" |  | ||||||
| 				>{new Date(toot.created_at).toLocaleString()}</a> |  | ||||||
| 			</div> |  | ||||||
| 		</div> |  | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,17 +24,23 @@ const React = require("react"); | ||||||
| module.exports = function FakeProfile({ avatar, header, display_name, username, role }) { | module.exports = function FakeProfile({ avatar, header, display_name, username, role }) { | ||||||
| 	return ( // Keep in sync with web/template/profile.tmpl | 	return ( // Keep in sync with web/template/profile.tmpl | ||||||
| 		<div className="profile"> | 		<div className="profile"> | ||||||
| 			<div className="headerimage"> | 			<div className="header"> | ||||||
| 				<img className="headerpreview" src={header} alt={header ? `header image for ${username}` : "None set"} /> | 				<div className="header-image"> | ||||||
|  | 					<img src={header} alt={header ? `header image for ${username}` : "None set"} /> | ||||||
| 				</div> | 				</div> | ||||||
| 			<div className="basic"> | 				<div className="basic-info" aria-hidden="true"> | ||||||
| 				<div id="profile-basic-filler2"></div> | 					<a className="avatar" href="{{.account.Avatar}}"> | ||||||
| 				<span className="avatar"><img className="avatarpreview" src={avatar} alt={avatar ? `avatar image for ${username}` : "None set"} /></span> | 						<img src={avatar} alt={avatar ? `avatar image for ${username}` : "None set"} /> | ||||||
| 				<div className="displayname">{display_name.trim().length > 0 ? display_name : username}</div> | 					</a> | ||||||
| 				<div className="usernamecontainer"> | 					<span className="displayname text-cutoff"> | ||||||
| 					<div className="username"><span>@{username}</span></div> | 						{display_name.trim().length > 0 ? display_name : username} | ||||||
|  | 						<span className="sr-only">.</span> | ||||||
|  | 					</span> | ||||||
|  | 					<span className="username text-cutoff">@{username}</span> | ||||||
| 					{(role && role != "user") && | 					{(role && role != "user") && | ||||||
| 						<div className={`role ${role}`}>{role}</div> | 						<div className={`role ${role}`}> | ||||||
|  | 							<span className="sr-only">Role: </span>{role} | ||||||
|  | 						</div> | ||||||
| 					} | 					} | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|  |  | ||||||
|  | @ -31,19 +31,22 @@ module.exports = function FakeToot({ children }) { | ||||||
| 	} } = query.useVerifyCredentialsQuery(); | 	} } = query.useVerifyCredentialsQuery(); | ||||||
| 
 | 
 | ||||||
| 	return ( | 	return ( | ||||||
| 		<div className="toot expanded"> | 		<article className="toot expanded"> | ||||||
| 			<div className="contentgrid"> | 			<section className="author"> | ||||||
| 				<span className="avatar"> | 				<a> | ||||||
| 					<img src={account.avatar} alt="" /> | 					<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> | ||||||
| 				<span className="displayname">{account.display_name.trim().length > 0 ? account.display_name : account.username}</span> |  | ||||||
| 					<span className="username">@{account.username}</span> | 					<span className="username">@{account.username}</span> | ||||||
|  | 				</a> | ||||||
|  | 			</section> | ||||||
|  | 			<section className="body"> | ||||||
| 				<div className="text"> | 				<div className="text"> | ||||||
| 					<div className="content"> |  | ||||||
| 					{children} | 					{children} | ||||||
| 				</div> | 				</div> | ||||||
| 				</div> | 			</section> | ||||||
| 			</div> | 		</article> | ||||||
| 		</div> |  | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  | @ -16,11 +16,6 @@ | ||||||
|    along with this program.  If not, see <http://www.gnu.org/licenses/>. |    along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /* 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; |  | ||||||
| 
 |  | ||||||
| body { | body { | ||||||
| 	grid-template-rows: auto 1fr; | 	grid-template-rows: auto 1fr; | ||||||
| } | } | ||||||
|  | @ -30,10 +25,6 @@ body { | ||||||
| 	width: 100%; | 	width: 100%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| section { |  | ||||||
| 	grid-column: 2; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| header { | header { | ||||||
| 	justify-content: start; | 	justify-content: start; | ||||||
| 
 | 
 | ||||||
|  | @ -51,19 +42,26 @@ header { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| main section { |  | ||||||
| 	box-shadow: none; |  | ||||||
| 	border-radius: none; |  | ||||||
| 	border: none; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #root { | #root { | ||||||
| 	display: grid; |  | ||||||
| 	grid-template-columns: 1fr minmax(auto, 60rem) 1fr; |  | ||||||
| 	grid-template-columns: 1fr min(92%, 60rem) 1fr; |  | ||||||
| 	box-sizing: border-box; | 	box-sizing: border-box; | ||||||
|  | 	display: flex; | ||||||
|  | 	justify-content: center; | ||||||
|  | 	flex-wrap: wrap; | ||||||
|  | 	margin: 0 1rem; | ||||||
|  | 	gap: 1rem; | ||||||
|  | 
 | ||||||
|  | 	section.oauth { | ||||||
|  | 		max-width: 92%; | ||||||
|  | 		width: 60rem; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	section.with-sidebar { | 	section.with-sidebar { | ||||||
|  | 		flex-grow: 100; | ||||||
|  | 		flex-basis: 40rem; | ||||||
|  | 		background: $bg-accent; | ||||||
|  | 		padding: 2rem; | ||||||
|  | 		border-radius: $br; | ||||||
|  | 
 | ||||||
| 		& > div, & > form { | 		& > div, & > form { | ||||||
| 			border-left: 0.2rem solid $border-accent; | 			border-left: 0.2rem solid $border-accent; | ||||||
| 			padding-left: 0.4rem; | 			padding-left: 0.4rem; | ||||||
|  | @ -97,13 +95,13 @@ main section { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	.sidebar { | 	.sidebar { | ||||||
| 		margin: 0 1rem; | 		flex-grow: 1; | ||||||
|  | 		flex-basis: 20rem; | ||||||
| 		align-self: start; | 		align-self: start; | ||||||
| 		justify-self: end; | 		justify-self: end; | ||||||
| 		background: $bg; | 		background: $bg; | ||||||
| 		display: flex; | 		display: flex; | ||||||
| 		flex-direction: column; | 		flex-direction: column; | ||||||
| 		min-width: 12rem; |  | ||||||
| 
 | 
 | ||||||
| 		.account-card { | 		.account-card { | ||||||
| 			grid-template-columns: auto 1fr auto; | 			grid-template-columns: auto 1fr auto; | ||||||
|  | @ -240,10 +238,6 @@ nav.menu-tree { | ||||||
| 	text-transform: capitalize; | 	text-transform: capitalize; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| section { |  | ||||||
| 	margin-bottom: 1rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| input, select, textarea { | input, select, textarea { | ||||||
| 	box-sizing: border-box; | 	box-sizing: border-box; | ||||||
| } | } | ||||||
|  | @ -406,9 +400,10 @@ section.with-sidebar > div, section.with-sidebar > form { | ||||||
| 		gap: 1rem; | 		gap: 1rem; | ||||||
| 
 | 
 | ||||||
| 		.profile { | 		.profile { | ||||||
| 			.basic { | 			padding: 0; | ||||||
| 				margin-bottom: 0.5rem; | 
 | ||||||
| 				/* margin-top: 0; */ | 			.header { | ||||||
|  | 				border: 0.1rem solid $gray1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1498
									
								
								web/source/yarn.lock
									
										
									
									
									
								
							
							
						
						
									
										1498
									
								
								web/source/yarn.lock
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -21,46 +21,61 @@ | ||||||
| 
 | 
 | ||||||
| <!-- header.tmpl --> | <!-- header.tmpl --> | ||||||
| <html lang="en"> | <html lang="en"> | ||||||
|  | 
 | ||||||
| <head> | <head> | ||||||
| 	<meta charset="UTF-8"> | 	<meta charset="UTF-8"> | ||||||
| 	<meta http-equiv="X-UA-Compatible" content="IE=edge"> | 	<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> | 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
| 	<meta name="robots" content="{{ if .robotsMeta }}{{ .robotsMeta }}{{ else }}noindex, nofollow{{ end }}"> | 	<meta name="robots" content="{{ if .robotsMeta }}{{ .robotsMeta }}{{ else }}noindex, nofollow{{ end }}"> | ||||||
| 	{{ if .ogMeta }}{{ if .ogMeta.Locale }}<meta name="og:locale" content="{{ .ogMeta.Locale }}"> | 	{{ if .ogMeta }}{{ if .ogMeta.Locale }} | ||||||
| 	{{ end }}<meta property="og:type" content="{{ .ogMeta.Type }}"> | 	<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:title" content="{{ .ogMeta.Title }}"> | ||||||
| 	<meta property="og:url" content="{{ .ogMeta.URL }}"> | 	<meta property="og:url" content="{{ .ogMeta.URL }}"> | ||||||
| 	<meta property="og:site_name" content="{{ .ogMeta.SiteName }}"> | 	<meta property="og:site_name" content="{{ .ogMeta.SiteName }}"> | ||||||
| 	<meta property="og:description" {{ .ogMeta.Description | noescapeAttr }}> | 	<meta property="og:description" {{ .ogMeta.Description | noescapeAttr }}> | ||||||
| 	{{ if .ogMeta.ArticlePublisher }}<meta property="og:article:publisher" content="{{ .ogMeta.ArticlePublisher }}"> | 	{{ if .ogMeta.ArticlePublisher }} | ||||||
|  | 	<meta property="og:article:publisher" content="{{ .ogMeta.ArticlePublisher }}"> | ||||||
| 	<meta property="og:article:author" content="{{ .ogMeta.ArticleAuthor }}"> | 	<meta property="og:article:author" content="{{ .ogMeta.ArticleAuthor }}"> | ||||||
| 	<meta property="og:article:modified_time" content="{{ .ogMeta.ArticleModifiedTime }}"> | 	<meta property="og:article:modified_time" content="{{ .ogMeta.ArticleModifiedTime }}"> | ||||||
| 	<meta property="og:article:published_time" content="{{ .ogMeta.ArticlePublishedTime }}"> | 	<meta property="og:article:published_time" content="{{ .ogMeta.ArticlePublishedTime }}"> | ||||||
| 	{{ end }}{{ if .ogMeta.ProfileUsername }}<meta property="og:profile:username" content="{{ .ogMeta.ProfileUsername }}"> | 	{{ end }}{{ if .ogMeta.ProfileUsername }} | ||||||
| 	{{ end }}<meta property="og:image" content="{{ .ogMeta.Image }}"> | 	<meta property="og:profile:username" content="{{ .ogMeta.ProfileUsername }}"> | ||||||
| 	{{ if .ogMeta.ImageAlt }}<meta property="og:image:alt" content="{{ .ogMeta.ImageAlt }}"> | 	{{ end }} | ||||||
| 	{{ end }}{{ if .ogMeta.ImageWidth }}<meta property="og:image:width" content="{{ .ogMeta.ImageWidth }}"> | 	<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 }}"> | 	<meta property="og:image:height" content="{{ .ogMeta.ImageHeight }}"> | ||||||
| 	{{ end }}{{ end }}<link rel="shortcut icon" href="{{ .instance.Thumbnail }}" type="{{ if .instance.ThumbnailType }}{{ .instance.ThumbnailType }}{{ else }}image/png{{ end }}"> | 	{{ end }}{{ end }} | ||||||
| 	{{ if .rssFeed }}<link rel="alternate" type="application/rss+xml" href="{{ .rssFeed }}" title="{{ if .ogMeta }}{{ .ogMeta.Title }}{{ else }}{{.instance.Title}}{{ end }}">{{ end }} | 	<link rel="shortcut icon" href="{{ .instance.Thumbnail }}" | ||||||
|  | 		type="{{ if .instance.ThumbnailType }}{{ .instance.ThumbnailType }}{{ else }}image/png{{ end }}"> | ||||||
|  | 	{{ if .rssFeed }} | ||||||
|  | 	<link rel="alternate" type="application/rss+xml" href="{{ .rssFeed }}" | ||||||
|  | 		title="{{ if .ogMeta }}{{ .ogMeta.Title }}{{ else }}{{.instance.Title}}{{ end }}">{{ end }} | ||||||
| 	<link rel="preload" href="/assets/dist/_colors.css" as="style"> | 	<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/base.css" as="style"> | ||||||
| 	{{range .stylesheets}}<link rel="preload" href="{{.}}" as="style"> | 	{{range .stylesheets}} | ||||||
| 	{{end}}<link rel="stylesheet" href="/assets/dist/_colors.css"> | 	<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/base.css"> | ||||||
| 	{{range .stylesheets}}<link rel="stylesheet" href="{{.}}"> | 	{{range .stylesheets}} | ||||||
|  | 	<link rel="stylesheet" href="{{.}}"> | ||||||
| 	{{end}}<title>{{ if .ogMeta }}{{ .ogMeta.Title }}{{ else }}{{.instance.Title}} - GoToSocial{{ end }}</title> | 	{{end}}<title>{{ if .ogMeta }}{{ .ogMeta.Title }}{{ else }}{{.instance.Title}} - GoToSocial{{ end }}</title> | ||||||
| </head> | </head> | ||||||
|  | 
 | ||||||
| <body> | <body> | ||||||
| 	<div class="page"> | 	<div class="page"> | ||||||
| 		<header> | 		<header> | ||||||
| 			<a aria-label="instance homepage" href="/" class="nounderline 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 }}"/> | 				<img src="{{ .instance.Thumbnail }}" | ||||||
| 				<div> | 					alt="{{ if .instance.ThumbnailDescription }}{{ .instance.ThumbnailDescription }}{{ else }}Instance Logo{{ end }}" /> | ||||||
| 				<h1> | 				<h1> | ||||||
| 					{{.instance.Title}} | 					{{.instance.Title}} | ||||||
| 				</h1> | 				</h1> | ||||||
| 				</div> |  | ||||||
| 			</a> | 			</a> | ||||||
| 		</header> | 		</header> | ||||||
| 		<div class="content"> | 		<div class="content"> | ||||||
|  | @ -18,73 +18,120 @@ | ||||||
| */ -}} | */ -}} | ||||||
| 
 | 
 | ||||||
| {{ template "header.tmpl" .}} | {{ template "header.tmpl" .}} | ||||||
| <main> | 
 | ||||||
|     <div class="profile"> | <main class="profile"> | ||||||
|         <div class="headerimage"> | 	<div class="header"> | ||||||
|  | 		<div class="header-image"> | ||||||
| 			{{ if .account.Header }} | 			{{ if .account.Header }} | ||||||
|             <img | 			<img src="{{.account.Header}}" alt="" /> | ||||||
|                 src="{{.account.Header}}" |  | ||||||
|                 alt="{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}'s header" |  | ||||||
|             /> |  | ||||||
| 			{{ end }} | 			{{ end }} | ||||||
| 		</div> | 		</div> | ||||||
|         <div class="basic"> | 		<div class="basic-info" aria-hidden="true"> | ||||||
|             <div id="profile-basic-filler2"></div> | 			<a class="avatar" href="{{.account.Avatar}}"> | ||||||
|             <a href="{{.account.Avatar}}" class="avatar"><img src="{{.account.Avatar}}" alt="{{if .account.DisplayName}}{{.account.DisplayName}}{{else}}{{.account.Username}}{{end}}'s avatar"></a> | 				<img src="{{.account.Avatar}}" alt=""> | ||||||
|             <div class="displayname">{{if .account.DisplayName}}{{emojify .account.Emojis (escape .account.DisplayName)}}{{else}}{{.account.Username}}{{end}}</div> | 			</a> | ||||||
|             <div class="usernamecontainer"> | 			<span class="displayname text-cutoff"> | ||||||
|                 <div class="username">@{{ .account.Username }}@{{ .instance.AccountDomain }}</div> | 				{{if .account.DisplayName}} | ||||||
|  | 				{{emojify .account.Emojis (escape .account.DisplayName)}} | ||||||
|  | 				{{else}} | ||||||
|  | 				{{.account.Username}} | ||||||
|  | 				{{end}} | ||||||
|  | 				<span class="sr-only">.</span> | ||||||
|  | 			</span> | ||||||
|  | 			<span class="username text-cutoff">@{{.account.Username}}<span class="sr-only">, | ||||||
|  | 				</span>{{acctInstance .account.Acct}}</span> | ||||||
| 			{{- /* Only render account role if 1. it's present and 2. it's not equal to the standard 'user' role */ -}} | 			{{- /* 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 }} | 			{{ 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}}, {{acctInstance .account.Acct}}. | ||||||
|  | 			{{ if and (.account.Role) (ne .account.Role.Name "user") }} | ||||||
|  | 			Role: {{ .account.Role.Name }} | ||||||
|  | 			{{ end }} | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
|         <div class="detailed"> | 
 | ||||||
|  | 	<div class="column-split"> | ||||||
|  | 
 | ||||||
|  | 		<section class="about-user"> | ||||||
|  | 			<div class="col-header"> | ||||||
|  | 				<h3>About</h3> | ||||||
|  | 			</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"> | 			<div class="bio"> | ||||||
|                 {{ if .account.Note }}{{emojify .account.Emojis (noescape .account.Note)}}{{else}}This GoToSocial user hasn't written a bio yet!{{end}} | 				{{ if .account.Note }} | ||||||
|             </div> | 				{{emojify .account.Emojis (noescape .account.Note)}} | ||||||
|         </div> | 				{{else}} | ||||||
|         <div class="accountstats"> | 				This GoToSocial user hasn't written a bio yet! | ||||||
|             <div class="entry-group"> | 				{{end}} | ||||||
|                 <div class="entry">Joined <b>{{.account.CreatedAt | timestampVague}}</b></div> |  | ||||||
|                 <div class="entry">Followed by <b>{{.account.FollowersCount}}</b></div> |  | ||||||
|             </div> |  | ||||||
|             <div class="entry-group"> |  | ||||||
|                 <div class="entry">Following <b>{{.account.FollowingCount}}</b></div> |  | ||||||
|                 <div class="entry">Posted <b>{{.account.StatusesCount}}</b></div> |  | ||||||
| 			</div> | 			</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> | ||||||
|  | 
 | ||||||
|  | 			<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> | 			</div> | ||||||
|  | 		</section> | ||||||
|  | 
 | ||||||
|  | 		<section class="toots"> | ||||||
| 			{{ if .pinned_statuses }} | 			{{ if .pinned_statuses }} | ||||||
|         <h2 id="pinned"> | 			<div class="col-header"> | ||||||
|             <span>Pinned toots</span> | 				<h3>Pinned posts</h3> | ||||||
|         </h2> | 				<a href="#recent">jump to recent</a> | ||||||
|         <div class="thread"> | 			</div> | ||||||
|  | 			<section class="thread"> | ||||||
| 				{{ range .pinned_statuses }} | 				{{ range .pinned_statuses }} | ||||||
|             <div class="toot expanded"> | 				<article class="toot expanded" id="{{.ID}}"> | ||||||
| 					{{ template "status.tmpl" .}} | 					{{ template "status.tmpl" .}} | ||||||
|             </div> | 				</article> | ||||||
| 				{{ end }} | 				{{ end }} | ||||||
|         </div> | 			</section> | ||||||
| 			{{ end }} | 			{{ end }} | ||||||
|     <h2 id="recent"> | 
 | ||||||
|         <span>Latest public toots</span> | 			<div class="col-header"> | ||||||
|  | 				<h3 id="recent" tabindex="-1">Recent posts</h3> | ||||||
| 				{{ if .rssFeed }} | 				{{ if .rssFeed }} | ||||||
|             <a href="{{ .rssFeed }}" aria-label="RSS feed"> | 				<a href="{{ .rssFeed }}" class="rss-icon" aria-label="RSS feed"> | ||||||
|                 <i class="rss-icon fa fa-rss-square" aria-hidden="true"></i> | 					<i class="fa fa-rss-square" aria-hidden="true"></i> | ||||||
| 				</a> | 				</a> | ||||||
| 				{{ end }} | 				{{ end }} | ||||||
|     </h2> | 			</div> | ||||||
|  | 
 | ||||||
|  | 			<section class="thread"> | ||||||
| 				{{ if not .statuses }} | 				{{ if not .statuses }} | ||||||
| 				<div data-nosnippet class="nothinghere">Nothing here!</div> | 				<div data-nosnippet class="nothinghere">Nothing here!</div> | ||||||
| 				{{ else }} | 				{{ else }} | ||||||
|         <div class="thread"> |  | ||||||
| 				{{ range .statuses }} | 				{{ range .statuses }} | ||||||
|             <div class="toot expanded"> | 				<article class="toot expanded" id="{{.ID}}"> | ||||||
| 					{{ template "status.tmpl" .}} | 					{{ template "status.tmpl" .}} | ||||||
|             </div> | 				</article> | ||||||
| 				{{ end }} | 				{{ end }} | ||||||
|         </div> |  | ||||||
| 				{{ end }} | 				{{ end }} | ||||||
|  | 			</section> | ||||||
|  | 
 | ||||||
| 			<div class="backnextlinks"> | 			<div class="backnextlinks"> | ||||||
| 				{{ if .show_back_to_top }} | 				{{ if .show_back_to_top }} | ||||||
| 				<a href="/@{{ .account.Username }}">Back to top</a> | 				<a href="/@{{ .account.Username }}">Back to top</a> | ||||||
|  | @ -93,5 +140,8 @@ | ||||||
| 				<a href="{{ .statuses_next }}" class="next">Show older</a> | 				<a href="{{ .statuses_next }}" class="next">Show older</a> | ||||||
| 				{{ end }} | 				{{ end }} | ||||||
| 			</div> | 			</div> | ||||||
|  | 		</section> | ||||||
|  | 	</div> | ||||||
| </main> | </main> | ||||||
|  | 
 | ||||||
| {{ template "footer.tmpl" .}} | {{ template "footer.tmpl" .}} | ||||||
|  | @ -17,71 +17,110 @@ | ||||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ -}} | */ -}} | ||||||
| 
 | 
 | ||||||
| <div data-nosnippet class="contentgrid"> | <section class="author"> | ||||||
| 	<a href="{{.Account.URL}}" class="avatar"><img src="{{.Account.Avatar}}" alt=""></a> | 	<a href="{{.Account.URL}}"> | ||||||
| 	<a href="{{.Account.URL}}" class="displayname">{{if .Account.DisplayName}}{{emojify .Account.Emojis (escape .Account.DisplayName)}}{{else}}{{.Account.Username}}{{end}}</a> | 		<img class="avatar" src="{{.Account.Avatar}}" alt=""> | ||||||
| 	<a href="{{.Account.URL}}" class="username">@{{.Account.Acct}}</a> | 		<span class="displayname"> | ||||||
| 	<div class="not-expanded"> | 			{{if .Account.DisplayName}} | ||||||
| 		<span class="date">{{.CreatedAt | timestamp}}</span> | 			{{emojify .Account.Emojis (escape .Account.DisplayName)}} | ||||||
| 	</div> | 			{{else}} | ||||||
|  | 			{{.Account.Username}} | ||||||
|  | 			{{end}} | ||||||
|  | 			<span class="sr-only">.</span> | ||||||
|  | 		</span> | ||||||
|  | 		<span class="username">@{{.Account.Username}}<span class="sr-only">, </span>{{acctInstance .Account.Acct}}</span> | ||||||
|  | 	</a> | ||||||
|  | </section> | ||||||
|  | <section class="body"> | ||||||
| 	<div class="text"> | 	<div class="text"> | ||||||
| 		{{if .SpoilerText}} | 		{{if .SpoilerText}} | ||||||
| 		<input class="spoiler" id="hideSpoiler-{{.ID}}" type="checkbox" style="display: none" aria-hidden="true" checked="true" /> | 		<details class="text-spoiler"> | ||||||
| 		<div class="spoiler"> | 			<summary> | ||||||
| 				<span class="spoiler-text">{{emojify .Emojis (escape .SpoilerText)}}</span> | 				<span class="spoiler-text">{{emojify .Emojis (escape .SpoilerText)}}</span> | ||||||
| 			<label class="button spoiler-label" for="hideSpoiler-{{.ID}}" tabindex="0">Toggle visibility</label> | 				<span class="button" role="button" tabindex="0">Toggle visibility</span> | ||||||
| 		</div> | 			</summary> | ||||||
| 		{{end}} |  | ||||||
| 			<div class="content"> | 			<div class="content"> | ||||||
| 				{{emojify .Emojis (noescape .Content)}} | 				{{emojify .Emojis (noescape .Content)}} | ||||||
| 			</div> | 			</div> | ||||||
|  | 		</details> | ||||||
|  | 		{{else}} | ||||||
|  | 		<div class="content"> | ||||||
|  | 			{{emojify .Emojis (noescape .Content)}} | ||||||
|  | 		</div> | ||||||
|  | 		{{end}} | ||||||
| 	</div> | 	</div> | ||||||
| 	{{with .MediaAttachments}} | 	{{with .MediaAttachments}} | ||||||
| 	<div class="media photoswipe-gallery {{(len .) | oddOrEven }}{{if eq (len .) 1}} single{{end}}{{if eq (len .) 2}} double{{end}}"> | 	<div | ||||||
| 		{{range .}} | 		class="media photoswipe-gallery {{(len .) | oddOrEven }}{{if eq (len .) 1}} single{{end}}{{if eq (len .) 2}} double{{end}}"> | ||||||
|  | 		{{range $index, $media := .}} | ||||||
|  | 		{{with $media}} | ||||||
| 		<div class="media-wrapper"> | 		<div class="media-wrapper"> | ||||||
| 			{{if not .Description}} | 			<details class="{{.Type}}-spoiler" {{if not $.Sensitive}}open{{end}}> | ||||||
| 			<div class="no-image-desc" aria-hidden="true" ><i class="fa fa-info-circle"></i><span>Missing media description</span></div> | 				<summary> | ||||||
| 			{{end}}	 | 					<div class="show sensitive button" aria-hidden="true"> | ||||||
| 			<input type="checkbox" id="sensitiveMedia-{{.ID}}" class="sensitive-checkbox hidden" {{if not $.Sensitive}}checked{{end}}/> | 						Show sensitive media | ||||||
| 			<div class="sensitive"> |  | ||||||
| 				<div class="open"> |  | ||||||
| 					<label for="sensitiveMedia-{{.ID}}" class="button" role="button" tabindex="0"> |  | ||||||
| 						<i class="fa fa-eye-slash" title="Hide sensitive media"></i> |  | ||||||
| 					</label> |  | ||||||
| 					</div> | 					</div> | ||||||
| 				<div class="closed" {{if .Description}}title="{{.Description}}"{{end}}> | 					<span class="eye button" role="button" tabindex="0" aria-label="Toggle media"> | ||||||
| 					<label for="sensitiveMedia-{{.ID}}" class="button" role="button" tabindex="0">Show sensitive media</label> | 						<i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i> | ||||||
| 				</div> | 						<i class="show fa fa-fw fa-eye" aria-hidden="true"></i> | ||||||
| 			</div> |  | ||||||
| 			{{ if eq .Type "video" }} |  | ||||||
| 			<div class="video-play"> |  | ||||||
| 				<span class="icon-span fa-stack" aria-hidden="true"> |  | ||||||
| 					<i class="icon-bg fa fa-fw fa-circle fa-stack-1x"></i> |  | ||||||
| 					<i class="icon fa fa-fw fa-play-circle fa-stack-1x"></i> |  | ||||||
| 					</span> | 					</span> | ||||||
| 			</div> | 
 | ||||||
| 			{{ end }} | 					{{if eq .Type "video"}} | ||||||
| 			<a href="{{.URL}}" | 					<video {{if .Description}} title="{{.Description}}" {{end}}> | ||||||
| 				 target="_blank" | 						<source type="video/mp4" src="{{.URL}}" /> | ||||||
| 				 {{if .Description}}title="{{.Description}}"{{end}} | 					</video> | ||||||
| 				 data-pswp-width="{{.Meta.Original.Width}}px" | 					{{else}} | ||||||
| 				 data-pswp-height="{{.Meta.Original.Height}}px" | 					<img {{if .Description}} title="{{.Description}}" {{end}} src="{{.PreviewURL}}" /> | ||||||
| 				 {{if eq .Type "video"}}data-pswp-type="video"{{end}} | 					{{end}} | ||||||
|  | 				</summary> | ||||||
|  | 				{{if eq .Type "video"}} | ||||||
|  | 				<video class="plyr-video photoswipe-slide" controls {{if .Description}}alt="{{.Description}}" | ||||||
|  | 					title="{{.Description}}" {{end}} data-pswp-index="{{$index}}" data-pswp-width="{{.Meta.Original.Width}}px" | ||||||
|  | 					data-pswp-height="{{.Meta.Original.Height}}px"> | ||||||
|  | 					<source type="video/mp4" src="{{.URL}}" /> | ||||||
|  | 				</video> | ||||||
|  | 				{{else}} | ||||||
|  | 				<a class="photoswipe-slide" href="{{.URL}}" target="_blank" {{if .Description}}title="{{.Description}}" {{end}} | ||||||
|  | 					data-pswp-width="{{.Meta.Original.Width}}px" data-pswp-height="{{.Meta.Original.Height}}px" | ||||||
| 					data-cropped="true"> | 					data-cropped="true"> | ||||||
| 				<img src="{{.PreviewURL}}" {{if .Description}}alt="{{.Description}}"{{end}} data-blurhash="{{.Blurhash}}"/> | 					<img src="{{.PreviewURL}}" {{if .Description}}alt="{{.Description}}" {{end}} /> | ||||||
| 				</a> | 				</a> | ||||||
|  | 				{{end}} | ||||||
|  | 			</details> | ||||||
| 		</div> | 		</div> | ||||||
| 		{{end}} | 		{{end}} | ||||||
|  | 		{{end}} | ||||||
| 	</div> | 	</div> | ||||||
| 	{{end}} | 	{{end}} | ||||||
| </div> | </section> | ||||||
| <div class="info"> | <aside class="info"> | ||||||
| 	<div id="date">{{.CreatedAt | timestampPrecise}}</div> | 	<time datetime="{{.CreatedAt}}">{{.CreatedAt | timestampPrecise}}</time> | ||||||
| 	<div class="stats"> | 	<div class="stats" role="group"> | ||||||
| 		<div id="replies"><i aria-label="Replies" class="fa fa-reply-all"></i> {{.RepliesCount}}</div> | 		<div> | ||||||
| 		<div id="boosts"><i aria-label="Boosts" class="fa fa-retweet"></i> {{.ReblogsCount}}</div> | 			<span aria-hidden="true"> | ||||||
| 		<div id="favorites"><i aria-label="Favorites" class="fa fa-star"></i> {{.FavouritesCount}}</div> | 				<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> | ||||||
| </div> | 		<div> | ||||||
| <a data-nosnippet href="{{.URL}}" class="toot-link">View toot</a> | 			<span aria-hidden="true"> | ||||||
|  | 				<i class="fa fa-star"></i> {{.FavouritesCount}} | ||||||
|  | 			</span> | ||||||
|  | 			<span class="sr-only">{{.FavouritesCount}} favourite{{if .FavouritesCount | eq 1 | not}}s{{end}}</span> | ||||||
|  | 		</div> | ||||||
|  | 		<div> | ||||||
|  | 			<span aria-hidden="true"> | ||||||
|  | 				<i class="fa fa-retweet"></i> {{.ReblogsCount}} | ||||||
|  | 			</span> | ||||||
|  | 			<span class="sr-only">{{.ReblogsCount}} boost{{if .ReblogsCount | eq 1 | not}}s{{end}}</span> | ||||||
|  | 		</div> | ||||||
|  | 		{{if .Pinned}} | ||||||
|  | 		<div> | ||||||
|  | 			<i class="fa fa-thumb-tack" aria-hidden="true"></i> | ||||||
|  | 			<span class="sr-only">pinned</span> | ||||||
|  | 		</div> | ||||||
|  | 		{{end}} | ||||||
|  | 	</div> | ||||||
|  | </aside> | ||||||
|  | <a data-nosnippet href="{{.URL}}" class="toot-link">Open | ||||||
|  | 	thread</a> | ||||||
|  | @ -19,20 +19,20 @@ | ||||||
| 
 | 
 | ||||||
| {{ template "header.tmpl" .}} | {{ template "header.tmpl" .}} | ||||||
| <main> | <main> | ||||||
| 	<div data-nosnippet class="thread"> | 	<section data-nosnippet class="thread"> | ||||||
| 		{{range .context.Ancestors}} | 		{{range .context.Ancestors}} | ||||||
| 		<div class="toot" id="{{.ID}}"> | 		<article class="toot" id="{{.ID}}"> | ||||||
| 			{{ template "status.tmpl" .}} | 			{{ template "status.tmpl" .}} | ||||||
| 		</div> | 		</article> | ||||||
| 		{{end}} | 		{{end}} | ||||||
| 		<div class="toot expanded" id="{{.status.ID}}"> | 		<article class="toot expanded" id="{{.status.ID}}"> | ||||||
| 			{{ template "status.tmpl" .status}} | 			{{ template "status.tmpl" .status}} | ||||||
| 		</div> | 		</article> | ||||||
| 		{{range .context.Descendants}} | 		{{range .context.Descendants}} | ||||||
| 		<div class="toot" id="{{.ID}}"> | 		<article class="toot" id="{{.ID}}"> | ||||||
| 			{{ template "status.tmpl" .}} | 			{{ template "status.tmpl" .}} | ||||||
| 		</div> | 		</article> | ||||||
| 		{{end}} | 		{{end}} | ||||||
| 	</div> | 	</section> | ||||||
| </main> | </main> | ||||||
| {{ template "footer.tmpl" .}} | {{ template "footer.tmpl" .}} | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue