Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/marius-wieschollek/passwords-webextension.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/vue/Components')
-rw-r--r--src/vue/Components/Collected/MinedProperty.vue17
-rw-r--r--src/vue/Components/Form/InputField.vue49
-rw-r--r--src/vue/Components/Form/SelectField.vue29
-rw-r--r--src/vue/Components/Options/Theming.vue79
-rw-r--r--src/vue/Components/Popup/Collected.vue18
-rw-r--r--src/vue/Components/Tabs.vue2
-rw-r--r--src/vue/Components/Theming/BadgeIcon.vue61
-rw-r--r--src/vue/Components/Theming/CustomColorAlpha.vue81
-rw-r--r--src/vue/Components/Theming/CustomColorInherit.vue87
-rw-r--r--src/vue/Components/Theming/CustomColorSet.vue31
-rw-r--r--src/vue/Components/Theming/CustomColorToast.vue77
-rw-r--r--src/vue/Components/Theming/CustomFontFamily.vue52
-rw-r--r--src/vue/Components/Theming/CustomFontSize.vue59
-rw-r--r--src/vue/Components/Theming/CustomTheme.vue117
-rw-r--r--src/vue/Components/Theming/PreviewTheme.vue80
-rw-r--r--src/vue/Components/Toast/Toast.vue123
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