implement autoplay gif feature for avatars

This commit is contained in:
Nolan Lawson 2018-01-31 18:20:30 -08:00
parent 545d2a9d92
commit f1eaee4674
9 changed files with 142 additions and 20 deletions

View file

@ -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-backdrop"></div>
<div class="account-profile-grid">
<div class="account-profile-avatar">
<img src="{{profile.avatar}}" aria-hidden="true">
<Avatar account="{{profile}}" size="big" />
</div>
<div class="account-profile-name">
<ExternalLink href="{{profile.url}}">
@ -101,11 +102,6 @@
.account-profile-avatar {
grid-area: avatar;
}
.account-profile-avatar img {
border-radius: 4px;
width: 100px;
height: 100px;
}
.account-profile-username {
grid-area: username;
@ -159,10 +155,6 @@
}
@media (max-width: 767px) {
.account-profile-avatar img {
width: 80px;
height: 80px;
}
.account-profile-name {
font-size: 1.3em;
}
@ -190,14 +182,18 @@
<script>
import IconButton from './IconButton.html'
import ExternalLink from './ExternalLink.html'
import Avatar from './Status/Avatar.html'
import { store } from '../_store/store'
export default {
computed: {
headerIsMissing: (profile) => profile.header.endsWith('missing.png')
},
store: () => store,
components: {
IconButton,
ExternalLink
ExternalLink,
Avatar
}
}
</script>

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

View file

@ -1,16 +1,33 @@
{{#if error}}
<svg class="{{className}} avatar" aria-hidden="true">
<svg class="{{className}} avatar size-{{size}}" aria-hidden="true">
<use xlink:href="#fa-user" />
</svg>
{{else}}
<img class="{{className}} avatar" aria-hidden="true" alt=""
{{elseif $autoplayGifs}}
<img class="{{className}} avatar size-{{size}}" aria-hidden="true" alt=""
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}}
<style>
.avatar {
:global(.avatar) {
border-radius: 4px;
}
:global(.avatar.size-small) {
width: 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 {
@ -19,10 +36,16 @@
</style>
<script>
import { imgLoadError } from '../../_utils/events'
import { store } from '../../_store/store'
import NonAutoplayImg from '../NonAutoplayImg.html'
export default {
events: {
imgLoadError
},
store: () => store,
components: {
NonAutoplayImg
}
}
</script>

View file

@ -30,7 +30,7 @@
</a>
{{/if}}
</div>
<Avatar account={{originalAccount}} className="status-sidebar"/>
<Avatar account={{originalAccount}} className="status-sidebar" size="small" />
{{#if originalStatus.spoiler_text}}
<div class="status-spoiler">{{originalStatus.spoiler_text}}</div>
{{/if}}

View file

@ -10,7 +10,8 @@ const KEYS_TO_STORE_IN_LOCAL_STORAGE = new Set([
"instanceNameInSearch",
"instanceThemes",
"loggedInInstances",
"loggedInInstancesInOrder"
"loggedInInstancesInOrder",
"autoplayGifs"
])
class PinaforeStore extends LocalStorageStore {
@ -24,7 +25,8 @@ const store = new PinaforeStore({
currentInstance: null,
loggedInInstances: {},
loggedInInstancesInOrder: [],
instanceThemes: {}
instanceThemes: {},
autoplayGifs: false
})
mixins(PinaforeStore)

View file

@ -17,3 +17,20 @@ export function imgLoad (node, 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)
}
}
}

View file

@ -43,6 +43,7 @@
const NAV_ITEMS = {
'settings': 'Settings',
'settings/about': 'About Pinafore',
'settings/general': 'General',
'settings/instances': 'Instances',
'settings/instances/add': 'Add an instance',
}

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

View file

@ -7,6 +7,7 @@
<h1>Settings</h1>
<SettingsList>
<SettingsListItem href="/settings/general" label="General"/>
<SettingsListItem href="/settings/instances" label="Instances"/>
<SettingsListItem href="/settings/about" label="About Pinafore"/>
</SettingsList>