pinafore/src/routes/_components/compose/ComposeMediaItem.html
Nolan Lawson 880bc7a38a
perf: use a separate icons.svg file (#1067)
* perf: use a separate icons.svg file

This splits icons into inline and non-inline. The inline ones are high
priority; the rest go in an icons.svg file.

* create SvgIcon.html

* determine inlined svgs at build time
2019-03-02 19:02:06 -08:00

155 lines
3.9 KiB
HTML

<div class="compose-media compose-media-realm-{realm}">
<img src={mediaItem.data.preview_url} {alt} />
<div class="compose-media-delete">
<button class="compose-media-delete-button"
aria-label="Delete {shortName}"
on:click="onDeleteMedia()" >
<SvgIcon className="compose-media-delete-button-svg" href="#fa-times" />
</button>
</div>
<div class="compose-media-alt">
<input id="compose-media-input-{uuid}"
type="text"
class="compose-media-alt-input"
placeholder="Description"
bind:value=rawText
>
<label for="compose-media-input-{uuid}" class="sr-only">
Describe {shortName} for the visually impaired
</label>
</div>
</div>
<style>
.compose-media {
height: 200px;
overflow: hidden;
flex-direction: column;
position: relative;
display: flex;
background: var(--main-bg);
}
.compose-media img {
object-fit: contain;
object-position: center center;
flex: 1;
height: 100%;
width: 100%;
}
.compose-media-alt {
z-index: 10;
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
}
.compose-media-alt-input {
width: 100%;
font-size: 1.2em;
background: var(--alt-input-bg);
color: var(--body-text-color);
}
.compose-media-alt-input:focus {
background: var(--main-bg);
}
.compose-media-delete {
position: absolute;
z-index: 10;
top: 0;
right: 0;
left: 0;
display: flex;
justify-content: flex-end;
margin: 2px;
}
.compose-media-delete-button {
padding: 10px;
background: none;
border: none;
}
.compose-media-delete-button:hover {
background: var(--toast-border);
}
:global(.compose-media-delete-button-svg) {
fill: var(--button-text);
width: 18px;
height: 18px;
}
.compose-media-realm-dialog {
max-height: 20vh;
}
@media (max-width: 767px) {
.compose-media-realm-dialog {
max-height: 15vh;
}
}
</style>
<script>
import { store } from '../../_store/store'
import { deleteMedia } from '../../_actions/media'
import debounce from 'lodash-es/debounce'
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
import { observe } from 'svelte-extras'
import SvgIcon from '../SvgIcon.html'
export default {
oncreate () {
this.setupSyncFromStore()
this.setupSyncToStore()
},
data: () => ({
rawText: ''
}),
computed: {
filename: ({ mediaItem }) => mediaItem.file && mediaItem.file.name,
alt: ({ filename, mediaItem }) => (
// sometimes we no longer have the file, e.g. in a delete and redraft situation,
// so fall back to the description if it was provided
filename || mediaItem.description || ''
),
shortName: ({ filename }) => filename || 'media',
uuid: ({ realm, mediaItem }) => `${realm}-${mediaItem.data.id}`
},
store: () => store,
methods: {
observe,
setupSyncFromStore () {
this.observe('media', media => {
media = media || []
let { index, rawText } = this.get()
let text = (media[index] && media[index].description) || ''
if (rawText !== text) {
this.set({ rawText: text })
}
})
},
setupSyncToStore () {
const saveStore = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
this.observe('rawText', rawText => {
let { realm, index, media } = this.get()
if (media[index].description === rawText) {
return
}
media[index].description = rawText
this.store.setComposeData(realm, { media })
saveStore()
}, { init: false })
},
onDeleteMedia () {
let {
realm,
index
} = this.get()
deleteMedia(realm, index)
}
},
components: {
SvgIcon
}
}
</script>