aboutsummaryrefslogtreecommitdiffstats
path: root/apps/theming/src/AdminTheming.vue
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-02-16 15:13:27 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2024-05-21 20:36:21 +0200
commit752e3b9000e826207f1361373c6964c708868930 (patch)
tree11a2688cbf407d5e800056b4c167e067cd4b8980 /apps/theming/src/AdminTheming.vue
parentc8260924d60c80c4d1fec25d93979a84509701f7 (diff)
downloadnextcloud-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.vue174
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%;