You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
2.9 KiB
Vue

<template>
<header>
<h1>Story Baobab</h1>
<div class="intro">
Drag and drop images and video to sketch a print-friendly storyboard. Double click on shots' title & descriptions to edit!
</div>
</header>
<main>
<div class="insert-scene">
<input v-model="title" placeholder="Title">
<button @click="add">Add Scene</button>
</div>
<div class="load-scene">
<label > Open
<input type="file" multiple @input="load">
</label>
</div>
<SceneEntry
v-for="(scene, index) in scenes"
:title="scene.title"
:series="scene.series"
@remove="remove(index)"
/>
</main>
</template>
<script setup>
import SceneEntry from './components/SceneEntry.vue'
import {utils} from './composables/utils.js'
import {ref, onBeforeMount, onBeforeUnmount } from 'vue'
const {base64ToBlob} = utils()
const scenes = ref([])
const title = ref('')
const add = () => {
scenes.value.push({
title: title.value,
series: []
})
title.value = ""
}
const remove = (index) => {
scenes.value.splice(index, 1)
}
const load = (e) => {
let files = e.target.files
files.forEach((file) =>{
const reader = new FileReader()
reader.readAsText(file)
reader.onloadend = async (ev) => {
if (ev.target.readyState == FileReader.DONE) {
try {
let scene = JSON.parse(reader.result)
await Promise.all(scene.series.map(async (shot) =>{
let file = await base64ToBlob(shot.img, 'snapshot')
let filePath = (window.URL || window.webkitURL).createObjectURL(file)
shot.img = filePath
shot.file = file
}))
scenes.value.push(scene)
} catch (err) {
console.log(err)
}
}
}
})
}
// Prevent accidental navigation
const preventNav = (e) => {
console.log('Sure to leave?')
e.preventDefault()
e.returnValue = ""
}
onBeforeMount(()=>{
window.addEventListener("beforeunload", preventNav)
})
onBeforeUnmount(()=>{
window.addEventListener("beforeunload", preventNav)
})
</script>
<style>
header {
margin: 32px;
}
header h1 {
margin: 0;
}
main {
margin: 32px;
}
.insert-scene {
display: inline-flex;
gap: 8px;
padding: 16px;
background-color: #F3F3F3;
}
.load-scene {
display: inline-flex;
gap: 8px;
padding: 16px;
}
.load-scene input {
position: absolute;
top: -10000px;
}
.load-scene label {
background-color: #fff;
border: 1px solid currentColor;
padding: 8px;
border-radius: 50%;
cursor: pointer;
}
.load-scene label:hover {
background-color: #393939;
border-color: #393939;
color: #fff;
}
@media print {
header, .insert-scene, .load-scene, .add-shot {
display: none
}
}
</style>