v2 first commit

This commit is contained in:
denisdulici
2019-11-16 10:21:14 +03:00
parent 5b23e9c2c4
commit 6d50fa8442
3075 changed files with 3451681 additions and 65594 deletions

View File

@ -0,0 +1,77 @@
<template>
<div class="custom-control custom-checkbox"
:class="[
{disabled: disabled},
{[`custom-checkbox-${type}`]: type},inlineClass]">
<input :id="cbId"
class="custom-control-input"
:class="inputClasses"
type="checkbox"
:disabled="disabled"
v-model="model"/>
<label :for="cbId" class="custom-control-label">
<slot>
<span v-if="inline">&nbsp;</span>
</slot>
</label>
</div>
</template>
<script>
export default {
name: "base-checkbox",
model: {
prop: "checked"
},
props: {
checked: {
type: [Array, Boolean],
description: "Whether checkbox is checked"
},
disabled: {
type: Boolean,
description: "Whether checkbox is disabled"
},
inline: {
type: Boolean,
description: "Whether checkbox is inline"
},
inputClasses: {
type: [String, Object, Array],
description: "Checkbox input classes"
},
type: {
type: String,
description: 'Checkbox type (e.g info, danger etc)'
}
},
data() {
return {
cbId: "",
touched: false
};
},
computed: {
model: {
get() {
return this.checked;
},
set(check) {
if (!this.touched) {
this.touched = true;
}
this.$emit("input", check);
}
},
inlineClass() {
if (this.inline) {
return `form-check-inline`;
}
}
},
created() {
this.cbId = Math.random()
.toString(16)
.slice(2);
}
};
</script>

View File

@ -0,0 +1,176 @@
<template>
<div class="form-group" :class="[
{'has-error': error},
formClasses
]">
<slot name="label">
<label v-if="label" :class="labelClasses">
{{label}}
</label>
</slot>
<div :class="[
{'input-group input-group-merge': hasIcon},
{'focused': focused},
{'input-group-alternative': alternative},
{'has-label': label || $slots.label},
inputGroupClasses
]">
<div v-if="prependIcon || $slots.prepend" class="input-group-prepend">
<span class="input-group-text">
<slot name="prepend">
<i :class="prependIcon"></i>
</slot>
</span>
</div>
<slot v-bind="slotData">
<input
:value="value"
:type="type"
v-on="listeners"
v-bind="$attrs"
:valid="!error"
:required="required"
class="form-control"
:class="[{'is-valid': valid === true}, {'is-invalid': error}, inputClasses]">
</slot>
<div v-if="appendIcon || $slots.append" class="input-group-append">
<span class="input-group-text">
<slot name="append">
<i :class="appendIcon"></i>
</slot>
</span>
</div>
<slot name="infoBlock"></slot>
<slot name="error">
<div v-if="error" class="invalid-feedback d-block"
v-html="error">
</div>
</slot>
<slot name="success">
<div class="valid-feedback" v-if="!error && valid">
{{successMessage}}
</div>
</slot>
</div>
</div>
</template>
<script>
export default {
inheritAttrs: false,
name: "base-input",
props: {
required: {
type: Boolean,
description: "Whether input is required (adds an asterix *)"
},
group: {
type: Boolean,
description: "Whether input is an input group (manual override in special cases)"
},
valid: {
type: Boolean,
description: "Whether is valid",
default: undefined
},
alternative: {
type: Boolean,
description: "Whether input is of alternative layout"
},
label: {
type: String,
description: "Input label (text before input)"
},
error: {
type: String,
description: "Input error (below input)"
},
successMessage: {
type: String,
description: "Input success message",
default: 'Looks good!'
},
formClasses: {
type: String,
description: "Input form css classes"
},
labelClasses: {
type: String,
description: "Input label css classes",
default: "form-control-label"
},
inputClasses: {
type: String,
description: "Input css classes"
},
inputGroupClasses: {
type: String,
description: "Input group css classes"
},
value: {
type: [String, Number],
description: "Input value"
},
type: {
type: String,
description: "Input type",
default: "text"
},
appendIcon: {
type: String,
description: "Append icon (right)"
},
prependIcon: {
type: String,
description: "Prepend icon (left)"
}
},
data() {
return {
focused: false
};
},
computed: {
listeners() {
return {
...this.$listeners,
input: this.updateValue,
focus: this.onFocus,
blur: this.onBlur
};
},
slotData() {
return {
focused: this.focused,
error: this.error,
...this.listeners
};
},
hasIcon() {
const { append, prepend } = this.$slots;
return (
append !== undefined ||
prepend !== undefined ||
this.appendIcon !== undefined ||
this.prependIcon !== undefined ||
this.group
);
}
},
methods: {
updateValue(evt) {
let value = evt.target.value;
this.$emit("input", value);
},
onFocus(evt) {
this.focused = true;
this.$emit("focus", evt);
},
onBlur(evt) {
this.focused = false;
this.$emit("blur", evt);
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,68 @@
<template>
<div
class="custom-control custom-radio"
:class="[inlineClass, { disabled: disabled }]">
<input
:id="cbId"
class="custom-control-input"
type="radio"
:disabled="disabled"
:value="name"
v-model="model"
/>
<label :for="cbId" class="custom-control-label">
<slot>
<span v-if="inline">&nbsp;</span>
</slot>
</label>
</div>
</template>
<script>
export default {
name: 'base-radio',
props: {
name: {
type: [String, Number],
description: 'Radio label'
},
disabled: {
type: Boolean,
description: 'Whether radio is disabled'
},
value: {
type: [String, Boolean],
description: 'Radio value'
},
inline: {
type: Boolean,
description: 'Whether radio is inline'
}
},
data() {
return {
cbId: ''
};
},
computed: {
model: {
get() {
return this.value;
},
set(value) {
this.$emit('input', value);
}
},
inlineClass() {
if (this.inline) {
return `form-check-inline`;
}
return '';
}
},
created() {
this.cbId = Math.random()
.toString(16)
.slice(2);
}
};
</script>

View File

@ -0,0 +1,125 @@
<template>
<div class="dropzone mb-3 dz-clickable"
:class="[multiple ? 'dropzone-multiple': 'dropzone-single']">
<div class="fallback">
<div class="custom-file">
<input type="file"
class="custom-file-input"
id="projectCoverUploads"
:multiple="multiple">
<label class="custom-file-label" for="projectCoverUploads">Choose file</label>
</div>
</div>
<div class="dz-preview dz-preview-single"
v-if="!multiple"
:class="previewClasses"
ref="previewSingle">
<div class="dz-preview-cover">
<img class="dz-preview-img" data-dz-thumbnail>
</div>
</div>
<ul v-else
class="dz-preview dz-preview-multiple list-group list-group-lg list-group-flush"
:class="previewClasses"
ref="previewMultiple">
<li class="list-group-item px-0">
<div class="row align-items-center">
<div class="col-auto">
<div class="avatar">
<img class="avatar-img rounded" data-dz-thumbnail>
</div>
</div>
<div class="col ml--3">
<h4 class="mb-1" data-dz-name>...</h4>
<p class="small text-muted mb-0" data-dz-size>...</p>
</div>
<div class="col-auto">
<button data-dz-remove="true" class="btn btn-danger btn-sm">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'dropzone-file-upload',
props: {
options: {
type: Object,
default: () => ({})
},
value: [String, Object, Array],
url: {
type: String,
default: 'http://'
},
multiple: Boolean,
previewClasses: [String, Object, Array]
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
currentFile: null,
files: [],
showList: false,
}
},
methods: {
async initDropzone() {
let Dropzone = await import('dropzone')
Dropzone = Dropzone.default || Dropzone
Dropzone.autoDiscover = false
let preview = this.multiple ? this.$refs.previewMultiple : this.$refs.previewSingle;
let self = this
let finalOptions = {
...this.options,
url: this.url,
thumbnailWidth: null,
thumbnailHeight: null,
previewsContainer: preview,
previewTemplate: preview.innerHTML,
maxFiles: (!this.multiple) ? 1 : null,
acceptedFiles: (!this.multiple) ? 'image/*' : null,
init: function () {
this.on("addedfile", function (file) {
if (!self.multiple && self.currentFile) {
// this.removeFile(this.currentFile);
}
self.currentFile = file;
})
}
}
this.dropzone = new Dropzone(this.$el, finalOptions)
preview.innerHTML = ''
let evtList = ['drop', 'dragstart', 'dragend', 'dragenter', 'dragover', 'addedfile', 'removedfile', 'thumbnail', 'error', 'processing', 'uploadprogress', 'sending', 'success', 'complete', 'canceled', 'maxfilesreached', 'maxfilesexceeded', 'processingmultiple', 'sendingmultiple', 'successmultiple', 'completemultiple', 'canceledmultiple', 'totaluploadprogress', 'reset', 'queuecomplete']
evtList.forEach(evt => {
this.dropzone.on(evt, (data) => {
this.$emit(evt, data);
if (evt === 'addedfile') {
this.files.push(data)
this.$emit('change', this.files);
} else if (evt === 'removedfile') {
let index = this.files.findIndex(f => f.upload.uuid === data.upload.uuid)
if (index !== -1) {
this.files.splice(index, 1);
}
this.$emit('change', this.files);
}
})
})
}
},
async mounted() {
this.initDropzone()
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,54 @@
<template>
<div class="custom-file">
<input type="file"
class="custom-file-input"
id="customFileLang"
lang="en"
v-bind="$attrs"
v-on="listeners"
/>
<label class="custom-file-label" for="customFileLang">
{{label}}
</label>
</div>
</template>
<script>
export default {
name: 'file-input',
inheritAttrs: false,
props: {
initialLabel: {
type: String,
default: 'Select file'
}
},
data() {
return {
files: []
}
},
computed: {
listeners() {
return {
...this.$listeners,
change: this.fileChange
}
},
label() {
let fileNames = [];
for (let file of this.files) {
fileNames.push(file.name)
}
return fileNames.length ? fileNames.join(', ') : this.initialLabel
}
},
methods: {
fileChange(evt) {
this.files = evt.target.files
this.$emit('change', this.files)
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,96 @@
<template>
<div class="quill">
<div :id="toolbarId">
<div class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-link"></button>
<button class="ql-blockquote"></button>
<button class="ql-code"></button>
<button class="ql-image"></button>
<button type="button" class="ql-list" value="ordered"></button>
<button type="button" class="ql-list" value="bullet"></button>
</div>
</div>
<div :id="editorId" :name="name" class="" ref="editor">
</div>
</div>
</template>
<script>
export default {
name: 'html-editor',
props: {
value: {
type: String,
default: ''
},
name: String
},
data () {
return {
editor: null,
content: null,
lastHtmlValue: '',
editorId: null,
toolbarId: null
}
},
methods: {
initialize (Quill) {
this.editor = new Quill(`#${this.editorId}`, {
theme: 'snow',
modules: {
toolbar: `#${this.toolbarId}`
}
})
if (this.value.length > 0) {
this.editor.pasteHTML(this.value)
}
let editorRef = this.$refs.editor;
let node = editorRef.children[0];
this.editor.on('text-change', () => {
let html = node.innerHTML
if (html === '<p><br></p>') {
html = '';
}
this.content = html
this.$emit('input', this.content);
})
},
pasteHTML () {
if (!this.editor) {
return
}
this.editor.pasteHTML(this.value)
},
randomString() {
let text = "";
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (let i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
},
async mounted () {
let Quill = await import('quill')
Quill = Quill.default || Quill
this.editorId = this.randomString();
this.toolbarId = this.randomString();
this.$nextTick(() => {
this.initialize(Quill)
});
},
watch: {
value (newVal) {
if (newVal !== this.content) {
this.pasteHTML(newVal);
}
}
}
}
</script>

View File

@ -0,0 +1,45 @@
<template>
<div
class="choice"
:class="{ active: checked }"
data-toggle="wizard-checkbox"
@click="updateValue"
>
<input
type="checkbox"
:name="name"
:disabled="disabled"
:checked="checked"
/>
<div class="icon">
<slot name="icon"> <i :class="icon"></i> </slot>
</div>
<slot name="title">
<h6>{{ title }}</h6>
</slot>
</div>
</template>
<script>
export default {
name: 'icon-checkbox',
model: {
prop: 'checked'
},
props: {
checked: {
type: Boolean,
default: false
},
name: String,
title: String,
icon: String,
disabled: Boolean
},
methods: {
updateValue() {
this.$emit('input', !this.checked);
}
}
};
</script>
<style></style>

View File

@ -0,0 +1,95 @@
<template>
<div class="tags-input__wrapper">
<el-tag
v-for="(tag, index) in dynamicTags"
:key="tag + index"
size="small"
:type="tagType"
:closable="true"
:close-transition="false"
@close="handleClose(tag)"
>
{{ tag }}
</el-tag>
<input
type="text"
placeholder="Add new tag"
class="form-control"
v-model="inputValue"
ref="saveTagInput"
size="mini"
@input="onInput"
@keyup.enter="handleInputConfirm"
@blur="handleInputConfirm"
/>
</div>
</template>
<script>
import { Tag } from 'element-ui';
export default {
name: 'tags-input',
components: {
[Tag.name]: Tag
},
props: {
value: {
type: Array,
default: () => [],
description: 'List of tags'
},
tagType: {
type: String,
default: 'primary',
description: 'Tag type (primary|danger etc)'
}
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
dynamicTags: [],
inputVisible: false,
inputValue: ''
};
},
methods: {
handleClose(tag) {
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
this.$emit('change', this.dynamicTags);
},
showInput() {
this.inputVisible = true;
this.$nextTick(() => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.dynamicTags.push(inputValue);
this.$emit('change', this.dynamicTags);
}
this.inputVisible = false;
this.inputValue = '';
},
onInput(evt) {
this.$emit('input', evt.target.value);
}
},
created() {
this.$watch(
'value',
newVal => {
this.dynamicTags = [...newVal];
},
{ immediate: true }
);
}
};
</script>