first draft of media picker

This commit is contained in:
2020-05-05 16:07:06 +02:00
parent 0ec6291ef2
commit dd96bdb9f6
10 changed files with 365 additions and 26 deletions
+13 -1
View File
@@ -6,6 +6,18 @@ namespace zero.Core.Renderer
{
public class MediaOptions : AbstractFieldOptions
{
public uint Limit { get; set; } = 1;
public decimal MaxFileSize { get; set; } = 10;
public MediaOptionsType Type { get; set; }
public MediaOptionsDisplay Display { get; set; }
public List<string> FileExtensions { get; set; } = new List<string>();
public bool DisallowSelect { get; set; }
public bool DisallowUpload { get; set; }
}
}
}
@@ -0,0 +1,9 @@
namespace zero.Core.Renderer
{
public enum MediaOptionsDisplay
{
Default = 0,
Big = 1,
Grid = 2
}
}
@@ -6,8 +6,10 @@ namespace zero.Core.Renderer
{
public enum MediaOptionsType
{
All,
Image,
Video
All = 0,
Image = 1,
Video = 2,
Document = 3,
Other = 99
}
}
+294
View File
@@ -0,0 +1,294 @@
<template>
<div class="ui-media">
<div class="ui-media-previews">
<div v-for="item in items" class="ui-media-preview">
<div class="ui-media-preview-image">
<img v-if="item.source" :src="getPreview(item)" :alt="item.name" />
</div>
</div>
</div>
<div class="ui-media-add" v-if="canAdd">
<ui-select-button v-if="!configuration.disallowSelect" icon="fth-folder" label="@mediapicker.select_text" description="@mediapicker.select_description" :disabled="disabled" />
<div v-if="!configuration.disallowUpload" class="ui-media-add-upload">
<input type="file" :accept="acceptedFileExtensions" :multiple="multiple" @change="onUpload" />
<ui-select-button icon="fth-upload" label="@mediapicker.upload_text" :description="uploadDescription" :disabled="true" />
</div>
</div>
</div>
</template>
<script>
import { each as _each, extend as _extend, debounce as _debounce, isArray as _isArray } from 'underscore';
import Strings from 'zero/services/strings.js';
const TYPES = {
ALL: 'all',
IMAGE: 'image',
VIDEO: 'video',
DOCUMENT: 'document',
OTHER: 'other'
};
const DISPLAY = {
DEFAULT: 'default',
BIG: 'big',
GRID: 'grid'
};
const defaultConfig = {
// maximum media items
limit: 1,
// media type
type: TYPES.ALL,
// how the previews are displayed
display: DISPLAY.DEFAULT,
// whether the select button is disallowed
disallowSelect: false,
// whether file upload is disallowed
disallowUpload: false,
// allowed file extensions
fileExtensions: [],
// maximum file size in MiB
maxFileSize: 10
};
export default {
name: 'uiMedia',
props: {
disabled: {
type: Boolean,
default: false
},
config: {
type: Object,
default: () =>
{
return defaultConfig;
}
},
value: {
type: [Array, Object]
}
},
data: () => ({
configuration: {},
items: []
}),
watch: {
config: {
deep: true,
handler: function ()
{
this.initialize();
}
},
value: {
deep: true,
handler: function ()
{
this.initialize();
}
}
},
computed: {
multiple()
{
return this.configuration.limit > 1;
},
canAdd()
{
return this.configuration.limit - this.items.length > 0;
},
uploadDescription()
{
return this.configuration.fileExtensions.length > 0 ? this.displayedFileExtensions : '@mediapicker.upload_description';
},
acceptedFileExtensions()
{
return this.configuration.fileExtensions.join(',');
},
displayedFileExtensions()
{
return this.configuration.fileExtensions.join(', ').replace(/\./g, '');
}
},
created()
{
this.initialize();
},
methods: {
initialize()
{
this.configuration = _extend(defaultConfig, this.config);
if (_isArray(this.value))
{
this.items = this.value;
}
else if (!!this.value && typeof this.value === 'object' && this.value.source)
{
this.items = [this.value];
}
},
onUpload(event)
{
let remaining = this.configuration.limit - this.items.length;
const files = event.target.files;
if (files && files.length > 0)
{
for (var i = 0; i < files.length; i++)
{
if (i >= remaining)
{
break;
}
this.addFile(files[i]);
}
}
this.update();
},
addFromLibrary(item)
{
this.items.push(item);
this.update();
},
addFile(file)
{
var source = URL.createObjectURL(file);
var media = {
id: 'upload:' + Strings.guid(),
name: file.name,
source: source,
size: file.size,
mimeType: file.type
};
this.items.push(media);
var reader = new FileReader();
reader.onload = function (e)
{
media.source = e.target.result;
};
reader.readAsDataURL(file);
},
update()
{
this.$emit('input', this.multiple ? this.items : this.items[0]);
},
getPreview(item)
{
if (!item.id || item.id.indexOf('upload:') > -1 || item.source.indexOf("http") === 0)
{
return item.source;
}
if (item.id.indexOf("native:") > -1)
{
return item.source + "?width=100&height=100";
}
if (!item.hasThumb)
{
return item.source;
}
var extension = '.' + item.source.split('.').pop();
return item.source.replace(extension, ".thumb" + extension);
}
}
}
</script>
<style lang="scss">
.ui-media
{
}
.ui-media-add
{
}
.ui-media-add-upload
{
display: inline-block;
position: relative;
.ui-select-button + &
{
margin-left: var(--padding);
}
input[type="file"]
{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
border: none;
cursor: pointer;
opacity: 0;
}
}
.ui-media-preview
{
}
.ui-media-preview-image
{
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 80px;
/*background: var(--color-bg);*/
border: 1px solid var(--color-line-light);
padding: 5px;
border-radius: var(--radius);
color: var(--color-fg);
position: relative;
overflow: hidden;
img
{
border-radius: 3px;
max-width: 100%;
max-height: 100%;
margin: auto;
display: block;
color: transprent;
overflow: hidden;
font-size: 0;
position: relative;
z-index: 2;
}
}
</style>
+6 -1
View File
@@ -114,7 +114,12 @@
position: relative;
transition: color 0.2s ease;
border-radius: var(--radius) var(--radius) 0 0;
background: rgba(white, 0.5); // TODO
background: var(--color-bg);
.theme-dark &
{
background: rgba(black, 0.5);
}
& + .ui-tabs-list-item
{
+17 -20
View File
@@ -26,14 +26,10 @@
<input v-model="model.email" type="email" class="ui-input" maxlength="200" :readonly="disabled" />
</ui-property>
<ui-property label="@application.fields.image" description="@application.fields.image_text" :required="true">
upload
<ui-media :config="mediaConfig" v-model="model.image" />
</ui-property>
<ui-property label="@application.fields.icon" description="@application.fields.icon_text" :required="true">
upload
</ui-property>
<ui-property label="@application.fields.domains" description="@application.fields.domains_text" :required="true">
<ui-input-list v-model="model.domains" :disabled="disabled" add-label="@application.fields.domains_add" />
<p class="ui-property-help" v-localize="'@application.fields.domains_help'"></p>
<ui-media :config="mediaConfig" v-model="model.icon" />
</ui-property>
</div>
</div>
@@ -51,6 +47,13 @@
</aside>
</ui-tab>
<ui-tab label="@application.tab_domains" class="ui-box">
<ui-property label="@application.fields.domains" description="@application.fields.domains_text" :required="true">
<ui-input-list v-model="model.domains" :disabled="disabled" add-label="@application.fields.domains_add" />
<p class="ui-property-help" v-localize="'@application.fields.domains_help'"></p>
</ui-property>
</ui-tab>
<ui-tab v-if="features.length > 0" label="@application.tab_features" class="ui-box" :count="model.features.length">
<ui-property v-for="feature in features" :label="feature.name" :description="feature.description">
<ui-toggle :value="model.features.indexOf(feature.alias) > -1" @input="onFeatureToggle($event, feature)" />
@@ -73,7 +76,10 @@
actions: [],
model: { name: null, features: [] },
disabled: false,
features: []
features: [],
mediaConfig: {
fileExtensions: zero.config.media.defaults.images_artificial
}
}),
created()
@@ -111,6 +117,9 @@
onSubmit(form)
{
console.info(JSON.parse(JSON.stringify(this.model)));
return;
form.handle(ApplicationsApi.save(this.model)).then(response =>
{
console.info(response);
@@ -160,16 +169,4 @@
}
}
}
</script>
<style lang="scss">
/*.role-permission-toggle + .role-permission-toggle
{
padding-top: 0;
}
.role .ui-box + .ui-permissions
{
margin-top: var(--padding);
}*/
</style>
</script>
+1
View File
@@ -21,6 +21,7 @@
import AuthApi from 'zero/services/auth.js'
import 'zero/vue.config.js'
import 'zero/axios.config.js'
import 'zero/zero.config.js'
export default {
name: 'app',
+11
View File
@@ -0,0 +1,11 @@
window.zero = window.zero || {};
window.zero.config = window.zero.config || {};
window.zero.config.media = {
defaults: {
images: ['.jpg', '.jpeg', '.png', '.webp', '.svg'],
images_natural: ['.jpg', '.jpeg', '.webp'],
images_artificial: ['.png', '.webp', '.svg']
}
};
@@ -261,6 +261,13 @@
"title": "Pick an icon"
},
"mediapicker": {
"select_text": "Select",
"select_description": "Choose from library",
"upload_text": "Upload",
"upload_description": "Upload a new file"
},
"application": {
"list": "Applications",
"name": "Application",
+2 -1
View File
@@ -292,7 +292,7 @@ button::-moz-focus-inner
background: var(--color-bg-mid);
color: var(--color-fg);
text-align: center;
font-size: 20px;
font-size: 16px;
margin-right: 16px;
}
@@ -310,4 +310,5 @@ button::-moz-focus-inner
{
color: var(--color-fg-mid);
margin-top: 3px;
font-size: var(--font-size-xs);
}