From 3c05fc53cec799d33b59c9596a06a119138b0566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Pardou?= <jeremie@baserow.io> Date: Fri, 22 Dec 2023 10:06:35 +0000 Subject: [PATCH] Resolve "Allow to set more styles on non Root page elements" --- .../builder/api/domains/serializers.py | 6 + .../builder/api/elements/serializers.py | 18 +++ .../contrib/builder/elements/element_types.py | 67 +++++++-- .../contrib/builder/elements/handler.py | 12 ++ .../contrib/builder/elements/models.py | 58 +++++++- .../migrations/0035_add_more_styles.py | 131 ++++++++++++++++++ backend/src/baserow/contrib/builder/types.py | 6 + .../builder/test_builder_application_type.py | 39 ++++++ web-frontend/locales/en.json | 3 +- .../components/elements/ElementPreview.vue | 6 +- .../elements/components/ButtonElement.vue | 8 +- .../components/FormContainerElement.vue | 6 +- .../elements/components/HeadingElement.vue | 1 + .../elements/components/LinkElement.vue | 8 +- .../elements/components/TableElement.vue | 6 +- .../forms/general/ButtonElementForm.vue | 21 +-- .../forms/general/ColumnElementForm.vue | 3 +- .../general/FormContainerElementForm.vue | 13 +- .../forms/general/HeadingElementForm.vue | 44 +++--- .../forms/general/ImageElementForm.vue | 8 +- .../forms/general/InputTextElementForm.vue | 8 +- .../forms/general/LinkElementForm.vue | 17 ++- .../forms/general/ParagraphElementForm.vue | 9 +- .../forms/general/TableElementForm.vue | 14 +- .../forms/general/settings/FontSelector.vue | 31 +---- .../forms/style/DefaultStyleForm.vue | 112 ++++++--------- .../components/forms/style/StyleBoxForm.vue | 106 ++++++-------- .../builder/components/page/PageContent.vue | 6 +- .../builder/components/page/PageElement.vue | 31 +++-- .../components/page/PageRootElement.vue | 61 ++------ .../components/theme/MainThemeConfigBlock.vue | 63 +++------ web-frontend/modules/builder/elementTypes.js | 25 ++-- web-frontend/modules/builder/locales/en.json | 66 +++++---- .../modules/builder/mixins/element.js | 7 + .../modules/builder/mixins/elementForm.js | 29 ++++ .../modules/builder/mixins/pageElement.js | 68 ++++++++- .../modules/builder/mixins/styleForm.js | 50 +++++-- .../core/assets/scss/components/all.scss | 1 + .../assets/scss/components/builder/all.scss | 1 - .../scss/components/builder/element.scss | 32 ++++- .../elements/link-button-element-button.scss | 4 +- .../components/builder/page_root_element.scss | 5 - .../assets/scss/components/color_input.scss | 14 +- .../scss/components/color_input_group.scss | 8 ++ .../modules/core/components/ColorInput.vue | 41 ++++++ .../core/components/ColorInputGroup.vue | 53 +++++++ .../modules/core/components/FormInput.vue | 1 + web-frontend/modules/core/plugins/global.js | 4 + web-frontend/modules/core/utils/colors.js | 3 + 49 files changed, 891 insertions(+), 443 deletions(-) create mode 100644 backend/src/baserow/contrib/builder/migrations/0035_add_more_styles.py create mode 100644 web-frontend/modules/builder/mixins/elementForm.js delete mode 100644 web-frontend/modules/core/assets/scss/components/builder/page_root_element.scss create mode 100644 web-frontend/modules/core/assets/scss/components/color_input_group.scss create mode 100644 web-frontend/modules/core/components/ColorInput.vue create mode 100644 web-frontend/modules/core/components/ColorInputGroup.vue diff --git a/backend/src/baserow/contrib/builder/api/domains/serializers.py b/backend/src/baserow/contrib/builder/api/domains/serializers.py index 460102a8e..bfde07823 100644 --- a/backend/src/baserow/contrib/builder/api/domains/serializers.py +++ b/backend/src/baserow/contrib/builder/api/domains/serializers.py @@ -105,6 +105,12 @@ class PublicElementSerializer(serializers.ModelSerializer): "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", diff --git a/backend/src/baserow/contrib/builder/api/elements/serializers.py b/backend/src/baserow/contrib/builder/api/elements/serializers.py index ffd5f0370..7daaf00f5 100644 --- a/backend/src/baserow/contrib/builder/api/elements/serializers.py +++ b/backend/src/baserow/contrib/builder/api/elements/serializers.py @@ -57,6 +57,12 @@ class ElementSerializer(serializers.ModelSerializer): "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", @@ -106,6 +112,12 @@ class CreateElementSerializer(serializers.ModelSerializer): "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", @@ -122,6 +134,12 @@ class UpdateElementSerializer(serializers.ModelSerializer): "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", diff --git a/backend/src/baserow/contrib/builder/elements/element_types.py b/backend/src/baserow/contrib/builder/elements/element_types.py index e01a551ac..eb5bfdfad 100644 --- a/backend/src/baserow/contrib/builder/elements/element_types.py +++ b/backend/src/baserow/contrib/builder/elements/element_types.py @@ -398,6 +398,7 @@ class HeadingElementType(ElementType): class SerializedDict(ElementDict): value: BaserowFormula + font_color: str level: int @property @@ -417,6 +418,12 @@ class HeadingElementType(ElementType): max_value=6, default=1, ), + "font_color": serializers.CharField( + max_length=20, + required=False, + allow_blank=True, + help_text="Heading font color.", + ), } return overrides @@ -500,6 +507,7 @@ class LinkElementType(ElementType): "target", "width", "alignment", + "button_color", ] allowed_fields = [ "value", @@ -512,6 +520,7 @@ class LinkElementType(ElementType): "target", "width", "alignment", + "button_color", ] class SerializedDict(ElementDict): @@ -524,6 +533,7 @@ class LinkElementType(ElementType): target: str width: str alignment: str + button_color: str def deserialize_property( self, prop_name: str, value: Any, id_mapping: Dict[str, Any] @@ -600,6 +610,12 @@ class LinkElementType(ElementType): help_text=LinkElement._meta.get_field("alignment").help_text, required=False, ), + "button_color": serializers.CharField( + max_length=20, + required=False, + default="primary", + help_text="Button color.", + ), } return overrides @@ -846,13 +862,14 @@ class InputTextElementType(InputElementType): class ButtonElementType(ElementType): type = "button" model_class = ButtonElement - allowed_fields = ["value", "alignment", "width"] - serializer_field_names = ["value", "alignment", "width"] + allowed_fields = ["value", "alignment", "width", "button_color"] + serializer_field_names = ["value", "alignment", "width", "button_color"] class SerializedDict(ElementDict): value: BaserowFormula width: str alignment: str + button_color: str @property def serializer_field_overrides(self): @@ -875,6 +892,12 @@ class ButtonElementType(ElementType): help_text=ButtonElement._meta.get_field("alignment").help_text, required=False, ), + "button_color": serializers.CharField( + max_length=20, + required=False, + default="primary", + help_text="Button color.", + ), } return overrides @@ -896,6 +919,29 @@ class TableElementType(CollectionElementType): type = "table" model_class = TableElement + class SerializedDict(CollectionElementType.SerializedDict): + button_color: str + + @property + def allowed_fields(self): + return super().allowed_fields + ["button_color"] + + @property + def serializer_field_names(self): + return super().serializer_field_names + ["button_color"] + + @property + def serializer_field_overrides(self): + return { + **super().serializer_field_overrides, + "button_color": serializers.CharField( + max_length=20, + required=False, + default="primary", + help_text="Button color.", + ), + } + def get_pytest_params(self, pytest_data_fixture) -> Dict[str, Any]: return {"data_source_id": None} @@ -903,11 +949,12 @@ class TableElementType(CollectionElementType): class FormContainerElementType(ContainerElementType): type = "form_container" model_class = FormContainerElement - allowed_fields = ["submit_button_label"] - serializer_field_names = ["submit_button_label"] + allowed_fields = ["submit_button_label", "button_color"] + serializer_field_names = ["submit_button_label", "button_color"] class SerializedDict(ElementDict): submit_button_label: BaserowFormula + button_color: str def get_pytest_params(self, pytest_data_fixture) -> Dict[str, Any]: return {"submit_button_label": "'Submit'"} @@ -916,7 +963,7 @@ class FormContainerElementType(ContainerElementType): def serializer_field_overrides(self): from baserow.core.formula.serializers import FormulaSerializerField - overrides = { + return { "submit_button_label": FormulaSerializerField( help_text=FormContainerElement._meta.get_field( "submit_button_label" @@ -924,11 +971,15 @@ class FormContainerElementType(ContainerElementType): required=False, allow_blank=True, default="", - ) + ), + "button_color": serializers.CharField( + max_length=20, + required=False, + default="primary", + help_text="Button color.", + ), } - return overrides - @property def child_types_allowed(self) -> List[str]: child_types_allowed = [] diff --git a/backend/src/baserow/contrib/builder/elements/handler.py b/backend/src/baserow/contrib/builder/elements/handler.py index 5cedc9348..ba634317e 100644 --- a/backend/src/baserow/contrib/builder/elements/handler.py +++ b/backend/src/baserow/contrib/builder/elements/handler.py @@ -34,6 +34,12 @@ class ElementHandler: "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", @@ -48,6 +54,12 @@ class ElementHandler: "style_border_bottom_color", "style_border_bottom_size", "style_padding_bottom", + "style_border_left_color", + "style_border_left_size", + "style_padding_left", + "style_border_right_color", + "style_border_right_size", + "style_padding_right", "style_background", "style_background_color", "style_width", diff --git a/backend/src/baserow/contrib/builder/elements/models.py b/backend/src/baserow/contrib/builder/elements/models.py index a2cfcd755..68bd30403 100644 --- a/backend/src/baserow/contrib/builder/elements/models.py +++ b/backend/src/baserow/contrib/builder/elements/models.py @@ -109,7 +109,7 @@ class Element( default=0, help_text="Pixel height of the top border." ) style_padding_top = models.PositiveIntegerField( - default=10, help_text="Padding height of the top border." + default=10, help_text="Padding size of the top border." ) style_border_bottom_color = models.CharField( @@ -122,7 +122,33 @@ class Element( default=0, help_text="Pixel height of the bottom border." ) style_padding_bottom = models.PositiveIntegerField( - default=10, help_text="Padding height of the bottom border." + default=10, help_text="Padding size of the bottom border." + ) + + style_border_left_color = models.CharField( + max_length=20, + default="border", + blank=True, + help_text="Left border color", + ) + style_border_left_size = models.PositiveIntegerField( + default=0, help_text="Pixel height of the left border." + ) + style_padding_left = models.PositiveIntegerField( + default=20, help_text="Padding size of the left border." + ) + + style_border_right_color = models.CharField( + max_length=20, + default="border", + blank=True, + help_text="Right border color", + ) + style_border_right_size = models.PositiveIntegerField( + default=0, help_text="Pixel height of the right border." + ) + style_padding_right = models.PositiveIntegerField( + default=20, help_text="Padding size of the right border." ) style_background = models.CharField( @@ -281,7 +307,7 @@ class ColumnElement(ContainerElement): ], ) column_gap = models.IntegerField( - default=30, + default=20, help_text="The amount of space between the columns.", validators=[ MinValueValidator(0, message="Value cannot be less than 0."), @@ -391,6 +417,12 @@ class LinkElement(Element): max_length=10, default=HorizontalAlignments.LEFT, ) + button_color = models.CharField( + max_length=20, + default="primary", + blank=True, + help_text="The color of the button", + ) class ImageElement(Element): @@ -479,6 +511,12 @@ class ButtonElement(Element): max_length=10, default=HorizontalAlignments.LEFT, ) + button_color = models.CharField( + max_length=20, + default="primary", + blank=True, + help_text="The color of the button", + ) class CollectionField(models.Model): @@ -542,6 +580,13 @@ class TableElement(CollectionElement): A table element """ + button_color = models.CharField( + max_length=20, + default="primary", + blank=True, + help_text="The color of the button", + ) + class FormContainerElement(ContainerElement): """ @@ -550,6 +595,13 @@ class FormContainerElement(ContainerElement): submit_button_label = FormulaField(default="") + button_color = models.CharField( + max_length=20, + default="primary", + blank=True, + help_text="The color of the button", + ) + class DropdownElement(Element): label = FormulaField( diff --git a/backend/src/baserow/contrib/builder/migrations/0035_add_more_styles.py b/backend/src/baserow/contrib/builder/migrations/0035_add_more_styles.py new file mode 100644 index 000000000..58d15364e --- /dev/null +++ b/backend/src/baserow/contrib/builder/migrations/0035_add_more_styles.py @@ -0,0 +1,131 @@ +# Generated by Django 3.2.21 on 2023-12-19 13:35 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("builder", "0034_dropdownelement_dropdownelementoption"), + ] + + operations = [ + migrations.AddField( + model_name="buttonelement", + name="button_color", + field=models.CharField( + blank=True, + default="primary", + help_text="The color of the button", + max_length=20, + ), + ), + migrations.AddField( + model_name="element", + name="style_border_left_color", + field=models.CharField( + blank=True, + default="border", + help_text="Left border color", + max_length=20, + ), + ), + migrations.AddField( + model_name="element", + name="style_border_left_size", + field=models.PositiveIntegerField( + default=0, help_text="Pixel height of the left border." + ), + ), + migrations.AddField( + model_name="element", + name="style_border_right_color", + field=models.CharField( + blank=True, + default="border", + help_text="Right border color", + max_length=20, + ), + ), + migrations.AddField( + model_name="element", + name="style_border_right_size", + field=models.PositiveIntegerField( + default=0, help_text="Pixel height of the right border." + ), + ), + migrations.AddField( + model_name="element", + name="style_padding_left", + field=models.PositiveIntegerField( + default=20, help_text="Padding size of the left border." + ), + ), + migrations.AddField( + model_name="element", + name="style_padding_right", + field=models.PositiveIntegerField( + default=20, help_text="Padding size of the right border." + ), + ), + migrations.AddField( + model_name="formcontainerelement", + name="button_color", + field=models.CharField( + blank=True, + default="primary", + help_text="The color of the button", + max_length=20, + ), + ), + migrations.AddField( + model_name="linkelement", + name="button_color", + field=models.CharField( + blank=True, + default="primary", + help_text="The color of the button", + max_length=20, + ), + ), + migrations.AddField( + model_name="tableelement", + name="button_color", + field=models.CharField( + blank=True, + default="primary", + help_text="The color of the button", + max_length=20, + ), + ), + migrations.AlterField( + model_name="columnelement", + name="column_gap", + field=models.IntegerField( + default=20, + help_text="The amount of space between the columns.", + validators=[ + django.core.validators.MinValueValidator( + 0, message="Value cannot be less than 0." + ), + django.core.validators.MaxValueValidator( + 2000, message="Value cannot be greater than 2000." + ), + ], + ), + ), + migrations.AlterField( + model_name="element", + name="style_padding_bottom", + field=models.PositiveIntegerField( + default=10, help_text="Padding size of the bottom border." + ), + ), + migrations.AlterField( + model_name="element", + name="style_padding_top", + field=models.PositiveIntegerField( + default=10, help_text="Padding size of the top border." + ), + ), + ] diff --git a/backend/src/baserow/contrib/builder/types.py b/backend/src/baserow/contrib/builder/types.py index 8c1605809..0d751541f 100644 --- a/backend/src/baserow/contrib/builder/types.py +++ b/backend/src/baserow/contrib/builder/types.py @@ -19,6 +19,12 @@ class ElementDict(TypedDict): style_border_bottom_color: str style_border_bottom_size: int style_padding_bottom: int + style_border_left_color: str + style_border_left_size: int + style_padding_left: int + style_border_right_color: str + style_border_right_size: int + style_padding_right: int style_background: str style_background_color: str style_width: str diff --git a/backend/tests/baserow/contrib/builder/test_builder_application_type.py b/backend/tests/baserow/contrib/builder/test_builder_application_type.py index 535d5f0f8..7301c7a67 100644 --- a/backend/tests/baserow/contrib/builder/test_builder_application_type.py +++ b/backend/tests/baserow/contrib/builder/test_builder_application_type.py @@ -128,14 +128,21 @@ def test_builder_application_export(data_fixture): "order": str(element1.order), "parent_element_id": None, "place_in_container": None, + "font_color": "default", "style_background_color": "#ffffffff", "style_border_bottom_color": "border", "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "value": element1.value, "level": element1.level, @@ -151,9 +158,15 @@ def test_builder_application_export(data_fixture): "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "value": element2.value, }, @@ -167,9 +180,15 @@ def test_builder_application_export(data_fixture): "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "order": str(element_container.order), "column_amount": 3, @@ -186,9 +205,15 @@ def test_builder_application_export(data_fixture): "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "order": str(element_inside_container.order), "value": element_inside_container.value, @@ -241,14 +266,21 @@ def test_builder_application_export(data_fixture): "order": str(element3.order), "parent_element_id": None, "place_in_container": None, + "font_color": "default", "style_background_color": "#ffffffff", "style_border_bottom_color": "border", "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "value": element3.value, "level": element3.level, @@ -257,6 +289,7 @@ def test_builder_application_export(data_fixture): "id": element4.id, "type": "table", "order": str(element4.order), + "button_color": "primary", "parent_element_id": None, "place_in_container": None, "style_background_color": "#ffffffff", @@ -264,9 +297,15 @@ def test_builder_application_export(data_fixture): "style_border_bottom_size": 0, "style_border_top_color": "border", "style_border_top_size": 0, + "style_border_left_color": "border", + "style_border_left_size": 0, + "style_border_right_color": "border", + "style_border_right_size": 0, "style_width": "normal", "style_padding_top": 10, "style_padding_bottom": 10, + "style_padding_left": 20, + "style_padding_right": 20, "style_background": "none", "items_per_page": 42, "data_source_id": element4.data_source.id, diff --git a/web-frontend/locales/en.json b/web-frontend/locales/en.json index 103a826d3..1ae7006f0 100644 --- a/web-frontend/locales/en.json +++ b/web-frontend/locales/en.json @@ -73,7 +73,8 @@ "requiredField": "This field is required.", "integerField": "The field must be an integer.", "minValueField": "The field must be greater than or equal to {min}.", - "maxValueField": "The field must be less than or equal to {max}." + "maxValueField": "The field must be less than or equal to {max}.", + "minMaxValueField": "The field value must be between {min} and {max}." }, "permission": { "admin": "Admin", diff --git a/web-frontend/modules/builder/components/elements/ElementPreview.vue b/web-frontend/modules/builder/components/elements/ElementPreview.vue index 6d59c40c1..6cb20ba4a 100644 --- a/web-frontend/modules/builder/components/elements/ElementPreview.vue +++ b/web-frontend/modules/builder/components/elements/ElementPreview.vue @@ -25,11 +25,11 @@ @select-parent="actionSelectElement({ element: parentElement })" /> - <PageRootElement + <PageElement v-if="isRootElement" :element="element" :mode="mode" - ></PageRootElement> + ></PageElement> <PageElement v-else :element="element" :mode="mode" /> <InsertElementButton @@ -58,7 +58,6 @@ import { PLACEMENTS } from '@baserow/modules/builder/enums' import AddElementModal from '@baserow/modules/builder/components/elements/AddElementModal' import { notifyIf } from '@baserow/modules/core/utils/error' import { mapActions, mapGetters } from 'vuex' -import PageRootElement from '@baserow/modules/builder/components/page/PageRootElement' import { checkIntermediateElements } from '@baserow/modules/core/utils/dom' export default { @@ -68,7 +67,6 @@ export default { ElementMenu, InsertElementButton, PageElement, - PageRootElement, }, inject: ['builder', 'page', 'mode'], props: { diff --git a/web-frontend/modules/builder/components/elements/components/ButtonElement.vue b/web-frontend/modules/builder/components/elements/components/ButtonElement.vue index a6626dc23..08ffc9596 100644 --- a/web-frontend/modules/builder/components/elements/components/ButtonElement.vue +++ b/web-frontend/modules/builder/components/elements/components/ButtonElement.vue @@ -1,5 +1,11 @@ <template> - <div class="button-element" :class="classes"> + <div + class="button-element" + :class="classes" + :style="{ + '--button-color': resolveColor(element.button_color, colorVariables), + }" + > <button class="link-button-element-button" :class="{ diff --git a/web-frontend/modules/builder/components/elements/components/FormContainerElement.vue b/web-frontend/modules/builder/components/elements/components/FormContainerElement.vue index 9c9f2a875..4423d77ea 100644 --- a/web-frontend/modules/builder/components/elements/components/FormContainerElement.vue +++ b/web-frontend/modules/builder/components/elements/components/FormContainerElement.vue @@ -1,5 +1,9 @@ <template> - <div> + <div + :style="{ + '--button-color': resolveColor(element.button_color, colorVariables), + }" + > <div v-if="mode === 'editing' && children.length === 0"> <AddElementZone @add-element="showAddElementModal"></AddElementZone> <AddElementModal diff --git a/web-frontend/modules/builder/components/elements/components/HeadingElement.vue b/web-frontend/modules/builder/components/elements/components/HeadingElement.vue index 2d296f8ca..0c2dfdf87 100644 --- a/web-frontend/modules/builder/components/elements/components/HeadingElement.vue +++ b/web-frontend/modules/builder/components/elements/components/HeadingElement.vue @@ -5,6 +5,7 @@ :class="{ 'element--no-value': !resolvedValue }" :style="{ '--color': resolveColor(element.font_color, headingColorVariables), + '--font-size': `${builder.theme[`heading_${element.level}_font_size`]}px`, }" > {{ resolvedValue || $t('headingElement.noValue') }} diff --git a/web-frontend/modules/builder/components/elements/components/LinkElement.vue b/web-frontend/modules/builder/components/elements/components/LinkElement.vue index b840a4a4a..8340fc293 100644 --- a/web-frontend/modules/builder/components/elements/components/LinkElement.vue +++ b/web-frontend/modules/builder/components/elements/components/LinkElement.vue @@ -1,5 +1,11 @@ <template> - <div class="link-element" :class="classes"> + <div + class="link-element" + :class="classes" + :style="{ + '--button-color': resolveColor(element.button_color, colorVariables), + }" + > <a :class="{ 'link-element__link': element.variant !== 'button', diff --git a/web-frontend/modules/builder/components/elements/components/TableElement.vue b/web-frontend/modules/builder/components/elements/components/TableElement.vue index 6ced799c6..a0c05a71a 100644 --- a/web-frontend/modules/builder/components/elements/components/TableElement.vue +++ b/web-frontend/modules/builder/components/elements/components/TableElement.vue @@ -1,5 +1,9 @@ <template> - <div> + <div + :style="{ + '--button-color': resolveColor(element.button_color, colorVariables), + }" + > <BaserowTable :fields="element.fields" :rows="rows"> <template #cell-content="{ field, value }"> <component diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/ButtonElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/ButtonElementForm.vue index e504cc31e..77fb86f0e 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/ButtonElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/ButtonElementForm.vue @@ -12,20 +12,21 @@ <FormElement class="control"> <WidthSelector v-model="values.width" /> </FormElement> + <ColorInputGroup + v-model="values.button_color" + :label="$t('buttonElementForm.buttonColor')" + :color-variables="colorVariables" + /> </form> </template> <script> import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup' -import form from '@baserow/modules/core/mixins/form' -import { - DATA_PROVIDERS_ALLOWED_ELEMENTS, - HORIZONTAL_ALIGNMENTS, - WIDTHS, -} from '@baserow/modules/builder/enums' +import { HORIZONTAL_ALIGNMENTS, WIDTHS } from '@baserow/modules/builder/enums' import HorizontalAlignmentsSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/HorizontalAlignmentsSelector' - import WidthSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/WidthSelector' +import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'ButtonElementForm', @@ -34,7 +35,7 @@ export default { ApplicationBuilderFormulaInputGroup, HorizontalAlignmentsSelector, }, - mixins: [form], + mixins: [elementForm], data() { return { values: { @@ -45,7 +46,9 @@ export default { } }, computed: { - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, + colorVariables() { + return themeToColorVariables(this.builder.theme) + }, }, } </script> diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/ColumnElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/ColumnElementForm.vue index db450ee15..65756d95e 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/ColumnElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/ColumnElementForm.vue @@ -48,13 +48,14 @@ import form from '@baserow/modules/core/mixins/form' import { VERTICAL_ALIGNMENTS } from '@baserow/modules/builder/enums' import { required, integer, minValue, maxValue } from 'vuelidate/lib/validators' import VerticalAlignmentSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/VerticalAlignmentSelector' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'ColumnElementForm', components: { VerticalAlignmentSelector, }, - mixins: [form], + mixins: [elementForm], data() { return { values: { diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/FormContainerElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/FormContainerElementForm.vue index d31075fbb..353dc1cdd 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/FormContainerElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/FormContainerElementForm.vue @@ -6,18 +6,22 @@ :label="$t('formContainerElementForm.submitButtonLabel')" :placeholder="$t('formContainerElementForm.submitButtonPlaceholder')" /> + <ColorInputGroup + v-model="values.button_color" + :label="$t('formContainerElementForm.buttonColor')" + :color-variables="colorVariables" + /> </form> </template> <script> -import form from '@baserow/modules/core/mixins/form' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup.vue' -import { DATA_PROVIDERS_ALLOWED_ELEMENTS } from '@baserow/modules/builder/enums' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'FormContainerElementForm', components: { ApplicationBuilderFormulaInputGroup }, - mixins: [form], + mixins: [elementForm], data() { return { values: { @@ -25,8 +29,5 @@ export default { }, } }, - computed: { - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, - }, } </script> diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/HeadingElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/HeadingElementForm.vue index 15bf31fb1..c785c2e4f 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/HeadingElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/HeadingElementForm.vue @@ -1,22 +1,17 @@ <template> <form @submit.prevent @keydown.enter.prevent> - <FormElement class="control"> - <label class="control__label"> - {{ $t('headingElementForm.levelTitle') }} - </label> - <div class="control__elements"> - <Dropdown v-model="values.level" :show-search="false"> - <DropdownItem - v-for="level in levels" - :key="level.value" - :name="level.name" - :value="level.value" - > - {{ level.name }} - </DropdownItem> - </Dropdown> - </div> - </FormElement> + <FormGroup :label="$t('headingElementForm.levelTitle')"> + <Dropdown v-model="values.level" :show-search="false"> + <DropdownItem + v-for="level in levels" + :key="level.value" + :name="level.name" + :value="level.value" + > + {{ level.name }} + </DropdownItem> + </Dropdown> + </FormGroup> <ApplicationBuilderFormulaInputGroup v-model="values.value" :label="$t('headingElementForm.textTitle')" @@ -32,22 +27,24 @@ </template> <script> -import form from '@baserow/modules/core/mixins/form' -import { DATA_PROVIDERS_ALLOWED_ELEMENTS } from '@baserow/modules/builder/enums' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup' import headingElement from '@baserow/modules/builder/mixins/headingElement' import FontSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/FontSelector' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'HeaderElementForm', - components: { FontSelector, ApplicationBuilderFormulaInputGroup }, - mixins: [form, headingElement], - inject: ['builder'], + components: { + FontSelector, + ApplicationBuilderFormulaInputGroup, + }, + mixins: [elementForm, headingElement], data() { return { values: { value: '', level: 1, + font_color: '', }, levels: [...Array(6).keys()].map((level) => ({ name: this.$t('headingElementForm.headingName', { level: level + 1 }), @@ -55,8 +52,5 @@ export default { })), } }, - computed: { - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, - }, } </script> diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/ImageElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/ImageElementForm.vue index aac54bf20..74431e689 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/ImageElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/ImageElementForm.vue @@ -46,7 +46,6 @@ <FormElement v-if="values.image_source_type === IMAGE_SOURCE_TYPES.URL" class="control" - :error="fieldHasErrors('image_url')" > <div class="control__elements"> <div class="control__description"> @@ -54,7 +53,6 @@ </div> <ApplicationBuilderFormulaInputGroup v-model="values.image_url" - :class="{ 'input--error': fieldHasErrors('image_url') }" :placeholder="$t('elementForms.urlInputPlaceholder')" :data-providers-allowed="DATA_PROVIDERS_ALLOWED_ELEMENTS" /> @@ -82,9 +80,7 @@ </template> <script> -import form from '@baserow/modules/core/mixins/form' import { - DATA_PROVIDERS_ALLOWED_ELEMENTS, HORIZONTAL_ALIGNMENTS, IMAGE_SOURCE_TYPES, } from '@baserow/modules/builder/enums' @@ -93,6 +89,7 @@ import UserFilesModal from '@baserow/modules/core/components/files/UserFilesModa import { UploadFileUserFileUploadType } from '@baserow/modules/core/userFileUploadTypes' import HorizontalAlignmentSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/HorizontalAlignmentsSelector' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup.vue' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'ImageElementForm', @@ -101,7 +98,7 @@ export default { HorizontalAlignmentSelector, UserFilesModal, }, - mixins: [form], + mixins: [elementForm], data() { return { values: { @@ -120,7 +117,6 @@ export default { IMAGE_FILE_TYPES() { return IMAGE_FILE_TYPES }, - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, }, methods: { openFileUploadModal() { diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/InputTextElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/InputTextElementForm.vue index 603bc026c..fa7a168e4 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/InputTextElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/InputTextElementForm.vue @@ -32,12 +32,12 @@ <script> import form from '@baserow/modules/core/mixins/form' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup.vue' -import { DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS } from '@baserow/modules/builder/enums' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'InputTextElementForm', components: { ApplicationBuilderFormulaInputGroup }, - mixins: [form], + mixins: [elementForm], data() { return { values: { @@ -48,10 +48,6 @@ export default { }, } }, - computed: { - DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS: () => - DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS, - }, methods: { emitChange(newValues) { if (this.isFormValid()) { diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/LinkElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/LinkElementForm.vue index cc938f803..6c2ede55b 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/LinkElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/LinkElementForm.vue @@ -113,21 +113,22 @@ <FormElement v-if="values.variant === 'button'" class="control"> <WidthSelector v-model="values.width" /> </FormElement> + <ColorInputGroup + v-model="values.button_color" + :label="$t('linkElementForm.buttonColor')" + :color-variables="colorVariables" + /> </form> </template> <script> -import form from '@baserow/modules/core/mixins/form' import { LinkElementType } from '@baserow/modules/builder/elementTypes' import HorizontalAlignmentSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/HorizontalAlignmentsSelector' -import { - DATA_PROVIDERS_ALLOWED_ELEMENTS, - HORIZONTAL_ALIGNMENTS, - WIDTHS, -} from '@baserow/modules/builder/enums' +import { HORIZONTAL_ALIGNMENTS, WIDTHS } from '@baserow/modules/builder/enums' import WidthSelector from '@baserow/modules/builder/components/elements/components/forms/general/settings/WidthSelector' import { PageParameterDataProviderType } from '@baserow/modules/builder/dataProviderTypes' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'LinkElementForm', @@ -136,8 +137,7 @@ export default { ApplicationBuilderFormulaInputGroup, HorizontalAlignmentSelector, }, - mixins: [form], - inject: ['builder', 'page'], + mixins: [elementForm], data() { let navigateTo = '' if (this.defaultValues.navigation_type === 'page') { @@ -164,7 +164,6 @@ export default { } }, computed: { - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, DATA_PROVIDERS_ALLOWED_PAGE_PARAMETERS() { const PROVIDERS_TO_REMOVE = [ new PageParameterDataProviderType().getType(), diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/ParagraphElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/ParagraphElementForm.vue index 60271f412..31a3ef1d7 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/ParagraphElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/ParagraphElementForm.vue @@ -10,15 +10,13 @@ </template> <script> -import form from '@baserow/modules/core/mixins/form' - -import { DATA_PROVIDERS_ALLOWED_ELEMENTS } from '@baserow/modules/builder/enums' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'ParagraphElementForm', components: { ApplicationBuilderFormulaInputGroup }, - mixins: [form], + mixins: [elementForm], data() { return { values: { @@ -26,8 +24,5 @@ export default { }, } }, - computed: { - DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, - }, } </script> diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/TableElementForm.vue b/web-frontend/modules/builder/components/elements/components/forms/general/TableElementForm.vue index 0e04dc9db..4914ea114 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/TableElementForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/TableElementForm.vue @@ -133,12 +133,15 @@ </template> <p v-else>{{ $t('tableElementForm.selectSourceFirst') }}</p> </FormElement> + <ColorInputGroup + v-model="values.button_color" + :label="$t('tableElementForm.buttonColor')" + :color-variables="colorVariables" + /> </form> </template> <script> -import form from '@baserow/modules/core/mixins/form' -import { DATA_PROVIDERS_ALLOWED_ELEMENTS } from '@baserow/modules/builder/enums' import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup' import { getNextAvailableNameInSequence, @@ -152,12 +155,12 @@ import { maxValue, } from 'vuelidate/lib/validators' import { mapGetters } from 'vuex' +import elementForm from '@baserow/modules/builder/mixins/elementForm' export default { name: 'TableElementForm', components: { ApplicationBuilderFormulaInputGroup }, - mixins: [form], - inject: ['page'], + mixins: [elementForm], data() { return { allowedValues: ['data_source_id', 'fields', 'items_per_page'], @@ -206,9 +209,6 @@ export default { collectionTypes() { return this.$registry.getAll('collectionField') }, - DATA_PROVIDERS_ALLOWED_ELEMENTS() { - return DATA_PROVIDERS_ALLOWED_ELEMENTS - }, ...mapGetters({ element: 'element/getSelected', }), diff --git a/web-frontend/modules/builder/components/elements/components/forms/general/settings/FontSelector.vue b/web-frontend/modules/builder/components/elements/components/forms/general/settings/FontSelector.vue index 17fb1612b..d3abe283a 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/general/settings/FontSelector.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/general/settings/FontSelector.vue @@ -1,36 +1,19 @@ <template> - <FormElement class="control"> - <label class="control__label"> - {{ $t('fontSidePanelForm.label') }} - </label> - <div class="control__elements"> - <div class="color-input"> - <ColorPickerContext - ref="colorPicker" - v-model="values.font_color" - :variables="colorVariables" - ></ColorPickerContext> - <a - ref="fontColor" - class="color-input__preview" - :style="{ - 'background-color': resolveColor(values.font_color, colorVariables), - }" - @click="$refs.colorPicker.toggle($refs.fontColor)" - ></a> - </div> - </div> - </FormElement> + <ColorInputGroup + v-model="values.font_color" + :label="$t('fontSidePanelForm.label')" + :color-variables="colorVariables" + /> </template> <script> -import ColorPickerContext from '@baserow/modules/core/components/ColorPickerContext' +import ColorInputGroup from '@baserow/modules/core/components/ColorInputGroup' import form from '@baserow/modules/core/mixins/form' import { resolveColor } from '@baserow/modules/core/utils/colors' export default { name: 'FontSelector', - components: { ColorPickerContext }, + components: { ColorInputGroup }, mixins: [form], props: { colorVariables: { diff --git a/web-frontend/modules/builder/components/elements/components/forms/style/DefaultStyleForm.vue b/web-frontend/modules/builder/components/elements/components/forms/style/DefaultStyleForm.vue index c35c5c44f..2237f5e92 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/style/DefaultStyleForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/style/DefaultStyleForm.vue @@ -1,74 +1,49 @@ <template> <form @submit.prevent> <StyleBoxForm - v-model="boxStyles.top" - :label="$t('defaultStyleForm.boxTop')" - :padding-is-allowed="isStyleAllowed('style_padding_top')" - :border-color-is-allowed="isStyleAllowed('style_border_top_color')" - :border-size-is-allowed="isStyleAllowed('style_border_top_size')" + v-for="{ name, label } in borders" + :key="name" + v-model="boxStyles[name]" + :label="label" + :padding-is-allowed="isStyleAllowed(`style_padding_${name}`)" + :border-is-allowed="isStyleAllowed(`style_border_${name}`)" /> - <StyleBoxForm - v-model="boxStyles.bottom" - :label="$t('defaultStyleForm.boxBottom')" - :padding-is-allowed="isStyleAllowed('style_padding_bottom')" - :border-color-is-allowed="isStyleAllowed('style_border_bottom_color')" - :border-size-is-allowed="isStyleAllowed('style_border_bottom_size')" - /> - <FormElement v-if="isStyleAllowed('style_background')" class="control"> - <label class="control__label">{{ - $t('defaultStyleForm.backgroundLabel') - }}</label> - <div class="control__elements"> - <Dropdown v-model="values.style_background"> - <DropdownItem - v-for="type in Object.values(BACKGROUND_TYPES)" - :key="type.value" - :name="$t(type.name)" - :value="type.value" - ></DropdownItem> - </Dropdown> - <div - v-if=" - values.style_background === BACKGROUND_TYPES.COLOR.value && - isStyleAllowed('style_background_color') - " - class="color-input margin-top-2" - > - <ColorPickerContext - ref="colorPicker" - v-model="values.style_background_color" - :variables="colorVariables" - ></ColorPickerContext> - <a - ref="backgroundColor" - class="color-input__preview margin-right-2" - :style="{ - 'background-color': resolveColor( - values.style_background_color, - colorVariables - ), - }" - @click="$refs.colorPicker.toggle($refs.backgroundColor)" - ></a> - {{ $t('defaultStyleForm.backgroundColor') }} - </div> - </div> - </FormElement> - <FormElement v-if="isStyleAllowed('style_width')" class="control"> - <label class="control__label">{{ - $t('defaultStyleForm.widthLabel') - }}</label> - <div class="control__elements"> - <Dropdown v-model="values.style_width"> - <DropdownItem - v-for="type in Object.values(WIDTH_TYPES)" - :key="type.value" - :name="$t(type.name)" - :value="type.value" - ></DropdownItem> - </Dropdown> - </div> - </FormElement> + <FormGroup + v-if="isStyleAllowed('style_background')" + :label="$t('defaultStyleForm.backgroundLabel')" + > + <Dropdown v-model="values.style_background"> + <DropdownItem + v-for="type in Object.values(BACKGROUND_TYPES)" + :key="type.value" + :name="$t(type.name)" + :value="type.value" + /> + </Dropdown> + <ColorInputGroup + v-if=" + values.style_background === BACKGROUND_TYPES.COLOR.value && + isStyleAllowed('style_background_color') + " + v-model="values.style_background_color" + label-after + class="margin-top-2" + :label="$t('defaultStyleForm.backgroundColor')" + :color-variables="colorVariables" + /> + </FormGroup> + <FormGroup + v-if="isStyleAllowed('style_width')" + :label="$t('defaultStyleForm.widthLabel')" + > + <Dropdown v-model="values.style_width"> + <DropdownItem + v-for="type in Object.values(WIDTH_TYPES)" + :key="type.value" + :name="$t(type.name)" + :value="type.value" + ></DropdownItem> </Dropdown + ></FormGroup> </form> </template> @@ -76,10 +51,9 @@ import StyleBoxForm from '@baserow/modules/builder/components/elements/components/forms/style/StyleBoxForm' import styleForm from '@baserow/modules/builder/mixins/styleForm' import { BACKGROUND_TYPES, WIDTH_TYPES } from '@baserow/modules/builder/enums' -import ColorPickerContext from '@baserow/modules/core/components/ColorPickerContext' export default { - components: { StyleBoxForm, ColorPickerContext }, + components: { StyleBoxForm }, mixins: [styleForm], computed: { BACKGROUND_TYPES: () => BACKGROUND_TYPES, diff --git a/web-frontend/modules/builder/components/elements/components/forms/style/StyleBoxForm.vue b/web-frontend/modules/builder/components/elements/components/forms/style/StyleBoxForm.vue index af2cd06e9..1bcaf179f 100644 --- a/web-frontend/modules/builder/components/elements/components/forms/style/StyleBoxForm.vue +++ b/web-frontend/modules/builder/components/elements/components/forms/style/StyleBoxForm.vue @@ -1,79 +1,60 @@ <template> <form @submit.prevent> - <FormElement class="control"> - <label class="control__label">{{ label }}</label> - <div class="control__elements"> - <div - v-if="borderSizeIsAllowed || paddingIsAllowed" - class="row margin-bottom-2" - style="--gap: 6px" - > - <div v-if="borderSizeIsAllowed" class="col col-3"> - <div class="margin-bottom-1"> - {{ $t('styleBoxForm.borderLabel') }} - </div> - <input - v-model="values.border_size" - type="number" - class="input" - :class="{ - 'input--error': error, - }" - @blur="$v.values.border_size.$touch()" - /> + <FormGroup :label="label" :error="error"> + <div + v-if="borderIsAllowed || paddingIsAllowed" + class="row margin-bottom-2" + style="--gap: 6px" + > + <div v-if="borderIsAllowed" class="col col-3"> + <div class="margin-bottom-1"> + {{ $t('styleBoxForm.borderLabel') }} </div> - <div v-if="paddingIsAllowed" class="col col-3"> - <div class="margin-bottom-1"> - {{ $t('styleBoxForm.paddingLabel') }} - </div> - <input - v-model="values.padding" - type="number" - class="input" - :class="{ - 'input--error': error, - }" - @blur="$v.values.padding.$touch()" - /> - </div> - </div> - <div v-if="borderColorIsAllowed" class="color-input"> - <ColorPickerContext - ref="colorPicker" - v-model="values.border_color" - :variables="colorVariables" - ></ColorPickerContext> - <a - ref="borderColor" - class="color-input__preview margin-right-2" - :style="{ - 'background-color': resolveColor( - values.border_color, - colorVariables - ), + <input + v-model="values.border_size" + type="number" + class="input" + :class="{ + 'input--error': error, }" - @click="$refs.colorPicker.toggle($refs.borderColor)" - ></a> - {{ $t('styleBoxForm.borderLabel') }} + @blur="$v.values.border_size.$touch()" + /> </div> - <div v-if="error" class="error"> - {{ error }} + <div v-if="paddingIsAllowed" class="col col-3"> + <div class="margin-bottom-1"> + {{ $t('styleBoxForm.paddingLabel') }} + </div> + <input + v-model="values.padding" + type="number" + class="input" + :class="{ + 'input--error': error, + }" + @blur="$v.values.padding.$touch()" + /> </div> </div> - </FormElement> + <ColorInputGroup + v-if="borderIsAllowed" + v-model="values.border_color" + label-after + class="margin-top-2" + :label="$t('styleBoxForm.borderLabel')" + :color-variables="colorVariables" + /> + </FormGroup> </form> </template> <script> import { required, integer, between } from 'vuelidate/lib/validators' import form from '@baserow/modules/core/mixins/form' -import ColorPickerContext from '@baserow/modules/core/components/ColorPickerContext.vue' import { resolveColor } from '@baserow/modules/core/utils/colors' import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' export default { name: 'StyleBoxForm', - components: { ColorPickerContext }, mixins: [form], inject: ['builder'], props: { @@ -90,12 +71,7 @@ export default { required: false, default: () => false, }, - borderColorIsAllowed: { - type: Boolean, - required: false, - default: () => false, - }, - borderSizeIsAllowed: { + borderIsAllowed: { type: Boolean, required: false, default: () => false, @@ -120,7 +96,7 @@ export default { */ error() { if (this.$v.values.padding.$error || this.$v.values.border_size.$error) { - return this.$t('error.minMaxLength', { min: 0, max: 200 }) + return this.$t('error.minMaxValueField', { min: 0, max: 200 }) } else { return '' } diff --git a/web-frontend/modules/builder/components/page/PageContent.vue b/web-frontend/modules/builder/components/page/PageContent.vue index 0f0281fd2..36da4f235 100644 --- a/web-frontend/modules/builder/components/page/PageContent.vue +++ b/web-frontend/modules/builder/components/page/PageContent.vue @@ -1,6 +1,6 @@ <template> <div> - <PageRootElement + <PageElement v-for="element in elements" :key="element.id" :element="element" @@ -10,10 +10,10 @@ </template> <script> -import PageRootElement from '@baserow/modules/builder/components/page/PageRootElement' +import PageElement from '@baserow/modules/builder/components/page/PageElement' export default { - components: { PageRootElement }, + components: { PageElement }, inject: ['builder', 'mode'], props: { page: { diff --git a/web-frontend/modules/builder/components/page/PageElement.vue b/web-frontend/modules/builder/components/page/PageElement.vue index 3b422470a..7500f1e68 100644 --- a/web-frontend/modules/builder/components/page/PageElement.vue +++ b/web-frontend/modules/builder/components/page/PageElement.vue @@ -1,19 +1,32 @@ <template> - <div class="element__wrapper" :style="wrapperStyles"> - <component - :is="component" - :element="element" - :children="children" - class="element" - /> + <div + class="element__wrapper" + :class="{ + 'element__wrapper--full-width': + element.style_width === WIDTH_TYPES.FULL.value, + 'element__wrapper--medium-width': + element.style_width === WIDTH_TYPES.MEDIUM.value, + 'element__wrapper--small-width': + element.style_width === WIDTH_TYPES.SMALL.value, + }" + :style="wrapperStyles" + > + <div class="element__inner-wrapper" :style="innerWrapperStyles"> + <component + :is="component" + :element="element" + :children="children" + class="element" + /> + </div> </div> </template> <script> -import PageElement from '@baserow/modules/builder/mixins/pageElement' +import pageElement from '@baserow/modules/builder/mixins/pageElement' export default { name: 'PageElement', - mixins: [PageElement], + mixins: [pageElement], } </script> diff --git a/web-frontend/modules/builder/components/page/PageRootElement.vue b/web-frontend/modules/builder/components/page/PageRootElement.vue index 912abd4d2..e7a76f5af 100644 --- a/web-frontend/modules/builder/components/page/PageRootElement.vue +++ b/web-frontend/modules/builder/components/page/PageRootElement.vue @@ -1,61 +1,30 @@ <template> <div - class="page-root-element__inner" - :style="{ - '--background-color': - element.style_background === BACKGROUND_TYPES.COLOR.value - ? resolveColor(element.style_background_color, colorVariables) - : 'transparent', - '--border-top': border( - element.style_border_top_size, - element.style_border_top_color - ), - '--border-bottom': border( - element.style_border_bottom_size, - element.style_border_bottom_color - ), + class="element__wrapper" + :class="{ + 'element__wrapper--full-width': + element.style_width === WIDTH_TYPES.FULL.value, + 'element__wrapper--medium-width': + element.style_width === WIDTH_TYPES.MEDIUM.value, + 'element__wrapper--small-width': + element.style_width === WIDTH_TYPES.SMALL.value, }" + :style="wrapperStyles" > - <div - class="element__wrapper element__wrapper--normal-width" - :class="{ - 'element__wrapper--full-width': - element.style_width === WIDTH_TYPES.FULL.value, - 'element__wrapper--medium-width': - element.style_width === WIDTH_TYPES.MEDIUM.value, - 'element__wrapper--small-width': - element.style_width === WIDTH_TYPES.SMALL.value, - }" - :style="wrapperStyles" - > - <component - :is="component" - :element="element" - :children="children" - class="element" - /> - </div> + <component + :is="component" + :element="element" + :children="children" + class="element" + /> </div> </template> <script> import pageElement from '@baserow/modules/builder/mixins/pageElement' -import { BACKGROUND_TYPES, WIDTH_TYPES } from '@baserow/modules/builder/enums' export default { name: 'PageRootElement', mixins: [pageElement], - computed: { - BACKGROUND_TYPES: () => BACKGROUND_TYPES, - WIDTH_TYPES: () => WIDTH_TYPES, - }, - methods: { - border(size, color) { - return `solid ${size || 0}px ${this.resolveColor( - color, - this.colorVariables - )}` - }, - }, } </script> diff --git a/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue b/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue index a3545667a..d0c7e1e36 100644 --- a/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue +++ b/web-frontend/modules/builder/components/theme/MainThemeConfigBlock.vue @@ -22,38 +22,18 @@ ></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> + <ColorInputGroup + :value="builder.theme.primary_color" + label-after + :label="$t('mainThemeConfigBlock.primaryColor')" + @input="setPropertyInStore('primary_color', $event)" + /> + <ColorInputGroup + :value="builder.theme.secondary_color" + label-after + :label="$t('mainThemeConfigBlock.secondaryColor')" + @input="setPropertyInStore('secondary_color', $event)" + /> </div> </div> </div> @@ -88,21 +68,10 @@ {{ $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> + <ColorInput + :value="builder.theme[`heading_${i}_color`]" + @input="setPropertyInStore(`heading_${i}_color`, $event)" + /> <div class="input__with-icon"> <input type="number" diff --git a/web-frontend/modules/builder/elementTypes.js b/web-frontend/modules/builder/elementTypes.js index bad9ea40d..fd7996940 100644 --- a/web-frontend/modules/builder/elementTypes.js +++ b/web-frontend/modules/builder/elementTypes.js @@ -62,13 +62,14 @@ export class ElementType extends Registerable { get stylesAll() { return [ - 'style_border_top_color', - 'style_border_top_size', 'style_padding_top', - 'style_border_bottom_color', - 'style_border_bottom_size', - 'style_padding_bottom', 'style_padding_bottom', + 'style_padding_left', + 'style_padding_right', + 'style_border_top', + 'style_border_bottom', + 'style_border_left', + 'style_border_right', 'style_background', 'style_background_color', 'style_width', @@ -218,15 +219,7 @@ export class ColumnElementType extends ContainerElementType { } get childStylesForbidden() { - return [ - 'style_border_top_color', - 'style_border_top_size', - 'style_border_bottom_color', - 'style_border_bottom_size', - 'style_background', - 'style_background_color', - 'style_width', - ] + return ['style_width'] } get defaultPlaceInContainer() { @@ -667,4 +660,8 @@ export class FormContainerElementType extends ContainerElementType { get events() { return [SubmitEvent] } + + get childStylesForbidden() { + return ['style_width'] + } } diff --git a/web-frontend/modules/builder/locales/en.json b/web-frontend/modules/builder/locales/en.json index 33eaa0b25..96d7f825a 100644 --- a/web-frontend/modules/builder/locales/en.json +++ b/web-frontend/modules/builder/locales/en.json @@ -214,23 +214,24 @@ "noValue": "Unnamed..." }, "linkElementForm": { - "text": "Text", - "textPlaceholder": "Enter text...", - "navigateTo": "Navigate to", - "navigateToNotSet": "No destination", - "navigateToCustom": "Custom URL", - "url": "Destination URL", - "urlPlaceholder": "Enter an URL...", - "variant": "Variant", - "variantLink": "Link", - "variantButton": "Button", - "target": "Open in...", - "targetSelf": "Same tab", - "targetNewTab": "New tab", - "paramPlaceholder": "Enter a value...", - "paramsInErrorDescription": "The saved parameters don't match the page parameters. The page has probably been deleted or updated.", - "paramsInErrorButton": "Update parameters", - "pageParameterTypeError": "Invalid type" + "text": "Text", + "textPlaceholder": "Enter text...", + "navigateTo": "Navigate to", + "navigateToNotSet": "No destination", + "navigateToCustom": "Custom URL", + "url": "Destination URL", + "urlPlaceholder": "Enter an URL...", + "variant": "Variant", + "variantLink": "Link", + "variantButton": "Button", + "target": "Open in...", + "targetSelf": "Same tab", + "targetNewTab": "New tab", + "paramPlaceholder": "Enter a value...", + "paramsInErrorDescription": "The saved parameters don't match the page parameters. The page has probably been deleted or updated.", + "paramsInErrorButton": "Update parameters", + "pageParameterTypeError": "Invalid type", + "buttonColor": "Button color" }, "widthSelector": { "width": "Width", @@ -302,16 +303,17 @@ "noDataSourceMessage": "Data sources can be used to fetch data from internal or external sources and display it on the page." }, "defaultStyleForm": { - "boxTop": "Top", - "boxBottom": "Bottom", - "backgroundLabel": "Background", - "backgroundColor": "Background color", - "widthLabel": "Width" + "boxTop": "Top", + "boxBottom": "Bottom", + "boxLeft": "Left", + "boxRight": "Right", + "backgroundLabel": "Background", + "backgroundColor": "Background color", + "widthLabel": "Width" }, "styleBoxForm": { "borderLabel": "Border", - "paddingLabel": "Padding", - "error": "The value must be an integer between 0 and 200." + "paddingLabel": "Padding" }, "mainThemeConfigBlock": { "colorsLabel": "Colors", @@ -322,8 +324,9 @@ "headingValue": "Heading <h{i}>" }, "buttonElementForm": { - "valueLabel": "Text", - "valuePlaceholder": "Enter text..." + "valueLabel": "Text", + "valuePlaceholder": "Enter text...", + "buttonColor": "Button color" }, "buttonElement": { "noValue": "Unnamed..." @@ -348,7 +351,8 @@ "fieldDefaultName": "Column", "fieldType": "Type", "itemsPerPagePlaceholder": "Enter value...", - "selectSourceFirst": "Choose a list data source to begin configuring your fields." + "selectSourceFirst": "Choose a list data source to begin configuring your fields.", + "buttonColor": "Button color" }, "tableElement": { "empty": "No items have been found.", @@ -389,7 +393,8 @@ "fieldValueLabel": "Url", "fieldValuePlaceholder": "Enter value...", "fieldLinkNameLabel": "Link text", - "fieldLinkNamePlaceholder": "Enter value..." + "fieldLinkNamePlaceholder": "Enter value...", + "buttonColor": "Button color" }, "linkField": { "details": "Details" @@ -405,8 +410,9 @@ "integrationFieldLabel": "Integration" }, "formContainerElementForm": { - "submitButtonLabel": "Submit button", - "submitButtonPlaceholder": "Enter value..." + "submitButtonLabel": "Submit button", + "submitButtonPlaceholder": "Enter value...", + "buttonColor": "Button color" }, "dropdownOptionSelector": { "label": "Options", diff --git a/web-frontend/modules/builder/mixins/element.js b/web-frontend/modules/builder/mixins/element.js index bbd457318..c28414cc0 100644 --- a/web-frontend/modules/builder/mixins/element.js +++ b/web-frontend/modules/builder/mixins/element.js @@ -1,6 +1,8 @@ import RuntimeFormulaContext from '@baserow/modules/core/runtimeFormulaContext' import { resolveFormula } from '@baserow/modules/core/formula' import { ClickEvent, SubmitEvent } from '@baserow/modules/builder/eventTypes' +import { resolveColor } from '@baserow/modules/core/utils/colors' +import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' export default { inject: ['builder', 'page', 'mode'], @@ -53,6 +55,9 @@ export default { }, } }, + colorVariables() { + return themeToColorVariables(this.builder.theme) + }, }, methods: { resolveFormula(formula) { @@ -93,5 +98,7 @@ export default { fireSubmitEvent() { this.fireEvent(SubmitEvent) }, + + resolveColor, }, } diff --git a/web-frontend/modules/builder/mixins/elementForm.js b/web-frontend/modules/builder/mixins/elementForm.js new file mode 100644 index 000000000..686581ffe --- /dev/null +++ b/web-frontend/modules/builder/mixins/elementForm.js @@ -0,0 +1,29 @@ +import { resolveColor } from '@baserow/modules/core/utils/colors' +import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' +import form from '@baserow/modules/core/mixins/form' +import { + DATA_PROVIDERS_ALLOWED_ELEMENTS, + DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS, +} from '@baserow/modules/builder/enums' + +export default { + inject: ['builder', 'page', 'mode'], + mixins: [form], + data() { + return { + workflowActionsInProgress: false, + } + }, + computed: { + colorVariables() { + return themeToColorVariables(this.builder.theme) + }, + + DATA_PROVIDERS_ALLOWED_ELEMENTS: () => DATA_PROVIDERS_ALLOWED_ELEMENTS, + DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS: () => + DATA_PROVIDERS_ALLOWED_FORM_ELEMENTS, + }, + methods: { + resolveColor, + }, +} diff --git a/web-frontend/modules/builder/mixins/pageElement.js b/web-frontend/modules/builder/mixins/pageElement.js index e73e07423..29eb47a8a 100644 --- a/web-frontend/modules/builder/mixins/pageElement.js +++ b/web-frontend/modules/builder/mixins/pageElement.js @@ -2,6 +2,8 @@ import _ from 'lodash' import { resolveColor } from '@baserow/modules/core/utils/colors' import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' +import { BACKGROUND_TYPES, WIDTH_TYPES } from '@baserow/modules/builder/enums' + export default { inject: ['builder', 'page'], props: { @@ -16,6 +18,8 @@ export default { }, }, computed: { + BACKGROUND_TYPES: () => BACKGROUND_TYPES, + WIDTH_TYPES: () => WIDTH_TYPES, colorVariables() { return themeToColorVariables(this.builder.theme) }, @@ -46,13 +50,61 @@ export default { parentElementType.childStylesForbidden ) }, + /** * Computes an object containing all the style properties that must be set on * the element wrapper. */ wrapperStyles() { - const stylesAllowed = this.allowedStyles + const styles = { + style_background_color: { + '--background-color': + this.element.style_background === BACKGROUND_TYPES.COLOR.value + ? this.resolveColor( + this.element.style_background_color, + this.colorVariables + ) + : 'transparent', + }, + style_border_top: { + '--border-top': this.border( + this.element.style_border_top_size, + this.element.style_border_top_color + ), + }, + style_border_bottom: { + '--border-bottom': this.border( + this.element.style_border_bottom_size, + this.element.style_border_bottom_color + ), + }, + style_border_left: { + '--border-left': this.border( + this.element.style_border_left_size, + this.element.style_border_left_color + ), + }, + style_border_right: { + '--border-right': this.border( + this.element.style_border_right_size, + this.element.style_border_right_color + ), + }, + } + return Object.keys(styles).reduce((acc, key) => { + if (this.allowedStyles.includes(key)) { + acc = { ...acc, ...styles[key] } + } + return acc + }, {}) + }, + + /** + * Computes an object containing all the style properties that must be set on + * the element inner wrapper. + */ + innerWrapperStyles() { const styles = { style_padding_top: { '--padding-top': `${this.element.style_padding_top || 0}px`, @@ -60,10 +112,16 @@ export default { style_padding_bottom: { '--padding-bottom': `${this.element.style_padding_bottom || 0}px`, }, + style_padding_left: { + '--padding-left': `${this.element.style_padding_left || 0}px`, + }, + style_padding_right: { + '--padding-right': `${this.element.style_padding_right || 0}px`, + }, } return Object.keys(styles).reduce((acc, key) => { - if (stylesAllowed.includes(key)) { + if (this.allowedStyles.includes(key)) { acc = { ...acc, ...styles[key] } } return acc @@ -72,5 +130,11 @@ export default { }, methods: { resolveColor, + border(size, color) { + return `solid ${size || 0}px ${this.resolveColor( + color, + this.colorVariables + )}` + }, }, } diff --git a/web-frontend/modules/builder/mixins/styleForm.js b/web-frontend/modules/builder/mixins/styleForm.js index e8311cbfc..947c8c060 100644 --- a/web-frontend/modules/builder/mixins/styleForm.js +++ b/web-frontend/modules/builder/mixins/styleForm.js @@ -1,8 +1,11 @@ import _ from 'lodash' import form from '@baserow/modules/core/mixins/form' -import { resolveColor } from '@baserow/modules/core/utils/colors' import { themeToColorVariables } from '@baserow/modules/builder/utils/theme' +const borderNames = ['top', 'bottom', 'left', 'right'] + +const borderStyleNames = borderNames.map((pos) => `style_border_${pos}`) + export default { inject: ['builder'], props: { @@ -23,7 +26,7 @@ export default { allowedValues, values: this.getValuesFromElement(allowedValues), boxStyles: Object.fromEntries( - ['top', 'bottom'].map((pos) => [pos, this.getBoxStyleValue(pos)]) + borderNames.map((pos) => [pos, this.getBoxStyleValue(pos)]) ), } }, @@ -31,6 +34,17 @@ export default { colorVariables() { return themeToColorVariables(this.builder.theme) }, + allowedStyles() { + return this.getAllowedStyles() + }, + borders() { + return [ + { name: 'top', label: this.$t('defaultStyleForm.boxTop') }, + { name: 'bottom', label: this.$t('defaultStyleForm.boxBottom') }, + { name: 'left', label: this.$t('defaultStyleForm.boxLeft') }, + { name: 'right', label: this.$t('defaultStyleForm.boxRight') }, + ] + }, }, watch: { boxStyles: { @@ -43,9 +57,8 @@ export default { }, }, methods: { - resolveColor, isStyleAllowed(style) { - return this.allowedValues.includes(style) + return this.allowedStyles.includes(style) }, getBoxStyleValue(pos) { return { @@ -61,20 +74,33 @@ export default { this.values[`style_border_${pos}_size`] = newValue.border_size } }, - getAllowedValues() { + getAllowedStyles() { const elementType = this.$registry.get('element', this.element.type) const parentElementType = this.parentElement ? this.$registry.get('element', this.parentElement?.type) - : null + : [] - if (!parentElementType) { - return elementType.styles + let styles = elementType.styles + + if (parentElementType) { + styles = _.difference( + elementType.styles, + parentElementType.childStylesForbidden + ) } - return _.difference( - elementType.styles, - parentElementType.childStylesForbidden - ) + return styles + }, + getAllowedValues() { + // Rewrite border style names + return this.getAllowedStyles() + .map((style) => { + if (borderStyleNames.includes(style)) { + return [`${style}_color`, `${style}_size`] + } + return style + }) + .flat() }, getValuesFromElement(allowedValues) { return allowedValues.reduce((obj, value) => { diff --git a/web-frontend/modules/core/assets/scss/components/all.scss b/web-frontend/modules/core/assets/scss/components/all.scss index 89fb31d52..5f403cd48 100644 --- a/web-frontend/modules/core/assets/scss/components/all.scss +++ b/web-frontend/modules/core/assets/scss/components/all.scss @@ -136,6 +136,7 @@ @import 'notification_panel'; @import 'color_picker'; @import 'color_picker_context'; +@import 'color_input_group'; @import 'formula_input_field'; @import 'get_formula_component'; @import 'theme_settings'; diff --git a/web-frontend/modules/core/assets/scss/components/builder/all.scss b/web-frontend/modules/core/assets/scss/components/builder/all.scss index 213f98538..95a50d2ed 100644 --- a/web-frontend/modules/core/assets/scss/components/builder/all.scss +++ b/web-frontend/modules/core/assets/scss/components/builder/all.scss @@ -9,7 +9,6 @@ @import 'side_panels'; @import 'empty_side_panel_state'; @import 'page_editor'; -@import 'page_root_element'; @import 'page_settings_path_params_form_element'; @import 'domain_card'; @import 'dns_status'; diff --git a/web-frontend/modules/core/assets/scss/components/builder/element.scss b/web-frontend/modules/core/assets/scss/components/builder/element.scss index b59d74972..788b5a366 100644 --- a/web-frontend/modules/core/assets/scss/components/builder/element.scss +++ b/web-frontend/modules/core/assets/scss/components/builder/element.scss @@ -1,13 +1,31 @@ .element__wrapper { - padding: var(--padding-top, 0) 0 var(--padding-bottom, 0) 0; + background-color: var(--background-color, $black); + border-top: var(--border-top, none); + border-bottom: var(--border-bottom, none); + border-left: var(--border-left, none); + border-right: var(--border-right, none); + margin: 0 auto; + max-width: $builder-page-max-width; - &--normal-width { - margin: 0 auto; - padding-left: 20px; - padding-right: 20px; - max-width: $builder-page-max-width; + &--full-width { + max-width: 100%; } + &--medium-width { + max-width: 960px; + } + + &--small-width { + max-width: 680px; + } +} + +.element__inner-wrapper { + padding: var(--padding-top, 0) var(--padding-right, 0) + var(--padding-bottom, 0) var(--padding-left, 0); + margin: 0 auto; + max-width: $builder-page-max-width; + &--full-width { max-width: 100%; } @@ -22,7 +40,7 @@ } .element { - // this is a placeholder, the class will be added to every element component. + // Placeholder for element styles } .element--no-value { diff --git a/web-frontend/modules/core/assets/scss/components/builder/elements/link-button-element-button.scss b/web-frontend/modules/core/assets/scss/components/builder/elements/link-button-element-button.scss index 49e3bdf81..badf7fd8b 100644 --- a/web-frontend/modules/core/assets/scss/components/builder/elements/link-button-element-button.scss +++ b/web-frontend/modules/core/assets/scss/components/builder/elements/link-button-element-button.scss @@ -3,7 +3,7 @@ cursor: pointer; display: inline-block; color: $white; - background-color: $black; + background-color: var(--button-color, $black); line-height: 28px; padding: 0 12px; border: none; @@ -13,7 +13,7 @@ @include rounded($rounded); &:hover { - background-color: lighten($black, 10%); + filter: brightness(1.3); text-decoration: none; } diff --git a/web-frontend/modules/core/assets/scss/components/builder/page_root_element.scss b/web-frontend/modules/core/assets/scss/components/builder/page_root_element.scss deleted file mode 100644 index 4b2da865b..000000000 --- a/web-frontend/modules/core/assets/scss/components/builder/page_root_element.scss +++ /dev/null @@ -1,5 +0,0 @@ -.page-root-element__inner { - background-color: var(--background-color, $black); - border-top: var(--border-top, none); - border-bottom: var(--border-bottom, none); -} diff --git a/web-frontend/modules/core/assets/scss/components/color_input.scss b/web-frontend/modules/core/assets/scss/components/color_input.scss index 2b4f63226..0d18af43e 100644 --- a/web-frontend/modules/core/assets/scss/components/color_input.scss +++ b/web-frontend/modules/core/assets/scss/components/color_input.scss @@ -1,19 +1,11 @@ -.color-input { - display: flex; - align-items: center; -} - .color-input__preview { + display: block; width: 40px; height: 20px; border-radius: 2px; - box-shadow: 0 0 1px 0 rgba($black, 0.16); + box-shadow: 1px 1px 1px 1px rgba($black, 0.2); &:hover { - box-shadow: 0 0 2px 0 rgba($black, 0.16); + box-shadow: 1px 1px 1px 0 rgba($black, 0.2); } } - -.color-input__label { - margin-left: 10px; -} diff --git a/web-frontend/modules/core/assets/scss/components/color_input_group.scss b/web-frontend/modules/core/assets/scss/components/color_input_group.scss new file mode 100644 index 000000000..6814b11e9 --- /dev/null +++ b/web-frontend/modules/core/assets/scss/components/color_input_group.scss @@ -0,0 +1,8 @@ +.color-input-group--label-after { + display: flex; + align-items: center; +} + +.color-input-group__label-after { + margin-left: 16px; +} diff --git a/web-frontend/modules/core/components/ColorInput.vue b/web-frontend/modules/core/components/ColorInput.vue new file mode 100644 index 000000000..7a27d3e04 --- /dev/null +++ b/web-frontend/modules/core/components/ColorInput.vue @@ -0,0 +1,41 @@ +<template> + <div> + <ColorPickerContext + ref="colorPicker" + :value="value" + :variables="colorVariables" + @input="$emit('input', $event)" + /> + <a + ref="opener" + class="color-input__preview" + :style="{ + 'background-color': resolveColor(value, colorVariables), + }" + @click="$refs.colorPicker.toggle($refs.opener)" + /> + </div> +</template> + +<script> +import ColorPickerContext from '@baserow/modules/core/components/ColorPickerContext' +import { resolveColor } from '@baserow/modules/core/utils/colors' + +export default { + name: 'ColorInput', + components: { ColorPickerContext }, + props: { + value: { + type: String, + required: false, + default: 'primary', + }, + colorVariables: { + type: Array, + required: false, + default: () => [], + }, + }, + methods: { resolveColor }, +} +</script> diff --git a/web-frontend/modules/core/components/ColorInputGroup.vue b/web-frontend/modules/core/components/ColorInputGroup.vue new file mode 100644 index 000000000..af521abec --- /dev/null +++ b/web-frontend/modules/core/components/ColorInputGroup.vue @@ -0,0 +1,53 @@ +<template> + <FormGroup v-if="!labelAfter" :label="label"> + <ColorInput + :value="value" + :color-variables="colorVariables" + @input="$emit('input', $event)" + /> + </FormGroup> + <div v-else class="control"> + <div class="control__elements"> + <div class="color-input-group--label-after"> + <ColorInput + :value="value" + :color-variables="colorVariables" + @input="$emit('input', $event)" + /> + <div class="color-input-group__label-after"> + {{ label }} + </div> + </div> + </div> + </div> +</template> + +<script> +import ColorInput from '@baserow/modules/core/components/ColorInput' + +export default { + name: 'ColorInputGroup', + components: { ColorInput }, + props: { + value: { + type: String, + required: false, + default: 'primary', + }, + label: { + type: String, + required: true, + }, + labelAfter: { + type: Boolean, + required: false, + default: false, + }, + colorVariables: { + type: Array, + required: false, + default: () => [], + }, + }, +} +</script> diff --git a/web-frontend/modules/core/components/FormInput.vue b/web-frontend/modules/core/components/FormInput.vue index 846684d87..3b4e0db41 100644 --- a/web-frontend/modules/core/components/FormInput.vue +++ b/web-frontend/modules/core/components/FormInput.vue @@ -33,6 +33,7 @@ <input ref="base_url" class="form-input__input" + :class="{ 'remove-number-input-controls': true }" :value="fromValue(value)" :disabled="disabled" :type="type" diff --git a/web-frontend/modules/core/plugins/global.js b/web-frontend/modules/core/plugins/global.js index 5fe87af28..cf98cc67a 100644 --- a/web-frontend/modules/core/plugins/global.js +++ b/web-frontend/modules/core/plugins/global.js @@ -45,6 +45,8 @@ import Badge from '@baserow/modules/core/components/Badge' import Expandable from '@baserow/modules/core/components/Expandable.vue' import RadioButton from '@baserow/modules/core/components/RadioButton' import Thumbnail from '@baserow/modules/core/components/Thumbnail' +import ColorInput from '@baserow/modules/core/components/ColorInput' +import ColorInputGroup from '@baserow/modules/core/components/ColorInputGroup' function setupVue(Vue) { Vue.component('Context', Context) @@ -79,6 +81,8 @@ function setupVue(Vue) { Vue.component('CallToAction', CallToAction) Vue.component('FormGroup', FormGroup) Vue.component('FormRow', FormRow) + Vue.component('ColorInput', ColorInput) + Vue.component('ColorInputGroup', ColorInputGroup) Vue.filter('lowercase', lowercase) Vue.filter('uppercase', uppercase) diff --git a/web-frontend/modules/core/utils/colors.js b/web-frontend/modules/core/utils/colors.js index 34fa3c593..f8814e0ef 100644 --- a/web-frontend/modules/core/utils/colors.js +++ b/web-frontend/modules/core/utils/colors.js @@ -260,6 +260,9 @@ export const conversionsMap = { } export function isColorVariable(value) { + if (!value) { + return false + } return value.substring(0, 1) !== '#' }