diff options
author | greta <gretadoci@gmail.com> | 2022-08-29 15:11:41 +0200 |
---|---|---|
committer | Christopher Ng <chrng8@gmail.com> | 2022-09-14 20:17:01 +0000 |
commit | 02cc42d40ae7334609a3270ee1d16eec75098aa6 (patch) | |
tree | d6668a5a9834f70d300d0e3384ed7293dbd9b0c7 /apps/theming/src | |
parent | bd03c7978537334822f1fc05049045d89cc56533 (diff) | |
download | nextcloud-server-02cc42d40ae7334609a3270ee1d16eec75098aa6.tar.gz nextcloud-server-02cc42d40ae7334609a3270ee1d16eec75098aa6.zip |
Move background settings from dashboard app to Appearance and accessibility settings
Signed-off-by: greta <gretadoci@gmail.com>
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Diffstat (limited to 'apps/theming/src')
-rw-r--r-- | apps/theming/src/UserThemes.vue | 151 | ||||
-rw-r--r-- | apps/theming/src/components/BackgroundSettings.vue | 195 | ||||
-rw-r--r-- | apps/theming/src/helpers/getBackgroundUrl.js | 51 | ||||
-rw-r--r-- | apps/theming/src/helpers/prefixWithBaseUrl.js | 27 |
4 files changed, 396 insertions, 28 deletions
diff --git a/apps/theming/src/UserThemes.vue b/apps/theming/src/UserThemes.vue index 8e7f1d54e37..c886394136a 100644 --- a/apps/theming/src/UserThemes.vue +++ b/apps/theming/src/UserThemes.vue @@ -1,42 +1,83 @@ +<!-- + - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + - @copyright Copyright (c) 2022 Greta Doci <gretadoci@gmail.com> + - + - @author Christopher Ng <chrng8@gmail.com> + - + - @license AGPL-3.0-or-later + - + - 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/>. + - +--> + <template> - <NcSettingsSection class="theming" :title="t('themes', 'Appearance and accessibility')"> - <p v-html="description" /> - <p v-html="descriptionDetail" /> - - <div class="theming__preview-list"> - <ItemPreview v-for="theme in themes" - :key="theme.id" - :enforced="theme.id === enforceTheme" - :selected="selectedTheme.id === theme.id" - :theme="theme" - :unique="themes.length === 1" - type="theme" - @change="changeTheme" /> - </div> - - <div class="theming__preview-list"> - <ItemPreview v-for="theme in fonts" - :key="theme.id" - :selected="theme.enabled" - :theme="theme" - :unique="fonts.length === 1" - type="font" - @change="changeFont" /> - </div> - </NcSettingsSection> + <section> + <NcSettingsSection class="theming" :title="t('theming', 'Appearance and accessibility')"> + <p v-html="description" /> + <p v-html="descriptionDetail" /> + + <div class="theming__preview-list"> + <ItemPreview v-for="theme in themes" + :key="theme.id" + :enforced="theme.id === enforceTheme" + :selected="selectedTheme.id === theme.id" + :theme="theme" + :unique="themes.length === 1" + type="theme" + @change="changeTheme" /> + </div> + + <div class="theming__preview-list"> + <ItemPreview v-for="theme in fonts" + :key="theme.id" + :selected="theme.enabled" + :theme="theme" + :unique="fonts.length === 1" + type="font" + @change="changeFont" /> + </div> + </NcSettingsSection> + <NcSettingsSection :title="t('theming', 'Background')" + class="background"> + <p>{{ t('theming', 'Set a custom background') }}</p> + <BackgroundSettings class="background__grid" + :background="background" + :theming-default-background="themingDefaultBackground" + @update:background="updateBackground" /> + </NcSettingsSection> + </section> </template> <script> -import { generateOcsUrl } from '@nextcloud/router' +import { generateOcsUrl, imagePath } from '@nextcloud/router' import { loadState } from '@nextcloud/initial-state' import axios from '@nextcloud/axios' import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection' -import ItemPreview from './components/ItemPreview' +import BackgroundSettings from './components/BackgroundSettings.vue' +import ItemPreview from './components/ItemPreview.vue' + +import { getBackgroundUrl } from '../src/helpers/getBackgroundUrl.js' const availableThemes = loadState('theming', 'themes', []) const enforceTheme = loadState('theming', 'enforceTheme', '') +const background = loadState('theming', 'background') +const backgroundVersion = loadState('theming', 'backgroundVersion') +const themingDefaultBackground = loadState('theming', 'themingDefaultBackground') +const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') + console.debug('Available themes', availableThemes) export default { @@ -44,16 +85,32 @@ export default { components: { ItemPreview, NcSettingsSection, + BackgroundSettings, }, data() { return { availableThemes, enforceTheme, + background, + themingDefaultBackground, } }, computed: { + backgroundImage() { + return getBackgroundUrl(this.background, backgroundVersion, this.themingDefaultBackground) + }, + backgroundStyle() { + if ((this.background === 'default' && this.themingDefaultBackground === 'backgroundColor') + || this.background.match(/#[0-9A-Fa-f]{6}/g)) { + return null + } + + return { + backgroundImage: this.background === 'default' ? 'var(--image-main-background)' : `url('${this.backgroundImage}')`, + } + }, themes() { return this.availableThemes.filter(theme => theme.type === 1) }, @@ -94,7 +151,40 @@ export default { return '<a target="_blank" href="https://nextcloud.com/design" rel="noreferrer nofollow">' }, }, + mounted() { + this.updateGlobalStyles() + }, methods: { + updateBackground(data) { + this.background = (data.type === 'custom' || data.type === 'default') ? data.type : data.value + this.updateGlobalStyles() + }, + updateGlobalStyles() { + // Override primary-invert-if-bright and color-primary-text if background is set + const isBackgroundBright = shippedBackgroundList[this.background]?.theming === 'dark' + if (isBackgroundBright) { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'invert(100%)') + document.querySelector('#header').style.setProperty('--color-primary-text', '#000000') + // document.body.removeAttribute('data-theme-dark') + // document.body.setAttribute('data-theme-light', 'true') + } else { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'no') + document.querySelector('#header').style.setProperty('--color-primary-text', '#ffffff') + // document.body.removeAttribute('data-theme-light') + // document.body.setAttribute('data-theme-dark', 'true') + } + + const themeElements = [document.documentElement, document.querySelector('#header'), document.querySelector('body')] + for (const element of themeElements) { + if (this.background === 'default') { + element.style.setProperty('--image-main-background', `url('${imagePath('core', 'app-background.jpg')}')`) + } else if (this.background.match(/#[0-9A-Fa-f]{6}/g)) { + element.style.setProperty('--image-main-background', undefined) + } else { + element.style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) + } + } + }, changeTheme({ enabled, id }) { // Reset selected and select new one this.themes.forEach(theme => { @@ -194,11 +284,16 @@ export default { } } +.background { + &__grid { + margin-top: 30px; + } +} + @media (max-width: 1440px) { .theming__preview-list { display: flex; flex-direction: column; } } - </style> diff --git a/apps/theming/src/components/BackgroundSettings.vue b/apps/theming/src/components/BackgroundSettings.vue new file mode 100644 index 00000000000..3de68d5abed --- /dev/null +++ b/apps/theming/src/components/BackgroundSettings.vue @@ -0,0 +1,195 @@ +<!-- + - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + - @copyright Copyright (c) 2022 Greta Doci <gretadoci@gmail.com> + - + - @author Julius Härtl <jus@bitgrid.net> + - @author Greta Doci <gretadoci@gmail.com> + - @author Christopher Ng <chrng8@gmail.com> + - + - @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/>. + - + --> + +<template> + <div class="background-selector"> + <button class="background filepicker" + :class="{ active: background === 'custom' }" + tabindex="0" + @click="pickFile"> + {{ t('theming', 'Pick from Files') }} + </button> + <button class="background default" + tabindex="0" + :class="{ 'icon-loading': loading === 'default', active: background === 'default' }" + @click="setDefault"> + {{ t('theming', 'Default image') }} + </button> + <button class="background color" + :class="{ active: background === 'custom' }" + tabindex="0" + @click="pickColor"> + {{ t('theming', 'Plain background') }} + </button> + <button v-for="shippedBackground in shippedBackgrounds" + :key="shippedBackground.name" + v-tooltip="shippedBackground.details.attribution" + :class="{ 'icon-loading': loading === shippedBackground.name, active: background === shippedBackground.name }" + tabindex="0" + class="background" + :style="{ 'background-image': 'url(' + shippedBackground.preview + ')' }" + @click="setShipped(shippedBackground.name)" /> + </div> +</template> + +<script> +import axios from '@nextcloud/axios' +import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip' +import { generateUrl } from '@nextcloud/router' +import { loadState } from '@nextcloud/initial-state' +import { getBackgroundUrl } from '../helpers/getBackgroundUrl.js' +import { prefixWithBaseUrl } from '../helpers/prefixWithBaseUrl.js' + +const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') + +export default { + name: 'BackgroundSettings', + directives: { + Tooltip, + }, + props: { + background: { + type: String, + default: 'default', + }, + themingDefaultBackground: { + type: String, + default: '', + }, + }, + data() { + return { + backgroundImage: generateUrl('/apps/theming/background') + '?v=' + Date.now(), + loading: false, + } + }, + computed: { + shippedBackgrounds() { + return Object.keys(shippedBackgroundList).map(fileName => { + return { + name: fileName, + url: prefixWithBaseUrl(fileName), + preview: prefixWithBaseUrl('preview/' + fileName), + details: shippedBackgroundList[fileName], + } + }) + }, + }, + methods: { + async update(data) { + const background = data.type === 'custom' || data.type === 'default' ? data.type : data.value + this.backgroundImage = getBackgroundUrl(background, data.version, this.themingDefaultBackground) + if (data.type === 'color' || (data.type === 'default' && this.themingDefaultBackground === 'backgroundColor')) { + this.$emit('update:background', data) + this.loading = false + return + } + const image = new Image() + image.onload = () => { + this.$emit('update:background', data) + this.loading = false + } + image.src = this.backgroundImage + }, + async setDefault() { + this.loading = 'default' + const result = await axios.post(generateUrl('/apps/theming/background/default')) + this.update(result.data) + }, + async setShipped(shipped) { + this.loading = shipped + const result = await axios.post(generateUrl('/apps/theming/background/shipped'), { value: shipped }) + this.update(result.data) + }, + async setFile(path) { + this.loading = 'custom' + const result = await axios.post(generateUrl('/apps/theming/background/custom'), { value: path }) + this.update(result.data) + }, + async pickColor() { + this.loading = 'color' + const color = OCA && OCA.Theming ? OCA.Theming.color : '#0082c9' + const result = await axios.post(generateUrl('/apps/theming/background/color'), { value: color }) + this.update(result.data) + }, + pickFile() { + window.OC.dialogs.filepicker(t('theming', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => { + if (type === OC.dialogs.FILEPICKER_TYPE_CHOOSE) { + this.setFile(path) + } + }, false, ['image/png', 'image/gif', 'image/jpeg', 'image/svg'], true, OC.dialogs.FILEPICKER_TYPE_CHOOSE) + }, + }, +} +</script> + +<style scoped lang="scss"> +.background-selector { + display: flex; + flex-wrap: wrap; + justify-content: center; + + .background { + width: 176px; + height: 96px; + margin: 8px; + background-size: cover; + background-position: center center; + text-align: center; + border-radius: var(--border-radius-large); + border: 2px solid var(--color-main-background); + overflow: hidden; + + &.current { + background-image: var(--color-background-dark); + } + + &.filepicker, &.default, &.color { + border-color: var(--color-border); + } + + &.color { + background-color: var(--color-primary); + color: var(--color-primary-text); + } + + &.active, + &:hover, + &:focus { + border: 2px solid var(--color-primary); + } + + &.active:not(.icon-loading):after { + background-image: var(--icon-checkmark-white); + background-repeat: no-repeat; + background-position: center; + background-size: 44px; + content: ''; + display: block; + height: 100%; + } + } +} +</style> diff --git a/apps/theming/src/helpers/getBackgroundUrl.js b/apps/theming/src/helpers/getBackgroundUrl.js new file mode 100644 index 00000000000..2e0088f6d30 --- /dev/null +++ b/apps/theming/src/helpers/getBackgroundUrl.js @@ -0,0 +1,51 @@ +/** + * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + * + * @author Avior <florian.bouillon@delta-wings.net> + * @author Julien Veyssier <eneiluj@posteo.net> + * @author Julius Härtl <jus@bitgrid.net> + * + * @license AGPL-3.0-or-later + * + * 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/>. + * + */ + +// FIXME hoist this into a package? The same logic is used in `apps/dashboard/src/helpers/getBackgroundUrl.js` + +import { generateUrl } from '@nextcloud/router' +import { prefixWithBaseUrl } from './prefixWithBaseUrl.js' + +export const getBackgroundUrl = (background, time = 0, themingDefaultBackground = '') => { + const enabledThemes = window.OCA?.Theming?.enabledThemes || [] + const isDarkTheme = (enabledThemes.length === 0 || enabledThemes[0] === 'default') + ? window.matchMedia('(prefers-color-scheme: dark)').matches + : enabledThemes.join('').indexOf('dark') !== -1 + + if (background === 'default') { + if (themingDefaultBackground && themingDefaultBackground !== 'backgroundColor') { + return generateUrl('/apps/theming/image/background') + '?v=' + window.OCA.Theming.cacheBuster + } + + if (isDarkTheme) { + return prefixWithBaseUrl('eduardo-neves-pedra-azul.jpg') + } + + return prefixWithBaseUrl('kamil-porembinski-clouds.jpg') + } else if (background === 'custom') { + return generateUrl('/apps/theming/background') + '?v=' + time + } + + return prefixWithBaseUrl(background) +} diff --git a/apps/theming/src/helpers/prefixWithBaseUrl.js b/apps/theming/src/helpers/prefixWithBaseUrl.js new file mode 100644 index 00000000000..07e4986593c --- /dev/null +++ b/apps/theming/src/helpers/prefixWithBaseUrl.js @@ -0,0 +1,27 @@ +/** + * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license AGPL-3.0-or-later + * + * 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/>. + * + */ + +// FIXME hoist this into a package? The same logic is used in `apps/dashboard/src/helpers/prefixWithBaseUrl.js` + +import { generateFilePath } from '@nextcloud/router' + +export const prefixWithBaseUrl = (url) => generateFilePath('theming', '', 'img/background/') + url |