create generic icon component + start popover

This commit is contained in:
Jordan Blasenhauer 2024-06-07 12:45:29 +02:00
parent 71c81ae1d9
commit 1b55d2d632
24 changed files with 11897 additions and 7172 deletions

View file

@ -159,17 +159,40 @@ body {
}
/* INPUT */
.input-header-container {
@apply z-10;
}
.no-popover.input-header-container {
@apply flex justify-start;
}
.popover.input-header-container {
@apply flex justify-between;
}
.input-header-label {
@apply relative lowercase capitalize-first mb-1 transition duration-300 ease-in-out text-sm font-bold m-0 dark:text-gray-300 mr-2;
}
.input-header-required-sign {
@apply font-bold text-red-500 absolute ml-1;
}
.input-error-msg {
@apply text-red-500 dark:text-red-300 text-[0.75rem] font-semibold mb-0 mt-0.5;
}
.checkbox-container {
@apply relative z-10 flex flex-col items-start mt-1;
}
.checkbox {
@apply hover:border-gray-600 cursor-pointer disabled:cursor-default
relative dark:border-slate-600 dark:bg-slate-700 z-10 w-5 h-5
text-base rounded-1.4 duration-150 float-left
mt-1 appearance-none border border-gray-300 bg-white bg-contain bg-center
bg-no-repeat align-top transition-all disabled:bg-gray-400
appearance-none border border-gray-300 bg-white bg-contain bg-center
mt-1 bg-no-repeat align-top transition-all disabled:bg-gray-400
disabled:border-gray-400/0 dark:disabled:bg-gray-800
dark:disabled:border-gray-800/0 disabled:text-gray-700
dark:disabled:text-gray-300;
@ -184,7 +207,7 @@ body {
}
.select-btn {
@apply relative dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-800 dark:disabled:border-gray-800/0 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 hover:border-gray-600 focus:border-gray-600 flex justify-between align-middle items-center text-left text-sm leading-5.6 w-full md:max-w-[350px] rounded-lg border border-solid border-gray-400 bg-white bg-clip-padding px-1.5 py-1 md:px-2.5 md:py-1.5 font-normal text-gray-700 transition-all placeholder:text-gray-500;
@apply relative dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-800 dark:disabled:border-gray-800/0 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 hover:border-gray-600 focus:border-gray-600 flex justify-between align-middle items-center text-left text-sm leading-5.6 w-full rounded-lg border border-solid border-gray-400 bg-white bg-clip-padding px-1.5 py-1 md:px-2.5 md:py-1.5 font-normal text-gray-700 transition-all placeholder:text-gray-500;
}
.select-btn-name {
@ -220,7 +243,7 @@ body {
}
.input-regular {
@apply hover:border-gray-600 outline-none dark:border-slate-600 dark:bg-slate-700 dark:text-gray-200 focus:border-gray-300/0 dark:focus:border-gray-600/0 focus:ring-1 focus:valid:ring-green-500 focus:invalid:ring-red-500 text-sm leading-5.6 ease-in block w-full md:max-w-[350px] appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-2.5 md:py-1.5 font-normal text-gray-700 transition-all placeholder:text-gray-500 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-800 dark:disabled:border-gray-800/0 dark:disabled:text-gray-300 disabled:text-gray-700;
@apply hover:border-gray-600 outline-none dark:border-slate-600 dark:bg-slate-700 dark:text-gray-200 focus:border-gray-300/0 dark:focus:border-gray-600/0 focus:ring-1 focus:valid:ring-green-500 focus:invalid:ring-red-500 text-sm leading-5.6 ease-in block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-2.5 md:py-1.5 font-normal text-gray-700 transition-all placeholder:text-gray-500 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-800 dark:disabled:border-gray-800/0 dark:disabled:text-gray-300 disabled:text-gray-700;
}
.invalid.input-regular,
@ -340,40 +363,28 @@ body {
/* POPOVER */
.popover-settings-container {
@apply z-10 absolute h-fit w-full bottom-6 -left-20 min-w-[225px] opacity-100 justify-center items-center dark:brightness-90 transition z-50 rounded-md p-3 bg-blue-500;
.popover-btn {
@apply cursor-pointer flex justify-start w-full;
}
.popover-background {
@apply bg-white w-3 h-3 rounded -z-0 translate-x-3 translate-y-1 absolute;
.popover-container {
@apply pointer-events-none z-10 fixed max-w-[80vw] sm:max-w-[350px] opacity-100 justify-center items-center dark:brightness-90 transition z-50 rounded-md py-3 px-5;
}
.popover-settings-text {
.open.popover-container {
@apply z-10 opacity-100;
}
.close.popover-container {
@apply -z-10 opacity-0;
}
.popover-text {
@apply whitespace-normal pointer-events-none text-center transition duration-300 ease-in-out font-semibold text-sm text-white dark:text-white m-0;
}
.popover-settings-svg {
@apply z-0 hover:brightness-95 fill-blue-500 h-5 w-5 ml-2;
}
.popover-tab-container {
@apply z-10 fixed md:absolute bottom-0 h-fit w-full md:min-w-[200px] opacity-100 justify-center items-center dark:brightness-90 transition z-50 rounded-md p-3 bg-blue-500;
}
.mobile.popover-tab-container {
@apply max-w-[200px];
}
.desktop.popover-tab-container {
@apply top-6 -left-20;
}
.popover-tab-text {
@apply whitespace-normal pointer-events-none text-center transition duration-300 ease-in-out font-semibold text-sm text-white dark:text-white m-0;
}
.popover-tab-svg {
@apply z-0 hover:brightness-95 fill-blue-500 h-5 w-5 ml-2;
.popover-svg {
@apply pointer-events-none z-0 hover:brightness-95 fill-blue-500 h-5 w-5;
}
/* TABS */
@ -1587,185 +1598,221 @@ body {
.success.status-icon,
.success.stat-svg-container,
.success.feedback-alert-wrap {
.success.feedback-alert-wrap,
.success.popover-container {
@apply bg-green-500;
}
.error.status-icon,
.error.stat-svg-container,
.error.feedback-alert-wrap {
.error.feedback-alert-wrap,
.error.popover-container {
@apply bg-red-500;
}
.warning.status-icon,
.warning.stat-svg-container,
.warning.feedback-alert-wrap {
.warning.feedback-alert-wrap,
.warning.popover-container {
@apply bg-yellow-500;
}
.info.status-icon,
.info.stat-svg-container,
.info.feedback-alert-wrap {
.info.feedback-alert-wrap,
.info.popover-container {
@apply bg-sky-500;
}
.purple.stat-svg-container,
.purple.feedback-alert-wrap {
.purple.feedback-alert-wrap,
.purple.popover-container {
@apply bg-purple-500;
}
.green.stat-svg-container,
.green.feedback-alert-wrap {
.green.feedback-alert-wrap,
.green.popover-container {
@apply bg-green-500;
}
.red.stat-svg-container,
.red.feedback-alert-wrap {
.red.feedback-alert-wrap,
.red.popover-container {
@apply bg-red-500;
}
.orange.stat-svg-container,
.orange.feedback-alert-wrap {
.orange.feedback-alert-wrap,
.orange.popover-container {
@apply bg-orange-500;
}
.blue.stat-svg-container,
.blue.feedback-alert-wrap {
.blue.feedback-alert-wrap,
.blue.popover-container {
@apply bg-blue-500;
}
.yellow.stat-svg-container,
.yellow.feedback-alert-wrap {
.yellow.feedback-alert-wrap,
.yellow.popover-container {
@apply bg-yellow-500;
}
.gray.stat-svg-container,
.gray.feedback-alert-wrap {
.gray.feedback-alert-wrap,
.gray.popover-container {
@apply bg-gray-500;
}
.dark.stat-svg-container,
.dark.feedback-alert-wrap {
.dark.feedback-alert-wrap,
.dark.popover-container {
@apply bg-slate-500;
}
.amber.stat-svg-container,
.amber.feedback-alert-wrap {
.amber.feedback-alert-wrap,
.amber.popover-container {
@apply bg-amber-500;
}
.emerald.stat-svg-container,
.emerald.feedback-alert-wrap {
.emerald.feedback-alert-wrap,
.emerald.popover-container {
@apply bg-emerald-500;
}
.teal.stat-svg-container,
.teal.feedback-alert-wrap {
.teal.feedback-alert-wrap,
.teal.popover-container {
@apply bg-teal-500;
}
.indigo.stat-svg-container,
.indigo.feedback-alert-wrap {
.indigo.feedback-alert-wrap,
.indigo.popover-container {
@apply bg-indigo-500;
}
.cyan.stat-svg-container,
.cyan.feedback-alert-wrap {
.cyan.feedback-alert-wrap,
.cyan.popover-container {
@apply bg-cyan-500;
}
.sky.stat-svg-container,
.sky.feedback-alert-wrap {
.sky.feedback-alert-wrap,
.sky.popover-container {
@apply bg-sky-500;
}
.pink.stat-svg-container,
.pink.feedback-alert-wrap {
.pink.feedback-alert-wrap,
.pink.popover-container {
@apply bg-pink-500;
}
.lime.stat-svg-container,
.lime.feedback-alert-wrap {
.lime.feedback-alert-wrap,
.lime.popover-container {
@apply bg-lime-500;
}
.purple-darker.stat-svg-container,
.purle-darker.feedback-alert-wrap {
.purle-darker.feedback-alert-wrap,
.purple-darker.popover-container {
@apply bg-purple-600;
}
.green-darker.stat-svg-container,
.green-darker.feedback-alert-wrap {
.green-darker.feedback-alert-wrap,
.green-darker.popover-container {
@apply bg-green-700;
}
.red-darker.stat-svg-container,
.red-darker.feedback-alert-wrap {
.red-darker.feedback-alert-wrap,
.red-darker.popover-container {
@apply bg-red-700;
}
.orange-darker.stat-svg-container,
.orange-darker.feedback-alert-wrap {
.orange-darker.feedback-alert-wrap,
.orange-darker.popover-container {
@apply bg-orange-600;
}
.blue-darker.stat-svg-container,
.blue-darker.feedback-alert-wrap {
.blue-darker.feedback-alert-wrap,
.blue-darker.popover-container {
@apply bg-blue-600;
}
.yellow-darker.stat-svg-container,
.yellow-darker.feedback-alert-wrap {
.yellow-darker.feedback-alert-wrap,
.yellow-darker.popover-container {
@apply bg-yellow-600;
}
.gray-darker.stat-svg-container,
.gray-darker.feedback-alert-wrap {
.gray-darker.feedback-alert-wrap,
.gray-darker.popover-container {
@apply bg-gray-600;
}
.dark-darker.stat-svg-container,
.dark-darker.feedback-alert-wrap {
.dark-darker.feedback-alert-wrap,
.dark-darker.popover-container {
@apply bg-slate-600;
}
.amber-darker.stat-svg-container,
.amber-darker.feedback-alert-wrap {
.amber-darker.feedback-alert-wrap,
.amber-darker.popover-container {
@apply bg-amber-600;
}
.emerald-darker.stat-svg-container,
.emerald-darker.feedback-alert-wrap {
.emerald-darker.feedback-alert-wrap,
.emerald-darker.popover-container {
@apply bg-emerald-600;
}
.teal-darker.stat-svg-container,
.teal-darker.feedback-alert-wrap {
.teal-darker.feedback-alert-wrap,
.teal-darker.popover-container {
@apply bg-teal-600;
}
.indigo-darker.stat-svg-container,
.indigo-darker.feedback-alert-wrap {
.indigo-darker.feedback-alert-wrap,
.indigo-darker.popover-container {
@apply bg-indigo-600;
}
.cyan-darker.stat-svg-container,
.cyan-darker.feedback-alert-wrap {
.cyan-darker.feedback-alert-wrap,
.cyan-darker.popover-container {
@apply bg-cyan-600;
}
.sky-darker.stat-svg-container,
.sky-darker.feedback-alert-wrap {
.sky-darker.feedback-alert-wrap,
.sky-darker.popover-container {
@apply bg-sky-700;
}
.pink-darker.stat-svg-container,
.pink-darker.feedback-alert-wrap {
.pink-darker.feedback-alert-wrap,
.pink-darker.popover-container {
@apply bg-pink-600;
}
.lime-darker.stat-svg-container,
.lime-darker.feedback-alert-wrap {
.lime-darker.feedback-alert-wrap,
.lime-darker.popover-container {
@apply bg-lime-600;
}
@ -1775,7 +1822,8 @@ body {
.success.btn-svg,
.success.menu-svg,
.success.social-svg,
.success.stat-svg {
.success.stat-svg,
.success.popover-svg {
@apply fill-green-500;
}
@ -1783,7 +1831,8 @@ body {
.error.btn-svg,
.error.menu-svg,
.error.social-svg,
.error.stat-svg {
.error.stat-svg,
.error.popover-svg {
@apply fill-red-500;
}
@ -1791,7 +1840,8 @@ body {
.warning.btn-svg,
.warning.menu-svg,
.warning.social-svg,
.warning.stat-svg {
.warning.stat-svg,
.warning.popover-svg {
@apply fill-yellow-500;
}
@ -1799,7 +1849,8 @@ body {
.info.btn-svg,
.info.menu-svg,
.info.social-svg,
.info.stat-svg {
.info.stat-svg,
.info.popover-svg {
@apply fill-sky-500;
}
@ -1807,7 +1858,8 @@ body {
.white.btn-svg,
.white.menu-svg,
.white.social-svg,
.white.stat-svg {
.white.stat-svg,
.white.popover-svg {
@apply fill-white;
}
@ -1815,7 +1867,8 @@ body {
.purple.btn-svg,
.purple.menu-svg,
.purple.social-svg,
.purple.stat-svg {
.purple.stat-svg,
.purple.popover-svg {
@apply fill-purple-500;
}
@ -1823,7 +1876,8 @@ body {
.green.btn-svg,
.green.menu-svg,
.green.social-svg,
.green.stat-svg {
.green.stat-svg,
.green.popover-svg {
@apply fill-green-500;
}
@ -1831,7 +1885,8 @@ body {
.red.btn-svg,
.red.menu-svg,
.red.social-svg,
.red.stat-svg {
.red.stat-svg,
.red.popover-svg {
@apply fill-red-500;
}
@ -1839,7 +1894,8 @@ body {
.orange.btn-svg,
.orange.menu-svg,
.orange.social-svg,
.orange.stat-svg {
.orange.stat-svg,
.orange.popover-svg {
@apply fill-orange-500;
}
@ -1847,7 +1903,8 @@ body {
.blue.btn-svg,
.blue.menu-svg,
.blue.social-svg,
.blue.stat-svg {
.blue.stat-svg,
.blue.popover-svg {
@apply fill-blue-500;
}
@ -1855,7 +1912,8 @@ body {
.yellow.btn-svg,
.yellow.menu-svg,
.yellow.social-svg,
.yellow.stat-svg {
.yellow.stat-svg,
.yellow.popover-svg {
@apply fill-yellow-500;
}
@ -1863,7 +1921,8 @@ body {
.gray.btn-svg,
.gray.menu-svg,
.gray.social-svg,
.gray.stat-svg {
.gray.stat-svg,
.gray.popover-svg {
@apply fill-gray-500;
}
@ -1871,7 +1930,8 @@ body {
.dark.btn-svg,
.dark.menu-svg,
.dark.social-svg,
.dark.stat-svg {
.dark.stat-svg,
.dark.popover-svg {
@apply fill-slate-500;
}
@ -1879,7 +1939,8 @@ body {
.amber.btn-svg,
.amber.menu-svg,
.amber.social-svg,
.amber.stat-svg {
.amber.stat-svg,
.amber.popover-svg {
@apply fill-amber-500;
}
@ -1887,7 +1948,8 @@ body {
.emerald.btn-svg,
.emerald.menu-svg,
.emerald.social-svg,
.emerald.stat-svg {
.emerald.stat-svg,
.emerald.popover-svg {
@apply fill-emerald-500;
}
@ -1895,7 +1957,8 @@ body {
.teal.btn-svg,
.teal.menu-svg,
.teal.social-svg,
.teal.stat-svg {
.teal.stat-svg,
.teal.popover-svg {
@apply fill-teal-500;
}
@ -1903,7 +1966,8 @@ body {
.indigo.btn-svg,
.indigo.menu-svg,
.indigo.social-svg,
.indigo.stat-svg {
.indigo.stat-svg,
.indigo.popover-svg {
@apply fill-indigo-500;
}
@ -1911,7 +1975,8 @@ body {
.cyan.btn-svg,
.cyan.menu-svg,
.cyan.social-svg,
.cyan.stat-svg {
.cyan.stat-svg,
.cyan.popover-svg {
@apply fill-cyan-500;
}
@ -1919,7 +1984,8 @@ body {
.sky.btn-svg,
.sky.menu-svg,
.sky.social-svg,
.sky.stat-svg {
.sky.stat-svg,
.sky.popover-svg {
@apply fill-sky-500;
}
@ -1927,7 +1993,8 @@ body {
.pink.btn-svg,
.pink.menu-svg,
.pink.social-svg,
.pink.stat-svg {
.pink.stat-svg,
.pink.popover-svg {
@apply fill-pink-500;
}
@ -1935,7 +2002,8 @@ body {
.lime.btn-svg,
.lime.menu-svg,
.lime.social-svg,
.lime.stat-svg {
.lime.stat-svg,
.lime.popover-svg {
@apply fill-lime-500;
}
@ -1943,7 +2011,8 @@ body {
.twitter.btn-svg,
.twitter.menu-svg,
.twitter.social-svg,
.twitter.stat-svg {
.twitter.stat-svg,
.twitter.popover-svg {
@apply fill-[#1DA1F2];
}
@ -1951,7 +2020,8 @@ body {
.linkedin.btn-svg,
.linkedin.menu-svg,
.linkedin.social-svg,
.linkedin.stat-svg {
.linkedin.stat-svg,
.linkedin.popover-svg {
@apply fill-[#0A63BC];
}
@ -1959,7 +2029,8 @@ body {
.discord.btn-svg,
.discord.menu-svg,
.discord.social-svg,
.discord.stat-svg {
.discord.stat-svg,
.discord.popover-svg {
@apply fill-[#5562EA];
}
@ -1967,7 +2038,8 @@ body {
.github.btn-svg,
.github.menu-svg,
.github.social-svg,
.github.stat-svg {
.github.stat-svg,
.github.popover-svg {
@apply fill-[#171A1F] dark:fill-gray-300;
}
@ -1975,7 +2047,8 @@ body {
.purle-darker.btn-svg,
.purple-darker.menu-svg,
.purple-darker.social-svg,
.purple-darker.stat-svg {
.purple-darker.stat-svg,
.purple-darker.popover-svg {
@apply fill-purple-600;
}
@ -1983,7 +2056,8 @@ body {
.green-darker.btn-svg,
.green-darker.menu-svg,
.green-darker.social-svg,
.green-darker.stat-svg {
.green-darker.stat-svg,
.green-darker.popover-svg {
@apply fill-green-700;
}
@ -1991,7 +2065,8 @@ body {
.red-darker.btn-svg,
.red-darker.menu-svg,
.red-darker.social-svg,
.red-darker.stat-svg {
.red-darker.stat-svg,
.red-darker.popover-svg {
@apply fill-red-700;
}
@ -1999,7 +2074,8 @@ body {
.orange-darker.btn-svg,
.orange-darker.menu-svg,
.orange-darker.social-svg,
.orange-darker.stat-svg {
.orange-darker.stat-svg,
.orange-darker.popover-svg {
@apply fill-orange-600;
}
@ -2007,7 +2083,8 @@ body {
.blue-darker.btn-svg,
.blue-darker.menu-svg,
.blue-darker.social-svg,
.blue-darker.stat-svg {
.blue-darker.stat-svg,
.blue-darker.popover-svg {
@apply fill-blue-600;
}
@ -2015,7 +2092,8 @@ body {
.yellow-darker.btn-svg,
.yellow-darker.menu-svg,
.yellow-darker.social-svg,
.yellow-darker.stat-svg {
.yellow-darker.stat-svg,
.yellow-darker.popover-svg {
@apply fill-yellow-600;
}
@ -2023,7 +2101,8 @@ body {
.gray-darker.btn-svg,
.gray-darker.menu-svg,
.gray-darker.social-svg,
.gray-darker.stat-svg {
.gray-darker.stat-svg,
.gray-darker.popover-svg {
@apply fill-gray-600;
}
@ -2031,7 +2110,8 @@ body {
.dark-darker.btn-svg,
.dark-darker.menu-svg,
.dark-darker.social-svg,
.dark-darker.stat-svg {
.dark-darker.stat-svg,
.dark-darker.popover-svg {
@apply fill-slate-600;
}
@ -2039,7 +2119,8 @@ body {
.amber-darker.btn-svg,
.amber-darker.menu-svg,
.amber-darker.social-svg,
.amber-darker.stat-svg {
.amber-darker.stat-svg,
.amber-darker.popover-svg {
@apply fill-amber-600;
}
@ -2047,7 +2128,8 @@ body {
.emerald-darker.btn-svg,
.emerald-darker.menu-svg,
.emerald-darker.social-svg,
.emerald-darker.stat-svg {
.emerald-darker.stat-svg,
.emerald-darker.popover-svg {
@apply fill-emerald-600;
}
@ -2055,7 +2137,8 @@ body {
.teal-darker.btn-svg,
.teal-darker.menu-svg,
.teal-darker.social-svg,
.teal-darker.stat-svg {
.teal-darker.stat-svg,
.teal-darker.popover-svg {
@apply fill-teal-600;
}
@ -2063,7 +2146,8 @@ body {
.indigo-darker.btn-svg,
.indigo-darker.menu-svg,
.indigo-darker.social-svg,
.indigo-darker.stat-svg {
.indigo-darker.stat-svg,
.indigo-darker.popover-svg {
@apply fill-indigo-600;
}
@ -2071,7 +2155,8 @@ body {
.cyan-darker.btn-svg,
.cyan-darker.menu-svg,
.cyan-darker.social-svg,
.cyan-darker.stat-svg {
.cyan-darker.stat-svg,
.cyan-darker.popover-svg {
@apply fill-cyan-600;
}
@ -2079,7 +2164,8 @@ body {
.sky-darker.btn-svg,
.sky-darker.menu-svg,
.sky-darker.social-svg,
.sky-darker.stat-svg {
.sky-darker.stat-svg,
.sky-darker.popover-svg {
@apply fill-sky-700;
}
@ -2087,7 +2173,8 @@ body {
.pink-darker.btn-svg,
.pink-darker.menu-svg,
.pink-darker.social-svg,
.pink-darker.stat-svg {
.pink-darker.stat-svg,
.pink-darker.popover-svg {
@apply fill-pink-600;
}
@ -2095,6 +2182,7 @@ body {
.lime-darker.btn-svg,
.lime-darker.menu-svg,
.lime-darker.social-svg,
.lime-darker.stat-svg {
.lime-darker.stat-svg,
.lime-darker.popover-svg {
@apply fill-lime-600;
}

File diff suppressed because one or more lines are too long

View file

@ -10,8 +10,7 @@ import Subtitle from "@components/Widget/Subtitle.vue";
import ContentStat from "@components/Content/Stat.vue";
import ContentDetailList from "@components/Content/DetailList.vue";
// Icon
import IconStat from "@components/Icon/Stat.vue";
import IconStatus from "@components/Icon/Status.vue";
import IconStatus from "@components/Widget/Status.vue";
// Form
import Checkbox from "@components/Forms/Field/Checkbox.vue";
import Select from "@components/Forms/Field/Select.vue";

View file

@ -21,11 +21,19 @@ import ErrorField from "@components/Forms/Error/Field.vue";
hideLabel: false,
inpType: "checkbox",
headerClass: "text-red-500"
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
]
}
@param {string} id
@param {string} label - The label of the field. Can be a translation key or by default raw text.
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.
@param {string} value
@param {array} [popovers] - List of popovers to display more information
@param {string} [inpType="checkbox"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {boolean} [disabled=false]
@param {boolean} [required=false]
@ -52,6 +60,11 @@ const props = defineProps({
type: String,
required: true,
},
popovers: {
type: Array,
required: false,
default: [],
},
inpType: {
type: String,
required: false,
@ -73,11 +86,6 @@ const props = defineProps({
type: String,
required: true,
},
version: {
type: String,
required: false,
default: "",
},
hideLabel: {
type: Boolean,
required: false,
@ -130,6 +138,7 @@ onMounted(() => {
:columns="props.columns"
>
<Header
:popovers="props.popovers"
:required="props.required"
:name="props.name"
:label="props.label"
@ -137,7 +146,7 @@ onMounted(() => {
:headerClass="props.headerClass"
/>
<div class="relative z-10 flex flex-col items-start">
<div class="checkbox-container">
<input
ref="checkboxEl"
:tabindex="props.tabId"

View file

@ -28,10 +28,18 @@ import "@assets/css/flatpickr.dark.css";
noPickAfterStamp: 1735689600000,
inpClass: "text-center",
inpType : ""
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
],
}
@param {string} id
@param {string} label - The label of the field. Can be a translation key or by default raw text.
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.
@param {array} popovers - List of popovers to display more information
@param {string} [inpType="datepicker"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {string|number|date} [defaultDate=null] - Default date when instanciate
@param {string|number} [noPickBeforeStamp=""] - Impossible to pick a date before this date
@ -59,6 +67,11 @@ const props = defineProps({
type: String,
required: false,
},
popovers: {
type: Array,
required: false,
default: [],
},
inpType: {
type: String,
required: false,
@ -626,6 +639,7 @@ function setIndex(calendarEl, tabindex) {
:columns="props.columns"
>
<Header
:popovers="props.popovers"
:required="props.required"
:name="props.name"
:label="props.label"

View file

@ -23,13 +23,21 @@ import ErrorField from "@components/Forms/Error/Field.vue";
label: 'Test input',
pattern : "(test)",
inpType: "input",
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
],
}
@param {string} id
@param {string} type - text, email, password, number, tel, url
@param {string} label - The label of the field. Can be a translation key or by default raw text.
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text. @param {string} label
@param {string} value
@param {string} [inpType="input"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {array} [popovers] - List of popovers to display more information
@param {string} [inpType="input"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {object} [columns={"pc": "12", "tablet": "12", "mobile": "12}] - Field has a grid system. This allow to get multiple field in the same row if needed.
@param {boolean} [disabled=false]
@param {boolean} [required=false]
@ -100,9 +108,10 @@ const props = defineProps({
type: String,
required: true,
},
version: {
type: String,
popovers: {
type: Array,
required: false,
default: [],
},
hideLabel: {
type: Boolean,
@ -178,6 +187,7 @@ onMounted(() => {
:columns="props.columns"
>
<Header
:popovers="props.popovers"
:required="props.required"
:name="props.name"
:label="props.label"

View file

@ -22,13 +22,20 @@ import ErrorField from "@components/Forms/Error/Field.vue";
requiredValues : ['no'], // need required to be checked
label: 'Test select',
inpType: "select",
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},]
}
@param {string} id
@param {string} label - The label of the field. Can be a translation key or by default raw text.
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.
@param {string} value
@param {array} values
@param {string} [inpType="select"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {array} [popovers] - List of popovers to display more information
@param {string} [inpType="select"] - The type of the field, useful when we have multiple fields in the same container to display the right field
@param {boolean} [disabled=false]
@param {boolean} [required=false]
@param {array} [requiredValues=[]] - values that need to be selected to be valid, works only if required is true
@ -85,10 +92,10 @@ const props = defineProps({
type: String,
required: true,
},
version: {
type: String,
popovers: {
type: Array,
required: false,
default: "",
default: [],
},
hideLabel: {
type: Boolean,
@ -208,6 +215,7 @@ const emits = defineEmits(["inp"]);
:columns="props.columns"
>
<Header
:popovers="props.popovers"
:required="props.required"
:name="props.name"
:label="props.label"

View file

@ -1,5 +1,6 @@
<script setup>
import { defineProps } from "vue";
import PopoverGroup from "@components/Widget/PopoverGroup.vue";
/**
@name Forms/Header/Field.vue
@ -12,9 +13,17 @@ import { defineProps } from "vue";
version : "0.1.0",
name: 'test-input',
required: true,
popovers : [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
],
}
@param {string} label - The label of the field. Can be a translation key or by default raw text.
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.
@param {array} [popovers] - List of popovers to display more information
@param {boolean} [required=false]
@param {boolean} [hideLabel=false]
@param {string} [headerClass=""]
@ -29,14 +38,15 @@ const props = defineProps({
type: String,
required: true,
},
required: {
type: Boolean,
required: false,
},
version: {
type: String,
required: {
type: Boolean,
required: false,
},
popovers: {
type: Array,
required: false,
default: [],
},
hideLabel: {
type: Boolean,
required: false,
@ -49,18 +59,31 @@ const props = defineProps({
</script>
<template>
<div :class="['relative', props.hideLabel ? 'hidden' : '', props.headerClass]">
<label
:class="[props.label ? '' : 'sr-only']"
:for="props.name"
class="relative lowercase capitalize-first my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-300"
>
{{ props.label ? $t(props.label, props.label) : $t(props.name, props.name) }} <span v-if="props.version">{{ props.version }}</span>
</label>
<span
v-if="props.required"
class="font-bold text-red-500 absolute ml-1"
>*
</span>
<div
:class="[
'relative',
props.hideLabel ? 'hidden' : '',
props.headerClass,
'input-header-container',
props.popovers.length ? 'popover' : 'no-popover',
]"
>
<div>
<label
:class="[props.label ? '' : 'sr-only']"
:for="props.name"
class="input-header-label"
>
{{
props.label
? $t(props.label, props.label)
: $t(props.name, props.name)
}}
</label>
<span v-if="props.required" class="input-header-required-sign">*</span>
</div>
<div v-if="props.popovers.length">
<PopoverGroup :popovers="props.popovers"></PopoverGroup>
</div>
</div>
</template>

View file

@ -72,20 +72,22 @@ const props = defineProps({
:containerClass="`col-span-12 w-full m-1 p-1`"
:columns="props.columns"
>
<Container class="col-span-12 w-full" v-for="plugin in plugins">
<Title type="card" :title="plugin.name" />
<Subtitle type="card" :subtitle="plugin.description" />
<Container v-for="form in props.forms">
<Container class="col-span-12 w-full" v-for="plugin in form">
<Title type="card" :title="plugin.name" />
<Subtitle type="card" :subtitle="plugin.description" />
<Container class="grid grid-cols-12 w-full">
<template v-for="(setting, 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" />
</template>
<Container class="grid grid-cols-12 w-full">
<template v-for="(setting, 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" />
</template>
</Container>
</Container>
</Container>
</Container>

View file

@ -1,52 +0,0 @@
<script setup>
import Icons from "@/components/Widget/Icons.vue";
/**
@name Icon/Stat.vue
@description This component is a icon used with stats.
This can be used alone in case we don't need a complete stat widget.
In case you have a title, subtitle, stat and icon to display, you can directly use Stat widget.
@example
{
iconName: "crown",
iconColor: "info",
iconClass: "text-sm"
}
@param {string} iconName - The icon name of the stat. Can be a translation key or by default raw text.
@param {string} [iconColor="info"] - The color of the icon between error, success, warning, info
@param {string} [iconClass=""] - Additional class, useful when component is used directly on a grid system.
*/
const props = defineProps({
iconName: {
type: String,
required: false,
default: "",
},
iconColor: {
type: String,
required: false,
default: "",
},
iconClass: {
type: String,
required: false,
default: "",
},
});
</script>
<template>
<div
v-if="props.iconName"
role="img"
aria-label="version"
:class="['stat-svg-container', props.iconColor, props.iconClass]"
>
<Icons
:iconName="props.iconName"
:iconClass="'stat-svg'"
:iconColor="'white'"
/>
</div>
</template>

View file

@ -0,0 +1,44 @@
<script setup>
/**
@name Icons/Disks.vue
@description This component is a svg icon representing disks.
@example
{
iconColor: 'info',
}
@param {string} [iconClass=""]
@param {string} [iconColor="info"] - The color of the icon between some tailwind css available colors (purple, green, red, orange, blue, yellow, gray, dark, amber, emerald, teal, indigo, cyan, sky, pink...). Darker colors are also available using the base color and adding '-darker' (e.g. 'red-darker').
*/
const props = defineProps({
iconClass: {
type: String,
required: false,
default: "default-svg",
},
iconColor: {
type: String,
required: false,
default: "info",
},
});
</script>
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
role="img"
aria-hidden="true"
:class="[props.iconClass, props.iconColor]"
>
<path
d="M5.507 4.048A3 3 0 0 1 7.785 3h8.43a3 3 0 0 1 2.278 1.048l1.722 2.008A4.533 4.533 0 0 0 19.5 6h-15c-.243 0-.482.02-.715.056l1.722-2.008Z"
/>
<path
fill-rule="evenodd"
d="M1.5 10.5a3 3 0 0 1 3-3h15a3 3 0 1 1 0 6h-15a3 3 0 0 1-3-3Zm15 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm2.25.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5ZM4.5 15a3 3 0 1 0 0 6h15a3 3 0 1 0 0-6h-15Zm11.25 3.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5ZM19.5 18a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z"
clip-rule="evenodd"
/>
</svg>
</template>

View file

@ -0,0 +1,39 @@
<script setup>
/**
@name Icons/Globe.vue
@description This component is a svg icon representing globe.
@example
{
iconColor: 'info',
}
@param {string} [iconClass=""]
@param {string} [iconColor="info"] - The color of the icon between some tailwind css available colors (purple, green, red, orange, blue, yellow, gray, dark, amber, emerald, teal, indigo, cyan, sky, pink...). Darker colors are also available using the base color and adding '-darker' (e.g. 'red-darker').
*/
const props = defineProps({
iconClass: {
type: String,
required: false,
default: "default-svg",
},
iconColor: {
type: String,
required: false,
default: "info",
},
});
</script>
<template>
<svg
role="img"
aria-hidden="true"
:class="[props.iconClass, props.iconColor]"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z"
/>
</svg>
</template>

View file

@ -0,0 +1,41 @@
<script setup>
/**
@name Icons/Info.vue
@description This component is a svg icon representing info.
@example
{
iconColor: 'info',
}
@param {string} [iconClass=""]
@param {string} [iconColor="info"] - The color of the icon between some tailwind css available colors (purple, green, red, orange, blue, yellow, gray, dark, amber, emerald, teal, indigo, cyan, sky, pink...). Darker colors are also available using the base color and adding '-darker' (e.g. 'red-darker').
*/
const props = defineProps({
iconClass: {
type: String,
required: false,
default: "default-svg",
},
iconColor: {
type: String,
required: false,
default: "info",
},
});
</script>
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
role="img"
aria-hidden="true"
:class="[props.iconClass, props.iconColor]"
>
<path
fill-rule="evenodd"
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm8.706-1.442c1.146-.573 2.437.463 2.126 1.706l-.709 2.836.042-.02a.75.75 0 0 1 .67 1.34l-.04.022c-1.147.573-2.438-.463-2.127-1.706l.71-2.836-.042.02a.75.75 0 1 1-.671-1.34l.041-.022ZM12 9a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z"
clip-rule="evenodd"
/>
</svg>
</template>

View file

@ -8,9 +8,6 @@ import { v4 as uuidv4 } from "uuid";
/**
@name Widget/Button.vue
@description This component is a standard button.
You can link this button to the event store with the clickAttr object.
This will allow you to share a value with other components, for example switching form on a click.
The prop attrs is an object that can contain multiple attributes to add to the button.
@example
{
id: "open-modal-btn",
@ -25,7 +22,7 @@ import { v4 as uuidv4 } from "uuid";
{ key: "modal", defaultValue: "close", clickValue: "open", targetId: "modal_id", valueExpanded: "open" },
],
}
@param {string} [id=uuid()] - Unique id of the button
@param {string} [id=uuidv4()] - Unique id of the button
@param {string} text - Content of the button. Can be a translation key or by default raw text.
@param {string} [type="button"] - Can be of type button || submit
@param {boolean} [disabled=false]

View file

@ -65,7 +65,7 @@ const props = defineProps({
<Flex v-if="props.buttons.length > 0" :flexClass="props.groupClass">
<Button
v-for="(button, id) in props.buttons"
:key="button.id"
:key="button"
v-bind="button"
:class="[id === props.buttons.length - 1 ? '' : 'mr-2']"
/>

View file

@ -2,24 +2,27 @@
import Box from "@components/Icons/Box.vue";
import Carton from "@components/Icons/Carton.vue";
import Core from "@components/Icons/Core.vue";
import Crown from "@components/Icons/Crown.vue";
import Discord from "@components/Icons/Discord.vue";
import Disk from "@components/Icons/Disk.vue";
import Flag from "@components/Icons/Flag.vue";
import Gear from "@components/Icons/Gear.vue";
import Github from "@components/Icons/Github.vue";
import House from "@components/Icons/House.vue";
import List from "@components/Icons/List.vue";
import Key from "@components/Icons/Key.vue";
import Linkedin from "@components/Icons/Linkedin.vue";
import Plus from "@components/Icons/Plus.vue";
import Puzzle from "@components/Icons/Puzzle.vue";
import Settings from "@components/Icons/Settings.vue";
import Task from "@components/Icons/Task.vue";
import Trespass from "@components/Icons/Trespass.vue";
import Twitter from "@components/Icons/Twitter.vue";
import Wire from "@components/Icons/Wire.vue";
import Funnel from "@components/Icons/Funnel.vue";
import Crown from "@components/Icons/Crown.vue";
import Discord from "@components/Icons/Discord.vue";
import Disk from "@components/Icons/Disk.vue";
import Flag from "@components/Icons/Flag.vue";
import Gear from "@components/Icons/Gear.vue";
import Github from "@components/Icons/Github.vue";
import House from "@components/Icons/House.vue";
import List from "@components/Icons/List.vue";
import Key from "@components/Icons/Key.vue";
import Linkedin from "@components/Icons/Linkedin.vue";
import Plus from "@components/Icons/Plus.vue";
import Puzzle from "@components/Icons/Puzzle.vue";
import Settings from "@components/Icons/Settings.vue";
import Task from "@components/Icons/Task.vue";
import Trespass from "@components/Icons/Trespass.vue";
import Twitter from "@components/Icons/Twitter.vue";
import Wire from "@components/Icons/Wire.vue";
import Funnel from "@components/Icons/Funnel.vue";
import Disks from "@components/Icons/Disks.vue";
import Globe from "@components/Icons/Globe.vue";
import Info from "@components/Icons/Info.vue";
import { computed } from "vue";
@ -44,6 +47,11 @@ const props = defineProps({
type: String,
required: true,
},
iconType: {
type: String,
required: false,
default: "default",
},
iconClass: {
type: String,
required: false,
@ -56,27 +64,147 @@ const props = defineProps({
},
});
const tag = computed(() => {
if (props.iconType === "stat") return "div";
return "template";
});
const containerClass = computed(() => {
if (props.iconType === "stat") return "stat-svg-container";
return "";
});
const iconColor = computed(() => {
if (props.iconType === "stat") return "white";
return props.iconColor;
});
const iconClass = computed(() => {
if (props.iconType === "stat") return "stat-svg";
return props.iconClass;
});
</script>
<template>
<Box v-if="props.iconName === 'box'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Carton v-if="props.iconName === 'carton'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Core v-if="props.iconName === 'core'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Crown v-if="props.iconName === 'crown'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Discord v-if="props.iconName === 'discord'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Disk v-if="props.iconName === 'disk'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Flag v-if="props.iconName === 'flag'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Gear v-if="props.iconName === 'gear'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Github v-if="props.iconName === 'github'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<House v-if="props.iconName === 'house'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<List v-if="props.iconName === 'list'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Key v-if="props.iconName === 'key'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Linkedin v-if="props.iconName === 'linkedin'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Plus v-if="props.iconName === 'plus'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Puzzle v-if="props.iconName === 'puzzle'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Settings v-if="props.iconName === 'settings'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Task v-if="props.iconName === 'task'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Trespass v-if="props.iconName === 'trespass'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Twitter v-if="props.iconName === 'twitter'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Wire v-if="props.iconName === 'wire'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
<Funnel v-if="props.iconName === 'funnel'" :iconClass="props.iconClass" :iconColor="props.iconColor" />
</template>
<div :class="[containerClass, props.iconColor, props.iconClass]">
<Box
v-if="props.iconName === 'box'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Carton
v-if="props.iconName === 'carton'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Core
v-if="props.iconName === 'core'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Crown
v-if="props.iconName === 'crown'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Discord
v-if="props.iconName === 'discord'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Disk
v-if="props.iconName === 'disk'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Disks
v-if="props.iconName === 'disks'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Globe
v-if="props.iconName === 'globe'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Info
v-if="props.iconName === 'info'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Flag
v-if="props.iconName === 'flag'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Gear
v-if="props.iconName === 'gear'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Github
v-if="props.iconName === 'github'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<House
v-if="props.iconName === 'house'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<List
v-if="props.iconName === 'list'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Key
v-if="props.iconName === 'key'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Linkedin
v-if="props.iconName === 'linkedin'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Plus
v-if="props.iconName === 'plus'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Puzzle
v-if="props.iconName === 'puzzle'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Settings
v-if="props.iconName === 'settings'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Task
v-if="props.iconName === 'task'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Trespass
v-if="props.iconName === 'trespass'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Twitter
v-if="props.iconName === 'twitter'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Wire
v-if="props.iconName === 'wire'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
<Funnel
v-if="props.iconName === 'funnel'"
:iconClass="iconClass"
:iconColor="iconColor"
/>
</div>
</template>

View file

@ -2,7 +2,7 @@
import { defineProps } from "vue";
import Container from "@components/Widget/Container.vue";
import Title from "@components/Widget/Title.vue";
import IconStatus from "@components/Icon/Status.vue";
import Status from "@components/Widget/Status.vue";
import ContentDetailList from "@components/Content/DetailList.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import { v4 as uuidv4 } from "uuid";
@ -71,7 +71,7 @@ const props = defineProps({
<template>
<Container :columns="{ pc: 12, tablet: 12, mobile: 12 }">
<IconStatus :id="props.title" :status="props.status" />
<Status :id="props.title" :status="props.status" />
<Title type="card" :title="props.title" />
<ContentDetailList :details="props.details" />
<ButtonGroup

View file

@ -1,17 +1,38 @@
<script setup>
import { reactive, onMounted, defineProps } from "vue";
import { reactive, ref, onMounted, defineProps } from "vue";
import { contentIndex } from "@utils/tabindex.js";
import { v4 as uuidv4 } from "uuid";
import Icons from "@components/Widget/Icons.vue";
/**
@name Widget/Popover.vue
@description This component is a standard popover.
@example
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
}
@param {string} [id=uuidv4()] - Unique id of the button
@param {string} text - Content of the button. Can be a translation key or by default raw text.
@param {string} iconName - Name in lowercase of icons store on /Icons. If falsy value, no icon displayed.
@param {string} iconColor - Color of the icon between tailwind colors
@param {string} [tag="button"] - By default it is a button tag, but we can use other tag like div in case of popover on another button
@param {string} [popoverClass=""] - Additional class for the popover container
@param {string|number} [tabId=contentIndex] - The tabindex of the field, by default it is the contentIndex
*/
const props = defineProps({
id: {
type: String,
required: true,
required: false,
default: uuidv4(),
},
content: {
text: {
type: String,
required: false,
},
icon : {
iconName: {
type: String,
required: false,
},
@ -25,6 +46,16 @@ const props = defineProps({
required: false,
default: "button",
},
popoverClass: {
type: String,
required: false,
default: "",
},
tabId: {
type: String,
required: false,
default: contentIndex,
},
});
// Determine popover need to be display
@ -33,8 +64,22 @@ const popover = reactive({
isHover: false,
});
const popoverContainer = ref();
const popoverBtn = ref();
function showPopover() {
popover.isHover = true;
// Position popover relative to btn
const popoverBtnRect = popoverBtn.value.getBoundingClientRect();
const popoverContainerRect = popoverContainer.value.getBoundingClientRect();
// Get current window scroll positio
popoverContainer.value.style.right = `${
window.innerWidth - popoverBtnRect.left - popoverBtnRect.width
}px`;
// Show popover
setTimeout(() => {
popover.isOpen = popover.isHover ? true : false;
}, 450);
@ -48,38 +93,40 @@ function hidePopover() {
<template>
<component
:tabindex="contentIndex"
ref="popoverBtn"
:tabindex="props.tabId"
:aria-controls="`${props.id}-popover-text`"
:aria-expanded="popover.isOpen ? 'true' : 'false'"
:aria-describedby="`${props.id}-popover-text`"
:is="props.tag"
role="button"
@click.prevent
@focusin="showPopover()"
@focusout="hidePopover()"
@pointerover="showPopover()"
@pointerleave="hidePopover()"
class="cursor-pointer flex justify-start w-full"
:class="['popover-btn', props.popoverClass]"
>
<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>
<Icons
:iconClass="'popover-svg'"
:iconName="props.iconName"
:iconColor="props.iconColor"
/>
</component>
<div
ref="popoverContainer"
:id="`${props.id}-popover-container`"
role="status"
:aria-hidden="popover.isOpen ? 'false' : 'true'"
v-show="popover.isOpen"
:class="['popover-settings-container']"
:class="[
'popover-container',
props.iconColor,
popover.isOpen ? 'open' : 'close',
]"
:aria-description="$t('dashboard_popover_detail_desc')"
>
<p :id="`${props.id}-popover-text`" class="popover-settings-text"><slot></slot></p>
<p :id="`${props.id}-popover-text`" class="popover-text">
{{ $t(props.text, props.text) }}
</p>
</div>
</template>
</template>

View file

@ -0,0 +1,61 @@
<script setup>
import Flex from "@components/Widget/Flex.vue";
import Popover from "@components/Widget/Popover.vue";
import { v4 as uuidv4 } from "uuid";
/**
@name Widget/PopoverGroup.vue
@description This component allow to display multiple popovers in the same row using flex.
We can define additional class too for the flex container.
We need a list of popovers to display.
@example
{
id: "group-popover",
popoverClass : "justify-center",
popovers: [
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
{
text: "This is a popover text",
iconName: "info",
iconColor: "info",
},
],
}
@param {string} [id=uuidv4()] - Unique id of the popover group
@param {string} [flexClass="justify-center align-center"] - Additional class for the flex container
@param {array} popovers - List of popovers to display. Popover component is used.
*/
const props = defineProps({
id: {
type: String,
required: false,
default: uuidv4(),
},
popovers: {
type: Array,
required: true,
default: [],
},
flexClass: {
type: String,
required: false,
default: "justify-center align-center",
},
});
</script>
<template>
<Flex v-if="props.popovers.length > 0" :flexClass="props.flexClass">
<Popover
v-for="(popover, id) in props.popovers"
:key="popover"
v-bind="popover"
:popoverClass="id === props.popovers.length - 1 ? '' : 'mr-2'"
/>
</Flex>
</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 IconStat from "@components/Icon/Stat.vue";
import Icon from "@components/Widget/Icons.vue";
/**
@name Widget/Stat.vue
@ -83,10 +83,11 @@ const props = defineProps({
:subtitleColor="props.subtitleColor"
/>
</div>
<IconStat
<Icon
v-if="props.iconName"
:iconName="props.iconName"
:iconColor="props.iconColor"
:iconType="'stat'"
/>
</Container>
</template>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,8 @@ def set_advanced():
# Update settings with global config data
for plugin in plugins :
for setting, value in plugin["settings"].items() :
# set id base on template name
value["id"] = f"{value["id"]}-{template_name}"
# set inpType based on type define for each settings
inpType = "checkbox" if value.get("type") == "check" else "select" if value.get("type") == "select" else "datepicker" if value.get("type") == "date" else "input"
value["inpType"] = inpType
@ -56,13 +58,16 @@ def set_advanced():
popovers = []
if(value.get("help")):
popovers.append({"color": "info", "svg": "help", "text" : value.get("help")})
popovers.append({"iconColor": "info", "iconName": "info", "text" : value.get("help")})
if(value.get("context")):
popovers.append({"color": "orange" if value.get("context") == "multisite" else "blue",
"svg": "disk" if value.get("context") == "multisite" else "globe",
popovers.append({"iconColor": "orange" if value.get("context") == "multisite" else "blue",
"iconName": "disk" if value.get("context") == "multisite" else "globe",
"text" : "inp_popover_multisite" if value.get("context") == "multisite" else "inp_popover_global"
})
print(popovers)
value["popovers"] = popovers
advanced_forms[template_name] = plugins