<template> <div> <ColorPickerContext ref="colorPicker" :value="builder.theme[colorPickerPropertyName] || '#000000ff'" @input="colorPickerColorChanged" ></ColorPickerContext> <div class="theme_settings__section margin-bottom-3"> <div class="theme_settings__section-properties"> <a class="theme_settings__section-title" @click="toggleClosed('colors')" > {{ $t('mainThemeConfigBlock.colorsLabel') }} <i class="iconoir-nav-arrow-down theme_settings__section-title-icon" :class="{ 'theme_settings__section-title-icon': true, 'iconoir-nav-arrow-down': !isClosed('colors'), 'iconoir-nav-arrow-right': isClosed('colors'), }" ></i> </a> <div v-show="!isClosed('colors')"> <div class="control"> <div class="control__elements"> <div class="color-input"> <a ref="primaryColor" class="color-input__preview" :style="{ 'background-color': builder.theme.primary_color }" @click="openColorPicker($refs.primaryColor, 'primary_color')" ></a> <div class="color-input__label"> {{ $t('mainThemeConfigBlock.primaryColor') }} </div> </div> </div> </div> <div class="control"> <div class="control__elements"> <div class="color-input"> <a ref="secondaryColor" class="color-input__preview" :style="{ 'background-color': builder.theme.secondary_color }" @click=" openColorPicker($refs.secondaryColor, 'secondary_color') " ></a> <div class="color-input__label"> {{ $t('mainThemeConfigBlock.secondaryColor') }} </div> </div> </div> </div> </div> </div> </div> <div> <div class="theme_settings__section"> <div class="theme_settings__section-properties"> <a class="theme_settings__section-title" @click="toggleClosed('typography')" > {{ $t('mainThemeConfigBlock.typography') }} <i class="iconoir-nav-arrow-down theme_settings__section-title-icon" :class="{ 'theme_settings__section-title-icon': true, 'iconoir-nav-arrow-down': !isClosed('typography'), 'iconoir-nav-arrow-right': isClosed('typography'), }" ></i> </a> </div> </div> <div v-for="i in headings" v-show="!isClosed('typography')" :key="i" class="theme_settings__section" > <div class="theme_settings__section-properties"> <div class="control"> <div class="control__label"> {{ $t('mainThemeConfigBlock.headingLabel', { i }) }} </div> <div class="control__elements control__elements--flex"> <div class="color-input"> <a ref="headingColor" class="color-input__preview" :style="{ 'background-color': builder.theme[`heading_${i}_color`], }" @click=" openColorPicker( $refs.headingColor[i - 1], `heading_${i}_color` ) " ></a> </div> <div class="input__with-icon"> <input type="number" class="input remove-number-input-controls" :min="fontSizeMin" :max="fontSizeMax" :class="{ 'input--error': $v.builder.theme[`heading_${i}_font_size`].$error, }" :value="builder.theme[`heading_${i}_font_size`]" @input=" ;[ $v.builder.theme[`heading_${i}_font_size`].$touch(), setPropertyInStore( `heading_${i}_font_size`, $event.target.value, !$v.builder.theme[`heading_${i}_font_size`].$error ), ] " /> <i>px</i> </div> </div> <div v-if="$v.builder.theme[`heading_${i}_font_size`].$error" class="error" > {{ $t('mainThemeConfigBlock.fontSizeError') }} </div> </div> </div> <div class="theme_settings__section-preview"> <h1 class="heading-element margin-bottom-2 theme_settings__section-ellipsis" :style="{ '--color': builder.theme[`heading_${i}_color`], '--font-size': builder.theme[`heading_${i}_font_size`] + 'px', }" > {{ $t('mainThemeConfigBlock.headingValue', { i }) }} </h1> </div> </div> </div> </div> </template> <script> import { mapActions } from 'vuex' import { required, integer, minValue, maxValue } from 'vuelidate/lib/validators' import ColorPickerContext from '@baserow/modules/core/components/ColorPickerContext' import { notifyIf } from '@baserow/modules/core/utils/error' const fontSizeMin = 1 const fontSizeMax = 100 const headings = [1, 2, 3] export default { name: 'MainThemeConfigBlock', components: { ColorPickerContext }, props: { builder: { type: Object, required: true, }, }, data() { return { closed: [], colorPickerPropertyName: '', } }, computed: { headings() { return headings }, fontSizeMin() { return fontSizeMin }, fontSizeMax() { return fontSizeMax }, }, methods: { ...mapActions({ setThemeProperty: 'theme/setProperty', forceSetThemeProperty: 'theme/forceSetProperty', }), toggleClosed(value) { const index = this.closed.indexOf(value) if (index < 0) { this.closed.push(value) } else { this.closed.splice(index, 1) } }, isClosed(value) { return this.closed.includes(value) }, openColorPicker(opener, propertyName) { this.colorPickerPropertyName = propertyName this.$refs.colorPicker.toggle(opener) }, colorPickerColorChanged(value) { this.setPropertyInStore(this.colorPickerPropertyName, value) }, async setPropertyInStore(key, value, makeRequest = true) { const action = makeRequest ? 'setThemeProperty' : 'forceSetThemeProperty' try { await this[action]({ builder: this.builder, key, value, }) } catch (error) { notifyIf(error, 'row') } }, }, validations: { builder: { theme: headings.reduce((o, i) => { o[`heading_${i}_font_size`] = { required, integer, minValue: minValue(fontSizeMin), maxValue: maxValue(fontSizeMax), } return o }, {}), }, }, } </script>