Skip to content

Instantly share code, notes, and snippets.

@rodrigopedra
Last active February 3, 2019 16:05
Show Gist options
  • Save rodrigopedra/db023f59d7a19cb8f78bf92eaeb0bdff to your computer and use it in GitHub Desktop.
Save rodrigopedra/db023f59d7a19cb8f78bf92eaeb0bdff to your computer and use it in GitHub Desktop.
const AssetsManager = {
name : 'AssetsManager',
template : '#assets-manager-template',
components : { ImageForm, LinkForm },
data () {
return {
showImageForm : false,
showLinkForm : false,
resolveCallback : null,
rejectCallback : null,
assets : [],
};
},
methods : {
addAsset ( type ) {
if ( type === 'link' ) {
return this.addLink();
}
if ( type === 'image' ) {
return this.addImage();
}
return Promise.reject( 'Invalid asset' );
},
addLink () {
this.showLinkForm = true;
this.$nextTick( () => {
this.$refs.linkForm.focus();
} );
return new Promise( ( resolve, reject ) => {
this.resolveCallback = resolve;
this.rejectCallback = reject;
} );
},
addImage () {
this.showImageForm = true;
this.$nextTick( () => {
this.$refs.imageForm.focus();
} );
return new Promise( ( resolve, reject ) => {
this.resolveCallback = resolve;
this.rejectCallback = reject;
} );
},
saveImage ( url ) {
const asset = {
id : 'image_' + Date.now(),
type : 'image',
url : url,
};
// Here you could upload the image to the server
// and resolve the form callback after uploading
this.assets.push( asset );
this.resolveCallback( asset );
this.showImageForm = false;
},
saveLink ( link ) {
const asset = {
id : 'link_' + Date.now(),
type : 'link',
label : link.label,
url : link.url,
};
this.assets.push( asset );
// Here you could upload the link info to the server
// and resolve the form callback after uploading
this.resolveCallback( asset );
this.showLinkForm = false;
},
cancel () {
this.rejectCallback();
this.showLinkForm = false;
this.showImageForm = false;
},
removeAsset ( asset ) {
if (!confirm('Remove this asset?')) return;
this.assets = this.assets.filter( ( item ) => item.id !== asset.id );
this.$emit( 'remove', asset );
},
},
};
const Dashboard = {
name : 'Dashboard',
components : { AssetsManager, ImagesList, LinksList },
template : '#dashboard-template',
data () {
return {
disabled : false,
items : [],
};
},
mounted () {
this.hydrate();
},
methods : {
addLinkList () {
this.items.push( {
id : 'links_' + Date.now(),
type : 'links-list',
assets : [],
} );
},
addImagesList () {
this.items.push( {
id : 'images_' + Date.now(),
type : 'images-list',
assets : [],
} );
},
addAsset ( item ) {
this.disabled = true;
const assetType = item.type === 'links-list'
? 'link'
: 'image';
this.$refs.assets
.addAsset( assetType, item.id )
.then( ( asset ) => {
item.assets.push( asset );
this.disabled = false;
} )
.catch( () => {
this.disabled = false;
} );
},
removeAsset ( asset ) {
this.items.forEach( ( item ) => {
item.assets = item.assets.filter( ( item ) => item.id !== asset.id );
} );
},
hydrate () {
// Here you could fetch current assets from the server
this.addLinkList();
this.addImagesList();
},
}
};
const ImageForm = {
name : 'ImageForm',
template : '#image-form-template',
data () {
return {
image : null,
};
},
mounted () {
this.image = null;
},
methods : {
submit () {
const url = `http://lorempixel.com/100/75/${this.image}/`;
this.$emit( 'submit', url );
},
cancel () {
this.$emit( 'cancel' );
},
focus () {
this.$nextTick( () => {
this.$refs.autofocus.focus();
} );
},
},
};
const ImagesList = {
name : 'ImagesList',
template : '#images-list-template',
props : {
item : { type : Object, required : true },
disabled : { type : Boolean, default : false },
},
methods : {
addImage () {
this.$emit( 'add' );
},
}
};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dashboard</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- components -->
<script src="image-form.js"></script>
<script src="link-form.js"></script>
<script src="assets-manager.js"></script>
<script src="links-list.js"></script>
<script src="images-list.js"></script>
<script src="dashboard.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const app = new Vue({
components: {Dashboard},
render: (h) => h('Dashboard')
});
document.addEventListener('DOMContentLoaded', () => app.$mount('#app'));
</script>
<script type="text/x-template" id="dashboard-template">
<div class="container">
<h1>Dashboard</h1>
<div class="row">
<div class="col-4">
<assets-manager
ref="assets"
@remove="(asset) => removeAsset(asset)"></assets-manager>
</div>
<div class="col-8">
<p class="text-right">
<button
class="btn btn-primary"
type="button"
:disabled="disabled"
@click="addLinkList()">
Add Links List
</button>
<button
class="btn btn-warning"
type="submit"
:disabled="disabled"
@click="addImagesList()">
Add Images List
</button>
</p>
<hr>
<component
class="mb-3"
:is="item.type"
:item="item"
:disabled="disabled"
:key="item.id"
@add="addAsset(item)"
v-for="item in items"></component>
</div>
</div>
</div>
</script>
<script type="text/x-template" id="links-list-template">
<div class="card">
<div class="card-header bg-primary d-flex align-items-center text-white">
<h4 class="mb-0">Links</h4>
<button
class="ml-auto btn btn-sm btn-success"
type="button"
:disabled="disabled"
@click="addLink()">
add link
</button>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item text-center text-muted" v-if="item.assets.length === 0">
<em>no links yet</em>
</li>
<li
class="list-group-item"
:key="link.id"
v-for="link in item.assets">
<a :href="link.url" target="_blank">{{ link.label }}</a>
</li>
</ul>
</div>
</script>
<script type="text/x-template" id="images-list-template">
<div class="card">
<div class="card-header bg-warning d-flex align-items-center">
<h4 class="mb-0">Images</h4>
<button
class="ml-auto btn btn-sm btn-success"
type="button"
:disabled="disabled"
@click="addImage()">
add image
</button>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item text-center text-muted" v-if="item.assets.length === 0">
<em>no images yet</em>
</li>
<li
class="list-group-item"
:key="image.id"
v-for="image in item.assets">
<img :src="image.url" class="d-block" style="max-height: 75px;">
</li>
</ul>
</div>
</script>
<script type="text/x-template" id="assets-manager-template">
<div>
<div class="card">
<div class="card-header d-flex align-items-center">
<h4 class="mb-0">Assets</h4>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item text-center text-muted" v-if="assets.length === 0">
<em>no assets yet</em>
</li>
<li
class="list-group-item d-flex align-items-center"
:key="asset.id"
v-for="asset in assets">
<span class="badge badge-primary mr-2" v-if="asset.type == 'link'">link</span>
<span class="badge badge-info mr-2" v-if="asset.type == 'image'">image</span>
<strong class="flex-grow-1 text-truncate mr-2" :title="asset.url">{{ asset.url }}</strong>
<button
type="button"
class="btn btn-sm btn-outline-danger ml-auto"
@click="removeAsset(asset)">remove</button>
</li>
</ul>
</div>
<image-form
class="mt-3"
ref="imageForm"
v-if="showImageForm"
@submit="(url) => saveImage(url)"
@cancel="cancel()"></image-form>
<link-form
class="mt-3"
ref="linkForm"
v-if="showLinkForm"
@submit="(link) => saveLink(link)"
@cancel="cancel()"></link-form>
</div>
</script>
<script type="text/x-template" id="image-form-template">
<form @submit.prevent="submit()" @reset="cancel()">
<div class="card">
<h4 class="card-header">Add an image</h4>
<div class="card-body">
<div class="form-group">
<select class="form-control" ref="autofocus" v-model="image" required>
<option :value="null">Choose an image...</option>
<option value="animals">Animal</option>
<option value="city">City</option>
<option value="food">Food</option>
<option value="nature">Nature</option>
<option value="people">People</option>
</select>
</div>
</div>
<div class="card-footer text-right">
<button type="reset" class="btn btn-sm btn-link">cancel</button>
<button type="submit" class="btn btn-sm btn-success">Add</button>
</div>
</div>
</form>
</script>
<script type="text/x-template" id="link-form-template">
<form @submit.prevent="submit()" @reset="cancel()">
<div class="card">
<h4 class="card-header">Add a link</h4>
<div class="card-body">
<div class="form-group">
<label for="link-label">Label</label>
<input
type="text"
class="form-control"
id="link-label"
required
ref="autofocus"
v-model="label">
</div>
<div class="form-group">
<label for="link-label">URL</label>
<input type="url" class="form-control" id="link-label" required v-model="url">
</div>
</div>
<div class="card-footer text-right">
<button type="reset" class="btn btn-sm btn-link">cancel</button>
<button type="submit" class="btn btn-sm btn-success">Add</button>
</div>
</div>
</form>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment