Compare commits

..

13 Commits
dev ... master

Author SHA1 Message Date
philipp lang e4fa326f35 Add query params for later registration 2025-07-26 01:28:20 +02:00
philipp lang a6ca0d2a6c Add button for disabled registrations 2024-12-12 16:00:37 +01:00
philipp lang a4a2a2b3fd Add intro for text field 2024-09-12 11:10:01 +02:00
philipp lang 54efebf12e Add loginState to skip nami login 2024-07-30 23:22:46 +02:00
philipp lang 38d56d1285 Mod index 2024-07-30 22:58:05 +02:00
philipp lang 768cf47bd3 Fix emits 2024-07-12 20:06:27 +02:00
philipp lang 4dd0fc4c4b Add save button 2024-07-12 20:03:51 +02:00
philipp lang c0a18e8ee1 Add every host to vite config 2024-07-11 22:44:09 +02:00
philipp lang 0c0961dac4 Fix mobile slide 2024-07-11 22:43:38 +02:00
philipp lang 25d36a53ce Fix radio 2024-07-03 21:52:41 +02:00
philipp lang bd4118040f Add js files to tailwind content 2024-06-18 22:00:43 +02:00
philipp lang 41adb7ecb0 Add cursor pointer for accordion header 2024-06-18 21:49:14 +02:00
philipp lang bf94349dca Add label to checkbox 2024-06-18 21:48:41 +02:00
14 changed files with 170 additions and 203 deletions

View File

@ -6,167 +6,72 @@
<title>Vite + Vue</title> <title>Vite + Vue</title>
<meta name="adrema_base_url" content="/" /> <meta name="adrema_base_url" content="/" />
</head> </head>
<body style="padding: 50px"> <body>
<event-form <event-form
style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)" style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)"
value='{"sections":[ value='{
{ "sections": [
"name": "tet", {
"intro": "", "name": "sdfs",
"fields": [ "fields": [
{ {
"name": "checkbox", "required": true,
"type": "CheckboxField", "key": "vorname",
"columns": { "name": "Vorname",
"nami_type": null,
"columns": {
"mobile": 2, "mobile": 2,
"tablet": 4, "tablet": 4,
"desktop": 6 "desktop": 6
}, },
"value": false, "for_members": true,
"required": true, "special_type": null,
"nami_type": null, "hint": null,
"for_members": true, "intro": null,
"special_type": null, "value": null,
"description": "Sed laoreet mattis sem, vel sodales leo ullamcorper ut. Aliquam hendrerit vestibulum ex, sit amet consequat dolor donec.", "type": "TextField"
"hint": "Quisque justo leo, ultricies vestibulum.", },
"key": "checkbox" {
}, "required": true,
{ "key": "nachname",
"name": "checkboxes Praesent tortor ligula, accumsan quis neque eget, laoreet convallis nunc. Morbi a urna sem. Mauris venenatis a felis ex.", "name": "Nachname",
"hint": "Quisque justo leo, ultricies vestibulum.", "nami_type": null,
"type": "CheckboxesField", "columns": {
"columns": {
"mobile": 2, "mobile": 2,
"tablet": 4, "tablet": 4,
"desktop": 6 "desktop": 3
}, },
"value": [], "for_members": true,
"required": false, "special_type": null,
"nami_type": null, "hint": null,
"for_members": true, "intro": null,
"special_type": null, "value": null,
"options": [ "type": "TextField"
"Integer molestie enim vitae enim tellus.", },
"Cras ut magna ac metus rutrum efficitur." {
], "required": true,
"key": "checkboxes" "key": "mail",
}, "name": "Mail",
{ "nami_type": null,
"name": "date", "columns": {
"hint": "Quisque justo leo, ultricies vestibulum.", "mobile": 1,
"type": "DateField", "tablet": 2,
"columns": { "desktop": 3
"mobile": 2, },
"tablet": 4, "for_members": true,
"desktop": 6 "special_type": null,
}, "hint": null,
"value": null, "intro": null,
"required": false, "value": null,
"nami_type": null, "type": "EmailField"
"for_members": true, }
"special_type": null, ],
"max_today": false, "intro": null
"key": "date" }
}, ]
{ }'
"name": "dropdown", payload='{"vorname": "Philipp", "nachname": "Lang", "mail": "a@b.de"}'
"hint": "Quisque justo leo, ultricies vestibulum.",
"type": "DropdownField",
"columns": {
"mobile": 2,
"tablet": 4,
"desktop": 6
},
"value": null,
"required": false,
"nami_type": null,
"for_members": true,
"special_type": null,
"options": [
"a",
"v"
],
"key": "dropdown",
"allowcustom": false
},
{
"name": "radio",
"hint": "Quisque justo leo, ultricies vestibulum.",
"type": "RadioField",
"columns": {
"mobile": 2,
"tablet": 4,
"desktop": 6
},
"value": null,
"required": false,
"nami_type": null,
"for_members": true,
"special_type": null,
"options": [
"a",
"v"
],
"key": "radio",
"allowcustom": false
},
{
"name": "text",
"hint": "Quisque justo leo, ultricies vestibulum.",
"type": "TextField",
"columns": {
"mobile": 2,
"tablet": 4,
"desktop": 6
},
"value": "",
"required": false,
"nami_type": null,
"for_members": true,
"special_type": null,
"key": "text"
},
{
"name": "textarea",
"hint": "Quisque justo leo, ultricies vestibulum.",
"type": "TextareaField",
"columns": {
"mobile": 2,
"tablet": 4,
"desktop": 6
},
"value": "",
"required": false,
"nami_type": null,
"for_members": true,
"special_type": null,
"rows": 5,
"key": "textarea"
},
{
"name": "numerisch",
"hint": "Quisque justo leo, ultricies vestibulum.",
"type": "NumberField",
"columns": {
"mobile": 2,
"tablet": 4,
"desktop": 6
},
"value": null,
"required": false,
"nami_type": null,
"for_members": true,
"special_type": null,
"key": "numerisch",
"min": null,
"max": "7"
},
{"required":true,"parent_field":null,"parent_group":2,"has_empty_option":true,"key":"stamm","name":"Stamm","nami_type":null,"columns":{"mobile":2,"tablet":4,"desktop":6},"for_members":true,"special_type":null,"hint":null,"value":null,"type":"GroupField", "empty_option_value": "Kein Stamm"}
]
}
]}'
url="http://localhost:8000" url="http://localhost:8000"
editable
></event-form> ></event-form>
<event-overview <event-overview
style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)" style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)"

View File

@ -57,18 +57,12 @@
<path d="M 4.95,6.364 5.657,7.071 11.314,1.414 9.9,0 5.657,4.242 1.414,0 0,1.414 Z" /> <path d="M 4.95,6.364 5.657,7.071 11.314,1.414 9.9,0 5.657,4.242 1.414,0 0,1.414 Z" />
</svg> </svg>
</a> </a>
<div class="overflow-hidden"> <div class="overflow-hidden grow">
<carousel :touch-drag="false" :mouse-drag="false" v-model="active"> <carousel :touch-drag="false" :mouse-drag="false" v-model="active">
<slide v-for="(section, index) in v.sections" :key="index" class="relative flex flex-no-wrap overflow-hidden"> <slide v-for="(section, index) in v.sections" :key="index">
<div class="flex-none w-full"> <div v-if="active === index" class="w-full flex-none px-2 flex flex-col items-center justify-center h-12" @click="active = index">
<div <span class="flex items-center justify-center w-4 h-4 rounded-full bg-circle text-font transition duration-300" v-html="index + 1"></span>
href="#" <span class="text-sm text-font" v-html="section.name"></span>
class="flex flex-col @md:flex-row items-center justify-center @md:justify-start px-2 flex-auto @md:pl-6 h-12 @md:h-16 transition duration-300 relative"
@click="active = index"
>
<span class="flex items-center justify-center w-4 @md:w-6 h-4 @md:h-6 rounded-full bg-circle text-font transition duration-300" v-html="index + 1"></span>
<span class="text-sm text-font" v-html="section.name"></span>
</div>
</div> </div>
</slide> </slide>
</carousel> </carousel>
@ -119,7 +113,7 @@
</div> </div>
</div> </div>
<navigation v-if="active === index" v-model="active" :last="v.sections.length"></navigation> <navigation v-if="active === index" :as-form="asForm" v-model="active" :last="v.sections.length"></navigation>
</slide> </slide>
</carousel> </carousel>
</div> </div>
@ -155,14 +149,16 @@ import useToastify from './composables/useToastify.js';
import useFields from './composables/useFields.js'; import useFields from './composables/useFields.js';
import SettingIcon from './components/icons/SettingIcon.vue'; import SettingIcon from './components/icons/SettingIcon.vue';
import useColumns from './composables/useColumns.js'; import useColumns from './composables/useColumns.js';
import usePageMeta from './composables/usePageMeta.js';
const {scroll} = useScroll(); const {scroll} = useScroll();
const {errorFromResponse} = useToastify(); const {errorFromResponse} = useToastify();
const {colClassesForField, containerClasses} = useColumns(); const {colClassesForField, containerClasses} = useColumns();
const finished = ref(false); const finished = ref(false);
const eventForm = ref(null); const eventForm = ref(null);
const pageMeta = usePageMeta();
const emits = defineEmits(['addSection', 'editSection', 'deleteSection', 'editField', 'deleteField', 'active']); const emits = defineEmits(['addSection', 'editSection', 'deleteSection', 'editField', 'deleteField', 'active', 'save']);
const props = defineProps({ const props = defineProps({
editable: { editable: {
@ -185,6 +181,10 @@ const props = defineProps({
default: () => false, default: () => false,
type: Boolean, type: Boolean,
}, },
asForm: {
type: Boolean,
default: () => false,
},
}); });
const active = ref(0); const active = ref(0);
@ -233,8 +233,14 @@ const {back, next, backable, nextable} = useNav(active, v.value.sections.length)
const {resolveComponentName} = useFields(); const {resolveComponentName} = useFields();
async function submit() { async function submit() {
if (props.asForm) {
emits('save', payload.value);
return;
}
try { try {
await axios.post('/api/form/' + props.formId + '/register', payload.value); await axios.post('/api/form/' + props.formId + '/register', payload.value, {
params: pageMeta.value.later === '1' ? pageMeta.value : {},
});
finished.value = true; finished.value = true;
} catch (e) { } catch (e) {
errorFromResponse(e); errorFromResponse(e);

View File

@ -1,6 +1,6 @@
<template> <template>
<box size="none" class="opacity-[0.8] hover:opacity-[1.0]" :type="type"> <box size="none" class="opacity-[0.8] hover:opacity-[1.0]" :type="type">
<div href="#" @click.prevent="emit('update:model-value', modelValue === index ? -1 : index)" class="flex items-center justify-between p-2"> <div href="#" @click.prevent="emit('update:model-value', modelValue === index ? -1 : index)" class="flex items-center justify-between p-2 cursor-pointer">
<div v-text="title"></div> <div v-text="title"></div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<slot name="buttons"></slot> <slot name="buttons"></slot>

View File

@ -13,9 +13,17 @@
<a <a
:href="registerUrl.replace(':slug', event.slug)" :href="registerUrl.replace(':slug', event.slug)"
class="px-3 py-2 text-xs font-nunito font-semibold rounded sm:px-4 sm:py-2 sm:text-sm sm:rounded focus:ring-2 focus:ring-offset-1 focus:ring-font focus:outline-none bg-primary text-font" class="px-3 py-2 text-xs font-nunito font-semibold rounded sm:px-4 sm:py-2 sm:text-sm sm:rounded focus:ring-2 focus:ring-offset-1 focus:ring-font focus:outline-none bg-primary text-font"
v-if="event.can_register"
> >
Zur Anmeldung Zur Anmeldung
</a> </a>
<button
type="button"
class="px-3 py-2 text-xs font-nunito font-semibold rounded sm:px-4 sm:py-2 sm:text-sm sm:rounded focus:ring-2 focus:ring-offset-1 focus:ring-font focus:outline-none bg-gray-700 text-font"
v-else
>
Anmeldung zzt nicht möglich
</button>
</div> </div>
</popup> </popup>
</template> </template>

View File

@ -10,7 +10,7 @@
<div></div> <div></div>
</div> </div>
</div> </div>
Anmeldung absenden <span v-text="asForm ? 'Speichern' : 'Anmeldung absenden'"></span>
</button> </button>
</div> </div>
</template> </template>
@ -29,6 +29,10 @@ const props = defineProps({
type: Number, type: Number,
required: true, required: true,
}, },
asForm: {
type: Boolean,
required: true,
},
}); });
const innerValue = computed({ const innerValue = computed({

View File

@ -1,5 +1,5 @@
<template> <template>
<v-checkbox :id="innerId" v-model="inner" :name="field.key" :label="field.description" :required="field.required" :intro="field.intro" :hint="field.hint"></v-checkbox> <v-checkbox :id="innerId" v-model="inner" :label="field.name" :description="field.description" :name="field.key" :required="field.required" :intro="field.intro" :hint="field.hint"></v-checkbox>
</template> </template>
<script setup> <script setup>

View File

@ -13,16 +13,27 @@
Bitte achte außerdem darauf, dass du mindestens <span class="font-semibold">Leserechte</span> auf deine Gruppierung hast. Diese kann dir i.d.R. dein Bitte achte außerdem darauf, dass du mindestens <span class="font-semibold">Leserechte</span> auf deine Gruppierung hast. Diese kann dir i.d.R. dein
<span class="font-semibold">StaVo</span> erteilen. <span class="font-semibold">StaVo</span> erteilen.
</p> </p>
<v-checkbox
:modelValue="loginState !== 'nami'"
@update:modelValue="loginState = $event ? 'skipping' : 'nami'"
name="login_state"
id="login_state"
description="Ich bin kein Mitglied der DPSG im DV Köln und möchte daher meine Mitglieder selbst eingeben."
intro=""
></v-checkbox>
</div> </div>
<div class="flex mt-4 space-x-3"> <div class="flex mt-4 space-x-3">
<v-text @keypress.enter="innerLogin" name="nami_mglnr" label="Mitgliedsnummer" id="nami_mglnr" v-model="loginData.mglnr" required></v-text> <v-text @keypress.enter="innerLogin" name="nami_mglnr" label="Mitgliedsnummer" id="nami_mglnr" v-model="loginData.mglnr" required></v-text>
<v-text @keypress.enter="innerLogin" name="nami_password" label="Passwort" id="nami_password" v-model="loginData.password" type="password" required></v-text> <v-text @keypress.enter="innerLogin" name="nami_password" label="Passwort" id="nami_password" v-model="loginData.password" type="password" required></v-text>
<v-btn class="self-end" @click.prevent="innerLogin">Anmelden</v-btn> <v-btn class="self-end" @click.prevent="innerLogin">
<span v-text="loginState === 'nami' ? 'Anmelden' : 'Weiter'"></span>
</v-btn>
</div> </div>
</template> </template>
<template #finished> <template #finished>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div>Erfolgreich eingeloggt als {{ user }}.</div> <div v-if="user">Erfolgreich eingeloggt als {{ user }}.</div>
<div v-else>Nicht eingeloggt</div>
<v-btn class="self-end" @click.prevent="innerLogout">Abmelden</v-btn> <v-btn class="self-end" @click.prevent="innerLogout">Abmelden</v-btn>
</div> </div>
</template> </template>
@ -57,7 +68,7 @@
@update:modelValue="toggleMember(member)" @update:modelValue="toggleMember(member)"
:name="`${field.key}-memberselect-${member.id}`" :name="`${field.key}-memberselect-${member.id}`"
:id="`${field.key}-memberselect-${member.id}`" :id="`${field.key}-memberselect-${member.id}`"
:label="member.name" :description="member.name"
intro="" intro=""
v-for="member in searchResults.data" v-for="member in searchResults.data"
></v-checkbox> ></v-checkbox>
@ -102,7 +113,7 @@
v-model="member[memberField.key]" v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`" :name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`" :id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.description" :description="memberField.description"
intro="" intro=""
:required="memberField.required" :required="memberField.required"
:class="colClassesForField(memberField)" :class="colClassesForField(memberField)"
@ -225,7 +236,7 @@ if (user.value !== null) {
const {resolveComponentName} = useFields(); const {resolveComponentName} = useFields();
const step = computed(() => { const step = computed(() => {
if (user.value === null) { if (user.value === null && loginState.value !== 'skipped') {
return 1; return 1;
} }
@ -247,6 +258,7 @@ function deleteMember(index) {
} }
const membersAccepted = ref(false); const membersAccepted = ref(false);
const loginState = ref('nami');
const membersCompleted = ref(false); const membersCompleted = ref(false);
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -288,6 +300,13 @@ const inner = computed(
{deep: true}, {deep: true},
); );
async function innerLogin() { async function innerLogin() {
if (loginState.value === 'skipping') {
loginState.value = 'skipped';
membersAccepted.value = true;
membersCompleted.value = false;
return;
}
await login(); await login();
membersAccepted.value = false; membersAccepted.value = false;
membersCompleted.value = false; membersCompleted.value = false;
@ -312,8 +331,11 @@ function toggleMember(member) {
} }
async function innerLogout() { async function innerLogout() {
logout(); if (loginState.value !== 'skipped') {
resetSearchData(); logout();
resetSearchData();
}
loginState.value = 'nami';
membersAccepted.value = false; membersAccepted.value = false;
membersCompleted.value = false; membersCompleted.value = false;
inner.value = []; inner.value = [];

View File

@ -1,5 +1,5 @@
<template> <template>
<v-text type="text" :required="field.required" :name="field.key" :label="field.name" :id="field.key" :hint="field.hint" v-model="inner"></v-text> <v-text type="text" :required="field.required" :name="field.key" :label="field.name" :id="field.key" :hint="field.hint" :intro="field.intro" v-model="inner"></v-text>
</template> </template>
<script setup> <script setup>

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="relative"> <div class="relative">
<div class="grid grid-cols-1 gap-2"> <field-label v-if="label" :name="label" :required="required" :hint="hint" inline></field-label>
<div class="grid grid-cols-1 gap-2 pt-1">
<div class="text-sm text-gray-600" v-text="intro" v-if="intro"></div> <div class="text-sm text-gray-600" v-text="intro" v-if="intro"></div>
<label :for="id" class="p-0 block leading-none relative flex items-start"> <label :for="id" class="p-0 block leading-none relative flex items-start">
<input :id="id" v-model="inner" type="checkbox" :name="name" class="peer absolute invisible" /> <input :id="id" v-model="inner" type="checkbox" :name="name" class="peer absolute invisible" />
@ -8,11 +9,9 @@
class="border-neutral-400 border-4 group-[.box]:border-2 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 group-[.box]:w-4 group-[.box]:h-4 group-[.box]:top-[5px] rounded block top-0" class="border-neutral-400 border-4 group-[.box]:border-2 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 group-[.box]:w-4 group-[.box]:h-4 group-[.box]:top-[5px] rounded block top-0"
></span> ></span>
<span class="peer-checked:bg-primary left-[0.5rem] top-[0.5rem] group-[.box]:top-[0.58rem] group-[.box]:left-[0.25rem] w-2 h-2 absolute rounded block top-0"></span> <span class="peer-checked:bg-primary left-[0.5rem] top-[0.5rem] group-[.box]:top-[0.58rem] group-[.box]:left-[0.25rem] w-2 h-2 absolute rounded block top-0"></span>
<span v-if="label" class="pl-8 group-[.box]:pl-6 pt-1 @sm:pt-0 @sm:group-[.box]:pt-1 text-gray-600 text-sm @sm:text-base @sm:group-[.box]:text-sm"> <span v-if="description" class="pl-8 group-[.box]:pl-6 pt-1 @sm:pt-0 @sm:group-[.box]:pt-1 text-gray-600 text-sm @sm:text-base @sm:group-[.box]:text-sm">
<span v-text="label"></span> <span v-text="description"></span>
<span v-show="required" class="text-red-800"> *</span>
</span> </span>
<hint :value="hint" class="ml-2" v-if="hint"></hint>
</label> </label>
</div> </div>
</div> </div>
@ -20,7 +19,7 @@
<script setup> <script setup>
import {computed} from 'vue'; import {computed} from 'vue';
import Hint from '../Hint.vue'; import FieldLabel from '../FieldLabel.vue';
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -41,6 +40,10 @@ const props = defineProps({
type: String, type: String,
default: () => '', default: () => '',
}, },
description: {
required: false,
type: String,
},
required: { required: {
required: false, required: false,
type: Boolean, type: Boolean,

View File

@ -8,7 +8,7 @@
<span <span
class="border-neutral-400 border-4 group-[.box]:border-2 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 group-[.box]:w-4 group-[.box]:h-4 group-[.box]:top-[5px] rounded-full block top-0" class="border-neutral-400 border-4 group-[.box]:border-2 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 group-[.box]:w-4 group-[.box]:h-4 group-[.box]:top-[5px] rounded-full block top-0"
></span> ></span>
<span class="peer-checked:bg-primary left-2 group-[.box]:top-[0.58rem] group-[.box]:left-[0.25rem] w-2 h-2 absolute rounded-full block"></span> <span class="peer-checked:bg-primary left-2 top-2 group-[.box]:top-[0.58rem] group-[.box]:left-[0.25rem] w-2 h-2 absolute rounded-full block"></span>
<span v-if="option.iscustom" class="ml-8 w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex h-6"> <span v-if="option.iscustom" class="ml-8 w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex h-6">
<input <input
:id="`${id}-custom-value`" :id="`${id}-custom-value`"

View File

@ -1,21 +1,24 @@
<template> <template>
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex"> <div>
<input <div class="text-sm text-gray-600 mb-4" v-text="intro" v-if="intro"></div>
:id="id" <label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex">
v-model="inner" <input
:name="name" :id="id"
:min="min" v-model="inner"
:max="presentMax" :name="name"
:type="type" :min="min"
placeholder="" :max="presentMax"
class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left w-full py-1 @sm:py-2 @sm:group-[.box]:py-1 px-2 @sm:px-3 @sm:group-[.box]:px-2 text-sm @sm:text-base @sm:group-[.box]:text-sm" :type="type"
@keypress="$emit('keypress', $event)" placeholder=""
/> class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left w-full py-1 @sm:py-2 @sm:group-[.box]:py-1 px-2 @sm:px-3 @sm:group-[.box]:px-2 text-sm @sm:text-base @sm:group-[.box]:text-sm"
<div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full"> @keypress="$emit('keypress', $event)"
<hint :value="hint"></hint> />
</div> <div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full">
<field-label :name="label" :required="required"></field-label> <hint :value="hint"></hint>
</label> </div>
<field-label :name="label" :required="required"></field-label>
</label>
</div>
</template> </template>
<script setup> <script setup>
@ -70,6 +73,11 @@ const props = defineProps({
validator: (value) => value === null || typeof value === 'string', validator: (value) => value === null || typeof value === 'string',
default: () => null, default: () => null,
}, },
intro: {
required: false,
validator: (value) => value === null || typeof value === 'string',
default: () => null,
},
}); });
const presentMax = computed(() => { const presentMax = computed(() => {

View File

@ -0,0 +1,10 @@
import { ref } from 'vue';
export default function useEventMeta() {
const varName = 'adrema_page_meta';
const pageMeta = ref(null);
if (window[varName]) {
pageMeta.value = window[varName];
}
return pageMeta;
}

View File

@ -1,6 +1,6 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: ['./src/**/*.vue'], content: ['./src/**/*.vue', './src/**/*.js'],
theme: { theme: {
extend: { extend: {
colors: { colors: {

View File

@ -24,5 +24,6 @@ export default defineConfig({
}, },
server: { server: {
port: 5174, port: 5174,
host: '0.0.0.0',
}, },
}); });