Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add video panel support in editor #268

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/components/editor/dynamic-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,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 @@ -128,7 +131,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 @@ -157,6 +161,12 @@ export default class DynamicEditorV extends Vue {
config: '',
title: '',
scrollguard: false
},
video: {
type: PanelType.Video,
title: '',
videoType: '',
src: ''
}
};

Expand Down Expand Up @@ -226,6 +236,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="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 @@ -446,6 +447,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 @@ -250,13 +250,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 @@ -267,6 +269,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 @@ -292,6 +295,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 @@ -334,6 +338,12 @@ export default class SlideEditorV extends Vue {
config: '',
title: '',
scrollguard: false
},
video: {
type: PanelType.Video,
title: '',
videoType: '',
src: ''
}
};

Expand Down Expand Up @@ -386,6 +396,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 @@ -399,9 +422,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
Loading