implement autoplay gif feature for avatars
This commit is contained in:
parent
545d2a9d92
commit
f1eaee4674
|
@ -1,9 +1,10 @@
|
||||||
<div class="account-profile {{headerIsMissing ? 'header-is-missing' : ''}}" style="background-image: url({{profile.header}});">
|
<div class="account-profile {{headerIsMissing ? 'header-is-missing' : ''}}"
|
||||||
|
style="background-image: url({{$autoplayGifs ? profile.header : profile.header_static}});">
|
||||||
<div class="account-profile-grid-wrapper">
|
<div class="account-profile-grid-wrapper">
|
||||||
<div class="account-profile-backdrop"></div>
|
<div class="account-profile-backdrop"></div>
|
||||||
<div class="account-profile-grid">
|
<div class="account-profile-grid">
|
||||||
<div class="account-profile-avatar">
|
<div class="account-profile-avatar">
|
||||||
<img src="{{profile.avatar}}" aria-hidden="true">
|
<Avatar account="{{profile}}" size="big" />
|
||||||
</div>
|
</div>
|
||||||
<div class="account-profile-name">
|
<div class="account-profile-name">
|
||||||
<ExternalLink href="{{profile.url}}">
|
<ExternalLink href="{{profile.url}}">
|
||||||
|
@ -101,11 +102,6 @@
|
||||||
.account-profile-avatar {
|
.account-profile-avatar {
|
||||||
grid-area: avatar;
|
grid-area: avatar;
|
||||||
}
|
}
|
||||||
.account-profile-avatar img {
|
|
||||||
border-radius: 4px;
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-profile-username {
|
.account-profile-username {
|
||||||
grid-area: username;
|
grid-area: username;
|
||||||
|
@ -159,10 +155,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.account-profile-avatar img {
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
}
|
|
||||||
.account-profile-name {
|
.account-profile-name {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
|
@ -190,14 +182,18 @@
|
||||||
<script>
|
<script>
|
||||||
import IconButton from './IconButton.html'
|
import IconButton from './IconButton.html'
|
||||||
import ExternalLink from './ExternalLink.html'
|
import ExternalLink from './ExternalLink.html'
|
||||||
|
import Avatar from './Status/Avatar.html'
|
||||||
|
import { store } from '../_store/store'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
headerIsMissing: (profile) => profile.header.endsWith('missing.png')
|
headerIsMissing: (profile) => profile.header.endsWith('missing.png')
|
||||||
},
|
},
|
||||||
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
IconButton,
|
IconButton,
|
||||||
ExternalLink
|
ExternalLink,
|
||||||
|
Avatar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
38
routes/_components/NonAutoplayImg.html
Normal file
38
routes/_components/NonAutoplayImg.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{{#if staticSrc === src}}
|
||||||
|
<img class="{{className || ''}}"
|
||||||
|
aria-hidden="{{ariaHidden}}"
|
||||||
|
alt="{{alt}}"
|
||||||
|
src="{{src}}"
|
||||||
|
on:imgLoadError />
|
||||||
|
{{else}}
|
||||||
|
<img class="{{className || ''}} non-autoplay-zoom-in"
|
||||||
|
aria-hidden="{{ariaHidden}}"
|
||||||
|
alt="{{alt}}"
|
||||||
|
src="{{staticSrc}}"
|
||||||
|
on:imgLoadError
|
||||||
|
on:mouseover="onMouseOver(event)"
|
||||||
|
ref:node />
|
||||||
|
{{/if}}
|
||||||
|
<style>
|
||||||
|
.non-autoplay-zoom-in {
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import { imgLoadError, mouseover } from '../_utils/events'
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
onMouseOver(mouseOver) {
|
||||||
|
if (mouseOver) {
|
||||||
|
this.refs.node.src = this.get('src')
|
||||||
|
} else {
|
||||||
|
this.refs.node.src = this.get('staticSrc')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
imgLoadError,
|
||||||
|
mouseover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,16 +1,33 @@
|
||||||
{{#if error}}
|
{{#if error}}
|
||||||
<svg class="{{className}} avatar" aria-hidden="true">
|
<svg class="{{className}} avatar size-{{size}}" aria-hidden="true">
|
||||||
<use xlink:href="#fa-user" />
|
<use xlink:href="#fa-user" />
|
||||||
</svg>
|
</svg>
|
||||||
{{else}}
|
{{elseif $autoplayGifs}}
|
||||||
<img class="{{className}} avatar" aria-hidden="true" alt=""
|
<img class="{{className}} avatar size-{{size}}" aria-hidden="true" alt=""
|
||||||
src="{{account.avatar}}" on:imgLoadError="set({error: true})" />
|
src="{{account.avatar}}" on:imgLoadError="set({error: true})" />
|
||||||
|
{{else}}
|
||||||
|
<NonAutoplayImg className="{{className}} avatar size-{{size}}" ariaHidden="true" alt=""
|
||||||
|
src="{{account.avatar}}" staticSrc="{{account.avatar_static}}" on:imgLoadError="set({error: true})" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<style>
|
<style>
|
||||||
.avatar {
|
:global(.avatar) {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
:global(.avatar.size-small) {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
border-radius: 4px;
|
}
|
||||||
|
|
||||||
|
:global(.avatar.size-big) {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
:global(.avatar.size-big) {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svg.avatar {
|
svg.avatar {
|
||||||
|
@ -19,10 +36,16 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { imgLoadError } from '../../_utils/events'
|
import { imgLoadError } from '../../_utils/events'
|
||||||
|
import { store } from '../../_store/store'
|
||||||
|
import NonAutoplayImg from '../NonAutoplayImg.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
events: {
|
events: {
|
||||||
imgLoadError
|
imgLoadError
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
|
components: {
|
||||||
|
NonAutoplayImg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -30,7 +30,7 @@
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<Avatar account={{originalAccount}} className="status-sidebar"/>
|
<Avatar account={{originalAccount}} className="status-sidebar" size="small" />
|
||||||
{{#if originalStatus.spoiler_text}}
|
{{#if originalStatus.spoiler_text}}
|
||||||
<div class="status-spoiler">{{originalStatus.spoiler_text}}</div>
|
<div class="status-spoiler">{{originalStatus.spoiler_text}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -10,7 +10,8 @@ const KEYS_TO_STORE_IN_LOCAL_STORAGE = new Set([
|
||||||
"instanceNameInSearch",
|
"instanceNameInSearch",
|
||||||
"instanceThemes",
|
"instanceThemes",
|
||||||
"loggedInInstances",
|
"loggedInInstances",
|
||||||
"loggedInInstancesInOrder"
|
"loggedInInstancesInOrder",
|
||||||
|
"autoplayGifs"
|
||||||
])
|
])
|
||||||
|
|
||||||
class PinaforeStore extends LocalStorageStore {
|
class PinaforeStore extends LocalStorageStore {
|
||||||
|
@ -24,7 +25,8 @@ const store = new PinaforeStore({
|
||||||
currentInstance: null,
|
currentInstance: null,
|
||||||
loggedInInstances: {},
|
loggedInInstances: {},
|
||||||
loggedInInstancesInOrder: [],
|
loggedInInstancesInOrder: [],
|
||||||
instanceThemes: {}
|
instanceThemes: {},
|
||||||
|
autoplayGifs: false
|
||||||
})
|
})
|
||||||
|
|
||||||
mixins(PinaforeStore)
|
mixins(PinaforeStore)
|
||||||
|
|
|
@ -16,4 +16,21 @@ export function imgLoad (node, callback) {
|
||||||
node.removeEventListener('load', callback)
|
node.removeEventListener('load', callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mouseover(node, callback) {
|
||||||
|
function onMouseEnter() {
|
||||||
|
callback(true)
|
||||||
|
}
|
||||||
|
function onMouseLeave() {
|
||||||
|
callback(false)
|
||||||
|
}
|
||||||
|
node.addEventListener('mouseenter', onMouseEnter)
|
||||||
|
node.addEventListener('mouseleave', onMouseLeave)
|
||||||
|
return {
|
||||||
|
teardown () {
|
||||||
|
node.removeEventListener('mouseenter', onMouseEnter)
|
||||||
|
node.removeEventListener('mouseleave', onMouseLeave)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -43,6 +43,7 @@
|
||||||
const NAV_ITEMS = {
|
const NAV_ITEMS = {
|
||||||
'settings': 'Settings',
|
'settings': 'Settings',
|
||||||
'settings/about': 'About Pinafore',
|
'settings/about': 'About Pinafore',
|
||||||
|
'settings/general': 'General',
|
||||||
'settings/instances': 'Instances',
|
'settings/instances': 'Instances',
|
||||||
'settings/instances/add': 'Add an instance',
|
'settings/instances/add': 'Add an instance',
|
||||||
}
|
}
|
||||||
|
|
44
routes/settings/general.html
Normal file
44
routes/settings/general.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<:Head>
|
||||||
|
<title>General Settings</title>
|
||||||
|
</:Head>
|
||||||
|
|
||||||
|
<Layout page='settings'>
|
||||||
|
<SettingsLayout page='settings/general' label="General">
|
||||||
|
<h1>General Settings</h1>
|
||||||
|
|
||||||
|
<h2>UI</h2>
|
||||||
|
<form class="ui-settings" aria-label="UI settings">
|
||||||
|
<div class="setting-group">
|
||||||
|
<input type="checkbox" id="choice-autoplay-gif"
|
||||||
|
bind:checked="$autoplayGifs" on:change="store.save()">
|
||||||
|
<label for="choice-autoplay-gif">Autoplay GIFs</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</SettingsLayout>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ui-settings {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--form-bg);
|
||||||
|
border: 1px solid var(--main-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 20px;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import Layout from '../_components/Layout.html';
|
||||||
|
import SettingsLayout from './_components/SettingsLayout.html'
|
||||||
|
import { store } from '../_store/store'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Layout,
|
||||||
|
SettingsLayout
|
||||||
|
},
|
||||||
|
store: () => store
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -7,6 +7,7 @@
|
||||||
<h1>Settings</h1>
|
<h1>Settings</h1>
|
||||||
|
|
||||||
<SettingsList>
|
<SettingsList>
|
||||||
|
<SettingsListItem href="/settings/general" label="General"/>
|
||||||
<SettingsListItem href="/settings/instances" label="Instances"/>
|
<SettingsListItem href="/settings/instances" label="Instances"/>
|
||||||
<SettingsListItem href="/settings/about" label="About Pinafore"/>
|
<SettingsListItem href="/settings/about" label="About Pinafore"/>
|
||||||
</SettingsList>
|
</SettingsList>
|
||||||
|
|
Loading…
Reference in a new issue