Commit cbbf9110 by Jonathan Thomas

Adding comments to all HTML, updating README with more content

parent 0448bd13
simple-editor simple-editor
============= =============
Provide a very simple editor, so end-users can upload files, This is a very simple demo application for OpenShot Cloud API. You can log-in, upload files,
create clips, sequence clips, and export a video. create/edit clips, Move clips (up/down), and export & download a video.
urls: urls:
----- -----
- /login/: Allow user to login to API (keep track in vuex) - /login/: Allow user to login to API (auth saved to localStorage)
- /login/auto/: Allow a passed token to auto-login
- /projects/: List all projects (create, edit, copy, delete) - /projects/: List all projects (create, edit, copy, delete)
- /projects/ID/: Simple editor (files, clips, preview, export) - /projects/ID/: Video editor (files, clips, preview, export)
editor: editor:
------- -------
- files: upload & delete - files: upload (w/progress bars), filter, and delete
- clips: preview file/clip, start/end, position (create, update, delete) - clips: trimming (start, end), position (move clip), edit, delete
- preview: file & clips supported, play/pause, simple timeline w/ trimming, add-clip button
- export: progress bar, cancel, download, preview (show last export) - export: progress bar, cancel, download, preview (show last export)
## Project setup ## Project setup
......
<template> <template>
<!-- Navigation --> <!-- Base Template -->
<header> <header>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light nav-pills"> <nav class="navbar navbar-expand-lg navbar-light nav-pills">
<div class="container mb-3"> <div class="container mb-3">
<router-link to="/" class="navbar-brand" aria-current="page">Simple Editor</router-link> <router-link to="/" class="navbar-brand" aria-current="page">Simple Editor</router-link>
...@@ -25,11 +27,13 @@ ...@@ -25,11 +27,13 @@
</div> </div>
</div> </div>
</nav> </nav>
</header> </header>
<!--router content--> <!-- Router Content -->
<div class="container"> <div class="container">
<!-- show any errors from vuex -->
<!-- Show Errors -->
<div v-for="error in errors" :key="error.id" class="error-message alert alert-danger alert-dismissible fade show" role="alert"> <div v-for="error in errors" :key="error.id" class="error-message alert alert-danger alert-dismissible fade show" role="alert">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-exclamation-triangle-fill flex-shrink-0 me-2" viewBox="0 0 16 16" role="img" aria-label="Warning:"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-exclamation-triangle-fill flex-shrink-0 me-2" viewBox="0 0 16 16" role="img" aria-label="Warning:">
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/> <path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
...@@ -38,8 +42,9 @@ ...@@ -38,8 +42,9 @@
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" @click="removeError(error)"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" @click="removeError(error)"></button>
</div> </div>
<!-- main router content --> <!-- Current Router view content -->
<router-view/> <router-view/>
</div> </div>
</template> </template>
......
<template> <template>
<div class="row mb-3 gx-2 p-2 scrolling-container"> <!-- Clips header & Export button -->
<div class="row mb-3 gx-2 p-2">
<h3 v-if="thumbnailedClips.length > 0">Clips <button type="button" class="btn btn-danger export-btn">Export {{clips.length}} Clips</button></h3> <h3 v-if="thumbnailedClips.length > 0">Clips <button type="button" class="btn btn-danger export-btn">Export {{clips.length}} Clips</button></h3>
<!-- Loading spinner --> <!-- Loading spinner -->
...@@ -9,12 +10,15 @@ ...@@ -9,12 +10,15 @@
</div> </div>
</div> </div>
<div class="col-12"> <!-- Scrolling container for clips -->
<div class="col-12 scrolling-container">
<div class="row gy-2 gx-2 mb-2" v-for="(clip, index) in thumbnailedClips" :key="clip.id"> <div class="row gy-2 gx-2 mb-2" v-for="(clip, index) in thumbnailedClips" :key="clip.id">
<div class="col-12 text-center img-parent"> <div class="col-12 text-center img-parent">
<!-- Clip sequence # badge -->
<span class="clip-badge badge">{{ index + 1 }}</span> <span class="clip-badge badge">{{ index + 1 }}</span>
<!-- Context menu for clip -->
<div class="btn-group dropstart context-menu"> <div class="btn-group dropstart context-menu">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="dropdown-toggle bi bi-three-dots-vertical" data-bs-toggle="dropdown" aria-expanded="false" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="dropdown-toggle bi bi-three-dots-vertical" data-bs-toggle="dropdown" aria-expanded="false" viewBox="0 0 16 16">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/> <path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
...@@ -27,10 +31,12 @@ ...@@ -27,10 +31,12 @@
</ul> </ul>
</div> </div>
<!-- Clip length label -->
<div ref="clip" class="clip-label"> <div ref="clip" class="clip-label">
{{ (clip.end - clip.start).toFixed(1) }} Seconds {{ (clip.end - clip.start).toFixed(1) }} Seconds
</div> </div>
<!-- Clip thumbnail image -->
<img @click="toggleSelection(clip)" :class="getSelectedClass(clip)" class="img-fluid img-thumbnail clip-thumbnail" @load="thumbnailLoaded($event, clip)" :title="clip.name" :src="clip.thumbnail"/> <img @click="toggleSelection(clip)" :class="getSelectedClass(clip)" class="img-fluid img-thumbnail clip-thumbnail" @load="thumbnailLoaded($event, clip)" :title="clip.name" :src="clip.thumbnail"/>
</div> </div>
</div> </div>
......
<template> <template>
<div class="row mb-3 gx-2 p-2 scrolling-container"> <!-- File header & Upload button -->
<div class="row">
<h3>Files <button type="button" class="btn btn-primary upload-btn" @click="chooseFiles">Upload</button></h3> <h3>Files <button type="button" class="btn btn-primary upload-btn" @click="chooseFiles">Upload</button></h3>
<div class="col-sm-12"> <div class="col-sm-12">
<div class="form-floating mb-3"> <div class="form-floating mb-3">
...@@ -7,16 +8,19 @@ ...@@ -7,16 +8,19 @@
<label for="floatingInput">Search</label> <label for="floatingInput">Search</label>
</div> </div>
</div> </div>
</div>
<!-- Loading spinner --> <!-- Loading spinner -->
<div v-if="show_spinner" class="md-5 p-4 text-center"> <div v-if="show_spinner" class="md-5 p-4 text-center">
<div class="spinner-border" role="status"> <div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div>
</div> </div>
</div>
<!-- Scrolling container for files -->
<div class="row mb-3 gx-2 p-2 scrolling-container">
<div v-for="file in searchedFiles" :key="file.id" class="col-sm-12 col-lg-4" style="position: relative;"> <div v-for="file in searchedFiles" :key="file.id" class="col-sm-12 col-lg-4" style="position: relative;">
<!-- Context Menu -->
<div class="btn-group dropstart context-menu"> <div class="btn-group dropstart context-menu">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="dropdown-toggle bi bi-three-dots-vertical" data-bs-toggle="dropdown" aria-expanded="false" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="dropdown-toggle bi bi-three-dots-vertical" data-bs-toggle="dropdown" aria-expanded="false" viewBox="0 0 16 16">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/> <path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
...@@ -26,9 +30,12 @@ ...@@ -26,9 +30,12 @@
</ul> </ul>
</div> </div>
<!-- File thumbnail image -->
<img @click="toggleSelection(file)" :class="getSelectedClass(file)" class="file-thumbnail img-fluid img-thumbnail" :title="file.name" :src="file.thumbnail"/> <img @click="toggleSelection(file)" :class="getSelectedClass(file)" class="file-thumbnail img-fluid img-thumbnail" :title="file.name" :src="file.thumbnail"/>
<figcaption class="figure-caption">{{ getFileName(file) }}</figcaption> <figcaption class="figure-caption">{{ getFileName(file) }}</figcaption>
</div> </div>
<!-- Upload progress bars -->
<div v-for="upload in uploads" :key="upload.id" class="col-4"> <div v-for="upload in uploads" :key="upload.id" class="col-4">
<div class="row h-100"> <div class="row h-100">
<div class="col-sm-12 my-auto p-3"> <div class="col-sm-12 my-auto p-3">
...@@ -38,8 +45,10 @@ ...@@ -38,8 +45,10 @@
</div> </div>
</div> </div>
</div> </div>
<input ref="fileUpload" type="file" @change="fileChanged" multiple hidden>
</div> </div>
<!-- Actual file input used for upload -->
<input ref="fileUpload" type="file" @change="fileChanged" multiple hidden>
</template> </template>
<script> <script>
...@@ -129,7 +138,7 @@ export default { ...@@ -129,7 +138,7 @@ export default {
<style scoped> <style scoped>
.scrolling-container { .scrolling-container {
max-height: 300px; height: 150px;
overflow: scroll; overflow: scroll;
} }
.upload-btn { .upload-btn {
......
<template> <template>
<!-- Preview header -->
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<h3 class="p-2">Preview</h3> <h3 class="p-2">Preview</h3>
...@@ -14,15 +15,19 @@ ...@@ -14,15 +15,19 @@
</div> </div>
</div> </div>
<!-- Preview Video/Image -->
<div class="col-sm-12"> <div class="col-sm-12">
<video ref="video" v-if="!isImage && hasPreviewFile" v-show="media_loaded" @loadeddata="videoLoaded" @timeupdate="videoTimeUpdate" @pause="togglePause" @play="togglePause" loop preload="" poster="" class="video-responsive"> <video ref="video" v-if="!isImage && hasPreviewFile" v-show="media_loaded" @loadeddata="videoLoaded" @timeupdate="videoTimeUpdate" @pause="togglePause" @play="togglePause" loop preload="" poster="" class="video-responsive">
<source :type="previewFormat" :src="preview.file.media"> <source :type="previewFormat" :src="preview.file.media">
</video> </video>
<img v-if="isImage && hasPreviewFile" v-show="media_loaded" :src="preview.file.media" @load="imageLoaded" class="img-fluid img-thumbnail" /> <img v-if="isImage && hasPreviewFile" v-show="media_loaded" :src="preview.file.media" @load="imageLoaded" class="img-fluid img-thumbnail" />
</div> </div>
</div> </div>
<!-- Timeline Container -->
<div v-if="hasPreviewFile" class="d-flex flex-column d-sm-flex flex-sm-row"> <div v-if="hasPreviewFile" class="d-flex flex-column d-sm-flex flex-sm-row">
<!-- Play/Pause button -->
<div class="col-sm-1 d-flex flex-column p-1"> <div class="col-sm-1 d-flex flex-column p-1">
<button title="Play/Pause Preview" type="button" class="btn btn-secondary timeline-btn" @click="togglePlayback"> <button title="Play/Pause Preview" type="button" class="btn btn-secondary timeline-btn" @click="togglePlayback">
<svg v-show="is_paused" xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-play-fill" viewBox="0 0 16 16"> <svg v-show="is_paused" xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-play-fill" viewBox="0 0 16 16">
...@@ -33,6 +38,8 @@ ...@@ -33,6 +38,8 @@
</svg> </svg>
</button> </button>
</div> </div>
<!-- Timeline w/ Clip Trimming -->
<div class="col-sm-10 d-flex flex-column p-1"> <div class="col-sm-10 d-flex flex-column p-1">
<div class="timeline" ref="timeline" @mousedown="seekToCursor($event)" @mousemove="drag($event)" @touchmove="drag($event)" @mouseup="endDrag" @touchend="endDrag" @mouseleave="endDrag"> <div class="timeline" ref="timeline" @mousedown="seekToCursor($event)" @mousemove="drag($event)" @touchmove="drag($event)" @mouseup="endDrag" @touchend="endDrag" @mouseleave="endDrag">
<div title="Drag Playback Position" ref="playhead" class="playhead" @mousedown="startDrag($event, 'playhead')" @touchstart="startDrag($event, 'playhead')" :style="{left: preview.position * 100.0 + '%'}"></div> <div title="Drag Playback Position" ref="playhead" class="playhead" @mousedown="startDrag($event, 'playhead')" @touchstart="startDrag($event, 'playhead')" :style="{left: preview.position * 100.0 + '%'}"></div>
...@@ -51,6 +58,8 @@ ...@@ -51,6 +58,8 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Add Clip button -->
<div class="col-sm-1 d-flex flex-column p-1"> <div class="col-sm-1 d-flex flex-column p-1">
<button title="Add Clip" type="button" class="btn btn-secondary timeline-btn" @click="createClipBtn"> <button title="Add Clip" type="button" class="btn btn-secondary timeline-btn" @click="createClipBtn">
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16">
...@@ -60,6 +69,7 @@ ...@@ -60,6 +69,7 @@
</div> </div>
</div> </div>
<!-- No Preview / No File message -->
<div v-if="!hasPreviewFile" class="mb-5 text-center" style="margin-top: 7em;"> <div v-if="!hasPreviewFile" class="mb-5 text-center" style="margin-top: 7em;">
<div class="col-lg-6 mx-auto"> <div class="col-lg-6 mx-auto">
<p class="lead">Upload or select a video to begin!</p> <p class="lead">Upload or select a video to begin!</p>
......
<template> <template>
<!-- Create Project button -->
<div class="mb-5 text-center"> <div class="mb-5 text-center">
<div class="col-lg-6 mx-auto"> <div class="col-lg-6 mx-auto">
<p class="lead">Create and edit your own video editing projects!</p> <p class="lead">Create and edit your own video editing projects!</p>
...@@ -68,7 +69,7 @@ ...@@ -68,7 +69,7 @@
</div> </div>
</div> </div>
<!-- Delete Modal --> <!-- Delete Project Modal -->
<div class="modal fade" ref="deleteModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal fade" ref="deleteModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
......
<template> <template>
<!-- About OpenShot Cloud API header w/buttons -->
<div class="row"> <div class="row">
<div class="col-md-12 m-3 text-center"> <div class="col-md-12 m-5 text-center">
<div class="call-to-action-content" style="width: 50%; float: left;"> <div class="call-to-action-content" style="width: 50%; float: left;">
<h3><strong>Powered</strong> by OpenShot Cloud API</h3> <h3><strong>Powered</strong> by OpenShot Cloud API</h3>
<p>Fast, easy, and affordable cloud video editing!</p> <p>Fast, easy, and affordable cloud video editing!</p>
</div> </div>
<!-- Learn more buttons -->
<div class="call-to-action-btn animated tada" style="width: auto;"> <div class="call-to-action-btn animated tada" style="width: auto;">
<a class="btn btn-lg btn-primary" href="//openshot.org/cloud-api/" target="_blank" style="margin: 5px;"><i class="fa fa-compass"></i> <a class="btn btn-lg btn-primary" href="//openshot.org/cloud-api/" target="_blank" style="margin: 5px;"><i class="fa fa-compass"></i>
<strong>Learn More</strong> <strong>Learn More</strong>
...@@ -16,8 +19,9 @@ ...@@ -16,8 +19,9 @@
</div> </div>
</div> </div>
<!-- Description of OpenShot Cloud API -->
<div class="row"> <div class="row">
<div class="col-md-12 ms-3 me-3"> <div class="col-md-12 ms-5 me-5">
<p class="lead"> <p class="lead">
Simple <strong>RESTful</strong> interface, <strong>pay-as-you-go</strong> pricing, and industry leading video Simple <strong>RESTful</strong> interface, <strong>pay-as-you-go</strong> pricing, and industry leading video
editing capabilities. Easily create video templates in <a href="//openshot.org" target="_blank">OpenShot Video Editor</a>, our editing capabilities. Easily create video templates in <a href="//openshot.org" target="_blank">OpenShot Video Editor</a>, our
......
<template> <template>
<!-- Video Editor container -->
<div class="row"> <div class="row">
<!-- Left column -->
<div class="col-sm-12 col-md-4"> <div class="col-sm-12 col-md-4">
<Files v-if="hasData" :project="project"/> <Files v-if="hasData" :project="project"/>
<Clips v-if="hasData" :project="project"/> <Clips v-if="hasData" :project="project"/>
</div> </div>
<!-- Right Column -->
<div class="col-sm-12 col-md-8"> <div class="col-sm-12 col-md-8">
<Preview v-if="hasData" :project="project"/> <Preview v-if="hasData" :project="project"/>
</div> </div>
</div> </div>
</template> </template>
......
<template> <template>
<!-- Projects component -->
<Projects/> <Projects/>
</template> </template>
......
<template> <template>
<!-- Login container -->
<div class="row p-5 justify-content-center"> <div class="row p-5 justify-content-center">
<div class="col-xs-12 col-md-6 col-lg-4"> <div class="col-xs-12 col-md-6 col-lg-4">
<div class="mb-3"> <div class="mb-3">
...@@ -9,6 +10,7 @@ ...@@ -9,6 +10,7 @@
<label class="form-label">Password</label> <label class="form-label">Password</label>
<input type="password" class="form-control" v-model="password" @keyup.enter="loginClick"> <input type="password" class="form-control" v-model="password" @keyup.enter="loginClick">
</div> </div>
<!-- Login button -->
<button type="submit" class="btn btn-primary" @click="loginClick">Login</button> <button type="submit" class="btn btn-primary" @click="loginClick">Login</button>
</div> </div>
</div> </div>
......
<script> <script>
import { mapMutations } from 'vuex' import { mapMutations } from 'vuex'
...@@ -16,8 +14,4 @@ export default { ...@@ -16,8 +14,4 @@ export default {
this.$router.push('/login') this.$router.push('/login')
} }
} }
</script> </script>
\ No newline at end of file
<style scoped>
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment