server/apps/theming/src/AdminTheming.vue

311 lines
8.4 KiB
Vue

<!--
- @copyright 2022 Christopher Ng <chrng8@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>
<section>
<NcSettingsSection :title="t('theming', 'Theming')"
:description="t('theming', 'Theming makes it possible to easily customize the look and feel of your instance and supported clients. This will be visible for all users.')"
:doc-url="docUrl">
<div class="admin-theming">
<NcNoteCard v-if="!isThemable"
type="error"
:show-alert="true">
<p>{{ notThemableErrorMessage }}</p>
</NcNoteCard>
<TextField v-for="field in textFields"
:key="field.name"
:name="field.name"
:value.sync="field.value"
:default-value="field.defaultValue"
:type="field.type"
:display-name="field.displayName"
:placeholder="field.placeholder"
:maxlength="field.maxlength"
@update:theming="$emit('update:theming')" />
<ColorPickerField :name="colorPickerField.name"
:value.sync="colorPickerField.value"
:default-value="colorPickerField.defaultValue"
:display-name="colorPickerField.displayName"
@update:theming="$emit('update:theming')" />
<FileInputField v-for="field in fileInputFields"
:key="field.name"
:name="field.name"
:mime-name="field.mimeName"
:mime-value.sync="field.mimeValue"
:default-mime-value="field.defaultMimeValue"
:display-name="field.displayName"
:aria-label="field.ariaLabel"
@update:theming="$emit('update:theming')" />
<div class="admin-theming__preview">
<div class="admin-theming__preview-logo" />
</div>
</div>
</NcSettingsSection>
<NcSettingsSection :title="t('theming', 'Advanced options')">
<div class="admin-theming-advanced">
<TextField v-for="field in advancedTextFields"
:key="field.name"
:name="field.name"
:value.sync="field.value"
:default-value="field.defaultValue"
:type="field.type"
:display-name="field.displayName"
:placeholder="field.placeholder"
:maxlength="field.maxlength"
@update:theming="$emit('update:theming')" />
<FileInputField v-for="field in advancedFileInputFields"
:key="field.name"
:name="field.name"
:mime-name="field.mimeName"
:mime-value.sync="field.mimeValue"
:default-mime-value="field.defaultMimeValue"
:display-name="field.displayName"
:aria-label="field.ariaLabel"
@update:theming="$emit('update:theming')" />
<CheckboxField :name="userThemingField.name"
:value="userThemingField.value"
:default-value="userThemingField.defaultValue"
:display-name="userThemingField.displayName"
:label="userThemingField.label"
:description="userThemingField.description"
@update:theming="$emit('update:theming')" />
<a v-if="!canThemeIcons"
:href="docUrlIcons"
rel="noreferrer noopener">
<em>{{ t('theming', 'Install the ImageMagick PHP extension with support for SVG images to automatically generate favicons based on the uploaded logo and color.') }}</em>
</a>
</div>
</NcSettingsSection>
</section>
</template>
<script>
import { loadState } from '@nextcloud/initial-state'
import {
NcNoteCard,
NcSettingsSection,
} from '@nextcloud/vue'
import CheckboxField from './components/admin/CheckboxField.vue'
import ColorPickerField from './components/admin/ColorPickerField.vue'
import FileInputField from './components/admin/FileInputField.vue'
import TextField from './components/admin/TextField.vue'
const {
backgroundMime,
canThemeIcons,
color,
docUrl,
docUrlIcons,
faviconMime,
isThemable,
legalNoticeUrl,
logoheaderMime,
logoMime,
name,
notThemableErrorMessage,
privacyPolicyUrl,
slogan,
url,
userThemingDisabled,
} = loadState('theming', 'adminThemingParameters')
const textFields = [
{
name: 'name',
value: name,
defaultValue: 'Nextcloud',
type: 'text',
displayName: t('theming', 'Name'),
placeholder: t('theming', 'Name'),
maxlength: 250,
},
{
name: 'url',
value: url,
defaultValue: 'https://nextcloud.com',
type: 'url',
displayName: t('theming', 'Web link'),
placeholder: 'https://…',
maxlength: 500,
},
{
name: 'slogan',
value: slogan,
defaultValue: t('theming', 'a safe home for all your data'),
type: 'text',
displayName: t('theming', 'Slogan'),
placeholder: t('theming', 'Slogan'),
maxlength: 500,
},
]
const colorPickerField = {
name: 'color',
value: color,
defaultValue: '#0082c9',
displayName: t('theming', 'Color'),
}
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',
value: legalNoticeUrl,
defaultValue: '',
type: 'url',
displayName: t('theming', 'Legal notice link'),
placeholder: 'https://…',
maxlength: 500,
},
{
name: 'privacyUrl',
value: privacyPolicyUrl,
defaultValue: '',
type: 'url',
displayName: t('theming', 'Privacy policy link'),
placeholder: 'https://…',
maxlength: 500,
},
]
const advancedFileInputFields = [
{
name: 'logoheader',
mimeName: 'logoheaderMime',
mimeValue: logoheaderMime,
defaultMimeValue: '',
displayName: t('theming', 'Header logo'),
ariaLabel: t('theming', 'Upload new header logo'),
},
{
name: 'favicon',
mimeName: 'faviconMime',
mimeValue: faviconMime,
defaultMimeValue: '',
displayName: t('theming', 'Favicon'),
ariaLabel: t('theming', 'Upload new favicon'),
},
]
const userThemingField = {
name: 'disable-user-theming',
value: userThemingDisabled,
defaultValue: false,
displayName: t('theming', 'User settings'),
label: t('theming', 'Disable user theming'),
description: t('theming', 'Although you can select and customize your instance, users can change their background and colors. If you want to enforce your customization, you can toggle this on.'),
}
export default {
name: 'AdminTheming',
components: {
CheckboxField,
ColorPickerField,
FileInputField,
NcNoteCard,
NcSettingsSection,
TextField,
},
emits: [
'update:theming',
],
data() {
return {
textFields,
colorPickerField,
fileInputFields,
advancedTextFields,
advancedFileInputFields,
userThemingField,
canThemeIcons,
docUrl,
docUrlIcons,
isThemable,
notThemableErrorMessage,
}
},
}
</script>
<style lang="scss" scoped>
.admin-theming,
.admin-theming-advanced {
display: flex;
flex-direction: column;
gap: 8px 0;
}
.admin-theming {
&__preview {
width: 230px;
height: 140px;
background-size: cover;
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-default, #0082c9);
/* 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, linear-gradient(40deg, #0082c9 0%, #30b6ff 100%)));
&-logo {
width: 20%;
height: 20%;
margin-top: 20px;
display: inline-block;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
background-image: var(--image-logo, url('../../../core/img/logo/logo.svg'));
}
}
}
</style>