diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-01-20 01:56:18 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-05-21 20:36:21 +0200 |
commit | 705335e6a55b9ef0e4ebf0bb83c07efac23e52c8 (patch) | |
tree | f392d4cb7170ba1e4b78b02280cf18e2edf27cca /apps/theming/src | |
parent | 9d2c3c1164926eadb61d1ec8360644dfeb75a78c (diff) | |
download | nextcloud-server-705335e6a55b9ef0e4ebf0bb83c07efac23e52c8.tar.gz nextcloud-server-705335e6a55b9ef0e4ebf0bb83c07efac23e52c8.zip |
feat(theming): Allow to configure primary color separate from background in admin settings
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/theming/src')
-rw-r--r-- | apps/theming/src/AdminTheming.vue | 69 | ||||
-rw-r--r-- | apps/theming/src/components/BackgroundSettings.vue | 68 | ||||
-rw-r--r-- | apps/theming/src/components/admin/ColorPickerField.vue | 20 |
3 files changed, 104 insertions, 53 deletions
diff --git a/apps/theming/src/AdminTheming.vue b/apps/theming/src/AdminTheming.vue index 2face1629ef..f0831d8e944 100644 --- a/apps/theming/src/AdminTheming.vue +++ b/apps/theming/src/AdminTheming.vue @@ -47,10 +47,21 @@ @update:theming="$emit('update:theming')" /> <!-- Primary color picker --> - <ColorPickerField :name="colorPickerField.name" - :default-value="colorPickerField.defaultValue" - :display-name="colorPickerField.displayName" - :value.sync="colorPickerField.value" + <ColorPickerField :name="primaryColorPickerField.name" + :description="primaryColorPickerField.description" + :default-value="primaryColorPickerField.defaultValue" + :display-name="primaryColorPickerField.displayName" + :value.sync="primaryColorPickerField.value" + data-admin-theming-setting-primary-color + @update:theming="$emit('update:theming')" /> + + <!-- 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')" /> <!-- Default background picker --> @@ -122,8 +133,8 @@ import AppMenuSection from './components/admin/AppMenuSection.vue' const { backgroundMime, + backgroundColor, canThemeIcons, - color, docUrl, docUrlIcons, faviconMime, @@ -133,6 +144,7 @@ const { logoMime, name, notThemableErrorMessage, + primaryColor, privacyPolicyUrl, slogan, url, @@ -170,11 +182,19 @@ const textFields = [ }, ] -const colorPickerField = { - name: 'color', - value: color, +const primaryColorPickerField = { + name: 'primary_color', + value: primaryColor, defaultValue: '#0082c9', - displayName: t('theming', 'Color'), + displayName: t('theming', 'Primary color'), + 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 = [ @@ -267,7 +287,8 @@ export default { data() { return { textFields, - colorPickerField, + backgroundColorPickerField, + primaryColorPickerField, fileInputFields, advancedTextFields, advancedFileInputFields, @@ -279,8 +300,36 @@ export default { docUrlIcons, isThemable, notThemableErrorMessage, + + defaultBackground: this.calculateDefaultBackground(), } }, + + watch: { + backgroundColorPickerField: { + deep: true, + handler() { + this.defaultBackground = this.calculateDefaultBackground() + }, + }, + }, + + methods: { + 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('') + }, + }, } </script> diff --git a/apps/theming/src/components/BackgroundSettings.vue b/apps/theming/src/components/BackgroundSettings.vue index deb0a93a51a..166fdbc5f4b 100644 --- a/apps/theming/src/components/BackgroundSettings.vue +++ b/apps/theming/src/components/BackgroundSettings.vue @@ -32,15 +32,32 @@ '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" @input="debouncePickColor"> + <button :class="{ + 'icon-loading': loading === 'color', + 'background background__color': true, + 'background--active': 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"> + {{ 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="{ @@ -57,31 +74,6 @@ <Check :size="44" /> </button> - <!-- Custom color picker --> - <div class="background-color" - data-user-theming-background-color> - <NcColorPicker v-model="Theming.color" - @input="debouncePickColor"> - <NcButton type="ternary"> - {{ t('theming', 'Change color') }} - </NcButton> - </NcColorPicker> - </div> - - <!-- 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" @@ -93,7 +85,6 @@ 'icon-loading': loading === shippedBackground.name, 'background--active': backgroundImage === shippedBackground.name }" - :data-color-bright="shippedBackground.details.theming === 'dark'" :data-user-theming-background-shipped="shippedBackground.name" :style="{ backgroundImage: 'url(' + shippedBackground.preview + ')', '--border-color': shippedBackground.details.primary_color }" tabindex="0" @@ -112,12 +103,11 @@ 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 NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import Vibrant from 'node-vibrant' 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/Palette.vue' const backgroundImage = loadState('theming', 'backgroundImage') const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') @@ -126,14 +116,14 @@ const defaultShippedBackground = loadState('theming', 'defaultShippedBackground' const prefixWithBaseUrl = (url) => generateFilePath('theming', '', 'img/background/') + url +console.warn(loadState('theming', 'data', {})) export default { name: 'BackgroundSettings', components: { Check, - Close, + ColorPalette, ImageEdit, - NcButton, NcColorPicker, }, @@ -175,11 +165,6 @@ export default { isGlobalBackgroundDeleted() { return themingDefaultBackground === 'backgroundColor' }, - - isBackgroundDisabled() { - return this.backgroundImage === 'disabled' - || !this.backgroundImage - }, }, methods: { @@ -226,7 +211,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') @@ -359,14 +344,19 @@ export default { 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-main-text); + background-color: var(--color-background-dark); + &.background--active { - color: white; + color: var(--color-background-plain-text); background-image: var(--image-background); } } diff --git a/apps/theming/src/components/admin/ColorPickerField.vue b/apps/theming/src/components/admin/ColorPickerField.vue index fad40408b37..1cac5418d7a 100644 --- a/apps/theming/src/components/admin/ColorPickerField.vue +++ b/apps/theming/src/components/admin/ColorPickerField.vue @@ -26,14 +26,16 @@ <div class="field__row"> <NcColorPicker :value.sync="localValue" :advanced-fields="true" - data-admin-theming-setting-primary-color-picker @update:value="debounceSave"> - <NcButton type="secondary" - :id="id"> + <NcButton :id="id" + class="field__button" + type="primary" + :aria-label="t('theming', 'Select a custom color')" + data-admin-theming-setting-primary-color-picker> <template #icon> <Palette :size="20" /> </template> - {{ t('theming', 'Change color') }} + {{ value }} </NcButton> </NcColorPicker> <div class="field__color-preview" data-admin-theming-setting-primary-color /> @@ -47,6 +49,9 @@ </template> </NcButton> </div> + <div v-if="description" class="description"> + {{ description }} + </div> <NcNoteCard v-if="errorMessage" type="error" @@ -86,6 +91,10 @@ export default { type: String, required: true, }, + description: { + type: String, + default: '', + }, value: { type: String, required: true, @@ -110,6 +119,9 @@ export default { <style lang="scss" scoped> @import './shared/field.scss'; +.description { + color: var(--color-text-maxcontrast); +} .field { &__color-preview { |