refactor builders + create modal component

This commit is contained in:
Jordan Blasenhauer 2024-07-30 11:20:36 +02:00
parent edbfcc2284
commit ecb2781aa4
12 changed files with 236 additions and 182 deletions

View file

@ -47,13 +47,25 @@ const props = defineProps({
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<MessageUnmatch
v-if="widget.type === 'MessageUnmatch'"
v-if="widget.type.toLowerCase() === 'messageunmatch'"
v-bind="widget.data"
/>
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
<Subtitle
v-if="widget.type.toLowerCase() === 'subtitle'"
v-bind="widget.data"
/>
<Table
v-if="widget.type.toLowerCase() === 'table'"
v-bind="widget.data"
/>
<ListPairs
v-if="widget.type.toLowerCase() === 'listpairs'"
v-bind="widget.data"
/>
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Subtitle v-if="widget.type === 'Subtitle'" v-bind="widget.data" />
<Table v-if="widget.type === 'Table'" v-bind="widget.data" />
<ListPairs v-if="widget.type === 'ListPairs'" v-bind="widget.data" />
</template>
</Grid>
</GridLayout>

View file

@ -1,109 +0,0 @@
<script setup>
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
// Headings
import Title from "@components/Widget/Title.vue";
import Subtitle from "@components/Widget/Subtitle.vue";
// Content
import ContentStat from "@components/Content/Stat.vue";
import ContentDetailList from "@components/Content/DetailList.vue";
// Icon
import Icons from "@components/Widget/Icons.vue";
// Form
import Checkbox from "@components/Forms/Field/Checkbox.vue";
import Select from "@components/Forms/Field/Select.vue";
import Input from "@components/Forms/Field/Input.vue";
import Datepicker from "@components/Forms/Field/Datepicker.vue";
// Widget
import Button from "@components/Widget/Button.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import Stat from "@components/Widget/Stat.vue";
import Instance from "@components/Widget/Instance.vue";
/**
@name Builder/Collection.vue
@description This component is a builder containing all collection of widgets / containers / components to create a complete page.
We have to define each container and each widget inside it.
This is an abstract component that will be used to create any kind of page content (base dashboard elements like menu and news excluded)
@example
[
{
// this can be a "card", "modal", "table"... etc
"type": "card",
// container custom key
"title" : "My awesome card",
// additionnal tailwind css class
"containerClass": "",
// We can define the top level grid system (GridLayout.vue)
"containerColumns" : {"pc": 12, "tablet": 12, "mobile": 12},
// Each widget need a name (here type) and associated data
// We need to send specific data for each widget typ
widgets: [
{
type : "Checkbox",
data : {containerClass : "", columns : {"pc": 6, "tablet": 12, "mobile": 12}, id:"test-check", value: "yes", label: "Checkbox", name: "checkbox", required: true, version: "v1.0.0", hideLabel: false, headerClass: "text-red-500" }
}, {
type : "Select",
data : {containerClass : "", columns : {"pc": 6, "tablet": 12, "mobile": 12}, id: 'test-select', value: 'yes', values: ['yes', 'no'], name: 'test-select', disabled: false, required: true, label: 'Test select', tabId: '1',}
}
]
}
]
@param {array} builder - Array of containers and widgets
*/
const props = defineProps({
builder: {
type: Array,
required: true,
},
});
</script>
<template>
<!-- top level grid (layout) -->
<GridLayout
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
>
<!-- widget grid -->
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Subtitle v-if="widget.type === 'Subtitle'" v-bind="widget.data" />
<Checkbox v-if="widget.type === 'Checkbox'" v-bind="widget.data" />
<Select v-if="widget.type === 'Select'" v-bind="widget.data" />
<Input v-if="widget.type === 'Input'" v-bind="widget.data" />
<Datepicker v-if="widget.type === 'Datepicker'" v-bind="widget.data" />
<Button v-if="widget.type === 'Button'" v-bind="widget.data" />
<Stat v-if="widget.type === 'Stat'" v-bind="widget.data" />
<ContentStat
v-if="widget.type === 'ContentStat'"
v-bind="widget.data"
/>
<Icons v-if="widget.type === 'Icons'" v-bind="widget.data" />
<Instance v-if="widget.type === 'Instance'" v-bind="widget.data" />
<ContentDetailList
v-if="widget.type === 'ContentDetailList'"
v-bind="widget.data"
/>
<ButtonGroup
v-if="widget.type === 'ButtonGroup'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>
</template>

View file

@ -62,9 +62,18 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Subtitle v-if="widget.type === 'Subtitle'" v-bind="widget.data" />
<Templates v-if="widget.type === 'Templates'" v-bind="widget.data" />
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
<Subtitle
v-if="widget.type.toLowerCase() === 'subtitle'"
v-bind="widget.data"
/>
<Templates
v-if="widget.type.toLowerCase() === 'templates'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -54,7 +54,10 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Stat v-if="widget.type === 'Stat'" v-bind="widget.data" />
<Stat
v-if="widget.type.toLowerCase() === 'stat'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -57,7 +57,10 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Instance v-if="widget.type === 'Instance'" v-bind="widget.data" />
<Instance
v-if="widget.type.toLowerCase() === 'instance'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -84,8 +84,14 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Table v-if="widget.type === 'Table'" v-bind="widget.data" />
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Table
v-if="widget.type.toLowerCase() === 'table'"
v-bind="widget.data"
/>
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -69,14 +69,20 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<ListDetails
v-if="widget.type === 'ListDetails'"
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
<ListDetails
v-if="widget.type.toLowerCase() === 'listdetails'"
v-bind="widget.data"
/>
<Text
v-if="widget.type.toLowerCase() === 'text'"
v-bind="widget.data"
/>
<Text v-if="widget.type === 'Text'" v-bind="widget.data" />
<ButtonGroup
v-if="widget.type === 'ButtonGroup'"
v-if="widget.type.toLowerCase() === 'buttongroup'"
v-bind="widget.data"
/>
</template>

View file

@ -47,13 +47,25 @@ const props = defineProps({
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<MessageUnmatch
v-if="widget.type === 'MessageUnmatch'"
v-if="widget.type.toLowerCase() === 'messageunmatch'"
v-bind="widget.data"
/>
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
<Subtitle
v-if="widget.type.toLowerCase() === 'subtitle'"
v-bind="widget.data"
/>
<Table
v-if="widget.type.toLowerCase() === 'table'"
v-bind="widget.data"
/>
<ListPairs
v-if="widget.type.toLowerCase() === 'listpairs'"
v-bind="widget.data"
/>
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Subtitle v-if="widget.type === 'Subtitle'" v-bind="widget.data" />
<Table v-if="widget.type === 'Table'" v-bind="widget.data" />
<ListPairs v-if="widget.type === 'ListPairs'" v-bind="widget.data" />
</template>
</Grid>
</GridLayout>

View file

@ -314,8 +314,14 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Table v-if="widget.type === 'Table'" v-bind="widget.data" />
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
<Table
v-if="widget.type.toLowerCase() === 'table'"
v-bind="widget.data"
/>
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -2,7 +2,6 @@
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
import Instance from "@components/Widget/Instance.vue";
/**
@name Builder/Setup.vue
@ -37,7 +36,6 @@ const props = defineProps({
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Instance v-if="widget.type === 'Instance'" v-bind="widget.data" />
</template>
</Grid>
</GridLayout>

View file

@ -1,6 +1,5 @@
<script setup>
import { computed, ref, onMounted, reactive, onBeforeMount } from "vue";
import Button from "@components/Widget/Button.vue";
import { contentIndex } from "@utils/tabindex.js";
import { useUUID } from "@utils/global.js";
@ -17,7 +16,7 @@ import { useUUID } from "@utils/global.js";
columns: { pc: 12, tablet: 12, mobile: 12},
gridLayoutClass: "items-start"
}
@param {string} [type="card"] - Type of layout component, we can have "card" or "modal"
@param {string} [type="card"] - Type of layout component, we can have "card"
@param {string} [id=uuidv4()] - Id of the layout component, will be used to identify the component.
@param {string} [title=""] - Title of the layout component, will be displayed at the top if exists. Type of layout component will determine the style of the title.
@param {string} [link=""] - Will transform the container tag from a div to an a tag with the link as href. Useful with card type.
@ -74,7 +73,6 @@ const container = reactive({
const containerClass = computed(() => {
if (props.type === "card") return "layout-card";
if (props.type === "modal") return "layout-modal";
return "";
});
@ -101,49 +99,19 @@ onMounted(() => {
</script>
<template>
<!-- modal -->
<template v-if="props.type === 'modal'">
<div
:data-is="`${props.type}`"
data-modal
class="layout-modal-container hidden"
:id="container.id"
>
<div class="layout-backdrop"></div>
<div class="layout-modal-wrap" :data-hide-el="container.id">
<div class="layout-modal">
<div class="layout-modal-button-container">
<Button
:attrs="{ 'data-hide-el': container.id }"
:text="'action_close_modal'"
:hideText="true"
:iconName="'close'"
:color="'transparent'"
/>
</div>
<slot></slot>
</div>
</div>
</div>
</template>
<!-- end modal -->
<!-- card or elements on the document flow -->
<template v-if="props.type !== 'modal'">
<component
ref="flowEl"
:id="container.id"
:is="props.link ? 'a' : 'div'"
:data-is="`${props.type}`"
:class="[
containerClass,
gridClass,
props.gridLayoutClass,
'layout-grid-layout',
]"
>
<slot></slot>
</component>
</template>
<component
ref="flowEl"
:id="container.id"
:is="props.link ? 'a' : 'div'"
:data-is="`${props.type}`"
:class="[
containerClass,
gridClass,
props.gridLayoutClass,
'layout-grid-layout',
]"
>
<slot></slot>
</component>
<!-- end card or elements on the document flow -->
</template>

View file

@ -0,0 +1,140 @@
<script setup>
// Containers
import Grid from "@components/Widget/Grid.vue";
import Title from "@components/Widget/Title.vue";
import Text from "@components/Widget/Text.vue";
import Subtitle from "@components/Widget/Subtitle.vue";
import Button from "@components/Widget/Button.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import MessageUnmatch from "@components/Message/Unmatch.vue";
/**
@name Builder/Modal.vue
@description This component contains all widgets needed on a modal.
This is different from a page builder as we don't need to define the container and grid layout.
We can't create multiple grids or containers in a modal.
@example
[
"id": "modal-delete-plugin",
"widgets": [
{
"type": "Title",
"data": {
"title": "plugins_modal_delete_title",
"type": "modal"
}
},
{
"type": "Text",
"data": {
"text": "plugins_modal_delete_confirm"
}
},
{
"type": "Text",
"data": {
"text": "",
"bold": true,
"attrs": {
"data-modal-plugin-name": "true"
}
}
},
{
"type": "ButtonGroup",
"data": {
"buttons": [
{
"id": "delete-plugin-btn",
"text": "action_close",
"disabled": false,
"color": "close",
"size": "normal",
"attrs": {
"data-hide-el": "modal-delete-plugin"
}
},
{
"id": "delete-plugin-btn",
"text": "action_delete",
"disabled": false,
"color": "delete",
"size": "normal",
"attrs": {
"data-delete-plugin-submit": ""
}
}
],
}
}
]
];
@param {array} widgets - Array of containers and widgets
*/
const props = defineProps({
widgets: {
type: Array,
required: true,
},
isOpen: {
type: Boolean,
required: false,
default: false,
},
});
</script>
<template>
<div
:data-is="'modal'"
data-modal
:class="['layout-modal-container', props.isOpen ? '' : 'hidden']"
class="layout-modal-container hidden"
:id="props.id"
>
<div class="layout-backdrop"></div>
<div class="layout-modal-wrap" :data-hide-el="props.id">
<div class="layout-modal">
<div class="layout-modal-button-container">
<Button
:attrs="{ 'data-hide-el': props.id }"
:text="'action_close_modal'"
:hideText="true"
:iconName="'close'"
:color="'transparent'"
/>
</div>
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in props.widgets" :key="index">
<MessageUnmatch
v-if="widget.type.toLowerCase() === 'messageunmatch'"
v-bind="widget.data"
/>
<Title
v-if="widget.type.toLowerCase() === 'title'"
v-bind="widget.data"
/>
<Text
v-if="widget.type.toLowerCase() === 'text'"
v-bind="widget.data"
/>
<Subtitle
v-if="widget.type.toLowerCase() === 'subtitle'"
v-bind="widget.data"
/>
<Button
v-if="widget.type.toLowerCase() === 'button'"
v-bind="widget.data"
/>
<ButtonGroup
v-if="widget.type.toLowerCase() === 'buttongroup'"
v-bind="widget.data"
/>
</template>
</Grid>
</div>
</div>
</div>
</template>