diff options
Diffstat (limited to 'apps/theming/src/components/BackgroundSettings.vue')
-rw-r--r-- | apps/theming/src/components/BackgroundSettings.vue | 208 |
1 files changed, 75 insertions, 133 deletions
diff --git a/apps/theming/src/components/BackgroundSettings.vue b/apps/theming/src/components/BackgroundSettings.vue index 0a8c49be45e..58b76dd9602 100644 --- a/apps/theming/src/components/BackgroundSettings.vue +++ b/apps/theming/src/components/BackgroundSettings.vue @@ -1,27 +1,7 @@ <!-- - - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> - - - - @author Christopher Ng <chrng8@gmail.com> - - @author Greta Doci <gretadoci@gmail.com> - - @author John Molakvoæ <skjnldsv@protonmail.com> - - @author Julius Härtl <jus@bitgrid.net> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - This program is distributed in the hope that it will be useful, - - but WITHOUT ANY WARRANTY; without even the implied warranty of - - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - - GNU Affero General Public License for more details. - - - - You should have received a copy of the GNU Affero General Public License - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <div class="background-selector" data-user-theming-background-settings> @@ -32,15 +12,34 @@ 'background background__filepicker': true, 'background--active': backgroundImage === 'custom' }" - :data-color-bright="invertTextColor(Theming.color)" data-user-theming-background-custom tabindex="0" @click="pickFile"> {{ t('theming', 'Custom background') }} - <ImageEdit v-if="backgroundImage !== 'custom'" :size="26" /> + <ImageEdit v-if="backgroundImage !== 'custom'" :size="20" /> <Check :size="44" /> </button> + <!-- Custom color picker --> + <NcColorPicker v-model="Theming.backgroundColor" @update:value="debouncePickColor"> + <button :class="{ + 'icon-loading': loading === 'color', + 'background background__color': true, + 'background--active': backgroundImage === 'color' + }" + :aria-pressed="backgroundImage === 'color'" + :data-color="Theming.backgroundColor" + :data-color-bright="invertTextColor(Theming.backgroundColor)" + :style="{ backgroundColor: Theming.backgroundColor, '--border-color': Theming.backgroundColor}" + data-user-theming-background-color + tabindex="0" + @click="backgroundImage !== 'color' && debouncePickColor(Theming.backgroundColor)"> + {{ t('theming', 'Plain background') /* TRANSLATORS: Background using a single color */ }} + <ColorPalette v-if="backgroundImage !== 'color'" :size="20" /> + <Check :size="44" /> + </button> + </NcColorPicker> + <!-- Default background --> <button :aria-pressed="backgroundImage === 'default'" :class="{ @@ -48,8 +47,8 @@ 'background background__default': true, 'background--active': backgroundImage === 'default' }" - :data-color-bright="invertTextColor(Theming.defaultColor)" - :style="{ '--border-color': Theming.defaultColor }" + :data-color-bright="invertTextColor(Theming.defaultBackgroundColor)" + :style="{ '--border-color': Theming.defaultBackgroundColor }" data-user-theming-background-default tabindex="0" @click="setDefault"> @@ -57,32 +56,6 @@ <Check :size="44" /> </button> - <!-- Custom color picker --> - <NcColorPicker v-model="Theming.color" @input="debouncePickColor"> - <button class="background background__color" - :data-color="Theming.color" - :data-color-bright="invertTextColor(Theming.color)" - :style="{ backgroundColor: Theming.color, '--border-color': Theming.color}" - data-user-theming-background-color - tabindex="0"> - {{ t('theming', 'Change color') }} - </button> - </NcColorPicker> - - <!-- Remove background --> - <button :aria-pressed="isBackgroundDisabled" - :class="{ - 'background background__delete': true, - 'background--active': isBackgroundDisabled - }" - data-user-theming-background-clear - tabindex="0" - @click="removeBackground"> - {{ t('theming', 'No background') }} - <Close v-if="!isBackgroundDisabled" :size="32" /> - <Check :size="44" /> - </button> - <!-- Background set selection --> <button v-for="shippedBackground in shippedBackgrounds" :key="shippedBackground.name" @@ -94,7 +67,7 @@ 'icon-loading': loading === shippedBackground.name, 'background--active': backgroundImage === shippedBackground.name }" - :data-color-bright="shippedBackground.details.theming === 'dark'" + :data-color-bright="invertTextColor(shippedBackground.details.background_color)" :data-user-theming-background-shipped="shippedBackground.name" :style="{ backgroundImage: 'url(' + shippedBackground.preview + ')', '--border-color': shippedBackground.details.primary_color }" tabindex="0" @@ -105,24 +78,25 @@ </template> <script> -import { generateFilePath, generateRemoteUrl, generateUrl } from '@nextcloud/router' -import { getCurrentUser } from '@nextcloud/auth' +import { generateFilePath, generateUrl } from '@nextcloud/router' import { getFilePickerBuilder, showError } from '@nextcloud/dialogs' import { loadState } from '@nextcloud/initial-state' -import { Palette } from 'node-vibrant/lib/color.js' import axios from '@nextcloud/axios' import debounce from 'debounce' -import NcColorPicker from '@nextcloud/vue/dist/Components/NcColorPicker.js' -import Vibrant from 'node-vibrant' +import NcColorPicker from '@nextcloud/vue/components/NcColorPicker' import Check from 'vue-material-design-icons/Check.vue' -import Close from 'vue-material-design-icons/Close.vue' import ImageEdit from 'vue-material-design-icons/ImageEdit.vue' +import ColorPalette from 'vue-material-design-icons/PaletteOutline.vue' -const backgroundImage = loadState('theming', 'backgroundImage') const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') -const themingDefaultBackground = loadState('theming', 'themingDefaultBackground') -const defaultShippedBackground = loadState('theming', 'defaultShippedBackground') +const backgroundImage = loadState('theming', 'userBackgroundImage') +const { + backgroundImage: defaultBackgroundImage, + // backgroundColor: defaultBackgroundColor, + backgroundMime: defaultBackgroundMime, + defaultShippedBackground, +} = loadState('theming', 'themingDefaults') const prefixWithBaseUrl = (url) => generateFilePath('theming', '', 'img/background/') + url @@ -131,7 +105,7 @@ export default { components: { Check, - Close, + ColorPalette, ImageEdit, NcColorPicker, }, @@ -149,7 +123,12 @@ export default { computed: { shippedBackgrounds() { return Object.keys(shippedBackgroundList) - .map(fileName => { + .filter((background) => { + // If the admin did not changed the global background + // let's hide the default background to not show it twice + return background !== defaultShippedBackground || !this.isGlobalBackgroundDefault + }) + .map((fileName) => { return { name: fileName, url: prefixWithBaseUrl(fileName), @@ -157,27 +136,18 @@ export default { details: shippedBackgroundList[fileName], } }) - .filter(background => { - // If the admin did not changed the global background - // let's hide the default background to not show it twice - if (!this.isGlobalBackgroundDeleted && !this.isGlobalBackgroundDefault) { - return background.name !== defaultShippedBackground - } - return true - }) }, isGlobalBackgroundDefault() { - return !!themingDefaultBackground + return defaultBackgroundMime === '' }, isGlobalBackgroundDeleted() { - return themingDefaultBackground === 'backgroundColor' + return defaultBackgroundMime === 'backgroundColor' }, - isBackgroundDisabled() { - return this.backgroundImage === 'disabled' - || !this.backgroundImage + cssDefaultBackgroundImage() { + return `url('${defaultBackgroundImage}')` }, }, @@ -225,7 +195,7 @@ export default { async update(data) { // Update state this.backgroundImage = data.backgroundImage - this.Theming.color = data.backgroundColor + this.Theming.backgroundColor = data.backgroundColor // Notify parent and reload style this.$emit('update:background') @@ -244,9 +214,9 @@ export default { this.update(result.data) }, - async setFile(path, color = null) { + async setFile(path) { this.loading = 'custom' - const result = await axios.post(generateUrl('/apps/theming/background/custom'), { value: path, color }) + const result = await axios.post(generateUrl('/apps/theming/background/custom'), { value: path }) this.update(result.data) }, @@ -256,15 +226,15 @@ export default { this.update(result.data) }, - async pickColor(event) { + async pickColor(color) { this.loading = 'color' - const color = event?.target?.dataset?.color || this.Theming?.color || '#0082c9' - const result = await axios.post(generateUrl('/apps/theming/background/color'), { color }) - this.update(result.data) + const { data } = await axios.post(generateUrl('/apps/theming/background/color'), { color: color || '#0082c9' }) + this.update(data) }, + debouncePickColor: debounce(function(...args) { this.pickColor(...args) - }, 200), + }, 1000), pickFile() { const picker = getFilePickerBuilder(t('theming', 'Select a background from your files')) @@ -291,45 +261,7 @@ export default { } this.loading = 'custom' - - // Extract primary color from image - let response = null - let color = null - try { - const fileUrl = generateRemoteUrl('dav/files/' + getCurrentUser().uid + path) - response = await axios.get(fileUrl, { responseType: 'blob' }) - const blobUrl = URL.createObjectURL(response.data) - const palette = await this.getColorPaletteFromBlob(blobUrl) - - // DarkVibrant is accessible AND visually pleasing - // Vibrant is not accessible enough and others are boring - color = palette?.DarkVibrant?.hex - this.setFile(path, color) - - // Log data - console.debug('Extracted colour', color, 'from custom image', path, palette) - } catch (error) { - this.setFile(path) - console.error('Unable to extract colour from custom image', { error, path, response, color }) - } - }, - - /** - * Extract a Vibrant color palette from a blob URL - * - * @param {string} blobUrl the blob URL - * @return {Promise<Palette>} - */ - getColorPaletteFromBlob(blobUrl) { - return new Promise((resolve, reject) => { - const vibrant = new Vibrant(blobUrl) - vibrant.getPalette((error, palette) => { - if (error) { - reject(error) - } - resolve(palette) - }) - }) + this.setFile(path) }, }, } @@ -341,38 +273,48 @@ export default { flex-wrap: wrap; justify-content: center; + .background-color { + display: flex; + justify-content: center; + align-items: center; + width: 176px; + height: 96px; + margin: 8px; + border-radius: var(--border-radius-large); + background-color: var(--color-primary); + } + .background { overflow: hidden; width: 176px; height: 96px; margin: 8px; text-align: center; + word-wrap: break-word; + hyphens: auto; border: 2px solid var(--color-main-background); border-radius: var(--border-radius-large); background-position: center center; background-size: cover; &__filepicker { + background-color: var(--color-background-dark); + &.background--active { - color: white; + color: var(--color-background-plain-text); background-image: var(--image-background); } } &__default { - background-color: var(--color-primary-default); - background-image: linear-gradient(to bottom, rgba(23, 23, 23, 0.5), rgba(23, 23, 23, 0.5)), var(--image-background-plain, var(--image-background-default)); + background-color: var(--color-background-plain); + background-image: linear-gradient(to bottom, rgba(23, 23, 23, 0.5), rgba(23, 23, 23, 0.5)), v-bind(cssDefaultBackgroundImage); } &__filepicker, &__default, &__color { border-color: var(--color-border); } - &__color { - color: var(--color-primary-text); - background-color: var(--color-primary-default); - } - // Over a background image &__default, &__shipped { |