feat: combine alt/focal point into single "media edit" dialog (#1430)
* feat: combine alt/focal point into single "media edit" dialog * resize text automatically
This commit is contained in:
parent
7b32c71c93
commit
7f9195c2af
|
@ -7,12 +7,11 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<div class="compose-media-buttons">
|
<div class="compose-media-buttons">
|
||||||
<button class="compose-media-button compose-media-focal-button {focalHidden ? 'compose-media-hidden' : ''}"
|
<button class="compose-media-button compose-media-focal-button"
|
||||||
aria-hidden={focalHidden}
|
aria-label="Edit"
|
||||||
aria-label="Change preview"
|
title="Edit"
|
||||||
title="Change preview"
|
on:click="onEdit()" >
|
||||||
on:click="onSetFocalPoint()" >
|
<SvgIcon className="compose-media-button-svg" href="#fa-pencil" />
|
||||||
<SvgIcon className="compose-media-button-svg" href="#fa-crosshairs" />
|
|
||||||
</button>
|
</button>
|
||||||
<button class="compose-media-button compose-media-delete-button"
|
<button class="compose-media-button compose-media-delete-button"
|
||||||
aria-label="Delete"
|
aria-label="Delete"
|
||||||
|
@ -27,6 +26,7 @@
|
||||||
placeholder="Description"
|
placeholder="Description"
|
||||||
ref:textarea
|
ref:textarea
|
||||||
bind:value=rawText
|
bind:value=rawText
|
||||||
|
maxlength="420"
|
||||||
></textarea>
|
></textarea>
|
||||||
<label for="compose-media-input-{uuid}" class="sr-only">
|
<label for="compose-media-input-{uuid}" class="sr-only">
|
||||||
Describe for the visually impaired (image, video) or auditorily impaired (audio, video)
|
Describe for the visually impaired (image, video) or auditorily impaired (audio, video)
|
||||||
|
@ -98,11 +98,6 @@
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-media-hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.audio-preview {
|
.audio-preview {
|
||||||
background: var(--audio-bg);
|
background: var(--audio-bg);
|
||||||
}
|
}
|
||||||
|
@ -130,10 +125,11 @@
|
||||||
import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
|
import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
|
||||||
import { get } from '../../_utils/lodash-lite'
|
import { get } from '../../_utils/lodash-lite'
|
||||||
import { coordsToPercent } from '../../_utils/coordsToPercent'
|
import { coordsToPercent } from '../../_utils/coordsToPercent'
|
||||||
import { importMediaFocalPointDialog } from '../dialog/asyncDialogs'
|
import { importShowMediaEditDialog } from '../dialog/asyncDialogs'
|
||||||
import { throttleTimer } from '../../_utils/throttleTimer'
|
import { throttleTimer } from '../../_utils/throttleTimer'
|
||||||
|
|
||||||
const updateMediaInStore = throttleTimer(scheduleIdleTask)
|
const updateMediaInStore = throttleTimer(scheduleIdleTask)
|
||||||
|
const resizeTextarea = process.browser && throttleTimer(requestAnimationFrame)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -165,8 +161,7 @@
|
||||||
return 'center center'
|
return 'center center'
|
||||||
}
|
}
|
||||||
return `${coordsToPercent(focusX)}% ${100 - coordsToPercent(focusY)}%`
|
return `${coordsToPercent(focusX)}% ${100 - coordsToPercent(focusY)}%`
|
||||||
},
|
}
|
||||||
focalHidden: ({ type }) => type !== 'image'
|
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -178,6 +173,7 @@
|
||||||
const text = get(media, [index, 'description'], '')
|
const text = get(media, [index, 'description'], '')
|
||||||
if (rawText !== text) {
|
if (rawText !== text) {
|
||||||
this.set({ rawText: text })
|
this.set({ rawText: text })
|
||||||
|
resizeTextarea(() => autosize.update(this.refs.textarea))
|
||||||
}
|
}
|
||||||
const focusX = get(media, [index, 'focusX'], 0)
|
const focusX = get(media, [index, 'focusX'], 0)
|
||||||
const focusY = get(media, [index, 'focusY'], 0)
|
const focusY = get(media, [index, 'focusY'], 0)
|
||||||
|
@ -206,10 +202,10 @@
|
||||||
const { realm, index } = this.get()
|
const { realm, index } = this.get()
|
||||||
deleteMedia(realm, index)
|
deleteMedia(realm, index)
|
||||||
},
|
},
|
||||||
async onSetFocalPoint () {
|
async onEdit () {
|
||||||
const { realm, index } = this.get()
|
const { realm, index, type } = this.get()
|
||||||
const showMediaFocalPointDialog = await importMediaFocalPointDialog()
|
const showMediaEditDialog = await importShowMediaEditDialog()
|
||||||
showMediaFocalPointDialog(realm, index)
|
showMediaEditDialog(realm, index, type)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -44,6 +44,6 @@ export const importShowReportDialog = () => import(
|
||||||
/* webpackChunkName: 'showReportDialog' */ './creators/showReportDialog'
|
/* webpackChunkName: 'showReportDialog' */ './creators/showReportDialog'
|
||||||
).then(getDefault)
|
).then(getDefault)
|
||||||
|
|
||||||
export const importMediaFocalPointDialog = () => import(
|
export const importShowMediaEditDialog = () => import(
|
||||||
/* webpackChunkName: 'mediaFocalPointDialog' */ './creators/mediaFocalPointDialog'
|
/* webpackChunkName: 'showMediaEditDialog' */ './creators/showMediaEditDialog'
|
||||||
).then(getDefault)
|
).then(getDefault)
|
||||||
|
|
104
src/routes/_components/dialog/components/MediaAltEditor.html
Normal file
104
src/routes/_components/dialog/components/MediaAltEditor.html
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<div class="media-alt-editor">
|
||||||
|
<textarea
|
||||||
|
id="the-media-alt-input-{realm}-{index}"
|
||||||
|
class="media-alt-input"
|
||||||
|
placeholder="Description"
|
||||||
|
ref:textarea
|
||||||
|
bind:value=rawText
|
||||||
|
maxlength="420"
|
||||||
|
></textarea>
|
||||||
|
<label for="the-media-alt-input-{realm}-{index}" class="sr-only">
|
||||||
|
Describe for the visually impaired
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.media-alt-editor {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.media-alt-input {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid var(--input-border);
|
||||||
|
min-height: 75px;
|
||||||
|
resize: none;
|
||||||
|
overflow: hidden;
|
||||||
|
word-wrap: break-word;
|
||||||
|
/* Text must be at least 16px or else iOS Safari zooms in */
|
||||||
|
font-size: 1.2em;
|
||||||
|
max-height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 767px) {
|
||||||
|
.media-alt-input {
|
||||||
|
max-height: 40vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import { requestPostAnimationFrame } from '../../../_utils/requestPostAnimationFrame'
|
||||||
|
import { mark, stop } from '../../../_utils/marks'
|
||||||
|
import { autosize } from '../../../_thirdparty/autosize/autosize'
|
||||||
|
import { observe } from 'svelte-extras'
|
||||||
|
import { throttleTimer } from '../../../_utils/throttleTimer'
|
||||||
|
import { get } from '../../../_utils/lodash-lite'
|
||||||
|
import { store } from '../../../_store/store'
|
||||||
|
|
||||||
|
const updateRawTextInStore = throttleTimer(requestPostAnimationFrame)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
oncreate () {
|
||||||
|
this.setupAutosize()
|
||||||
|
this.setupSyncFromStore()
|
||||||
|
this.setupSyncToStore()
|
||||||
|
},
|
||||||
|
ondestroy () {
|
||||||
|
this.teardownAutosize()
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
|
data: () => ({
|
||||||
|
rawText: ''
|
||||||
|
}),
|
||||||
|
methods: {
|
||||||
|
observe,
|
||||||
|
setupSyncFromStore () {
|
||||||
|
this.observe('media', media => {
|
||||||
|
media = media || []
|
||||||
|
const { index, rawText } = this.get()
|
||||||
|
const text = get(media, [index, 'description'], '')
|
||||||
|
if (rawText !== text) {
|
||||||
|
this.set({ rawText: text })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setupSyncToStore () {
|
||||||
|
this.observe('rawText', rawText => {
|
||||||
|
updateRawTextInStore(() => {
|
||||||
|
const { realm, index, media } = this.get()
|
||||||
|
if (media[index].description !== rawText) {
|
||||||
|
media[index].description = rawText
|
||||||
|
this.store.setComposeData(realm, { media })
|
||||||
|
this.store.save()
|
||||||
|
}
|
||||||
|
this.fire('resize')
|
||||||
|
})
|
||||||
|
}, { init: false })
|
||||||
|
},
|
||||||
|
setupAutosize () {
|
||||||
|
const textarea = this.refs.textarea
|
||||||
|
requestPostAnimationFrame(() => {
|
||||||
|
mark('autosize()')
|
||||||
|
autosize(textarea)
|
||||||
|
stop('autosize()')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
teardownAutosize () {
|
||||||
|
mark('autosize.destroy()')
|
||||||
|
autosize.destroy(this.refs.textarea)
|
||||||
|
stop('autosize.destroy()')
|
||||||
|
},
|
||||||
|
measure () {
|
||||||
|
autosize.update(this.refs.textarea)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
100
src/routes/_components/dialog/components/MediaEditDialog.html
Normal file
100
src/routes/_components/dialog/components/MediaEditDialog.html
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<ModalDialog
|
||||||
|
{id}
|
||||||
|
{label}
|
||||||
|
{title}
|
||||||
|
background="var(--main-bg)"
|
||||||
|
className="media-edit-dialog"
|
||||||
|
on:show="measure()"
|
||||||
|
>
|
||||||
|
<div class="media-edit-dialog-container">
|
||||||
|
<div class="media-edit-header-and-item">
|
||||||
|
<h2>Description</h2>
|
||||||
|
<MediaAltEditor
|
||||||
|
{realm}
|
||||||
|
{index}
|
||||||
|
{media}
|
||||||
|
on:resize="measure()"
|
||||||
|
ref:altEditor
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{#if type === 'image'}
|
||||||
|
<div class="media-edit-header-and-item">
|
||||||
|
<h2>Preview (focal point)</h2>
|
||||||
|
<MediaFocalPointEditor
|
||||||
|
{realm}
|
||||||
|
{index}
|
||||||
|
{media}
|
||||||
|
ref:focalPointEditor
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</ModalDialog>
|
||||||
|
<style>
|
||||||
|
:global(.media-edit-dialog) {
|
||||||
|
max-width: calc(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-edit-dialog-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-height: calc(100% - 44px); /* 44px X button height */
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-edit-header-and-item {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-edit-header-and-item h2 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.media-edit-dialog-container {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-edit-dialog-container {
|
||||||
|
max-height: calc(100% - 25px); /* 25px X button height */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import ModalDialog from './ModalDialog.html'
|
||||||
|
import { show } from '../helpers/showDialog'
|
||||||
|
import { close } from '../helpers/closeDialog'
|
||||||
|
import { oncreate } from '../helpers/onCreateDialog'
|
||||||
|
import MediaFocalPointEditor from '../components/MediaFocalPointEditor.html'
|
||||||
|
import MediaAltEditor from '../components/MediaAltEditor.html'
|
||||||
|
import { store } from '../../../_store/store'
|
||||||
|
import { get } from '../../../_utils/lodash-lite'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
oncreate,
|
||||||
|
components: {
|
||||||
|
ModalDialog,
|
||||||
|
MediaFocalPointEditor,
|
||||||
|
MediaAltEditor
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show,
|
||||||
|
close,
|
||||||
|
measure () {
|
||||||
|
this.refs.altEditor.measure()
|
||||||
|
if (this.refs.focalPointEditor) {
|
||||||
|
this.refs.focalPointEditor.measure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
|
computed: {
|
||||||
|
media: ({ $currentInstance, $composeData, realm }) => (
|
||||||
|
get($composeData, [$currentInstance, realm, 'media'])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,11 +1,3 @@
|
||||||
<ModalDialog
|
|
||||||
{id}
|
|
||||||
{label}
|
|
||||||
{title}
|
|
||||||
background="var(--main-bg)"
|
|
||||||
className="media-focal-point-dialog"
|
|
||||||
on:show="measure()"
|
|
||||||
>
|
|
||||||
<form class="media-focal-point-container"
|
<form class="media-focal-point-container"
|
||||||
aria-label="Enter the focal point (X, Y) for this media"
|
aria-label="Enter the focal point (X, Y) for this media"
|
||||||
on:resize="measure()"
|
on:resize="measure()"
|
||||||
|
@ -72,15 +64,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</ModalDialog>
|
|
||||||
<style>
|
<style>
|
||||||
:global(.media-focal-point-dialog) {
|
|
||||||
max-width: calc(100%);
|
|
||||||
}
|
|
||||||
.media-focal-point-container {
|
.media-focal-point-container {
|
||||||
height: calc(100% - 44px); /* 44px X button height */
|
|
||||||
width: calc(100vw - 40px);
|
|
||||||
padding-top: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +105,7 @@
|
||||||
|
|
||||||
.media-focal-point-inputs {
|
.media-focal-point-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 20px 40px;
|
padding: 10px;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +115,10 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media-focal-point-input-pair:first-child {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.media-focal-point-input-pair input {
|
.media-focal-point-input-pair input {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
@ -180,10 +169,6 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import ModalDialog from './ModalDialog.html'
|
|
||||||
import { show } from '../helpers/showDialog'
|
|
||||||
import { close } from '../helpers/closeDialog'
|
|
||||||
import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
|
|
||||||
import { store } from '../../../_store/store'
|
import { store } from '../../../_store/store'
|
||||||
import { get } from '../../../_utils/lodash-lite'
|
import { get } from '../../../_utils/lodash-lite'
|
||||||
import { observe } from 'svelte-extras'
|
import { observe } from 'svelte-extras'
|
||||||
|
@ -207,12 +192,10 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
onCreateDialog.call(this)
|
|
||||||
this.setupSyncFromStore()
|
this.setupSyncFromStore()
|
||||||
this.setupSyncToStore()
|
this.setupSyncToStore()
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ModalDialog,
|
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
Draggable
|
Draggable
|
||||||
},
|
},
|
||||||
|
@ -226,9 +209,6 @@
|
||||||
}),
|
}),
|
||||||
store: () => store,
|
store: () => store,
|
||||||
computed: {
|
computed: {
|
||||||
media: ({ $currentInstance, $composeData, realm }) => (
|
|
||||||
get($composeData, [$currentInstance, realm, 'media'])
|
|
||||||
),
|
|
||||||
mediaItem: ({ media, index }) => get(media, [index]),
|
mediaItem: ({ media, index }) => get(media, [index]),
|
||||||
focusX: ({ mediaItem }) => get(mediaItem, ['focusX'], 0),
|
focusX: ({ mediaItem }) => get(mediaItem, ['focusX'], 0),
|
||||||
focusY: ({ mediaItem }) => get(mediaItem, ['focusY'], 0),
|
focusY: ({ mediaItem }) => get(mediaItem, ['focusY'], 0),
|
||||||
|
@ -267,8 +247,6 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
observe,
|
observe,
|
||||||
show,
|
|
||||||
close,
|
|
||||||
setupSyncFromStore () {
|
setupSyncFromStore () {
|
||||||
this.observe('mediaItem', mediaItem => {
|
this.observe('mediaItem', mediaItem => {
|
||||||
const { rawFocusX, rawFocusY } = this.get()
|
const { rawFocusX, rawFocusY } = this.get()
|
|
@ -1,11 +0,0 @@
|
||||||
import MediaFocalPointDialog from '../components/MediaFocalPointDialog.html'
|
|
||||||
import { showDialog } from './showDialog'
|
|
||||||
|
|
||||||
export default function showMediaFocalPointDialog (realm, index) {
|
|
||||||
return showDialog(MediaFocalPointDialog, {
|
|
||||||
label: 'Change preview dialog',
|
|
||||||
title: 'Change preview (focal point)',
|
|
||||||
realm,
|
|
||||||
index
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import MediaFocalPointDialog from '../components/MediaEditDialog.html'
|
||||||
|
import { showDialog } from './showDialog'
|
||||||
|
|
||||||
|
export default function showMediaEditDialog (realm, index, type) {
|
||||||
|
return showDialog(MediaFocalPointDialog, {
|
||||||
|
label: 'Edit media',
|
||||||
|
title: 'Edit media',
|
||||||
|
realm,
|
||||||
|
index,
|
||||||
|
type
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue