aboutsummaryrefslogtreecommitdiffstats
path: root/apps/theming/src
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-01-20 01:56:18 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2024-05-21 20:36:21 +0200
commit705335e6a55b9ef0e4ebf0bb83c07efac23e52c8 (patch)
treef392d4cb7170ba1e4b78b02280cf18e2edf27cca /apps/theming/src
parent9d2c3c1164926eadb61d1ec8360644dfeb75a78c (diff)
downloadnextcloud-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.vue69
-rw-r--r--apps/theming/src/components/BackgroundSettings.vue68
-rw-r--r--apps/theming/src/components/admin/ColorPickerField.vue20
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 {