add switch component logic with displayStore

*add a display store that will store a groupname and the value of the current component id to display + utils to update, this will allow to hide or show components after actions and this will work with a tabs component
* add and watch the display store logic on container or layout
This commit is contained in:
Jordan Blasenhauer 2024-08-11 18:31:51 +02:00
parent d7b512c7a1
commit 91fedab2f6
4 changed files with 127 additions and 8 deletions

View file

@ -1,6 +1,6 @@
<script setup>
import { computed } from "vue";
import { useDisplayStore } from "@store/global.js";
import { defineProps, watch, computed, reactive } from "vue";
/**
* @name Widget/Container.vue
* @description This component is a basic container that can be used to wrap other components.
@ -15,6 +15,7 @@ import { computed } from "vue";
* @param {string} [containerClass=""] - Additional class
* @param {object|boolean} [columns=false] - Work with grid system { pc: 12, tablet: 12, mobile: 12}
* @param {string} [tag="div"] - The tag for the container
* @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef.
*/
const props = defineProps({
@ -33,8 +34,32 @@ const props = defineProps({
required: false,
default: "div",
},
display: {
type: Array,
required: false,
default: [],
},
});
const displayStore = useDisplayStore();
const container = reactive({
// Check if component display is related to the displayStore
isDisplay: props.display.length
? displayStore.isCurrentDisplay(props.display[0], props.display[1])
: true,
});
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
});
}
const gridClass = computed(() => {
return props.columns
? `col-span-${props.columns.mobile} md:col-span-${props.columns.tablet} lg:col-span-${props.columns.pc}`
@ -44,6 +69,7 @@ const gridClass = computed(() => {
<template>
<component
v-if="container.isDisplay"
:is="props.tag"
data-container
:class="[props.containerClass ? props.containerClass : '', gridClass]"

View file

@ -1,4 +1,6 @@
<script setup>
import { useDisplayStore } from "@store/global.js";
import { defineProps, watch, reactive } from "vue";
/**
* @name Widget/Grid.vue
* @description This component is a basic container that can be used to wrap other components.
@ -11,6 +13,7 @@
* gridClass: "items-start"
* }
* @param {string} [gridClass="items-start"] - Additional class
* @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef.
*/
const props = defineProps({
@ -19,11 +22,39 @@ const props = defineProps({
required: false,
default: "items-start",
},
display: {
type: Array,
required: false,
default: [],
},
});
const displayStore = useDisplayStore();
const container = reactive({
// Check if component display is related to the displayStore
isDisplay: props.display.length
? displayStore.isCurrentDisplay(props.display[0], props.display[1])
: true,
});
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
});
}
</script>
<template>
<div data-grid :class="[props.gridClass, 'layout-grid']">
<div
v-if="container.isDisplay"
data-grid
:class="[props.gridClass, 'layout-grid']"
>
<slot></slot>
</div>
</template>

View file

@ -1,7 +1,8 @@
<script setup>
import { computed, ref, onMounted, reactive, onBeforeMount } from "vue";
import { computed, ref, onMounted, reactive, onBeforeMount, watch } from "vue";
import { contentIndex } from "@utils/tabindex.js";
import { useUUID } from "@utils/global.js";
import { useDisplayStore } from "@store/global.js";
/**
* @name Widget/GridLayout.vue
@ -14,7 +15,8 @@ import { useUUID } from "@utils/global.js";
* type: "card",
* title: "Test",
* columns: { pc: 12, tablet: 12, mobile: 12},
* gridLayoutClass: "items-start"
* gridLayoutClass: "items-start",
* display: ["main", 1],
* }
* @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.
@ -22,6 +24,7 @@ import { useUUID } from "@utils/global.js";
* @param {string} [link=""] - Will transform the container tag from a div to an a tag with the link as href. Useful with card type.
* @param {object} [columns={"pc": 12, "tablet": 12, "mobile": 12}] - Work with grid system { pc: 12, tablet: 12, mobile: 12}
* @param {string} [gridLayoutClass="items-start"] - Additional class
* @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef.
* @param {string} [tabId=contentIndex] - Case the container is converted to an anchor with a link, we can define the tabId, by default it is the contentIndex
*/
@ -65,12 +68,33 @@ const props = defineProps({
required: false,
default: "items-start",
},
display: {
type: Array,
required: false,
default: [],
},
});
const displayStore = useDisplayStore();
const container = reactive({
id: "",
// Check if component display is related to the displayStore
isDisplay: props.display.length
? displayStore.isCurrentDisplay(props.display[0], props.display[1])
: true,
});
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
});
}
const containerClass = computed(() => {
if (props.type === "card") return "layout-card";
return "";
@ -100,6 +124,7 @@ onMounted(() => {
<template>
<component
v-if="container.isDisplay"
ref="flowEl"
:id="container.id"
:is="props.link ? 'a' : 'div'"

View file

@ -11,7 +11,7 @@ export const useBannerStore = defineStore("banner", () => {
const isBanner = ref(true);
const bannerClass = ref("banner");
async function setBannerVisible(bool) {
function setBannerVisible(bool) {
isBanner.value = bool;
bannerClass.value = bool ? "banner" : "no-banner";
}
@ -28,13 +28,50 @@ export const useBannerStore = defineStore("banner", () => {
export const useReadonlyStore = defineStore("readonly", () => {
const isReadOnly = ref(true);
async function setReadOnly(bool) {
function setReadOnly(bool) {
isReadOnly.value = bool;
}
return { isReadOnly, setReadOnly };
});
/**
* @name useDisplayStore
* @description This store is used to share the display state of the components.
* This store will handle key-value with the display group name and the current component display name.
* This will allow to show or hide components based on the display group name. This is useful with tabs of after a button action to show a specific component.
* Because of builder approach, we can't directly update the display state on components (like in buttons) unless in dedicated tabs component.
* In case we can't update state on component, we need to declare the store on the page level, and add a script to switch the state by listening to components with classic selectors.
* @returns {object} - Object with the display data.
*/
export const useDisplayStore = defineStore("display", () => {
const display = ref({});
function setDisplay(groupName, componentName) {
display.value[groupName] = componentName;
}
function getDisplayByGroupName(groupName) {
return display.value[groupName];
}
function getDisplays() {
return display.value;
}
function isCurrentDisplay(groupName, componentName) {
return display.value[groupName] === componentName;
}
return {
display,
setDisplay,
getDisplayByGroupName,
getDisplays,
isCurrentDisplay,
};
});
/**
* @name useTableStore
* @description Store instiantiate Tabulator.js table using id prop component.
@ -44,7 +81,7 @@ export const useReadonlyStore = defineStore("readonly", () => {
export const useTableStore = defineStore("table", () => {
const tables = ref({});
async function setTable(id, tabulatorInstance) {
function setTable(id, tabulatorInstance) {
tables.value[id] = tabulatorInstance;
}