diff options
Diffstat (limited to 'src/vue/Components')
-rw-r--r-- | src/vue/Components/Collected/MinedProperty.vue | 17 | ||||
-rw-r--r-- | src/vue/Components/Form/InputField.vue | 49 | ||||
-rw-r--r-- | src/vue/Components/Form/SelectField.vue | 29 | ||||
-rw-r--r-- | src/vue/Components/Options/Theming.vue | 79 | ||||
-rw-r--r-- | src/vue/Components/Popup/Collected.vue | 18 | ||||
-rw-r--r-- | src/vue/Components/Tabs.vue | 2 | ||||
-rw-r--r-- | src/vue/Components/Theming/BadgeIcon.vue | 61 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomColorAlpha.vue | 81 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomColorInherit.vue | 87 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomColorSet.vue | 31 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomColorToast.vue | 77 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomFontFamily.vue | 52 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomFontSize.vue | 59 | ||||
-rw-r--r-- | src/vue/Components/Theming/CustomTheme.vue | 117 | ||||
-rw-r--r-- | src/vue/Components/Theming/PreviewTheme.vue | 80 | ||||
-rw-r--r-- | src/vue/Components/Toast/Toast.vue | 123 |
16 files changed, 720 insertions, 242 deletions
diff --git a/src/vue/Components/Collected/MinedProperty.vue b/src/vue/Components/Collected/MinedProperty.vue index eafc29d..09b9eb1 100644 --- a/src/vue/Components/Collected/MinedProperty.vue +++ b/src/vue/Components/Collected/MinedProperty.vue @@ -96,6 +96,7 @@ overflow : hidden; box-shadow : 0 0 0 1px transparent; transition : box-shadow .15s ease-in-out; + color : var(--element-fg-color); &:hover { box-shadow : 0 0 0 1px var(--element-hover-bg-color); @@ -103,13 +104,15 @@ } input { - width : 100%; - padding : .25rem; - box-sizing : border-box; - box-shadow : 0 0 0 1px var(--element-active-fg-color); - border-radius : 3px; - border : none; - line-height : 2rem; + width : 100%; + padding : .25rem; + box-sizing : border-box; + box-shadow : 0 0 0 1px var(--element-active-fg-color); + border-radius : 3px; + border : none; + line-height : 2rem; + background-color : var(--element-bg-color); + color : var(--element-fg-color); } &.password { diff --git a/src/vue/Components/Form/InputField.vue b/src/vue/Components/Form/InputField.vue index 7c07b58..73ecc4d 100644 --- a/src/vue/Components/Form/InputField.vue +++ b/src/vue/Components/Form/InputField.vue @@ -1,5 +1,11 @@ <template> - <input :placeholder="getPlaceholder" :title="getTitle" v-model="model"/> + <input :type="type" + :value="value" + :checked="isChecked" + :placeholder="getPlaceholder" + :title="getTitle" + @input="handleInput" + @change="handleChange"/> </template> <script> @@ -8,9 +14,17 @@ export default { props: { - value : { + type : { type : String, - default: '' + default: 'text' + }, + value : { + type : [String, Number, Boolean], + default: null + }, + checked : { + type : Boolean, + default: null }, placeholder: { type : String, @@ -22,13 +36,6 @@ } }, - data() { - return { - model: this.value, - emit : this.value - }; - }, - computed: { getPlaceholder() { if(this.placeholder.length === 0) return; @@ -39,19 +46,25 @@ if(this.title.length === 0) return; return LocalisationService.translate(this.title); + }, + isChecked() { + if(this.type !== 'checkbox' && this.type !== 'radio') return undefined; + + return this.checked || this.value; } }, - watch: { - model(value) { - if(this.emit !== value) { - this.emit = value; - this.$emit('input', value); + methods: { + handleInput($event) { + if(this.type !== 'checkbox' && this.type !== 'radio') { + this.$emit('input', $event.target.value); } }, - value(value) { - this.emit = value; - this.model = value; + handleChange($event) { + if(this.type === 'checkbox' || this.type === 'radio') { + this.$emit('change', $event.target.checked); + this.$emit('input', $event.target.checked); + } } } }; diff --git a/src/vue/Components/Form/SelectField.vue b/src/vue/Components/Form/SelectField.vue index 5ef325a..bfc3766 100644 --- a/src/vue/Components/Form/SelectField.vue +++ b/src/vue/Components/Form/SelectField.vue @@ -1,8 +1,10 @@ <template> - <select v-model="model"> + <select @change="handleChange"> <option v-for="option in optionList" :key="option.id" :value="option.id" + :disabled="option.disabled" + :selected="option.id === value" :title="getTranslated(option.description)">{{getTranslated(option.label)}} </option> </select> @@ -27,13 +29,6 @@ } }, - data() { - return { - model: this.value, - emit : this.value - }; - }, - computed: { optionList() { let options = []; @@ -43,11 +38,12 @@ let config = this.options[id]; if(typeof config === 'string') { - options.push({id, label: config, description: null}); + options.push({id, label: config, disabled: false, description: null}); } else { let option = { id : config.hasOwnProperty('id') ? config.id:id, label : config.label, + disabled : config.hasOwnProperty('disabled') ? config.disabled === true:false, description: config.hasOwnProperty('description') ? config.description:null }; @@ -64,19 +60,10 @@ if(!this.translate || !text) return text; return LocalisationService.translate(text); - } - }, - - watch: { - model(value) { - if(this.emit !== value) { - this.emit = value; - this.$emit('input', value); - } }, - value(value) { - this.emit = value; - this.model = value; + handleChange($event) { + this.$emit('change', $event.target.value); + this.$emit('input', $event.target.value); } } }; diff --git a/src/vue/Components/Options/Theming.vue b/src/vue/Components/Options/Theming.vue index 333610c..4477459 100644 --- a/src/vue/Components/Options/Theming.vue +++ b/src/vue/Components/Options/Theming.vue @@ -1,13 +1,13 @@ <template> - <div class="theming"> + <div class="theming" v-if="theme"> <div class="theme-settings"> <div class="setting"> - <translate tag="label" for="theme-current" say="SettingsCurrentTheme"/> - <select-field id="theme-current" :options="themeList" :translate="false" v-model="currentTheme"/> + <translate tag="label" for="theme-current" say="SettingsThemeId"/> + <select-field id="theme-current" :options="list" v-model="themeId"/> </div> - <custom-theme /> + <custom-theme :theme="customTheme" v-if="customTheme && themeId === 'custom'"/> </div> - <preview-theme :theme="currentTheme"/> + <preview-theme :theme="theme"/> </div> </template> @@ -18,29 +18,68 @@ import ToastService from '@js/Services/ToastService'; import PreviewTheme from '@vue/Components/Theming/PreviewTheme'; import CustomTheme from '@vue/Components/Theming/CustomTheme'; + import ErrorManager from '@js/Manager/ErrorManager'; export default { components: {CustomTheme, PreviewTheme, Translate, SelectField}, data() { return { - currentTheme: null, - themeList : {} + themeId: null, + theme : null, + themes : [] }; }, - mounted() { - MessageService.send({type: 'theme.list'}).then((r) => { this.themeList = r.getPayload(); }); - MessageService.send({type: 'setting.get', payload: 'theme.current'}).then((r) => { - this.currentTheme = - r.getPayload(); - }); + computed: { + list() { + let list = {}; + + for(let theme of this.themes) list[theme.getId()] = theme.getLabel(); + + return list; + }, + customTheme() { + for(let theme of this.themes) { + if(theme.getId() === 'custom') return theme; + } + } + }, + + async mounted() { + let reply = await MessageService.send({type: 'theme.list'}); + this.themes = reply.getPayload(); + + reply = await MessageService.send({type: 'setting.get', payload: 'theme.current'}); + this.themeId = reply.getPayload(); + + this.setCurrentTheme(this.themeId); + }, + + methods: { + setCurrentTheme(themeId) { + for(let theme of this.themes) { + if(theme.getId() === themeId) { + this.theme = theme; + return; + } + } + } }, watch: { - currentTheme(value) { + themeId(value) { MessageService.send({type: 'setting.set', payload: {setting: 'theme.current', value}}) .catch((e) => { ToastService.error(e.message); }); + + this.setCurrentTheme(this.themeId); + MessageService.send( + { + type : 'theme.preview', + payload : this.theme, + receiver: 'popup' + } + ).catch(ErrorManager.catch); } } }; @@ -53,15 +92,12 @@ grid-column-gap : 1rem; padding : 1rem; - .theme-preview { - background-color : grey; - } - .theme-settings { .setting { display : grid; - grid-template-areas : "label" "input"; - grid-template-columns : 2fr 1fr; + grid-template-areas : "label input"; + grid-template-columns : 3fr 2fr; + margin-bottom : .25rem; label { grid-area : label; @@ -70,6 +106,7 @@ select, input { grid-area : input; + width : 100%; } } } @@ -91,7 +128,7 @@ cursor : pointer; &[disabled] { - opacity: .25; + opacity : .25; } } } diff --git a/src/vue/Components/Popup/Collected.vue b/src/vue/Components/Popup/Collected.vue index fc66bd0..fa8c769 100644 --- a/src/vue/Components/Popup/Collected.vue +++ b/src/vue/Components/Popup/Collected.vue @@ -36,10 +36,19 @@ data() { return { items : MiningClient.getItems(), - current: null + current: null, + listener: (i) => { this.addItem(i); } }; }, + created() { + MiningClient.update.on(this.listener); + }, + + destroyed() { + MiningClient.update.off(this.listener); + }, + async mounted() { if(this.initialStatus.current !== null && this.tabs.hasOwnProperty(this.initialStatus.current)) { this.$refs.foldout.setActive(this.initialStatus.current); @@ -87,6 +96,13 @@ this.current = $event.tab; }, + /** + * @param {MiningItem} item + */ + addItem(item) { + this.items.push(item); + }, + sendStatus() { let status = { current: this.current diff --git a/src/vue/Components/Tabs.vue b/src/vue/Components/Tabs.vue index 797b100..d07ce0f 100644 --- a/src/vue/Components/Tabs.vue +++ b/src/vue/Components/Tabs.vue @@ -18,7 +18,7 @@ :class="`tab-content-${name}`" :style="{display: name===tab ? 'block':'none'}"> <keep-alive> - <slot :name="name"/> + <slot :name="name" v-if="name===tab"/> </keep-alive> </div> </div> diff --git a/src/vue/Components/Theming/BadgeIcon.vue b/src/vue/Components/Theming/BadgeIcon.vue new file mode 100644 index 0000000..6d5ef7a --- /dev/null +++ b/src/vue/Components/Theming/BadgeIcon.vue @@ -0,0 +1,61 @@ +<template> + <div class="setting"> + <translate tag="label" for="badge-icon" say="SettingsBadgeIcon"/> + <select-field id="badge-icon" :options="options" v-model="model"/> + </div> +</template> + +<script> + import SelectField from '@vue/Components/Form/SelectField'; + import Translate from '@vue/Components/Translate'; + + export default { + components: {Translate, SelectField}, + + props: ['value'], + + data() { + return { + model: this.mapValue(this.value) + }; + }, + + computed: { + options() { + return { + auto : 'BadgeIconAuto', + light : 'BadgeIconLight', + medium : 'BadgeIconMedium', + dark : 'BadgeIconDark', + 'new-light': 'BadgeIconNewLight', + 'new' : 'BadgeIconNewMedium', + 'new-dark' : 'BadgeIconNewDark' + }; + } + }, + + methods: { + mapValue(value) { + if(!value) return 'auto'; + if(value === 'passwords') return 'medium'; + + return value.substr(10); + }, + mapModel(value) { + if(value === 'auto') return null; + if(value === 'medium') return 'passwords'; + + return `passwords-${value}`; + } + }, + + watch: { + value(value) { + this.model = this.mapValue(value); + }, + model(value) { + this.$emit('input', this.mapModel(value)); + } + } + }; +</script>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomColorAlpha.vue b/src/vue/Components/Theming/CustomColorAlpha.vue deleted file mode 100644 index e09d346..0000000 --- a/src/vue/Components/Theming/CustomColorAlpha.vue +++ /dev/null @@ -1,81 +0,0 @@ -<template> - <div class="color-setting"> - <translate :say="label"/> - <input type="checkbox" v-model="currentBase"/> - <input type="checkbox" v-model="currentHover"/> - </div> -</template> - -<script> - import Translate from '@vue/Components/Translate'; - - export default { - components: {Translate}, - - props: { - name : String, - type : String, - colors: Object - }, - - data() { - let keyBase = `${this.name}-${this.type}`, - keyHover = `${this.name}-hover-${this.type}`; - - return { - colorBase : this.colors[keyBase], - colorHover : this.colors[keyHover], - defaultBase : this.colors[keyBase].length > 7, - defaultHover: this.colors[keyHover].length > 7, - currentBase : this.colors[keyBase].length > 7, - currentHover: this.colors[keyHover].length > 7, - keyBase, - keyHover - }; - }, - - computed: { - label() { - return this.type === 'bg' ? 'CustomAlphaBackground':'CustomAlphaForeground'; - } - }, - - methods: { - update() { - let colors = {}; - - colors[this.keyBase] = this.colorBase.substr(0, 7); - colors[this.keyHover] = this.colorHover.substr(0, 7); - - if(this.currentBase) colors[this.keyBase] += '00'; - if(this.currentHover) colors[this.keyHover] += '00'; - - this.$emit('update', colors); - } - }, - - watch: { - colors: { - deep: true, - handler(value) { - this.colorBase = value[this.keyBase]; - this.colorHover = value[this.keyHover]; - this.defaultBase = this.colorBase.length > 7; - this.defaultHover = this.colorHover.length > 7; - this.currentBase = this.defaultBase; - this.currentHover = this.defaultHover; - } - }, - currentBase(value) { - if(this.defaultBase !== value) this.update(); - }, - currentHover(value) { - if(this.defaultHover !== value) this.update(); - } - } - }; -</script> - -<style lang="scss"> - -</style>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomColorInherit.vue b/src/vue/Components/Theming/CustomColorInherit.vue new file mode 100644 index 0000000..092c763 --- /dev/null +++ b/src/vue/Components/Theming/CustomColorInherit.vue @@ -0,0 +1,87 @@ +<template> + <div class="color-setting"> + <translate :say="label"/> + <input-field type="checkbox" :title="title" v-model="currentBase"/> + <input-field type="checkbox" :title="title" v-model="currentHover"/> + </div> +</template> + +<script> + import Translate from '@vue/Components/Translate'; + import InputField from '@vue/Components/Form/InputField'; + + export default { + components: {InputField, Translate}, + + props: { + name : String, + type : String, + colors: Object + }, + + data() { + let keyBase = `${this.name}-${this.type}`, + keyHover = `${this.name}-hover-${this.type}`, + inheritBase = this.colors[keyBase] === 'inherit', + inheritHover = this.colors[keyHover] === 'inherit'; + + return { + colorBase : inheritBase ? '#000':this.colors[keyBase], + colorHover : inheritHover ? '#000':this.colors[keyHover], + defaultBase : inheritBase, + defaultHover: inheritHover, + currentBase : inheritBase, + currentHover: inheritHover, + keyBase, + keyHover + }; + }, + + computed: { + label() { + return this.type === 'bg' ? 'BackgroundInheritLabel':'ForegroundInheritLabel'; + }, + title() { + return this.type === 'bg' ? 'BackgroundInheritTitle':'ForegroundInheritTitle'; + } + }, + + methods: { + update() { + let colors = {}; + + colors[this.keyBase] = this.currentBase ? 'inherit':this.colorBase; + colors[this.keyHover] = this.currentHover ? 'inherit':this.colorHover; + + this.$emit('update', colors); + } + }, + + watch: { + colors: { + deep: true, + handler(value) { + let inheritBase = this.colors[this.keyBase] === 'inherit', + inheritHover = this.colors[this.keyHover] === 'inherit'; + + if(!inheritBase) this.colorBase = value[this.keyBase]; + if(!inheritHover) this.colorHover = value[this.keyHover]; + this.defaultBase = inheritBase; + this.defaultHover = inheritHover; + this.currentBase = inheritBase; + this.currentHover = inheritHover; + } + }, + currentBase() { + this.update(); + }, + currentHover() { + this.update(); + } + } + }; +</script> + +<style lang="scss"> + +</style>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomColorSet.vue b/src/vue/Components/Theming/CustomColorSet.vue index 3960acd..8d0dbe8 100644 --- a/src/vue/Components/Theming/CustomColorSet.vue +++ b/src/vue/Components/Theming/CustomColorSet.vue @@ -1,16 +1,17 @@ <template> <div class="color-setting"> <translate :say="label"/> - <input type="color" v-model="currentBase" :disabled="!baseEnabled"/> - <input type="color" v-model="currentHover" :disabled="!hoverEnabled"/> + <input-field type="color" v-model="currentBase" :title="baseTitle" :disabled="baseDisabled"/> + <input-field type="color" v-model="currentHover" :title="hoverTitle" :disabled="hoverDisabled"/> </div> </template> <script> import Translate from '@vue/Components/Translate'; + import InputField from '@vue/Components/Form/InputField'; export default { - components: {Translate}, + components: {InputField, Translate}, props: { name : String, @@ -34,13 +35,19 @@ computed: { label() { - return this.type === 'bg' ? 'CustomColorsBackground':'CustomColorsForeground'; + return this.type === 'bg' ? 'BackgroundColorLabel':'ForegroundColorLabel'; }, - baseEnabled() { - return this.defaultBase.length === 7; + baseTitle() { + return this.type === 'bg' ? 'BackgroundColorBaseTitle':'ForegroundColorBaseTitle'; }, - hoverEnabled() { - return this.defaultHover.length === 7; + hoverTitle() { + return this.type === 'bg' ? 'BackgroundColorHoverTitle':'ForegroundColorHoverTitle'; + }, + baseDisabled() { + return this.defaultBase === 'inherit'; + }, + hoverDisabled() { + return this.defaultHover === 'inherit'; } }, @@ -65,11 +72,11 @@ this.currentHover = value[this.keyHover]; } }, - currentBase(value) { - if(this.defaultBase !== value) this.update(); + currentBase() { + this.update(); }, - currentHover(value) { - if(this.defaultHover !== value) this.update(); + currentHover() { + this.update(); } } }; diff --git a/src/vue/Components/Theming/CustomColorToast.vue b/src/vue/Components/Theming/CustomColorToast.vue new file mode 100644 index 0000000..dc133af --- /dev/null +++ b/src/vue/Components/Theming/CustomColorToast.vue @@ -0,0 +1,77 @@ +<template> + <div class="color-setting"> + <translate :say="label"/> + <input-field type="color" v-model="currentBackground" :title="titleBg"/> + <input-field type="color" v-model="currentForeground" :title="titleFg"/> + </div> +</template> + +<script> + import Translate from '@vue/Components/Translate'; + import InputField from '@vue/Components/Form/InputField'; + + export default { + components: {InputField, Translate}, + + props: { + name : String, + label : String, + colors : Object, + titleBg: { + type : String, + default: 'ToastBackgroundTitle' + }, + titleFg: { + type : String, + default: 'ToastForegroundTitle' + } + }, + + data() { + let keyBackground = `${this.name}-bg`, + keyForeground = `${this.name}-fg`; + + return { + defaultBackground: this.colors[keyBackground], + defaultForeground: this.colors[keyForeground], + currentBackground: this.colors[keyBackground], + currentForeground: this.colors[keyForeground], + keyBackground, + keyForeground + }; + }, + + methods: { + update() { + let colors = {}; + + colors[this.keyBackground] = this.currentBackground; + colors[this.keyForeground] = this.currentForeground; + + this.$emit('update', colors); + } + }, + + watch: { + colors: { + deep: true, + handler(value) { + this.defaultBackground = value[this.keyBackground]; + this.defaultForeground = value[this.keyForeground]; + this.currentBackground = value[this.keyBackground]; + this.currentForeground = value[this.keyForeground]; + } + }, + currentBackground() { + this.update(); + }, + currentForeground() { + this.update(); + } + } + }; +</script> + +<style lang="scss"> + +</style>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomFontFamily.vue b/src/vue/Components/Theming/CustomFontFamily.vue new file mode 100644 index 0000000..4e521e0 --- /dev/null +++ b/src/vue/Components/Theming/CustomFontFamily.vue @@ -0,0 +1,52 @@ +<template> + <div class="setting"> + <translate tag="label" for="custom-font" say="SettingsCustomFont"/> + <select-field id="custom-font" :options="options" v-model="model"/> + </div> +</template> + +<script> + import SelectField from '@vue/Components/Form/SelectField'; + import Translate from '@vue/Components/Translate'; + + export default { + components: {Translate, SelectField}, + + props: ['value'], + + data() { + return { + model: this.value + }; + }, + + computed: { + options() { + let options = { + default : 'FontDefault', + mono : 'FontMono', + serif : 'FontSerif', + sans : 'FontSans', + light : 'FontLight', + nextcloud: 'FontNextcloud', + dyslexic : 'FontOpenDyslexic' + }; + + if(!options.hasOwnProperty(this.value)) { + options[this.value] = 'FontCustom'; + } + + return options; + } + }, + + watch: { + value(value) { + this.model = value; + }, + model(value) { + if(this.value !== value) this.$emit('input', value); + } + } + }; +</script>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomFontSize.vue b/src/vue/Components/Theming/CustomFontSize.vue new file mode 100644 index 0000000..9414057 --- /dev/null +++ b/src/vue/Components/Theming/CustomFontSize.vue @@ -0,0 +1,59 @@ +<template> + <div class="setting"> + <translate tag="label" for="custom-font" say="SettingsCustomFontSize"/> + <select-field id="custom-font" :options="options" v-model="model"/> + </div> +</template> + +<script> + import SelectField from '@vue/Components/Form/SelectField'; + import Translate from '@vue/Components/Translate'; + + export default { + components: {Translate, SelectField}, + + props: { + value: { + default: '11pt' + } + }, + + data() { + return { + model: this.value ? this.value:'11pt' + }; + }, + + mounted() { + this.model = this.value; + }, + + computed: { + options() { + let options = { + '8pt' : 'FontSizeVerySmall', + '10pt': 'FontSizeSmall', + '11pt': 'FontSizeDefault', + '12pt': 'FontSizeMedium', + '14pt': 'FontSizeLarge', + '16pt': 'FontSizeVeryLarge' + }; + + if(!options.hasOwnProperty(this.value)) { + options[this.value] = this.value; + } + + return options; + } + }, + + watch: { + value(value) { + this.model = value; + }, + model(value) { + this.$emit('input', value); + } + } + }; +</script>
\ No newline at end of file diff --git a/src/vue/Components/Theming/CustomTheme.vue b/src/vue/Components/Theming/CustomTheme.vue index 8013b0a..f06b9e3 100644 --- a/src/vue/Components/Theming/CustomTheme.vue +++ b/src/vue/Components/Theming/CustomTheme.vue @@ -1,38 +1,113 @@ <template> - <div> - <translate tag="h4" say="SettingsCustomTheme"/> - <div class="theme-colors"> - <translate tag="h4" say="CustomDefaultElement" /> - <custom-color-set name="element" type="bg" :colors="themeColors" v-on:update="update" /> - <custom-color-set name="element" type="fg" :colors="themeColors" v-on:update="update" /> - <translate tag="h4" say="CustomActiveElement" /> - <custom-color-set name="element-active" type="bg" :colors="themeColors" v-on:update="update" /> - <custom-color-set name="element-active" type="fg" :colors="themeColors" v-on:update="update" /> - <translate tag="h4" say="CustomButtons" /> - <custom-color-alpha name="button" type="bg" :colors="themeColors" v-on:update="update" /> - <custom-color-set name="button" type="bg" :colors="themeColors" v-on:update="update" /> - <custom-color-alpha name="button" type="fg" :colors="themeColors" v-on:update="update" /> - <custom-color-set name="button" type="fg" :colors="themeColors" v-on:update="update"/> - </div> + <div class="theme-colors"> + <translate tag="h4" say="CustomFont"/> + <custom-font-family v-model="font.family"/> + <custom-font-size v-model="font.size"/> + <translate tag="h4" say="CustomDefaultElement"/> + <custom-color-set name="element" type="bg" :colors="colors" v-on:update="update"/> + <custom-color-set name="element" type="fg" :colors="colors" v-on:update="update"/> + <translate tag="h4" say="CustomActiveElement"/> + <custom-color-set name="element-active" type="bg" :colors="colors" v-on:update="update"/> + <custom-color-set name="element-active" type="fg" :colors="colors" v-on:update="update"/> + <translate tag="h4" say="CustomButtons"/> + <custom-color-inherit name="button" type="bg" :colors="colors" v-on:update="update"/> + <custom-color-set name="button" type="bg" :colors="colors" v-on:update="update"/> + <custom-color-inherit name="button" type="fg" :colors="colors" v-on:update="update"/> + <custom-color-set name="button" type="fg" :colors="colors" v-on:update="update"/> + <translate tag="h4" say="CustomToasts"/> + <custom-color-toast name="info" label="ToastInfoColors" :colors="colors" v-on:update="update"/> + <custom-color-toast name="success" label="ToastSuccessColors" :colors="colors" v-on:update="update"/> + <custom-color-toast name="warning" label="ToastWarningColors" :colors="colors" v-on:update="update"/> + <custom-color-toast name="error" label="ToastErrorColors" :colors="colors" v-on:update="update"/> + <translate tag="h4" say="CustomBadge"/> + <badge-icon v-model="badge.icon"/> + <custom-color-toast name="color" + label="CustomBadgeColors" + title-bg="BadgeBackgroundTitle" + title-fg="BadgeForegroundTitle" + :colors="badge" + v-on:update="updateBadge"/> </div> </template> <script> - import LightTheme from '@js/Themes/Light'; + import Theme from '@js/Models/Theme/Theme'; import Translate from '@vue/Components/Translate'; + import MessageService from '@js/Services/MessageService'; + import BadgeIcon from '@vue/Components/Theming/BadgeIcon'; + import CustomFontSize from '@vue/Components/Theming/CustomFontSize'; import CustomColorSet from '@vue/Components/Theming/CustomColorSet'; - import CustomColorAlpha from '@vue/Components/Theming/CustomColorAlpha'; + import CustomFontFamily from '@vue/Components/Theming/CustomFontFamily'; + import CustomColorToast from '@vue/Components/Theming/CustomColorToast'; + import CustomColorInherit from '@vue/Components/Theming/CustomColorInherit'; + import ToastService from '@js/Services/ToastService'; + import ErrorManager from '@js/Manager/ErrorManager'; export default { - components: {CustomColorAlpha, CustomColorSet, Translate}, + components: { + CustomFontFamily, + CustomFontSize, + BadgeIcon, + CustomColorToast, + CustomColorInherit, + CustomColorSet, + Translate + }, + + props: { + theme: Theme + }, + data() { return { - themeColors: LightTheme.colors - } + font : this.theme.getFont(), + badge : this.theme.getBadge(), + colors: this.theme.getColors() + }; }, methods: { update(colors) { - this.themeColors = Object.assign(this.themeColors, colors); + this.colors = Object.assign(this.colors, colors); + this.theme.setColors(this.colors); + this.updatePreview(); + this.saveTheme(); + }, + updateBadge(colors) { + this.badge = Object.assign(this.badge, colors); + this.theme.setBadge(this.badge); + this.saveTheme(); + }, + updatePreview() { + MessageService.send( + { + type : 'theme.preview', + payload : this.theme, + receiver: 'popup' + } + ); + }, + async saveTheme() { + let reply = await MessageService.send({type: 'theme.save', payload: this.theme}); + if(!reply.getPayload().success) { + ToastService.error(['ThemeSaveError', reply.getPayload().message]) + .catch(ErrorManager.catch); + } + } + }, + watch : { + 'font.family'(value) { + this.theme.setFontFamily(value); + this.updatePreview(); + this.saveTheme(); + }, + 'font.size'(value) { + this.theme.setFontSize(value); + this.updatePreview(); + this.saveTheme(); + }, + 'badge.icon'(value) { + this.theme.setBadgeIcon(value); + this.saveTheme(); } } }; diff --git a/src/vue/Components/Theming/PreviewTheme.vue b/src/vue/Components/Theming/PreviewTheme.vue index be3f210..54b5d50 100644 --- a/src/vue/Components/Theming/PreviewTheme.vue +++ b/src/vue/Components/Theming/PreviewTheme.vue @@ -1,28 +1,54 @@ <template> - <iframe :src="url" class="theme-preview"/> + <div class="theme-preview"> + <div class="badge-preview"> + <img :src="icon" alt=""/> + <div class="badge" :style="style">8</div> + </div> + <iframe :src="url" class="popup-preview"/> + </div> </template> <script> + import Theme from '@js/Models/Theme/Theme'; + import SystemService from '@js/Services/SystemService'; + import ErrorManager from '@js/Manager/ErrorManager'; + export default { props: { - theme: { - type: String - } + theme: Theme }, data() { return { - url: 'about:blank' + url : 'about:blank', + icon: null }; }, mounted() { this.url = 'preview.html'; + SystemService.getFileUrl(`/img/${this.theme.getBadgeIcon()}.svg`) + .then((r) => {this.icon = r;}) + .catch(ErrorManager.catch); + }, + + computed: { + style() { + return { + backgroundColor: this.theme.getBadgeBackgroundColor(), + color : this.theme.getBadgeForegroundColor() + }; + } }, watch: { - theme(value, oldValue) { - if(oldValue !== null) this.$el.contentWindow.location.reload(); + theme: { + deep: true, + handler(theme) { + SystemService.getFileUrl(`/img/${theme.getBadgeIcon()}.svg`) + .then((r) => {this.icon = r;}) + .catch(ErrorManager.catch); + } } } }; @@ -30,7 +56,43 @@ <style lang="scss"> .theme-preview { - height : 360px; - border : 1px solid var(--element-hover-bg-color); + .badge-preview { + border : 1px solid var(--element-hover-bg-color); + border-radius : 5px; + width : 40px; + height : 40px; + margin : .5rem auto; + padding : 7px; + position : relative; + + img { + width : 24px; + height : 24px; + } + + .badge { + position : absolute; + width : 1rem; + height : 1rem; + font-size : .8rem; + line-height : 1rem; + text-align : center; + border-radius : 3px; + right : -.4rem; + top : -.4rem; + + &.bottom { + top : auto; + bottom : -.4rem; + } + } + } + + .popup-preview { + height : 360px; + border : 1px solid var(--element-hover-bg-color); + width : 100%; + border-radius : 5px; + } } </style>
\ No newline at end of file diff --git a/src/vue/Components/Toast/Toast.vue b/src/vue/Components/Toast/Toast.vue index 3f64c21..38d16c5 100644 --- a/src/vue/Components/Toast/Toast.vue +++ b/src/vue/Components/Toast/Toast.vue @@ -37,7 +37,7 @@ return className; }, hasCloseButton() { - return this.toast.getCloseable() && this.toast.getDefault() !== 'close' + return this.toast.getCloseable() && this.toast.getDefault() !== 'close'; } }, @@ -72,49 +72,94 @@ } .icon { - float : right; - position : relative; - margin : -.25rem; - padding : .25rem; + float : right; + position : relative; + margin : -.25rem; + padding : .2rem; + text-align : center; + cursor : pointer; + transition : background-color .15s; + border-radius : 3px; + + &:hover { + background-color : var(--success-hv-color); + } + } + + .button { + padding : .5rem; + margin : 0 -.5rem; text-align : center; + border-top : 1px solid var(--info-hv-color); + cursor : pointer; - &:before { - position : relative; - z-index : 1; + &:hover { + border-top-color : transparent; + background-color : var(--info-hv-color); } - &:after { - content : ''; - background-color : var(--element-fg-color); - opacity : 0; - position : absolute; - top : 0; - left : 0; - right : 0; - bottom : 0; - border-radius : 3px; - transition : opacity .15s; - cursor : pointer; + &:first-of-type { + margin-top : .5rem; } - &:hover:after { - opacity : .25; + &:last-of-type { + margin-bottom : -.5rem; + border-radius : 0 0 .25rem .25rem; + } + } + + &.success .toast-content { + background-color : var(--success-bg-color); + color : var(--success-fg-color); + + .icon:hover { + background-color : var(--success-hv-color); + } + + .button { + border-top-color : var(--warning-hv-color); + + &:hover { + border-top-color : transparent; + background-color : var(--warning-hv-color); + } } } &.warning .toast-content { background-color : var(--warning-bg-color); - color: var(--warning-fg-color); + color : var(--warning-fg-color); + + .icon:hover { + background-color : var(--warning-hv-color); + } + + .button { + border-top-color : var(--warning-hv-color); + + &:hover { + border-top-color : transparent; + background-color : var(--warning-hv-color); + } + } } &.error .toast-content { background-color : var(--error-bg-color); - color: var(--error-fg-color); - } + color : var(--error-fg-color); - &.success .toast-content { - background-color : var(--success-bg-color); - color: var(--success-fg-color); + .icon:hover { + background-color : var(--error-hv-color); + } + + .button { + border-top-color : var(--error-hv-color); + + &:hover { + border-top-color : transparent; + background-color : var(--error-hv-color); + } + } } &.has-default { @@ -130,27 +175,5 @@ .message { display : block; } - - .button { - padding : .5rem; - margin : 0 -.5rem; - text-align : center; - border-top : 1px solid rgba(0, 0, 0, .25); - cursor : pointer; - - &:hover { - background-color : rgba(0, 0, 0, .25); - border-top : 1px solid rgba(0, 0, 0, 0); - } - - &:first-of-type { - margin-top : .5rem; - } - - &:last-of-type { - margin-bottom : -.5rem; - border-radius : 0 0 .25rem .25rem; - } - } } </style>
\ No newline at end of file |