mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
update POC
This commit is contained in:
parent
d017514ccd
commit
93836285f0
10 changed files with 152 additions and 60 deletions
File diff suppressed because one or more lines are too long
33
vuejs/client/src/components/Builder.vue
Normal file
33
vuejs/client/src/components/Builder.vue
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<script setup>
|
||||
const builder = [{
|
||||
// we are starting with the top level container name
|
||||
// this can be a "card", "modal", "table"... etc
|
||||
"type": "card",
|
||||
// a card can have an icon and a color at the top right
|
||||
"icon": ["iconName", "iconColor"],
|
||||
// grid position for each screen
|
||||
"columns" : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
// container title
|
||||
"title" : "My awesome card",
|
||||
// group of widgets will share same columns
|
||||
// Case we want a button widget in a one column group and others in like a 3 columns group
|
||||
content: [
|
||||
{
|
||||
position="left",
|
||||
columns={
|
||||
pc=4,
|
||||
tablet=12,
|
||||
..
|
||||
},
|
||||
widgets=[Input1, Button2, { type="input", data = {...} }]
|
||||
},
|
||||
...
|
||||
]
|
||||
},
|
||||
// ... other containers
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="m-2 p-2">
|
||||
<div class="m-1 p-1">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -92,7 +92,7 @@ onMounted(() => {
|
|||
|
||||
<template>
|
||||
<Base>
|
||||
<Header :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
<Header :required="props.required" :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
|
||||
<div class="relative z-10 flex flex-col items-start">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ const props = defineProps({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -138,7 +142,7 @@ onMounted(() => {
|
|||
|
||||
<template>
|
||||
<Base>
|
||||
<Header :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
<Header :required="props.required" :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
|
||||
<div class="relative flex flex-col items-start">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ const emits = defineEmits(["inp"]);
|
|||
|
||||
<template>
|
||||
<Base>
|
||||
<Header :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
<Header :required="props.required" :name="props.name" :label="props.label" :hideLabel="props.hideLabel" :headerClass="props.headerClass" />
|
||||
|
||||
<select :name="props.name" class="hidden">
|
||||
<option
|
||||
|
|
@ -180,11 +180,6 @@ const emits = defineEmits(["inp"]);
|
|||
@click="toggleSelect()"
|
||||
:class="['select-btn', props.inpClass]"
|
||||
>
|
||||
<span
|
||||
v-if="props.required"
|
||||
class="font-bold text-red-500 absolute right-[5px] top-[-20px]"
|
||||
>*
|
||||
</span>
|
||||
<span :id="`${props.id}-text`" class="select-btn-name">
|
||||
{{ select.value || props.value }}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { defineProps } from "vue";
|
|||
*
|
||||
label: string,
|
||||
name: string,
|
||||
required: boolean,
|
||||
version: string,
|
||||
hideLabel: boolean,
|
||||
required: boolean,
|
||||
|
|
@ -23,6 +24,10 @@ const props = defineProps({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
version: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
|
@ -39,7 +44,7 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="[props.hideLabel ? 'hidden' : '', props.headerClass]">
|
||||
<div :class="['relative', props.hideLabel ? 'hidden' : '', props.headerClass]">
|
||||
<label
|
||||
:class="[props.label ? '' : 'sr-only']"
|
||||
:for="props.name"
|
||||
|
|
@ -49,7 +54,7 @@ const props = defineProps({
|
|||
</label>
|
||||
<span
|
||||
v-if="props.required"
|
||||
class="font-bold text-red-500 absolute right-[5px] top-[-20px]"
|
||||
class="font-bold text-red-500 absolute ml-1"
|
||||
>*
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
<script setup>
|
||||
const builder = [{
|
||||
// we are starting with the top level container name
|
||||
// this can be a "card", "modal", "table"... etc
|
||||
"card" : {
|
||||
// a card can have an icon and a color at the top right
|
||||
"icon": ["iconName", "iconColor"],
|
||||
// grid position for each screen
|
||||
"columns" : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
// container title
|
||||
"title" : "My awesome card",
|
||||
// group of widgets will share same columns
|
||||
// Case we want a button widget in a one column group and others in like a 3 columns group
|
||||
"groups" : [{
|
||||
// determine the number of columns for widgets in group for each screen
|
||||
"columns" : (1, 2, 3),
|
||||
"widgets" : [
|
||||
{
|
||||
"position" : "left", // "center" or "right" or "default"
|
||||
"type" : "widgetType", // "widgetType" is the name of the widget, for example "Detail" to render a Detail widget
|
||||
// Need to be a list in case we have multiple widgets in the same group
|
||||
// By default, widgetEls are horizontally aligned with flexbox
|
||||
"widgetEls" : [
|
||||
// data we need for one widget
|
||||
{
|
||||
"id" : "widgetId",
|
||||
"title" : "Widget title",
|
||||
"label" : "Widget label",
|
||||
"values" : ["value1", "value2"],
|
||||
},
|
||||
// ... other widgets
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// ... other groups
|
||||
]
|
||||
},
|
||||
// ... other containers
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
100
vuejs/client/src/components/Widget/Popover.vue
Normal file
100
vuejs/client/src/components/Widget/Popover.vue
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<script setup>
|
||||
import { reactive, onMounted, defineProps } from "vue";
|
||||
import { contentIndex } from "@utils/tabindex.js";
|
||||
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
icon : {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
// Sometimes we can't have a button tag (like popover on another btn)
|
||||
tag: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "button",
|
||||
},
|
||||
});
|
||||
|
||||
// Determine popover need to be display
|
||||
const popover = reactive({
|
||||
isOpen: false,
|
||||
isHover: false,
|
||||
});
|
||||
|
||||
// Different style for desktop and mobile
|
||||
const tab = reactive({
|
||||
isMobile: false,
|
||||
// format label to fit id
|
||||
id: props.content.trim().toLowerCase().replaceAll(" ", "-").substring(0, 15) + "popover",
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// When component is created but before is insert on DOM
|
||||
// Check window width to determine we need to display mobile or desktop tab design
|
||||
tab.isMobile = window.innerWidth >= 768 ? false : true;
|
||||
window.addEventListener("resize", () => {
|
||||
tab.isMobile = window.innerWidth >= 768 ? false : true;
|
||||
});
|
||||
});
|
||||
|
||||
function showPopover() {
|
||||
popover.isHover = true;
|
||||
setTimeout(() => {
|
||||
popover.isOpen = popover.isHover ? true : false;
|
||||
}, 450);
|
||||
}
|
||||
|
||||
function hidePopover() {
|
||||
popover.isHover = false;
|
||||
popover.isOpen = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:tabindex="contentIndex"
|
||||
:aria-controls="`${tab.id}`"
|
||||
:aria-expanded="popover.isOpen ? 'true' : 'false'"
|
||||
:aria-describedby="`${tab.id}-text`"
|
||||
:is="props.tag"
|
||||
role="button"
|
||||
@focusin="showPopover()"
|
||||
@focusout="hidePopover()"
|
||||
@pointerover="showPopover()"
|
||||
@pointerleave="hidePopover()"
|
||||
class="cursor-pointer flex justify-start w-full"
|
||||
>
|
||||
<span :id="`${tab.id}-text`" class="sr-only">
|
||||
{{ $t("dashboard_popover_button_desc") }}
|
||||
</span>
|
||||
<svg
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
class="popover-settings-svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z"
|
||||
/>
|
||||
</svg>
|
||||
</component>
|
||||
<div
|
||||
:id="`${tab.label}-popover-${tab.id}`"
|
||||
role="status"
|
||||
:aria-hidden="popover.isOpen ? 'false' : 'true'"
|
||||
v-show="popover.isOpen"
|
||||
:class="['popover-settings-container']"
|
||||
:aria-description="$t('dashboard_popover_detail_desc')"
|
||||
>
|
||||
<p :id="${tab.id}-text" class="popover-settings-text"><slot></slot></p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -21,7 +21,7 @@ const checkboxData = {
|
|||
value: 'yes',
|
||||
name: 'test-checkbox',
|
||||
disabled: false,
|
||||
required: false,
|
||||
required: true,
|
||||
label: 'Test checkbox',
|
||||
tabId: '1',
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ const selectData = {
|
|||
values: ['yes', 'no'],
|
||||
name: 'test-select',
|
||||
disabled: false,
|
||||
required: false,
|
||||
required: true,
|
||||
label: 'Test select',
|
||||
tabId: '1',
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ const inputData = {
|
|||
type: "text",
|
||||
name: 'test-input',
|
||||
disabled: false,
|
||||
required: false,
|
||||
required: true,
|
||||
label: 'Test input',
|
||||
pattern : "(test)",
|
||||
tabId: '1',
|
||||
|
|
|
|||
Loading…
Reference in a new issue