mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
refactor builders + create modal component
This commit is contained in:
parent
edbfcc2284
commit
ecb2781aa4
12 changed files with 236 additions and 182 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
140
src/ui/client/dashboard/components/Widget/Modal.vue
Normal file
140
src/ui/client/dashboard/components/Widget/Modal.vue
Normal 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>
|
||||
Loading…
Reference in a new issue