Add Tabler Icons and Refactor Form Components (#771)

- Updated `package.json` and `package-lock.json` to include `@iconify-json/tabler` for additional icon support.
- Refactored `ImageInput.vue` to utilize `nuxt/icon` for icon rendering, enhancing consistency across components.
- Introduced `OptionSelectorInput.vue` as a new form component for selecting options in a grid layout, integrating with the form system.
- Updated `FormCustomization.vue` and `FormEditorPreview.vue` to utilize the new `OptionSelectorInput` for improved user experience in form settings.
- Enhanced `HiddenRequiredDisabled.vue` to replace manual button rendering with `OptionSelectorInput`, streamlining the component structure.

These changes aim to improve the iconography and form component functionality, providing a more cohesive and user-friendly interface.
This commit is contained in:
Chirag Chhatrala
2025-06-02 19:24:38 +05:30
committed by GitHub
parent 9a42aacc3a
commit a140f789c2
8 changed files with 437 additions and 245 deletions

View File

@@ -1,87 +1,61 @@
<template>
<div class="grid grid-cols-3 gap-2">
<button
v-for="option in availableOptions"
:key="option.name"
class="flex flex-col items-center justify-center p-1.5 border rounded-lg transition-colors text-gray-500"
:class="[
option.class ? (typeof option.class === 'function' ? option.class(isSelected(option.name)) : option.class) : {},
{
'border-blue-500 bg-blue-50': isSelected(option.name),
'hover:bg-gray-100 border-gray-300': !isSelected(option.name)
}
]"
@click="toggleOption(option.name)"
>
<Icon
:name="isSelected(option.name) && option.selectedIcon ? option.selectedIcon : option.icon"
:class="[
'w-4 h-4 mb-1',
{
'text-blue-500': isSelected(option.name),
'text-inherit': !isSelected(option.name),
},
option.iconClass ? (typeof option.iconClass === 'function' ? option.iconClass(isSelected(option.name)) : option.iconClass) : {}
]"
/>
<span
class="text-xs"
:class="{
'text-blue-500': isSelected(option.name),
'text-inherit': !isSelected(option.name),
}"
>{{ isSelected(option.name) ? option.selectedLabel ?? option.label : option.label }}</span>
</button>
</div>
<OptionSelectorInput
:options="availableOptions"
v-model="selectedOption"
:multiple="false"
:disabled="false"
:columns="3"
name="field_state"
/>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
field: {
type: Object,
required: true
},
canBeDisabled: {
type: Boolean,
default: true
},
canBeRequired: {
type: Boolean,
default: true
},
canBeHidden: {
type: Boolean,
default: true
}
field: {
type: Object,
required: true
},
canBeDisabled: {
type: Boolean,
default: true
},
canBeRequired: {
type: Boolean,
default: true
},
canBeHidden: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['update:field'])
defineEmits(['update:field'])
const options = ref([
{
name: 'required',
label: 'Required',
icon: 'i-ph-asterisk-bold',
selectedIcon: 'i-ph-asterisk-bold',
const options = [
{
name: 'required',
label: 'Required',
icon: 'ph:asterisk-bold',
selectedIcon: 'ph:asterisk-bold',
iconClass: (isActive) => isActive ? 'text-red-500' : '',
},
{
name: 'hidden',
label: 'Hidden',
icon: 'i-heroicons-eye',
selectedIcon: 'i-heroicons-eye-slash-solid',
{
name: 'hidden',
label: 'Hidden',
icon: 'heroicons:eye',
selectedIcon: 'heroicons:eye-slash-solid',
},
{
name: 'disabled',
label: 'Disabled',
icon: 'i-heroicons-lock-open',
selectedIcon: 'i-heroicons-lock-closed-solid',
{
name: 'disabled',
label: 'Disabled',
icon: 'heroicons:lock-open',
selectedIcon: 'heroicons:lock-closed-solid',
}
])
]
const availableOptions = computed(() => {
return options.value.filter(option => {
return options.filter(option => {
if (option.name === 'disabled') return props.canBeDisabled
if (option.name === 'required') return props.canBeRequired
if (option.name === 'hidden') return props.canBeHidden
@@ -89,28 +63,34 @@ const availableOptions = computed(() => {
})
})
const isSelected = (optionName) => {
return props.field[optionName]
}
const toggleOption = (optionName) => {
const newValue = !props.field[optionName]
if (optionName === 'required' && newValue) {
props.field.hidden = false
} else if (optionName === 'hidden' && newValue) {
const selectedOption = computed({
get() {
// Only one can be true at a time, priority: required > hidden > disabled
if (props.field.required) return 'required'
if (props.field.hidden) return 'hidden'
if (props.field.disabled) return 'disabled'
return null
},
set(optionName) {
// Reset all
props.field.required = false
props.field.disabled = false
props.field.generates_uuid = false
props.field.generates_auto_increment_id = false
} else if (optionName === 'disabled' && newValue) {
props.field.hidden = false
props.field.disabled = false
// Apply business logic
if (optionName === 'required') {
props.field.required = true
props.field.hidden = false
} else if (optionName === 'hidden') {
props.field.hidden = true
props.field.required = false
props.field.disabled = false
props.field.generates_uuid = false
props.field.generates_auto_increment_id = false
} else if (optionName === 'disabled') {
props.field.disabled = true
props.field.hidden = false
}
emit('update:field', { ...props.field })
}
if ((optionName === 'disabled' && props.canBeDisabled) ||
(optionName === 'required' && props.canBeRequired) ||
(optionName === 'hidden' && props.canBeHidden)) {
props.field[optionName] = newValue
}
}
})
</script>