Compare commits

...

25 Commits

Author SHA1 Message Date
philipp lang d9586511c3 Add new members 2024-06-18 01:58:19 +02:00
philipp lang b76fc8133e Add: delete member in third step 2024-06-18 01:48:52 +02:00
philipp lang a4e9f3af0b Add textfield for nami 2024-06-18 01:36:39 +02:00
philipp lang 0aba0c8035 Add VRadio for nami 2024-06-18 01:24:18 +02:00
philipp lang fd02bdee18 Add radio file 2024-06-18 01:17:30 +02:00
philipp lang 900690e0c5 Add VDropdown for Group 2024-06-17 00:22:33 +02:00
philipp lang 039fd21969 Mod box class 2024-06-17 00:04:50 +02:00
philipp lang 4da70d94b9 Add container classes 2024-06-17 00:01:21 +02:00
philipp lang ce0d56f748 Add number field 2024-06-16 23:29:54 +02:00
philipp lang bc4cec48e4 fix presentMax 2024-06-16 23:24:25 +02:00
philipp lang 58c3616a30 Add date field 2024-06-16 23:19:40 +02:00
philipp lang aa4a91ee49 fixup! Add required for member checkbox field 2024-06-16 23:02:47 +02:00
philipp lang 253b748cee Add space before required sign 2024-06-16 23:01:34 +02:00
philipp lang 6fb323de1d Add required for member checkbox field 2024-06-16 23:01:23 +02:00
philipp lang 80b1195777 Add text field 2024-06-16 22:56:18 +02:00
philipp lang 335cfc8e9c Mod layout 2024-06-14 01:49:40 +02:00
philipp lang cd057cc52d Mod layout 2024-06-14 01:47:05 +02:00
philipp lang 57555afe2b Add form for nami 2024-06-14 01:46:06 +02:00
philipp lang 3a83c46430 Extract column logic 2024-06-14 01:40:27 +02:00
philipp lang 194cff40d5 Add accordion for member confirmation 2024-06-14 01:14:26 +02:00
philipp lang efb6db8b0b Set border width for small box size 2024-06-14 00:59:21 +02:00
philipp lang 20fa2cc2b8 Add size to box 2024-06-14 00:58:56 +02:00
philipp lang 5a7a301490 Extract box component 2024-06-14 00:53:48 +02:00
philipp lang 99811228f2 Fix prop validation for checkboxes 2024-06-14 00:29:00 +02:00
philipp lang 99b3b1f0cb Set allowcustom for dropdown 2024-06-14 00:00:04 +02:00
18 changed files with 513 additions and 243 deletions

View File

@ -90,16 +90,14 @@
<slide v-for="(section, index) in v.sections" :key="index"> <slide v-for="(section, index) in v.sections" :key="index">
<div v-if="active === index" class="w-full flex-none px-3 @xs:px-6"> <div v-if="active === index" class="w-full flex-none px-3 @xs:px-6">
<div class="text-sm sm_text-base text-gray-800 leading-tight mb-5" v-text="section.intro"></div> <div class="text-sm sm_text-base text-gray-800 leading-tight mb-5" v-text="section.intro"></div>
<div class="grid grid-cols-2 @sm:grid-cols-4 @lg:grid-cols-6 gap-6 mt-6 items-start"> <div class="mt-6" :class="containerClasses">
<div <div
v-for="(field, findex) in section.fields" v-for="(field, findex) in section.fields"
:key="findex" :key="findex"
class="flex justify-stretch relative group" class="flex justify-stretch relative group"
:class="{ :class="{
'hover:ring-edit hover:ring-4': editable, 'hover:ring-edit hover:ring-4': editable,
[colClasses.mobile[field.columns.mobile]]: true, ...colClassesForField(field),
[colClasses.tablet[field.columns.tablet]]: true,
[colClasses.desktop[field.columns.desktop]]: true,
}" }"
> >
<component :is="resolveComponentName(field)" v-model="payload[field.key]" :fields="allFields" :payload="payload" :field="field" class="grow"></component> <component :is="resolveComponentName(field)" v-model="payload[field.key]" :fields="allFields" :payload="payload" :field="field" class="grow"></component>
@ -135,19 +133,7 @@
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" /> <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg> </svg>
</div> </div>
<div class="isolate self-center justify-self-end row-span-2 sm:pt-8 sm:pb-8 relative -right-3"> <div class="isolate self-center justify-self-end row-span-2 sm:pt-8 sm:pb-8 relative -right-3"></div>
<!--
<div class="absolute right-0 top-0 h-full flex items-center justify-end">
<div class="bg-primary w-96 h-96 flex [clip-path:circle(50%_at_110%_50%)] sm:[clip-path:circle(50%_at_80%_50%)]"></div>
</div>
<div class="overflow-hidden rounded-l-lg rotate-2 shadow relative z-10 -left-2">
<img class="w-64 h-32 object-cover" src="" />
</div>
<div class="overflow-hidden rounded-l-lg -rotate-2 shadow relative left-2">
<img class="w-64 h-32 object-cover" src="" />
</div>
-->
</div>
<div class="self-end flex-grow pb-8 pl-8 pr-8 sm:pr-0 pt-6 sm:pt-0"> <div class="self-end flex-grow pb-8 pl-8 pr-8 sm:pr-0 pt-6 sm:pt-0">
<div class="font-bold text-xl">Vielen Dank für deine Anmeldung.</div> <div class="font-bold text-xl">Vielen Dank für deine Anmeldung.</div>
</div> </div>
@ -168,41 +154,16 @@ import DeleteIcon from './components/icons/DeleteIcon.vue';
import useToastify from './composables/useToastify.js'; 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';
const {scroll} = useScroll(); const {scroll} = useScroll();
const {errorFromResponse} = useToastify(); const {errorFromResponse} = useToastify();
const {colClassesForField, containerClasses} = useColumns();
const finished = ref(false); const finished = ref(false);
const eventForm = ref(null); const eventForm = ref(null);
const emits = defineEmits(['addSection', 'editSection', 'deleteSection', 'editField', 'deleteField', 'active']); const emits = defineEmits(['addSection', 'editSection', 'deleteSection', 'editField', 'deleteField', 'active']);
const colClasses = {
mobile: {
1: 'col-span-1',
2: 'col-span-2',
3: 'col-span-3',
4: 'col-span-4',
5: 'col-span-5',
6: 'col-span-6',
},
tablet: {
1: '@sm:col-span-1',
2: '@sm:col-span-2',
3: '@sm:col-span-3',
4: '@sm:col-span-4',
5: '@sm:col-span-5',
6: '@sm:col-span-6',
},
desktop: {
1: '@lg:col-span-1',
2: '@lg:col-span-2',
3: '@lg:col-span-3',
4: '@lg:col-span-4',
5: '@lg:col-span-5',
6: '@lg:col-span-6',
},
};
const props = defineProps({ const props = defineProps({
editable: { editable: {
type: Boolean, type: Boolean,

View File

@ -0,0 +1,40 @@
<template>
<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 v-text="title"></div>
<div class="flex items-center space-x-2">
<slot name="buttons"></slot>
<chevron :class="{'rotate-180': modelValue === index}" class="w-3 h-3"></chevron>
</div>
</div>
<div v-if="modelValue === index" class="p-2 pt-0">
<slot />
</div>
</box>
</template>
<script setup>
import Box from './Box.vue';
import Chevron from './icons/Chevron.vue';
const emit = defineEmits(['update:model-value']);
const props = defineProps({
type: {
required: true,
type: String,
},
title: {
required: true,
type: String,
},
modelValue: {
required: true,
type: Number,
},
index: {
required: true,
type: Number,
},
});
</script>

66
src/components/Box.vue Normal file
View File

@ -0,0 +1,66 @@
<template>
<div class="text-sm relative">
<div
class="flex items-center justify-center w-6 h-6 rounded-full border-solid border-2 absolute -top-2 -left-2 font-arvo font-bold"
:class="[colors[type].container, colors[type].lightText]"
v-text="step"
v-if="step"
></div>
<div class="flex flex-row items-center rounded form-group shadow-sm group" :class="[colors[type].container, type, 'box', sizes[size].container]">
<div class="flex-grow text-sm" :class="colors[type].text">
<slot />
</div>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue';
const colors = ref({
success: {
container: 'bg-green-200 border-green-600',
lightText: 'text-green-700',
text: 'text-green-900',
},
info: {
container: 'bg-blue-200 border-blue-600',
lightText: 'text-blue-700',
text: 'text-blue-900',
},
default: {
container: 'bg-neutral-200 border-neutral-600',
lightText: 'text-neutral-700',
text: 'text-neutral-900',
},
});
const sizes = ref({
default: {
container: 'p-4 border-2',
},
sm: {
container: 'p-2 border',
},
none: {
container: 'border',
},
});
const props = defineProps({
type: {
required: true,
type: String,
},
size: {
required: false,
type: String,
default: () => 'default',
},
step: {
required: false,
type: Number,
default: () => 0,
},
});
</script>

View File

@ -1,5 +1,5 @@
<template> <template>
<span class="text-gray-600 flex bg-white items-center text-xs @sm:text-sm" :class="{'left-0 ': inline, 'left-2 px-1 absolute -top-3': !inline}"> <span class="text-gray-600 flex bg-white items-center text-xs @sm:text-sm group-[.info]:bg-blue-200" :class="{'left-0 ': inline, 'left-2 px-1 absolute -top-3': !inline}">
<span v-text="name"></span> <span v-show="required" class="text-red-800 ml-1">*</span> <span v-text="name"></span> <span v-show="required" class="text-red-800 ml-1">*</span>
<hint :value="hint" class="ml-2" v-if="hint" small></hint> <hint :value="hint" class="ml-2" v-if="hint" small></hint>
<button <button

View File

@ -1,40 +1,14 @@
<template> <template>
<div class="text-sm relative"> <box :step="step" :type="type">
<div <slot name="current" v-if="modelValue === step"></slot>
class="flex items-center justify-center w-6 h-6 rounded-full border-solid border-2 absolute -top-2 -left-2 font-arvo font-bold" <slot name="finished" v-if="modelValue > step"></slot>
:class="[colors[type].container, colors[type].lightText]" <slot name="due" v-if="modelValue < step"></slot>
v-text="step" </box>
></div>
<div class="flex flex-row items-center p-4 border-2 rounded form-group shadow-sm group" :class="[colors[type].container, type]">
<div class="flex-grow text-sm" :class="colors[type].text">
<slot name="current" v-if="modelValue === step"></slot>
<slot name="finished" v-if="modelValue > step"></slot>
<slot name="due" v-if="modelValue < step"></slot>
</div>
</div>
</div>
</template> </template>
<script setup> <script setup>
import {ref, computed} from 'vue'; import {computed} from 'vue';
import Box from './Box.vue';
const colors = ref({
success: {
container: 'bg-green-200 border-green-600',
lightText: 'text-green-700',
text: 'text-green-900',
},
info: {
container: 'bg-blue-200 border-blue-600',
lightText: 'text-blue-700',
text: 'text-blue-900',
},
default: {
container: 'bg-neutral-200 border-neutral-600',
lightText: 'text-neutral-700',
text: 'text-neutral-900',
},
});
const type = computed(() => { const type = computed(() => {
if (props.modelValue === props.step) { if (props.modelValue === props.step) {
@ -52,8 +26,9 @@ const props = defineProps({
type: Number, type: Number,
}, },
step: { step: {
required: true, required: false,
type: Number, type: Number,
default: () => 0,
}, },
}); });
</script> </script>

View File

@ -1,21 +1,10 @@
<template> <template>
<div class="relative"> <v-checkboxes :intro="field.intro" :options="field.options" :label="field.name" :name="field.key" :id="field.key" :hint="field.hint" v-model="inner"></v-checkboxes>
<field-label :name="field.name" :required="false" :hint="field.hint" inline></field-label>
<div class="grid grid-cols-1 gap-2 pt-1">
<div class="text-sm text-gray-600" v-text="field.intro" v-if="field.intro"></div>
<label v-for="(option, index) in field.options" :key="index" :for="`${innerId}-${index}`" class="block relative flex items-start">
<input :id="`${innerId}-${index}`" v-model="inner" type="checkbox" :name="field.key" :value="option" class="peer absolute invisible" />
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded block"></span>
<span class="peer-checked:bg-primary left-[0.5rem] top-[0.5rem] w-2 h-2 absolute rounded block"></span>
<span class="pl-8 pt-1 @sm:pt-0 text-gray-600 text-sm @sm:text-base" v-text="option"></span>
</label>
</div>
</div>
</template> </template>
<script setup> <script setup>
import {computed} from 'vue'; import {computed} from 'vue';
import FieldLabel from '../FieldLabel.vue'; import VCheckboxes from './VCheckboxes.vue';
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -26,7 +15,7 @@ const props = defineProps({
field: { field: {
required: true, required: true,
validator: (value) => validator: (value) =>
hasKeys(value, [...globalFieldRules(), 'options']) && hasKeys(value, [...globalFieldRules(), 'options', 'min', 'max']) &&
typeof value.key === 'string' && typeof value.key === 'string' &&
value.key.length > 0 && value.key.length > 0 &&
typeof value.name === 'string' && typeof value.name === 'string' &&
@ -39,8 +28,6 @@ const props = defineProps({
}, },
}); });
const innerId = computed(() => (props.id ? props.id : props.field.key));
const inner = computed({ const inner = computed({
get: () => props.modelValue, get: () => props.modelValue,
set: (v) => emit('update:modelValue', v), set: (v) => emit('update:modelValue', v),

View File

@ -1,26 +1,10 @@
<template> <template>
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex"> <v-text type="date" :required="field.required" :name="field.key" :label="field.name" :id="innerId" :hint="field.hint" v-model="inner" :max-today="field.max_today"></v-text>
<input
:id="innerId"
v-model="inner"
:name="field.key"
type="date"
:max="max"
placeholder=""
class="bg-white rounded-lg focus:outline-none text-gray-600 text-left py-1 px-2 @sm:py-2 text-sm @sm:text-base @sm:px-3 w-full"
/>
<div v-if="field.hint" class="absolute right-0 mr-2 flex items-center h-full">
<hint :value="field.hint"></hint>
</div>
<field-label :name="field.name" :required="field.required"></field-label>
</label>
</template> </template>
<script setup> <script setup>
import {computed} from 'vue'; import {computed} from 'vue';
import FieldLabel from '../FieldLabel.vue'; import VText from './VText.vue';
import dayjs from 'dayjs';
import Hint from '../Hint.vue';
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -47,10 +31,6 @@ const props = defineProps({
const innerId = computed(() => (props.id ? props.id : props.field.key)); const innerId = computed(() => (props.id ? props.id : props.field.key));
const max = computed(() => {
return props.field.max_today ? dayjs().format('YYYY-MM-DD') : null;
});
const inner = computed({ const inner = computed({
get: () => props.modelValue, get: () => props.modelValue,
set: (v) => emit('update:modelValue', v), set: (v) => emit('update:modelValue', v),

View File

@ -1,23 +1,19 @@
<template> <template>
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex" :for="field.key"> <v-dropdown
<select v-model="inner"
:id="innerId" :label="field.name"
v-model="inner" :id="field.key"
:disabled="disabled" :name="field.key"
:name="field.key" :options="options"
class="bg-white rounded-lg focus:outline-none text-gray-600 text-left peer py-1 px-2 @sm:py-2 text-sm @sm:text-base @sm:px-3 w-full" :required="field.required"
> :allowcustom="false"
<option :value="null">-- keine Angabe --</option> :empty-option-value="field.empty_option_value"
<option v-for="(option, index) in options" :key="index" :value="option.id" v-text="option.name"></option> ></v-dropdown>
<option v-if="field.has_empty_option" :value="-1" v-text="field.empty_option_value"></option>
</select>
<field-label :name="field.name" :required="field.required"></field-label>
</label>
</template> </template>
<script setup> <script setup>
import {computed, ref, watch} from 'vue'; import {computed, ref, watch} from 'vue';
import FieldLabel from '../FieldLabel.vue'; import VDropdown from './VDropdown.vue';
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -44,8 +40,6 @@ const props = defineProps({
}, },
}); });
const innerId = computed(() => (props.id ? props.id : props.field.key));
const inner = computed({ const inner = computed({
get: () => props.modelValue, get: () => props.modelValue,
set: (v) => emit('update:modelValue', v), set: (v) => emit('update:modelValue', v),

View File

@ -40,7 +40,15 @@
<div class="flex mt-4 space-x-3"> <div class="flex mt-4 space-x-3">
<v-text name="search_firstname" label="Vorname" id="search_firstname" v-model="searchData.vorname" @input="searchForMember(1)"></v-text> <v-text name="search_firstname" label="Vorname" id="search_firstname" v-model="searchData.vorname" @input="searchForMember(1)"></v-text>
<v-text name="search_lastname" label="Nachname" id="search_lastname" v-model="searchData.nachname" @input="searchForMember(1)"></v-text> <v-text name="search_lastname" label="Nachname" id="search_lastname" v-model="searchData.nachname" @input="searchForMember(1)"></v-text>
<v-dropdown name="search_group" label="Stufe" id="search_group" v-model="searchData.untergliederungId" @input="searchForMember(1)" :options="eventMeta.agegroups"></v-dropdown> <v-dropdown
name="search_group"
:allowcustom="false"
label="Stufe"
id="search_group"
v-model="searchData.untergliederungId"
@input="searchForMember(1)"
:options="eventMeta.agegroups"
></v-dropdown>
</div> </div>
<div class="relative min-h-48"> <div class="relative min-h-48">
<div class="relative grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-2 mt-2"> <div class="relative grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-2 mt-2">
@ -80,35 +88,102 @@
Hier siehst du noch einmal alle ausgewählten Mitglieder. Ggf sind hier pro Mitglied noch weitere Informationen erforderlich. Bitte gebe diese pro Mitglied an und klicke dann auf Hier siehst du noch einmal alle ausgewählten Mitglieder. Ggf sind hier pro Mitglied noch weitere Informationen erforderlich. Bitte gebe diese pro Mitglied an und klicke dann auf
"weiter". "weiter".
</p> </p>
<div class="grid items-center gap-2 mt-6" :style="{'grid-template-columns': `max-content repeat(${memberFields.length}, 1fr)`}"> <div class="grid gap-2 mt-6">
<template v-for="member in inner" :key="member.id"> <accordion v-model="openValue" :index="index" :title="member.innerFormName" v-for="(member, index) in inner" :key="index" type="info">
<div v-text="member.innerFormName"></div> <template #buttons>
<template v-for="(memberField, memberIndex) in memberFields"> <a @click.prevent.stop="deleteMember(index)" href="#">
<v-checkbox <delete-icon class="w-3 h-3 text-red-700"></delete-icon>
v-if="memberField.type === 'CheckboxField'" </a>
v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
intro=""
></v-checkbox>
<v-dropdown
v-if="memberField.type === 'DropdownField'"
v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
:options="
memberField.options.map((o) => {
return {id: o, name: o};
})
"
></v-dropdown>
</template> </template>
</template> <div class="mt-2" :class="containerClassesSm">
<template v-for="(memberField, memberIndex) in member.id ? memberFields : newMemberFields">
<v-checkbox
v-if="memberField.type === 'CheckboxField'"
v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.description"
intro=""
:required="memberField.required"
:class="colClassesForField(memberField)"
></v-checkbox>
<v-dropdown
v-if="memberField.type === 'DropdownField'"
v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
:allowcustom="false"
:class="colClassesForField(memberField)"
:required="memberField.required"
:options="
memberField.options.map((o) => {
return {id: o, name: o};
})
"
></v-dropdown>
<v-text
v-if="memberField.type === 'TextField' || memberField.type === 'EmailField'"
v-model="member[memberField.key]"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
:required="memberField.required"
:class="colClassesForField(memberField)"
></v-text>
<v-text
v-if="memberField.type === 'DateField'"
v-model="member[memberField.key]"
:max-today="memberField.max_today"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
:required="memberField.required"
:class="colClassesForField(memberField)"
type="date"
></v-text>
<v-text
v-if="memberField.type === 'NumberField'"
v-model="member[memberField.key]"
:min="memberField.min"
:max="memberField.max"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:label="memberField.name"
:required="memberField.required"
:class="colClassesForField(memberField)"
type="number"
></v-text>
<v-checkboxes
v-if="memberField.type === 'CheckboxesField'"
:intro="memberField.intro"
:options="memberField.options"
:label="memberField.name"
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:hint="memberField.hint"
:class="colClassesForField(memberField)"
v-model="member[memberField.key]"
></v-checkboxes>
<v-radio
v-if="memberField.type === 'RadioField'"
:intro="memberField.intro"
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
:required="memberField.required"
:allowcustom="memberField.allowcustom"
:options="memberField.options"
:label="memberField.name"
:hint="memberField.hint"
:class="colClassesForField(memberField)"
v-model="member[memberField.key]"
></v-radio>
</template>
</div>
</accordion>
</div> </div>
<div class="flex justify-center mt-5"> <div class="flex justify-center space-x-3 mt-5">
<v-btn @click.prevent="membersCompleted = true">Mitgliederdaten speichern</v-btn> <v-btn @click.prevent="membersCompleted = true">Mitgliederdaten speichern</v-btn>
<v-btn @click.prevent="addMember">Mitglied hinzufügen</v-btn>
</div> </div>
</template> </template>
<template #finished> <template #finished>
@ -123,19 +198,24 @@
<script setup> <script setup>
import {computed, ref, warn} from 'vue'; import {computed, ref, warn} from 'vue';
import FieldLabel from '../FieldLabel.vue';
import VText from './VText.vue';
import VDropdown from './VDropdown.vue'; import VDropdown from './VDropdown.vue';
import VCheckboxes from './VCheckboxes.vue';
import VText from './VText.vue';
import useFields from '../../composables/useFieldsWithoutNami.js'; import useFields from '../../composables/useFieldsWithoutNami.js';
import Info from '../Info.vue'; import Info from '../Info.vue';
import VBtn from '../VBtn.vue'; import VBtn from '../VBtn.vue';
import VCheckbox from './VCheckbox.vue'; import VCheckbox from './VCheckbox.vue';
import VRadio from './VRadio.vue';
import Spinner from '../Spinner.vue'; import Spinner from '../Spinner.vue';
import useAdremaLogin from '../../composables/useAdremaLogin.js'; import useAdremaLogin from '../../composables/useAdremaLogin.js';
import useEventMeta from '../../composables/useEventMeta.js'; import useEventMeta from '../../composables/useEventMeta.js';
import Pagination from '../Pagination.vue'; import Pagination from '../Pagination.vue';
import Accordion from '../Accordion.vue';
import useColumns from '../../composables/useColumns.js';
import DeleteIcon from '../icons/DeleteIcon.vue';
const eventMeta = useEventMeta(); const eventMeta = useEventMeta();
const {colClassesForField, containerClassesSm} = useColumns();
const {login, logout, user, loginData, searchData, searchForMember, resetSearchData, searchResults, searching} = useAdremaLogin(); const {login, logout, user, loginData, searchData, searchForMember, resetSearchData, searchResults, searching} = useAdremaLogin();
if (user.value !== null) { if (user.value !== null) {
@ -160,6 +240,12 @@ const step = computed(() => {
return 4; return 4;
}); });
const openValue = ref(-1);
function deleteMember(index) {
inner.value = inner.value.toSpliced(index, 1);
}
const membersAccepted = ref(false); const membersAccepted = ref(false);
const membersCompleted = ref(false); const membersCompleted = ref(false);
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
@ -179,12 +265,20 @@ const props = defineProps({
const defaultMember = computed(() => { const defaultMember = computed(() => {
var fields = {}; var fields = {};
memberFields.value.forEach((field) => (fields[field.key] = field.default)); memberFields.value.forEach((field) => (fields[field.key] = field.value));
return fields;
});
const newDefaultMember = computed(() => {
var fields = {};
newMemberFields.value.forEach((field) => (fields[field.key] = field.value));
return fields; return fields;
}); });
const memberFields = computed(() => props.fields.filter((field) => field.for_members === true && field.nami_type === null)); const memberFields = computed(() => props.fields.filter((field) => field.for_members === true && field.nami_type === null));
const newMemberFields = computed(() => props.fields.filter((field) => field.for_members === true));
const inner = computed( const inner = computed(
{ {
@ -205,11 +299,15 @@ function memberSelected(member) {
return inner.value.map((m) => m.id).includes(member.id); return inner.value.map((m) => m.id).includes(member.id);
} }
function addMember(index) {
inner.value.push(JSON.parse(JSON.stringify({id: null, innerFormName: 'Neues Mitglied', ...newDefaultMember.value})));
}
function toggleMember(member) { function toggleMember(member) {
if (memberSelected(member)) { if (memberSelected(member)) {
inner.value = inner.value.filter((m) => m.id !== member.id); inner.value = inner.value.filter((m) => m.id !== member.id);
} else { } else {
inner.value.push({id: member.id, innerFormName: member.name, ...defaultMember.value}); inner.value.push(JSON.parse(JSON.stringify({id: member.id, innerFormName: member.name, ...defaultMember.value})));
} }
} }

View File

@ -1,36 +1,10 @@
<template> <template>
<div class="relative"> <v-radio :label="field.name" :options="field.options" :allowcustom="field.allowcustom" :intro="field.intro" v-model="inner" :hint="field.hint" :id="field.key" :required="field.required"></v-radio>
<field-label :name="field.name" :required="field.required" :hint="field.hint" :button="modelValue === null ? '' : 'Auswahl löschen'" @buttonclick="selected = null" inline></field-label>
<div class="grid grid-cols-1 gap-2 pt-1">
<div class="text-sm text-gray-600" v-text="field.intro" v-if="field.intro"></div>
<label v-for="(option, index) in field.options" :key="index" :for="`${innerId}-${index}`" class="block relative flex items-center">
<input :id="`${innerId}-${index}`" v-model="selected" type="radio" :name="field.key" :value="option" class="peer absolute invisible" />
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded-full block"></span>
<span class="peer-checked:bg-primary left-2 w-2 h-2 absolute rounded-full block"></span>
<span class="pl-8 text-gray-600 text-sm @sm:text-base" v-text="option"></span>
</label>
<label v-if="field.allowcustom" :for="`${innerId}-custom-value-selected`" class="block relative flex items-center">
<input :id="`${innerId}-custom-value-selected`" v-model="selected" type="radio" :name="field.key" value="custom-value-selected" class="peer absolute invisible" />
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded-full block"></span>
<span class="peer-checked:bg-primary left-2 w-2 h-2 absolute rounded-full block"></span>
<span class="ml-8 w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex h-6">
<input
:id="`${innerId}-custom-value`"
v-model="customValue"
:name="`${innerId}-custom-value`"
placeholder="eigener Wert"
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-[.info]:py-1 px-2 @sm:px-3 @sm:group-[.info]:px-2 text-sm @sm:text-base @sm:group-[.info]:text-sm"
/>
</span>
</label>
</div>
</div>
</template> </template>
<script setup> <script setup>
import {computed, ref, watch} from 'vue'; import {computed} from 'vue';
import FieldLabel from '../FieldLabel.vue'; import VRadio from './VRadio.vue';
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
@ -51,28 +25,10 @@ const props = defineProps({
hasKeys(value.columns, ['mobile', 'desktop', 'tablet']) && hasKeys(value.columns, ['mobile', 'desktop', 'tablet']) &&
typeof value.options === 'object', typeof value.options === 'object',
}, },
id: {
required: false,
},
}); });
const innerId = computed(() => (props.id ? props.id : props.field.key)); const inner = computed({
get: () => props.modelValue,
const selected = ref(props.modelValue === null || props.field.options.includes(props.modelValue) ? props.modelValue : 'custom-value-selected'); set: (v) => emit('update:modelValue', v),
watch(selected, (newValue) => {
customValue.value = newValue === 'custom-value-selected' ? '' : newValue;
});
const customValue = computed({
get: () => {
if (selected.value === 'custom-value-selected') {
return props.modelValue;
}
return '';
},
set: (v) => {
return emit('update:modelValue', v);
},
}); });
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<v-text :required="field.required" :name="field.key" :label="field.name" :id="innerId" :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" v-model="inner"></v-text>
</template> </template>
<script setup> <script setup>
@ -23,13 +23,8 @@ const props = defineProps({
value.name.length > 0 && value.name.length > 0 &&
hasKeys(value.columns, ['mobile', 'desktop', 'tablet']), hasKeys(value.columns, ['mobile', 'desktop', 'tablet']),
}, },
id: {
required: false,
},
}); });
const innerId = computed(() => (props.id ? props.id : props.field.key));
const inner = computed({ const inner = computed({
get: () => props.modelValue, get: () => props.modelValue,
set: (v) => emit('update:modelValue', v), set: (v) => emit('update:modelValue', v),

View File

@ -5,12 +5,12 @@
<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" />
<span <span
class="border-neutral-400 border-4 group-[.info]:border-2 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 group-[.info]:w-4 group-[.info]:h-4 group-[.info]: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-[.info]:top-[0.58rem] group-[.info]: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-[.info]:pl-6 pt-1 @sm:pt-0 @sm:group-[.info]:pt-1 text-gray-600 text-sm @sm:text-base @sm:group-[.info]:text-sm"> <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-text="label"></span> <span v-text="label"></span>
<span v-show="required" class="text-red-800">*</span> <span v-show="required" class="text-red-800"> *</span>
</span> </span>
<hint :value="hint" class="ml-2" v-if="hint"></hint> <hint :value="hint" class="ml-2" v-if="hint"></hint>
</label> </label>

View File

@ -0,0 +1,60 @@
<template>
<div class="relative">
<field-label :name="label" :required="false" :hint="hint" inline></field-label>
<div class="grid grid-cols-1 gap-2 pt-1 group-[.box]:gap-0">
<div class="text-sm text-gray-600" v-text="intro" v-if="intro"></div>
<label v-for="(option, index) in options" :key="index" :for="`${id}-${index}`" class="block relative flex items-start">
<input :id="`${id}-${index}`" v-model="inner" type="checkbox" :name="name" :value="option" class="peer absolute invisible" />
<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 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 class="pl-8 pt-1 @sm:pt-0 text-gray-600 text-sm @sm:text-base" v-text="option"></span>
</label>
</div>
</div>
</template>
<script setup>
import {computed} from 'vue';
import FieldLabel from '../FieldLabel.vue';
const emit = defineEmits(['update:modelValue']);
const props = defineProps({
modelValue: {
required: true,
},
name: {
required: true,
type: String,
},
id: {
required: true,
type: String,
},
label: {
required: true,
type: String,
},
options: {
required: true,
type: Object,
},
hint: {
required: false,
validator: (value) => value === null || typeof value === 'string',
default: () => null,
},
intro: {
required: false,
validator: (value) => value === null || typeof value === 'string',
default: () => null,
},
});
const inner = computed({
get: () => props.modelValue,
set: (v) => emit('update:modelValue', v),
});
</script>

View File

@ -7,15 +7,16 @@
:id="id" :id="id"
v-model="inner" v-model="inner"
:name="name" :name="name"
class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left py-1 px-2 @sm:py-2 @sm:group-[.info]:py-1 text-sm @sm:text-base @sm:group-[.info]:text-sm @sm:px-3 @sm:group-[.info]:px-2 w-full" class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left py-1 px-2 @sm:py-2 @sm:group-[.box]:py-1 text-sm @sm:text-base @sm:group-[.box]:text-sm @sm:px-3 @sm:group-[.box]:px-2 w-full"
> >
<option :value="null">-- keine Angabe --</option> <option :value="null">-- keine Angabe --</option>
<option v-for="(option, index) in options" :key="index" :value="option.id" v-text="option.name"></option> <option v-for="(option, index) in options" :key="index" :value="option.id" v-text="option.name"></option>
<option v-if="emptyOptionValue" :value="-1" v-text="emptyOptionValue"></option>
</select> </select>
<input <input
v-if="allowcustom" v-if="allowcustom"
v-model="inner" v-model="inner"
class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left py-1 px-2 @sm:py-2 @sm:group-[.info]:py-1 text-sm @sm:text-base @sm:group-[.info]:text-sm @sm:px-3 @sm:group-[.info]:px-2 w-full" class="bg-white group-[.info]:bg-blue-200 rounded-lg focus:outline-none text-gray-600 text-left py-1 px-2 @sm:py-2 @sm:group-[.box]:py-1 text-sm @sm:text-base @sm:group-[.box]:text-sm @sm:px-3 @sm:group-[.box]:px-2 w-full"
type="text" type="text"
:list="`${id}-list`" :list="`${id}-list`"
/> />
@ -25,7 +26,7 @@
<div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full"> <div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full">
<hint :value="hint"></hint> <hint :value="hint"></hint>
</div> </div>
<field-label :name="label" class="group-[.info]:bg-blue-200" :required="required"></field-label> <field-label :name="label" :required="required"></field-label>
</label> </label>
</div> </div>
</template> </template>
@ -39,7 +40,7 @@ const emit = defineEmits(['update:modelValue']);
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
required: true, required: true,
validator: (value) => value === null || typeof value === 'string', validator: (value) => value === null || typeof value === 'string' || typeof value === 'number',
}, },
required: { required: {
required: false, required: false,
@ -50,6 +51,10 @@ const props = defineProps({
required: true, required: true,
type: String, type: String,
}, },
emptyOptionValue: {
required: false,
default: () => '',
},
id: { id: {
required: true, required: true,
type: String, type: String,

View File

@ -0,0 +1,85 @@
<template>
<div class="relative">
<field-label :name="label" :required="required" :hint="hint" :button="modelValue === null ? '' : 'Auswahl löschen'" @buttonclick="selected = null" inline></field-label>
<div class="grid grid-cols-1 gap-2 group-[.box]:gap-0 pt-1">
<div class="text-sm text-gray-600" v-text="intro" v-if="intro"></div>
<label v-for="(option, index) in innerOptions" :key="index" :for="`${id}-${index}`" class="block relative flex items-center">
<input :id="`${id}-${index}`" v-model="selected" type="radio" :name="id" :value="option.id" class="peer absolute invisible" />
<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"
></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 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
:id="`${id}-custom-value`"
v-model="customValue"
:name="`${id}-custom-value`"
placeholder="eigener Wert"
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"
/>
</span>
<span v-else class="pl-8 text-gray-600 text-sm @sm:text-base" v-text="option.name"></span>
</label>
</div>
</div>
</template>
<script setup>
import {computed, ref, watch} from 'vue';
import FieldLabel from '../FieldLabel.vue';
const emit = defineEmits(['update:modelValue']);
const props = defineProps({
label: {
required: true,
},
required: {
required: true,
},
hint: {
required: true,
},
modelValue: {
required: true,
validator: (value) => value === null || typeof value === 'string',
},
intro: {
required: true,
},
options: {
required: true,
},
allowcustom: {
required: true,
},
id: {
required: true,
},
});
const innerOptions = computed(() => {
var fieldValues = props.options.map(function (option) {
return {id: option, name: option, iscustom: false};
});
if (props.allowcustom) {
fieldValues.push({id: 'custom-value-selected', iscustom: true});
}
return fieldValues;
});
const optionIds = computed(() => innerOptions.value.map((option) => option.id));
const selected = ref(props.modelValue === null || optionIds.value.includes(props.modelValue) ? props.modelValue : 'custom-value-selected');
watch(selected, (newValue) => {
customValue.value = newValue === 'custom-value-selected' ? '' : newValue;
});
const customValue = computed({
get: () => (selected.value === 'custom-value-selected' ? props.modelValue : ''),
set: (v) => {
return emit('update:modelValue', v);
},
});
</script>

View File

@ -5,16 +5,16 @@
v-model="inner" v-model="inner"
:name="name" :name="name"
:min="min" :min="min"
:max="max" :max="presentMax"
:type="type" :type="type"
placeholder="" 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-[.info]:py-1 px-2 @sm:px-3 @sm:group-[.info]:px-2 text-sm @sm:text-base @sm:group-[.info]:text-sm" 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"
@keypress="$emit('keypress', $event)" @keypress="$emit('keypress', $event)"
/> />
<div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full"> <div v-if="hint" class="absolute right-0 mr-2 flex items-center h-full">
<hint :value="hint"></hint> <hint :value="hint"></hint>
</div> </div>
<field-label :name="label" class="group-[.info]:bg-blue-200" :required="required"></field-label> <field-label :name="label" :required="required"></field-label>
</label> </label>
</template> </template>
@ -22,12 +22,13 @@
import {computed} from 'vue'; import {computed} from 'vue';
import FieldLabel from '../FieldLabel.vue'; import FieldLabel from '../FieldLabel.vue';
import Hint from '../Hint.vue'; import Hint from '../Hint.vue';
import dayjs from 'dayjs';
const emit = defineEmits(['update:modelValue', 'keypress']); const emit = defineEmits(['update:modelValue', 'keypress']);
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
required: true, required: true,
validator: (value) => value === null || typeof value === 'string', validator: (value) => value === null || typeof value === 'string' || typeof value === 'number',
}, },
required: { required: {
required: false, required: false,
@ -43,17 +44,22 @@ const props = defineProps({
type: String, type: String,
}, },
min: { min: {
type: String, type: Number,
default: () => '', default: () => undefined,
}, },
max: { max: {
type: String, type: Number,
default: () => '', default: () => undefined,
}, },
label: { label: {
required: true, required: true,
type: String, type: String,
}, },
maxToday: {
required: false,
type: Boolean,
default: () => false,
},
type: { type: {
required: false, required: false,
type: String, type: String,
@ -66,6 +72,18 @@ const props = defineProps({
}, },
}); });
const presentMax = computed(() => {
if (props.type === 'date' && props.maxToday) {
return dayjs().format('YYYY-MM-DD');
}
if (props.type === 'number') {
return props.max;
}
return null;
});
const inner = computed({ const inner = computed({
get: () => props.modelValue, get: () => props.modelValue,
set: (v) => emit('update:modelValue', v), set: (v) => emit('update:modelValue', v),

View File

@ -9,13 +9,14 @@
viewBox="0 0 512 512" viewBox="0 0 512 512"
style="enable-background: new 0 0 512 512" style="enable-background: new 0 0 512 512"
xml:space="preserve" xml:space="preserve"
fill="currentColor"
> >
<g> <g>
<g> <g>
<path <path
d="M486.4,102.4h-128V25.6c0-15.36-10.24-25.6-25.6-25.6H179.2c-15.36,0-25.6,10.24-25.6,25.6v76.8h-128 d="M486.4,102.4h-128V25.6c0-15.36-10.24-25.6-25.6-25.6H179.2c-15.36,0-25.6,10.24-25.6,25.6v76.8h-128
C10.24,102.4,0,112.64,0,128s10.24,25.6,25.6,25.6h460.8c15.36,0,25.6-10.24,25.6-25.6S501.76,102.4,486.4,102.4z M307.2,102.4 C10.24,102.4,0,112.64,0,128s10.24,25.6,25.6,25.6h460.8c15.36,0,25.6-10.24,25.6-25.6S501.76,102.4,486.4,102.4z M307.2,102.4
H204.8V51.2h102.4V102.4z" H204.8V51.2h102.4V102.4z"
/> />
</g> </g>
</g> </g>
@ -23,10 +24,10 @@
<g> <g>
<path <path
d="M25.6,204.8l48.64,284.16c2.56,12.8,12.8,23.04,25.6,23.04h312.32c12.8,0,23.04-10.24,25.6-23.04L486.4,204.8H25.6z d="M25.6,204.8l48.64,284.16c2.56,12.8,12.8,23.04,25.6,23.04h312.32c12.8,0,23.04-10.24,25.6-23.04L486.4,204.8H25.6z
M153.6,460.8c-15.36,0-25.6-10.24-25.6-25.6l-25.6-153.6c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6l25.6,153.6 M153.6,460.8c-15.36,0-25.6-10.24-25.6-25.6l-25.6-153.6c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6l25.6,153.6
C179.2,450.56,168.96,460.8,153.6,460.8z M281.6,435.2c0,15.36-10.24,25.6-25.6,25.6s-25.6-10.24-25.6-25.6V281.6 C179.2,450.56,168.96,460.8,153.6,460.8z M281.6,435.2c0,15.36-10.24,25.6-25.6,25.6s-25.6-10.24-25.6-25.6V281.6
c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6V435.2z M384,435.2c0,15.36-10.24,25.6-25.6,25.6 c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6V435.2z M384,435.2c0,15.36-10.24,25.6-25.6,25.6
c-15.36,0-25.6-10.24-25.6-25.6l25.6-153.6c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6L384,435.2z" c-15.36,0-25.6-10.24-25.6-25.6l25.6-153.6c0-15.36,10.24-25.6,25.6-25.6s25.6,10.24,25.6,25.6L384,435.2z"
/> />
</g> </g>
</g> </g>

View File

@ -0,0 +1,49 @@
import {ref} from 'vue';
export default function useColumns() {
const colClasses = {
mobile: {
1: 'col-span-1',
2: 'col-span-2',
3: 'col-span-3',
4: 'col-span-4',
5: 'col-span-5',
6: 'col-span-6',
},
tablet: {
1: '@sm:col-span-1',
2: '@sm:col-span-2',
3: '@sm:col-span-3',
4: '@sm:col-span-4',
5: '@sm:col-span-5',
6: '@sm:col-span-6',
},
desktop: {
1: '@lg:col-span-1',
2: '@lg:col-span-2',
3: '@lg:col-span-3',
4: '@lg:col-span-4',
5: '@lg:col-span-5',
6: '@lg:col-span-6',
},
};
const containerClassesDefault = 'grid grid-cols-2 @sm:grid-cols-4 @lg:grid-cols-6 items-start';
const containerClassesSm = containerClassesDefault + ' gap-4';
const containerClasses = containerClassesDefault + ' gap-6';
function colClassesForField(field) {
return {
[colClasses.mobile[field.columns.mobile]]: true,
[colClasses.tablet[field.columns.tablet]]: true,
[colClasses.desktop[field.columns.desktop]]: true,
};
}
return {
colClasses,
colClassesForField,
containerClasses,
containerClassesSm,
};
}