From 3eb8e7599ef3e3e493c9b800a9a04141fbf3d0fd Mon Sep 17 00:00:00 2001 From: Teal Bauer <teal@starsong.eu> Date: Sun, 9 Mar 2025 23:49:00 +0100 Subject: [PATCH] Redesign conference form with improved UI organization - Group form into logical sections with background color and headers - Add labels and placeholder text --- app/views/admin/conferences/_form.html.erb | 180 +++++++++++---------- 1 file changed, 98 insertions(+), 82 deletions(-) diff --git a/app/views/admin/conferences/_form.html.erb b/app/views/admin/conferences/_form.html.erb index 63b52d4..a439f29 100644 --- a/app/views/admin/conferences/_form.html.erb +++ b/app/views/admin/conferences/_form.html.erb @@ -12,106 +12,122 @@ <% end %> <div class="space-y-4"> - <div> - <%= form.label :name, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.text_field :name, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> - </div> + <div class="bg-gray-50 dark:bg-gray-700/30 p-4 rounded-md"> + <h3 class="text-lg font-medium text-gray-700 dark:text-gray-300 mb-4">Basic Information</h3> + <div class="grid grid-cols-1 gap-4 md:grid-cols-3"> + <div> + <%= form.label :name, "Conference Name", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.text_field :name, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white", placeholder: "e.g. Tech Conference 2025" %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">The official name of the conference</p> + </div> - <div> - <%= form.label :slug, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.text_field :slug, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> - <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Used in URLs. Should contain only lowercase letters, numbers, and hyphens.</p> - </div> + <div> + <%= form.label :url, "Official Website URL", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.url_field :url, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white", placeholder: "https://example.com" %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">The official website of the conference</p> + </div> - <div> - <%= form.label :url, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.url_field :url, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> + <div> + <%= form.label :slug, "URL Slug", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.text_field :slug, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white", placeholder: "e.g. tech-conf-2025" %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Used in URLs (e.g., /conferences/tech-conf-2025). Use only lowercase letters, numbers, and hyphens.</p> + </div> + </div> </div> - <div> - <%= form.label :time_zone, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.time_zone_select :time_zone, nil, { include_blank: "Select Time Zone" }, { class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" } %> - </div> + <div class="bg-gray-50 dark:bg-gray-700/30 p-4 rounded-md"> + <h3 class="text-lg font-medium text-gray-700 dark:text-gray-300 mb-4">Timing & Location</h3> + <div class="grid grid-cols-1 gap-4 md:grid-cols-3"> + <div> + <%= form.label :time_zone, "Conference Time Zone", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.time_zone_select :time_zone, nil, { include_blank: "Select Time Zone" }, { class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" } %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">The local time zone where the conference takes place</p> + </div> - <div class="grid grid-cols-1 gap-4 md:grid-cols-2"> - <div> - <%= form.label :starts_at, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.datetime_local_field :starts_at, value: conference.starts_at&.strftime('%Y-%m-%dT%H:%M'), class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> - </div> + <div> + <%= form.label :starts_at, "Start Date & Time", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.datetime_local_field :starts_at, value: conference.starts_at&.strftime('%Y-%m-%dT%H:%M'), class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">When the conference officially begins</p> + </div> - <div> - <%= form.label :ends_at, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.datetime_local_field :ends_at, value: conference.ends_at&.strftime('%Y-%m-%dT%H:%M'), class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> + <div> + <%= form.label :ends_at, "End Date & Time", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.datetime_local_field :ends_at, value: conference.ends_at&.strftime('%Y-%m-%dT%H:%M'), class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">When the conference officially ends</p> + </div> </div> </div> - <div> - <%= form.label :import_job_class, class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> - <%= form.select :import_job_class, - [["Select Import Job Class", ""]] + - ConferencesController.available_import_job_classes.map { |class_name, display_name| [display_name, class_name] }, - {}, - { class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white", - data: { conference_form_target: "importJobClass", action: "change->conference-form#importJobClassChanged" } } %> - <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select the import job class to see required data fields</p> - </div> + <div class="bg-gray-50 dark:bg-gray-700/30 p-4 rounded-md"> + <h3 class="text-lg font-medium text-gray-700 dark:text-gray-300 mb-4">Import Configuration</h3> + + <div> + <%= form.label :import_job_class, "Data Import Method", class: "block text-sm font-medium text-gray-700 dark:text-gray-300" %> + <%= form.select :import_job_class, + [["Select Import Job Class", ""]] + + ConferencesController.available_import_job_classes.map { |class_name, display_name| [display_name, class_name] }, + {}, + { class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white", + data: { conference_form_target: "importJobClass", action: "change->conference-form#importJobClassChanged" } } %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select the method used to import conference data (sessions, speakers, etc.). Each method requires specific data fields below.</p> + </div> - <!-- Add hidden inputs to preserve all data values --> - <% if conference.data.present? %> - <% conference.data.each do |key, value| %> - <input type="hidden" name="data[<%= key %>]" value="<%= value %>" id="hidden_data_<%= key %>"> + <!-- Add hidden inputs to preserve all data values --> + <% if conference.data.present? %> + <% conference.data.each do |key, value| %> + <input type="hidden" name="data[<%= key %>]" value="<%= value %>" id="hidden_data_<%= key %>"> + <% end %> <% end %> - <% end %> - <fieldset class="mt-6 border border-gray-300 rounded-md p-4 dark:border-gray-600"> - <legend class="px-2 text-sm font-medium text-gray-700 dark:text-gray-300">Required Data Fields</legend> - - <div class="space-y-4" data-conference-form-target="requiredFields"> - <% if conference.import_job_class.present? %> - <% begin %> - <% klass = conference.import_job_class.constantize %> - <% conference.required_data_fields.each do |field| %> - <% metadata = klass.respond_to?(:field_metadata) ? (klass.field_metadata[field] || {}) : {} %> - <div class="mb-4"> - <label for="data_<%= field %>" class="block text-sm font-medium text-gray-700 dark:text-gray-300"> - <%= metadata[:title] || field.humanize %><%= metadata[:required] ? ' <span class="text-red-500">*</span>'.html_safe : '' %> - </label> - <% if metadata[:description].present? %> - <p class="mt-1 text-xs text-gray-500 dark:text-gray-400"><%= metadata[:description] %></p> - <% end %> - <input - type="text" - id="data_<%= field %>" - name="data[<%= field %>]" - value="<%= conference.data&.dig(field) %>" - placeholder="<%= metadata[:placeholder] %>" - <%= 'required' if metadata[:required] %> - class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> - </div> + <div class="mt-6"> + <h4 class="text-md font-medium text-gray-700 dark:text-gray-300 mb-3">Required Data Fields for Import</h4> + + <div class="space-y-4" data-conference-form-target="requiredFields"> + <% if conference.import_job_class.present? %> + <% begin %> + <% klass = conference.import_job_class.constantize %> + <% conference.required_data_fields.each do |field| %> + <% metadata = klass.respond_to?(:field_metadata) ? (klass.field_metadata[field] || {}) : {} %> + <div class="mb-4"> + <label for="data_<%= field %>" class="block text-sm font-medium text-gray-700 dark:text-gray-300"> + <%= metadata[:title] || field.humanize %><%= metadata[:required] ? ' <span class="text-red-500">*</span>'.html_safe : '' %> + </label> + <% if metadata[:description].present? %> + <p class="mt-1 text-xs text-gray-500 dark:text-gray-400"><%= metadata[:description] %></p> + <% end %> + <input + type="text" + id="data_<%= field %>" + name="data[<%= field %>]" + value="<%= conference.data&.dig(field) %>" + placeholder="<%= metadata[:placeholder] %>" + <%= 'required' if metadata[:required] %> + class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> + </div> + <% end %> + <% rescue => e %> + <div class="text-red-500">Error loading field metadata: <%= e.message %></div> <% end %> - <% rescue => e %> - <div class="text-red-500">Error loading field metadata: <%= e.message %></div> + <% else %> + <p class="text-sm text-gray-500 dark:text-gray-400">Select an import job class to see required fields</p> <% end %> - <% else %> - <p class="text-sm text-gray-500 dark:text-gray-400">Select an import job class to see required fields</p> - <% end %> + </div> </div> - </fieldset> - <fieldset class="mt-6 border border-gray-300 rounded-md p-4 dark:border-gray-600"> - <legend class="px-2 text-sm font-medium text-gray-700 dark:text-gray-300">Custom Data Fields</legend> + <div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-600"> + <h4 class="text-md font-medium text-gray-700 dark:text-gray-300 mb-3">Additional Custom Data Fields</h4> <div class="space-y-4" data-conference-form-target="customFields"> <% if conference.data.present? %> <% conference.data.except(*conference.required_data_fields).each do |key, value| %> <div class="flex items-center space-x-2 custom-field-row"> <div class="flex-1"> - <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Key</label> - <input type="text" name="custom_field_keys[]" value="<%= key %>" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> + <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Field Name</label> + <input type="text" name="custom_field_keys[]" value="<%= key %>" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="e.g. venue_address"> </div> <div class="flex-1"> - <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Value</label> - <input type="text" name="custom_field_values[]" value="<%= value %>" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> + <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Field Value</label> + <input type="text" name="custom_field_values[]" value="<%= value %>" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="The field's value"> </div> <div class="flex items-end"> <button type="button" data-action="click->conference-form#removeCustomField" class="mt-1 p-2 text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300"> @@ -128,12 +144,12 @@ <template data-conference-form-target="customTemplate"> <div class="flex items-center space-x-2 custom-field-row"> <div class="flex-1"> - <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Key</label> - <input type="text" name="custom_field_keys[]" value="KEY_PLACEHOLDER" placeholder="Enter key" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> + <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Field Name</label> + <input type="text" name="custom_field_keys[]" value="KEY_PLACEHOLDER" placeholder="e.g. venue_address" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> </div> <div class="flex-1"> - <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Value</label> - <input type="text" name="custom_field_values[]" value="VALUE_PLACEHOLDER" placeholder="Enter value" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> + <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Field Value</label> + <input type="text" name="custom_field_values[]" value="VALUE_PLACEHOLDER" placeholder="The field's value" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"> </div> <div class="flex items-end"> <button type="button" data-action="click->conference-form#removeCustomField" class="mt-1 p-2 text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300"> @@ -150,10 +166,10 @@ <svg xmlns="http://www.w3.org/2000/svg" class="-ml-0.5 mr-2 h-4 w-4" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" /> </svg> - Add Custom Field + Add Additional Field </button> </div> - </fieldset> + </div> </div> </div> -- GitLab