feat: add support for audio attachments (#1293)
This is a new thing in Mastodon v2.9. I kept the "camera" icon because I like it better than the paperclip, and I think it covers the 99% use case.
This commit is contained in:
parent
ea220c32d3
commit
d31f2ce010
|
@ -1,5 +1,9 @@
|
|||
<li class="compose-media compose-media-realm-{realm}">
|
||||
<img src={mediaItem.data.preview_url} {alt} />
|
||||
<img
|
||||
class="{type === 'audio' ? 'audio-preview' : ''}"
|
||||
src={previewSrc}
|
||||
{alt}
|
||||
/>
|
||||
<div class="compose-media-delete">
|
||||
<button class="compose-media-delete-button"
|
||||
aria-label="Delete {shortName}"
|
||||
|
@ -10,13 +14,11 @@
|
|||
<div class="compose-media-alt">
|
||||
<textarea id="compose-media-input-{uuid}"
|
||||
class="compose-media-alt-input"
|
||||
placeholder="Describe for the visually impaired"
|
||||
placeholder="Description"
|
||||
ref:textarea
|
||||
bind:value=rawText
|
||||
></textarea>
|
||||
<label for="compose-media-input-{uuid}" class="sr-only">
|
||||
Describe {shortName} for the visually impaired
|
||||
</label>
|
||||
<label for="compose-media-input-{uuid}" class="sr-only">{label}</label>
|
||||
</div>
|
||||
</li>
|
||||
<style>
|
||||
|
@ -85,6 +87,10 @@
|
|||
height: 18px;
|
||||
}
|
||||
|
||||
.audio-preview {
|
||||
background: var(--audio-bg);
|
||||
}
|
||||
|
||||
.compose-media-realm-dialog {
|
||||
max-height: 20vh;
|
||||
}
|
||||
|
@ -106,6 +112,7 @@
|
|||
import { observe } from 'svelte-extras'
|
||||
import SvgIcon from '../SvgIcon.html'
|
||||
import { autosize } from '../../_thirdparty/autosize/autosize'
|
||||
import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
|
||||
|
||||
export default {
|
||||
oncreate () {
|
||||
|
@ -126,7 +133,14 @@
|
|||
// so fall back to the description if it was provided
|
||||
filename || mediaItem.description || ''
|
||||
),
|
||||
type: ({ mediaItem }) => mediaItem.data.type,
|
||||
shortName: ({ filename }) => filename || 'media',
|
||||
previewSrc: ({ mediaItem, type }) => (
|
||||
type === 'audio' ? ONE_TRANSPARENT_PIXEL : mediaItem.data.preview_url
|
||||
),
|
||||
label: ({ shortName }) => (
|
||||
`Describe ${shortName} for the visually impaired (image, video) or auditorily impaired (audio, video)`
|
||||
),
|
||||
uuid: ({ realm, mediaItem }) => `${realm}-${mediaItem.data.id}`
|
||||
},
|
||||
store: () => store,
|
||||
|
|
|
@ -217,7 +217,7 @@
|
|||
computed: {
|
||||
length: ({ mediaItems }) => mediaItems.length,
|
||||
dots: ({ length }) => times(length, i => ({ i })),
|
||||
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => media.type === 'video')
|
||||
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => ['video', 'audio'].includes(media.type))
|
||||
},
|
||||
components: {
|
||||
ModalDialog,
|
||||
|
|
|
@ -6,8 +6,18 @@
|
|||
{poster}
|
||||
controls
|
||||
{intrinsicsize}
|
||||
ref:video
|
||||
ref:player
|
||||
/>
|
||||
{:elseif type === 'audio'}
|
||||
<div class="audio-player-container">
|
||||
<audio
|
||||
class="audio-player"
|
||||
aria-label={description}
|
||||
src={url}
|
||||
controls
|
||||
ref:player
|
||||
/>
|
||||
</div>
|
||||
{:elseif type === 'gifv'}
|
||||
<video
|
||||
class="media-fit"
|
||||
|
@ -36,6 +46,27 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.audio-player-container {
|
||||
min-height: 400px;
|
||||
min-width: 400px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
background: var(--audio-bg);
|
||||
}
|
||||
.audio-player {
|
||||
padding: 30px 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.audio-player-container {
|
||||
min-height: 200px;
|
||||
min-width: calc(100vw - 40px);
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
export default {
|
||||
|
@ -54,8 +85,9 @@
|
|||
}
|
||||
},
|
||||
ondestroy () {
|
||||
if (this.refs.video && !this.refs.video.paused) {
|
||||
this.refs.video.pause()
|
||||
let player = this.refs.player
|
||||
if (player && !player.paused) {
|
||||
player.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
{#if type === 'video'}
|
||||
{#if type === 'video' || type === 'audio'}
|
||||
<button id={elementId}
|
||||
type="button"
|
||||
class="play-video-button {$largeInlineMedia ? '' : 'fixed-size'}"
|
||||
class="play-video-button {$largeInlineMedia ? '' : 'fixed-size'} {type === 'audio' ? 'play-audio-button' : ''}"
|
||||
aria-label="Play video: {description}"
|
||||
style="width: {inlineWidth}px; height: {inlineHeight}px;">
|
||||
<PlayVideoIcon />
|
||||
<LazyImage
|
||||
alt={description}
|
||||
title={description}
|
||||
src={previewUrl}
|
||||
fallback={oneTransparentPixel}
|
||||
width={inlineWidth}
|
||||
height={inlineHeight}
|
||||
background="var(--loading-bg)"
|
||||
{focus}
|
||||
/>
|
||||
{#if type === 'video'}
|
||||
<LazyImage
|
||||
alt={description}
|
||||
title={description}
|
||||
src={previewUrl}
|
||||
fallback={oneTransparentPixel}
|
||||
width={inlineWidth}
|
||||
height={inlineHeight}
|
||||
background="var(--loading-bg)"
|
||||
{focus}
|
||||
/>
|
||||
{/if}
|
||||
</button>
|
||||
{:else}
|
||||
<button id={elementId}
|
||||
|
@ -72,6 +74,9 @@
|
|||
background: none;
|
||||
position: relative;
|
||||
}
|
||||
.play-audio-button {
|
||||
background: var(--audio-bg);
|
||||
}
|
||||
|
||||
/* the actual focus outline is not very visible, so use an ::after pseudo-element */
|
||||
.play-video-button:focus, .show-image-button:focus {
|
||||
|
|
|
@ -118,4 +118,6 @@
|
|||
--floating-button-bg-active: #{darken(rgba($main-bg-color, 0.9), 10%)};
|
||||
|
||||
--length-indicator-color: #{$main-theme-color};
|
||||
|
||||
--audio-bg: #{rgba(30, 30, 30, 0.8)};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue