add custom pages builder

This commit is contained in:
Jordan Blasenhauer 2024-06-09 17:42:22 +02:00
parent 8ab947af11
commit 195f292599
9 changed files with 203 additions and 29 deletions

View file

@ -1,5 +1,4 @@
<script setup>
import { reactive, onBeforeMount } from "vue";
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
@ -10,7 +9,7 @@ import Subtitle from "@components/Widget/Subtitle.vue";
import ContentStat from "@components/Content/Stat.vue";
import ContentDetailList from "@components/Content/DetailList.vue";
// Icon
import IconStatus from "@components/Widget/Status.vue";
import Icons from "@components/Widget/Icons.vue";
// Form
import Checkbox from "@components/Forms/Field/Checkbox.vue";
import Select from "@components/Forms/Field/Select.vue";
@ -23,8 +22,8 @@ import Stat from "@components/Widget/Stat.vue";
import Instance from "@components/Widget/Instance.vue";
/**
@name Builder.vue
@description This component is a wrapper to create a complete page using containers and widgets.
@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
@ -93,9 +92,8 @@ const props = defineProps({
v-if="widget.type === 'ContentStat'"
v-bind="widget.data"
/>
<IconStat v-if="widget.type === 'IconStat'" v-bind="widget.data" />
<Icons v-if="widget.type === 'Icons'" v-bind="widget.data" />
<Instance v-if="widget.type === 'Instance'" v-bind="widget.data" />
<IconStatus v-if="widget.type === 'IconStatus'" v-bind="widget.data" />
<ContentDetailList
v-if="widget.type === 'ContentDetailList'"
v-bind="widget.data"

View file

@ -0,0 +1,61 @@
<script setup>
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
import Stat from "@components/Widget/Stat.vue";
/**
@name Builder/Home.vue
@description This component is lightweight builder containing only the necessary components to create the home page.
@example
[
{
type: "card",
link : "https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui"
containerColumns: { pc: 4, tablet: 6, mobile: 12 },
widgets: [
{
type: "Stat",
data: {
title: "home_version",
subtitle: "home_all_features_available" if is_pro_version else "home_upgrade_pro",
subtitleColor: "success" is is_pro_version else "warning",
stat: "home_pro" if is_pro_version else "home_free",
iconName: "crown" if is_pro_version else "core",
iconColor: "amber",
},
},
],
},
]
@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"
>
<!-- widget grid -->
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Stat v-if="widget.type === 'Stat'" v-bind="widget.data" />
</template>
</Grid>
</GridLayout>
</template>

View file

@ -0,0 +1,63 @@
<script setup>
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
import Instance from "@components/Widget/Instance.vue";
/**
@name Builder/Instances.vue
@description This component is lightweight builder containing only the necessary components to create the instances page.
@example
[
{
type: "Instance",
data: {
details: [
{ key: <instances_hostname="hostname">, value: "www.example.com" },
{ key: <instances_method="method">, value: <dashboard_ui> or <dashboard_scheduler>...},
{ key: <instances_port="port">, value: "1084" },
{ key: <instances_status="status">, value: <instances_active="active"> or <instances_inactive="inactive"> },
],
status: "success",
title: "www.example.com",
buttons: [
{
text: <action_*>,
color: "edit",
size: "normal",
},
],
},
},
];
@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"
>
<!-- widget grid -->
<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>
</template>

View file

@ -1,15 +1,12 @@
<script setup>
import { reactive, defineProps, onMounted, ref } from "vue";
import Container from "@components/Widget/Container.vue";
import Checkbox from "@components/Forms/Field/Checkbox.vue";
import Input from "@components/Forms/Field/Input.vue";
import Select from "@components/Forms/Field/Select.vue";
import Datepicker from "@components/Forms/Field/Datepicker.vue";
import Fields from "@components/Form/Fields.vue";
import Title from "@components/Widget/Title.vue";
import Subtitle from "@components/Widget/Subtitle.vue";
/**
@name Forms/Type/Advanced.vue
@name Form/Advanced.vue
@description This component is used to create a complete advanced form with plugin selection.
@example
const data = [
@ -85,13 +82,7 @@ const props = defineProps({
v-for="(setting, name, index) in plugin.settings"
:key="index"
>
<Checkbox v-if="setting.inpType === 'checkbox'" v-bind="setting" />
<Select v-if="setting.inpType === 'select'" v-bind="setting" />
<Datepicker
v-if="setting.inpType === 'datepicker'"
v-bind="setting"
/>
<Input v-if="setting.inpType === 'input'" v-bind="setting" />
<Fields :setting="setting" />
</template>
</Container>
</Container>

View file

@ -0,0 +1,54 @@
<script setup>
import { reactive, defineProps, onMounted, ref } from "vue";
import Checkbox from "@components/Forms/Field/Checkbox.vue";
import Input from "@components/Forms/Field/Input.vue";
import Select from "@components/Forms/Field/Select.vue";
import Datepicker from "@components/Forms/Field/Datepicker.vue";
/**
@name Form/Fields.vue
@description This component wraps all available fields for a form.
@example
{
columns : {"pc": 6, "tablet": 12, "mobile": 12},
id:"test-check",
value: "yes",
label: "Checkbox",
name: "checkbox",
required: true,
hideLabel: false,
inpType: "checkbox",
headerClass: "text-red-500"
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
]
}
@param {object} setting - Setting needed to render a field.
*/
const props = defineProps({
// id && value && method
setting: {
type: Object,
required: true,
default: {},
},
});
</script>
<template>
<Checkbox
v-if="props.setting.inpType === 'checkbox'"
v-bind="props.setting"
/>
<Select v-if="props.setting.inpType === 'select'" v-bind="props.setting" />
<Datepicker
v-if="props.setting.inpType === 'datepicker'"
v-bind="props.setting"
/>
<Input v-if="props.setting.inpType === 'input'" v-bind="props.setting" />
</template>

View file

@ -3,7 +3,7 @@ import Container from "@components/Widget/Container.vue";
import Title from "@components/Widget/Title.vue";
import Subtitle from "@components/Widget/Subtitle.vue";
import ContentStat from "@components/Content/Stat.vue";
import Icon from "@components/Widget/Icons.vue";
import Icons from "@components/Widget/Icons.vue";
/**
@name Widget/Stat.vue
@ -83,7 +83,7 @@ const props = defineProps({
:subtitleColor="props.subtitleColor"
/>
</div>
<Icon
<Icons
v-if="props.iconName"
:iconName="props.iconName"
:iconColor="props.iconColor"

View file

@ -1,8 +1,8 @@
<script setup>
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import Builder from "@components/Builder.vue";
import Advanced from "@components/Forms/Type/Advanced.vue";
import Builder from "@components/Builder/Collection.vue";
import Advanced from "@components/Form/Advanced.vue";
import { useGlobal } from "@utils/global.js";
import { useForm } from "@utils/form.js";

View file

@ -1,7 +1,9 @@
<script setup>
import { reactive, onBeforeMount } from "vue";
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import Builder from "@components/Builder.vue";
import BuilderHome from "@components/Builder/Home.vue";
import { useGlobal } from "@utils/global.js";
import { useForm } from "@utils/form.js";
/**
@name Page/Home.vue
@ -24,6 +26,11 @@ onBeforeMount(() => {
home.builder = data;
});
onMounted(() => {
useGlobal();
useForm();
});
// const data = [
// {
// type: "card",
@ -120,6 +127,6 @@ onBeforeMount(() => {
<template>
<DashboardLayout>
<Builder v-if="home.builder" :builder="home.builder" />
<BuilderHome v-if="home.builder" :builder="home.builder" />
</DashboardLayout>
</template>

View file

@ -1,7 +1,7 @@
<script setup>
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import Builder from "@components/Builder.vue";
import BuilderInstances from "@components/Builder/Instances.vue";
import { useGlobal } from "@utils/global.js";
import { useForm } from "@utils/form.js";
@ -11,7 +11,7 @@ import { useForm } from "@utils/form.js";
This page displays current instances and allows to manage them.
*/
const home = reactive({
const instances = reactive({
builder: "",
});
@ -23,7 +23,7 @@ onBeforeMount(() => {
dataEl && !dataEl.getAttribute(dataAtt).includes(dataAtt)
? JSON.parse(dataEl.getAttribute(dataAtt))
: {};
home.builder = data;
instances.builder = data;
});
onMounted(() => {
@ -57,7 +57,7 @@ onMounted(() => {
<template>
<DashboardLayout>
<Builder v-if="home.builder" :builder="home.builder" />
<BuilderInstances v-if="instances.builder" :builder="instances.builder" />
<div id="test-el"></div>
</DashboardLayout>
</template>