diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-02-16 15:13:27 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-05-21 20:36:21 +0200 |
commit | 752e3b9000e826207f1361373c6964c708868930 (patch) | |
tree | 11a2688cbf407d5e800056b4c167e067cd4b8980 /apps/theming/src/AdminTheming.vue | |
parent | c8260924d60c80c4d1fec25d93979a84509701f7 (diff) | |
download | nextcloud-server-752e3b9000e826207f1361373c6964c708868930.tar.gz nextcloud-server-752e3b9000e826207f1361373c6964c708868930.zip |
fix(settings): Make background selector be responsive to user changes
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/theming/src/AdminTheming.vue')
-rw-r--r-- | apps/theming/src/AdminTheming.vue | 174 |
1 files changed, 91 insertions, 83 deletions
diff --git a/apps/theming/src/AdminTheming.vue b/apps/theming/src/AdminTheming.vue index f0831d8e944..db2003730dc 100644 --- a/apps/theming/src/AdminTheming.vue +++ b/apps/theming/src/AdminTheming.vue @@ -44,7 +44,7 @@ :placeholder="field.placeholder" :type="field.type" :value.sync="field.value" - @update:theming="$emit('update:theming')" /> + @update:theming="refreshStyles" /> <!-- Primary color picker --> <ColorPickerField :name="primaryColorPickerField.name" @@ -53,33 +53,41 @@ :display-name="primaryColorPickerField.displayName" :value.sync="primaryColorPickerField.value" data-admin-theming-setting-primary-color - @update:theming="$emit('update:theming')" /> + @update:theming="refreshStyles" /> <!-- Background color picker --> - <ColorPickerField :name="backgroundColorPickerField.name" - :description="backgroundColorPickerField.description" - :default-value="defaultBackground" - :display-name="backgroundColorPickerField.displayName" - :value.sync="backgroundColorPickerField.value" - data-admin-theming-setting-primary-color - @update:theming="$emit('update:theming')" /> + <ColorPickerField name="background_color" + :description="t('theming', 'Instead of a background image you can also configure a plain background color. If you use a background image changing this color will influence the color of the app menu icons.')" + :default-value.sync="defaultBackgroundColor" + :display-name="t('theming', 'Background color')" + :value.sync="backgroundColor" + data-admin-theming-setting-background-color + @update:theming="refreshStyles" /> <!-- Default background picker --> - <FileInputField v-for="field in fileInputFields" - :key="field.name" - :aria-label="field.ariaLabel" - :data-admin-theming-setting-file="field.name" - :default-mime-value="field.defaultMimeValue" - :display-name="field.displayName" - :mime-name="field.mimeName" - :mime-value.sync="field.mimeValue" - :name="field.name" - @update:theming="$emit('update:theming')" /> + <FileInputField :aria-label="t('theming', 'Upload new logo')" + data-admin-theming-setting-file="logo" + :display-name="t('theming', 'Logo')" + mime-name="logoMime" + :mime-value.sync="logoMime" + name="logo" + @update:theming="refreshStyles" /> + + <FileInputField :aria-label="t('theming', 'Upload new background and login image')" + data-admin-theming-setting-file="background" + :display-name="t('theming', 'Background and login image')" + mime-name="backgroundMime" + :mime-value.sync="backgroundMime" + name="background" + @uploaded="backgroundURL = $event" + @update:theming="refreshStyles" /> + <div class="admin-theming__preview" data-admin-theming-preview> <div class="admin-theming__preview-logo" data-admin-theming-preview-logo /> </div> </div> </NcSettingsSection> + <NcSettingsSection :name="t('theming', 'Advanced options')"> <div class="admin-theming-advanced"> <TextField v-for="field in advancedTextFields" @@ -91,7 +99,7 @@ :display-name="field.displayName" :placeholder="field.placeholder" :maxlength="field.maxlength" - @update:theming="$emit('update:theming')" /> + @update:theming="refreshStyles" /> <FileInputField v-for="field in advancedFileInputFields" :key="field.name" :name="field.name" @@ -100,7 +108,7 @@ :default-mime-value="field.defaultMimeValue" :display-name="field.displayName" :aria-label="field.ariaLabel" - @update:theming="$emit('update:theming')" /> + @update:theming="refreshStyles" /> <CheckboxField :name="userThemingField.name" :value="userThemingField.value" :default-value="userThemingField.defaultValue" @@ -108,7 +116,7 @@ :label="userThemingField.label" :description="userThemingField.description" data-admin-theming-setting-disable-user-theming - @update:theming="$emit('update:theming')" /> + @update:theming="refreshStyles" /> <a v-if="!canThemeIcons" :href="docUrlIcons" rel="noreferrer noopener"> @@ -122,6 +130,7 @@ <script> import { loadState } from '@nextcloud/initial-state' +import { refreshStyles } from './helpers/refreshStyles.js' import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js' import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js' @@ -132,7 +141,10 @@ import TextField from './components/admin/TextField.vue' import AppMenuSection from './components/admin/AppMenuSection.vue' const { + defaultBackgroundURL, + backgroundMime, + backgroundURL, backgroundColor, canThemeIcons, docUrl, @@ -190,32 +202,6 @@ const primaryColorPickerField = { description: t('theming', 'The primary color is used for highlighting elements like important buttons. It might get slightly adjusted depending on the current color schema.'), } -const backgroundColorPickerField = { - name: 'background_color', - value: backgroundColor, - displayName: t('theming', 'Background color'), - description: t('theming', 'Instead of a background image you can also configure a plain background color. If you use a background image changing this color will influence the color of the app menu icons.'), -} - -const fileInputFields = [ - { - name: 'logo', - mimeName: 'logoMime', - mimeValue: logoMime, - defaultMimeValue: '', - displayName: t('theming', 'Logo'), - ariaLabel: t('theming', 'Upload new logo'), - }, - { - name: 'background', - mimeName: 'backgroundMime', - mimeValue: backgroundMime, - defaultMimeValue: '', - displayName: t('theming', 'Background and login image'), - ariaLabel: t('theming', 'Upload new background and login image'), - }, -] - const advancedTextFields = [ { name: 'imprintUrl', @@ -278,18 +264,17 @@ export default { TextField, }, - emits: [ - 'update:theming', - ], - - textFields, - data() { return { + backgroundMime, + backgroundURL, + backgroundColor, + defaultBackgroundColor: '#0069c3', + + logoMime, + textFields, - backgroundColorPickerField, primaryColorPickerField, - fileInputFields, advancedTextFields, advancedFileInputFields, userThemingField, @@ -300,34 +285,64 @@ export default { docUrlIcons, isThemable, notThemableErrorMessage, - - defaultBackground: this.calculateDefaultBackground(), } }, + computed: { + cssBackgroundImage() { + if (this.backgroundURL) { + return `url('${this.backgroundURL}')` + } + return 'unset' + }, + }, + watch: { - backgroundColorPickerField: { - deep: true, - handler() { - this.defaultBackground = this.calculateDefaultBackground() - }, + backgroundMime() { + if (this.backgroundMime === '') { + // Reset URL to default value for preview + this.backgroundURL = defaultBackgroundURL + } else if (this.backgroundMime === 'backgroundColor') { + // Reset URL to empty image when only color is configured + this.backgroundURL = '' + } }, + async backgroundURL() { + // When the background is changed we need to emulate the background color change + if (this.backgroundURL !== '') { + const color = await this.calculateDefaultBackground() + this.defaultBackgroundColor = color + this.backgroundColor = color + } + }, + }, + + async mounted() { + if (this.backgroundURL) { + this.defaultBackgroundColor = await this.calculateDefaultBackground() + } }, methods: { + refreshStyles, + + /** + * Same as on server - if a user uploads an image the mean color will be set as the background color + */ calculateDefaultBackground() { const toHex = (num) => `00${num.toString(16)}`.slice(-2) - const style = window.getComputedStyle(document.body).backgroundImage - const match = style.match(/url\("(http.+)"\)/) - if (!match) { - return '#0082c9' - } - const context = document.createElement('canvas').getContext('2d') - const img = new Image() - img.src = match[1] - context.imageSmoothingEnabled = true - context.drawImage(img, 0, 0, 1, 1) - return '#' + [...context.getImageData(0, 0, 1, 1).data.slice(0, 3)].map(toHex).join('') + + return new Promise((resolve, reject) => { + const img = new Image() + img.src = this.backgroundURL + img.onload = () => { + const context = document.createElement('canvas').getContext('2d') + context.imageSmoothingEnabled = true + context.drawImage(img, 0, 0, 1, 1) + resolve('#' + [...context.getImageData(0, 0, 1, 1).data.slice(0, 3)].map(toHex).join('')) + } + img.onerror = reject + }) }, }, } @@ -349,15 +364,8 @@ export default { background-position: center; text-align: center; margin-top: 10px; - /* This is basically https://github.com/nextcloud/server/blob/master/core/css/guest.css - But without the user variables. That way the admin can preview the render as guest*/ - /* As guest, there is no user color color-background-plain */ - background-color: var(--color-primary-element-default); - /* As guest, there is no user background (--image-background) - 1. Empty background if defined - 2. Else default background - 3. Finally default gradient (should not happened, the background is always defined anyway) */ - background-image: var(--image-background-plain, var(--image-background-default)); + background-color: v-bind('backgroundColor'); + background-image: v-bind('cssBackgroundImage'); &-logo { width: 20%; |