Skip to content

Commit

Permalink
Merge pull request #268 from yileifeng/video-panel-editor
Browse files Browse the repository at this point in the history
Add video panel support in editor
  • Loading branch information
yileifeng authored Apr 4, 2024
2 parents a2294fb + 8bc3e03 commit 367a85b
Show file tree
Hide file tree
Showing 9 changed files with 490 additions and 16 deletions.
29 changes: 26 additions & 3 deletions src/components/editor/dynamic-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,24 @@ import {
MapPanel,
PanelType,
SlideshowPanel,
SourceCounts
SourceCounts,
VideoPanel
} from '@/definitions';
import ChartEditorV from './chart-editor.vue';
import ImageEditorV from './image-editor.vue';
import TextEditorV from './text-editor.vue';
import MapEditorV from './map-editor.vue';
import VideoEditorV from './video-editor.vue';
@Options({
components: {
'chart-editor': ChartEditorV,
'image-editor': ImageEditorV,
'text-editor': TextEditorV,
'dynamic-editor': DynamicEditorV,
'map-editor': MapEditorV
'map-editor': MapEditorV,
'video-editor': VideoEditorV
}
})
export default class DynamicEditorV extends Vue {
Expand All @@ -129,7 +132,8 @@ export default class DynamicEditorV extends Vue {
image: 'image-editor',
slideshow: 'image-editor',
chart: 'chart-editor',
map: 'map-editor'
map: 'map-editor',
video: 'video-editor'
};
startingConfig: DefaultConfigs = {
Expand Down Expand Up @@ -158,6 +162,12 @@ export default class DynamicEditorV extends Vue {
config: '',
title: '',
scrollguard: false
},
video: {
type: PanelType.Video,
title: '',
videoType: '',
src: ''
}
};
Expand Down Expand Up @@ -229,6 +239,19 @@ export default class DynamicEditorV extends Vue {
});
break;
}
case 'video': {
const videoPanel = panel as VideoPanel;
if (videoPanel.videoType === 'local') {
this.sourceCounts[videoPanel.src] -= 1;
if (this.sourceCounts[videoPanel.src] === 0) {
this.configFileStructure.zip.remove(
`${videoPanel.src.substring(videoPanel.src.indexOf('/') + 1)}`
);
}
}
break;
}
}
// Remove the panel itself.
Expand Down
87 changes: 87 additions & 0 deletions src/components/editor/helpers/video-preview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<template>
<div class="my-8 mx-4 overflow-hidden w-full">
<div class="relative text-center w-full grabbable">
<button
class="bg-white absolute h-6 w-6 leading-5 rounded-full top-0 right-0 p-0 cursor-pointer"
@click="() => $emit('delete', file)"
:content="$t('editor.video.delete')"
v-tippy="{ placement: 'top', hideOnClick: false, animateFill: true }"
>
<svg height="24px" width="24px" viewBox="0 0 352 512" xmlns="http://www.w3.org/2000/svg">
<path
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
/>
</svg>
</button>
<div class="video-container">
<!-- YouTube video -->
<template v-if="file.videoType === 'YouTube'">
<iframe
class="w-3/5"
:src="file.src"
:height="file.height ? file.height : 400"
:width="file.width"
allowfullscreen
></iframe>
</template>

<!-- video with local/external source -->
<template v-if="file.videoType === 'local' || file.videoType === 'external'">
<video
class="w-3/5"
:title="file.title"
:height="file.height ? file.height : 500"
:width="file.width"
controls
>
<source :type="fileType" :src="file.src" />
<!-- add captions with transcript -->
<track
kind="captions"
:src="file.caption"
:srclang="lang"
:label="langs[lang]"
v-if="file.caption"
/>
</video>
</template>
</div>
</div>
<slot></slot>
</div>
</template>

<script lang="ts">
import { Prop, Vue } from 'vue-property-decorator';
import { VideoFile } from '@/definitions';
import MarkdownIt from 'markdown-it';
export default class VideoPreviewV extends Vue {
@Prop() file!: VideoFile;
@Prop() fileType!: string;
@Prop() lang!: string;
md = new MarkdownIt({ html: true });
langs = { en: 'English', fr: 'French' } as Record<string, string>;
expandTranscript = false;
rawTranscript = '';
transcriptContent = '';
}
</script>

<style lang="scss" scoped>
.video-file {
max-height: 300px;
}
.video-container {
display: flex;
align-items: center;
justify-content: center;
}
button {
padding: 0 !important;
}
</style>
6 changes: 3 additions & 3 deletions src/components/editor/image-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
<span>
<div>{{ $t('editor.image.label.drag') }}</div>
<div>
{{ $t('editor.image.label.or') }}
<span class="text-blue-400 font-bold">{{ $t('editor.image.label.browse') }}</span>
{{ $t('editor.image.label.upload') }}
{{ $t('editor.label.or') }}
<span class="text-blue-400 font-bold">{{ $t('editor.label.browse') }}</span>
{{ $t('editor.label.upload') }}
</div>
</span>
<input type="file" class="cursor-pointer" @change="onFileChange" multiple />
Expand Down
7 changes: 6 additions & 1 deletion src/components/editor/metadata-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ import {
Slide,
SlideshowPanel,
SourceCounts,
StoryRampConfig
StoryRampConfig,
VideoPanel
} from '@/definitions';
import { VueSpinnerOval } from 'vue3-spinners';
import { VueFinalModal } from 'vue-final-modal';
Expand Down Expand Up @@ -450,6 +451,10 @@ export default class MetadataEditorV extends Vue {
break;
case 'image':
case 'video':
if ((panel as VideoPanel).videoType === 'local') {
this.incrementSourceCount((panel as VideoPanel).src);
}
break;
case 'audio':
this.incrementSourceCount((panel as AudioPanel).src);
break;
Expand Down
31 changes: 27 additions & 4 deletions src/components/editor/slide-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
ref="typeSelector"
@input="
$vfm.open(`change-slide-${slideIndex}`);
newType = $event.target.value;
newType = ($event.target as HTMLInputElement).value;
"
:value="currentSlide.panel[panelIndex].type"
>
Expand Down Expand Up @@ -251,13 +251,15 @@ import {
SlideshowPanel,
SourceCounts,
StoryRampConfig,
TextPanel
TextPanel,
VideoPanel
} from '@/definitions';
import ChartEditorV from './chart-editor.vue';
import ImageEditorV from './image-editor.vue';
import TextEditorV from './text-editor.vue';
import MapEditorV from './map-editor.vue';
import VideoEditorV from './video-editor.vue';
import LoadingPageV from './helpers/loading-page.vue';
import DynamicEditorV from './dynamic-editor.vue';
import ConfirmationModalV from './helpers/confirmation-modal.vue';
Expand All @@ -268,6 +270,7 @@ import ConfirmationModalV from './helpers/confirmation-modal.vue';
'image-editor': ImageEditorV,
'text-editor': TextEditorV,
'map-editor': MapEditorV,
'video-editor': VideoEditorV,
'loading-page': LoadingPageV,
'dynamic-editor': DynamicEditorV,
'confirmation-modal': ConfirmationModalV
Expand All @@ -293,6 +296,7 @@ export default class SlideEditorV extends Vue {
slideshow: 'image-editor',
chart: 'chart-editor',
map: 'map-editor',
video: 'video-editor',
loading: 'loading-page',
dynamic: 'dynamic-editor'
};
Expand Down Expand Up @@ -335,6 +339,12 @@ export default class SlideEditorV extends Vue {
config: '',
title: '',
scrollguard: false
},
video: {
type: PanelType.Video,
title: '',
videoType: '',
src: ''
}
};
Expand Down Expand Up @@ -387,6 +397,19 @@ export default class SlideEditorV extends Vue {
break;
}
case 'video': {
const videoPanel = panel as VideoPanel;
if (videoPanel.videoType === 'local') {
this.sourceCounts[videoPanel.src] -= 1;
if (this.sourceCounts[videoPanel.src] === 0) {
this.configFileStructure.zip.remove(
`${videoPanel.src.substring(videoPanel.src.indexOf('/') + 1)}`
);
}
}
break;
}
case 'dynamic': {
const dynamicPanel = panel as DynamicPanel;
dynamicPanel.children.forEach((subPanel: DynamicChildItem) => {
Expand All @@ -400,9 +423,9 @@ export default class SlideEditorV extends Vue {
saveChanges(): void {
if (
this.$refs.editor !== undefined &&
typeof (this.$refs.editor as ImageEditorV | ChartEditorV).saveChanges === 'function'
typeof (this.$refs.editor as ImageEditorV | ChartEditorV | VideoEditorV).saveChanges === 'function'
) {
(this.$refs.editor as ImageEditorV | ChartEditorV).saveChanges();
(this.$refs.editor as ImageEditorV | ChartEditorV | VideoEditorV).saveChanges();
}
}
Expand Down
18 changes: 16 additions & 2 deletions src/components/editor/slide-toc.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
>
{{ $t('editor.slides.copyAll') }}
</button>
<span class="text-lg font-bold my-6"> {{ $t('editor.image.label.or') }} </span>
<span class="text-lg font-bold my-6"> {{ $t('editor.or') }} </span>
<div class="flex">
<select v-model="selectedForCopying" class="overflow-ellipsis copy-select">
<option
Expand Down Expand Up @@ -150,7 +150,8 @@ import {
Slide,
SlideshowPanel,
SourceCounts,
TextPanel
TextPanel,
VideoPanel
} from '@/definitions';
import { VueFinalModal } from 'vue-final-modal';
import cloneDeep from 'clone-deep';
Expand Down Expand Up @@ -273,6 +274,19 @@ export default class SlideTocV extends Vue {
break;
}
case 'video': {
const videoPanel = panel as VideoPanel;
if (videoPanel.videoType === 'local') {
this.sourceCounts[videoPanel.src] -= 1;
if (this.sourceCounts[videoPanel.src] === 0) {
this.configFileStructure.zip.remove(
`${videoPanel.src.substring(videoPanel.src.indexOf('/') + 1)}`
);
}
}
break;
}
case 'dynamic': {
const dynamicPanel = panel as DynamicPanel;
dynamicPanel.children.forEach((subPanel: DynamicChildItem) => {
Expand Down
Loading

0 comments on commit 367a85b

Please sign in to comment.