Refactor Layout Settings in FormBuilderFieldSettingsModal.vue
- Removed the old layout and appearance section and replaced it with a new compact width selector for improved usability. - Introduced a layout tab for components that support width settings, enhancing the organization of field settings. - Updated styles for the new compact width selection, including button groups and visual previews, to provide a more intuitive user experience. - Ensured that the current width selection feedback is clearly displayed, improving user awareness of their choices.
This commit is contained in:
parent
bc7daed988
commit
bf5e1630b3
@ -306,93 +306,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout & Appearance Section -->
|
||||
<div v-if="showField('width')" class="settings-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">
|
||||
<Icon name="heroicons:squares-2x2" class="w-5 h-5 mr-2" />
|
||||
Layout & Size
|
||||
</h4>
|
||||
<p class="section-description">Control how this field appears in your form</p>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-3">Field Width</label>
|
||||
|
||||
<!-- Width Options with Visual Grid Preview -->
|
||||
<div class="width-selector">
|
||||
<div
|
||||
v-for="option in widthOptions"
|
||||
:key="option.value"
|
||||
@click="setComponentWidth(option.value, option.gridColumns)"
|
||||
class="width-option"
|
||||
:class="{
|
||||
'selected': getComponentWidthPercent() === option.value,
|
||||
'recommended': isRecommendedWidth(option.type)
|
||||
}"
|
||||
>
|
||||
<!-- Visual Grid Preview -->
|
||||
<div class="grid-preview">
|
||||
<div class="grid-container-mini">
|
||||
<div
|
||||
v-for="i in 12"
|
||||
:key="i"
|
||||
class="grid-cell"
|
||||
:class="{
|
||||
'active': i <= option.gridColumns,
|
||||
'inactive': i > option.gridColumns
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Option Info -->
|
||||
<div class="option-info">
|
||||
<div class="option-name">
|
||||
{{ option.name }}
|
||||
<span v-if="isRecommendedWidth(option.type)" class="recommended-badge">
|
||||
Recommended
|
||||
</span>
|
||||
</div>
|
||||
<div class="option-description">{{ option.description }}</div>
|
||||
<div class="option-use-case">{{ option.useCase }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Selection Feedback -->
|
||||
<div class="current-selection-feedback">
|
||||
<div class="feedback-row">
|
||||
<span class="feedback-label">Current width:</span>
|
||||
<span class="feedback-value">{{ getCurrentWidthOption()?.name || 'Custom' }}</span>
|
||||
</div>
|
||||
<div class="feedback-row">
|
||||
<span class="feedback-label">Grid columns:</span>
|
||||
<span class="feedback-value">{{ getCurrentGridColumns() }} of 12</span>
|
||||
</div>
|
||||
|
||||
<!-- Visual representation -->
|
||||
<div class="current-width-visual">
|
||||
<div class="visual-grid">
|
||||
<div
|
||||
v-for="i in 12"
|
||||
:key="i"
|
||||
class="visual-cell"
|
||||
:class="{
|
||||
'filled': i <= getCurrentGridColumns(),
|
||||
'empty': i > getCurrentGridColumns()
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
<div class="visual-label">
|
||||
{{ getCurrentGridColumns() }}/12 columns ({{ configModel.width || '100%' }})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Component-Specific Settings -->
|
||||
<div v-if="hasSpecificSettings" class="settings-section">
|
||||
@ -2459,6 +2372,61 @@ if (this.element.querySelector('.file-upload')) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout Tab -->
|
||||
<div v-if="activeTab === 'layout'" class="space-y-6">
|
||||
<div class="settings-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">
|
||||
<Icon name="heroicons:squares-2x2" class="w-5 h-5 mr-2" />
|
||||
Layout & Size
|
||||
</h4>
|
||||
<p class="section-description">Control how this field appears in your form</p>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-3">Field Width</label>
|
||||
|
||||
<!-- Compact Width Selector -->
|
||||
<div class="width-selector-compact">
|
||||
<!-- Button Group for Width Selection -->
|
||||
<div class="width-buttons">
|
||||
<button
|
||||
v-for="option in widthOptions"
|
||||
:key="option.value"
|
||||
@click="setComponentWidth(option.value, option.gridColumns)"
|
||||
type="button"
|
||||
class="width-button"
|
||||
:class="{
|
||||
'active': getComponentWidthPercent() === option.value,
|
||||
'recommended': isRecommendedWidth(option.type)
|
||||
}"
|
||||
:title="option.useCase"
|
||||
>
|
||||
<div class="width-visual">
|
||||
<div class="width-bar" :style="{ width: option.value + '%' }"></div>
|
||||
</div>
|
||||
<span class="width-label">{{ option.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Simple Visual Preview -->
|
||||
<div class="width-preview">
|
||||
<div class="preview-container">
|
||||
<div class="preview-field" :style="{ width: getComponentWidthPercent() + '%' }">
|
||||
<div class="preview-input"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-info">
|
||||
{{ getCurrentWidthOption()?.name || 'Custom' }} ({{ getComponentWidthPercent() }}%)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Validation Tab -->
|
||||
<div v-if="activeTab === 'validation'" class="space-y-6">
|
||||
<div class="settings-section">
|
||||
@ -2931,6 +2899,11 @@ const availableTabs = computed(() => {
|
||||
{ id: 'basic', label: 'Basic Settings', icon: 'heroicons:cog-6-tooth' }
|
||||
]
|
||||
|
||||
// Add layout tab for components that support width settings
|
||||
if (showField('width')) {
|
||||
tabs.push({ id: 'layout', label: 'Layout', icon: 'heroicons:squares-2x2' })
|
||||
}
|
||||
|
||||
if (hasOptions.value) {
|
||||
tabs.push({ id: 'options', label: 'Options', icon: 'heroicons:list-bullet' })
|
||||
}
|
||||
@ -4082,6 +4055,84 @@ const getDefaultPropsForType = (type) => {
|
||||
@apply flex justify-between items-center py-1;
|
||||
}
|
||||
|
||||
/* Compact Width Selection - New Styles */
|
||||
.width-selector-compact {
|
||||
@apply space-y-4;
|
||||
}
|
||||
|
||||
.width-buttons {
|
||||
@apply flex flex-wrap gap-2;
|
||||
}
|
||||
|
||||
.width-button {
|
||||
@apply flex-1 min-w-0 px-3 py-2 border border-gray-200 rounded-lg hover:border-blue-300 hover:bg-blue-50 transition-all duration-200 cursor-pointer text-center relative;
|
||||
}
|
||||
|
||||
.width-button.active {
|
||||
@apply border-blue-500 bg-blue-50 ring-1 ring-blue-200;
|
||||
}
|
||||
|
||||
.width-button.recommended::before {
|
||||
content: '';
|
||||
@apply absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full;
|
||||
}
|
||||
|
||||
.width-button.active.recommended {
|
||||
@apply border-green-500 bg-green-50 ring-1 ring-green-200;
|
||||
}
|
||||
|
||||
.width-visual {
|
||||
@apply w-full h-1.5 bg-gray-100 rounded-sm mb-2 overflow-hidden;
|
||||
}
|
||||
|
||||
.width-bar {
|
||||
@apply h-full bg-blue-500 rounded-sm transition-all duration-300;
|
||||
}
|
||||
|
||||
.width-button.active .width-bar {
|
||||
@apply bg-blue-600;
|
||||
}
|
||||
|
||||
.width-button.recommended .width-bar {
|
||||
@apply bg-green-500;
|
||||
}
|
||||
|
||||
.width-button.active.recommended .width-bar {
|
||||
@apply bg-green-600;
|
||||
}
|
||||
|
||||
.width-label {
|
||||
@apply text-sm font-medium text-gray-700;
|
||||
}
|
||||
|
||||
.width-button.active .width-label {
|
||||
@apply text-blue-700;
|
||||
}
|
||||
|
||||
.width-button.recommended .width-label {
|
||||
@apply text-green-700;
|
||||
}
|
||||
|
||||
.width-preview {
|
||||
@apply mt-4 p-3 bg-gray-50 rounded-lg border;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
@apply w-full bg-white rounded border p-2 mb-2;
|
||||
}
|
||||
|
||||
.preview-field {
|
||||
@apply transition-all duration-300;
|
||||
}
|
||||
|
||||
.preview-input {
|
||||
@apply w-full h-8 border border-gray-100 rounded px-2 bg-blue-600;
|
||||
}
|
||||
|
||||
.preview-info {
|
||||
@apply text-sm text-gray-600 text-center;
|
||||
}
|
||||
|
||||
.feedback-label {
|
||||
@apply text-sm font-medium text-gray-600;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user