Fix all accessibility gaps identified in codebase audit

HIGH PRIORITY — Icon-only buttons with no accessible name:
- _toggle_view.html.erb: aria-label on Templates/Submissions view buttons
- _template.html.erb: aria-label on move, restore, edit, clone, archive/delete
  (also fixes bug: was aria_label: t('restore') for all, now dynamic)
- _title.html.erb: aria-label on move-folder pencil link
- submissions/show.html.erb: aria-label on download options dropdown toggle,
  audit log link, event log link, edit submitter pencil in parties view
- submit_form/show.html.erb: aria-label on scroll decline button (mobile icon-only)
- contenteditable.vue: span→role=button + aria-label + keyboard handlers (Enter/Space)
  on edit pencil; aria-hidden on decorative icon
- signature_step.vue: aria-label + aria-hidden on minimize link

MEDIUM PRIORITY — Form inputs with missing labels:
- text_step.vue: conditional aria-label fallback on input/textarea when no
  visible label rendered (showFieldNames=false or field has no name)
- area.vue: aria-label on multiple-select checkbox (matches radio pattern)

MEDIUM PRIORITY — Images with generic hardcoded alt text:
- area.vue: replace 'Image'/'Stamp'/'Knowledge-based authentication' with
  t('image')/t('stamp')/t('kba') for i18n consistency

MEDIUM PRIORITY — Dropdown/menu ARIA:
- _navbar.html.erb: aria-controls="user-menu-list" on user menu trigger;
  id="user-menu-list" on menu <ul>

MEDIUM PRIORITY — Form grouping:
- storage_settings/index.html.erb: wrap radio buttons in <fieldset><legend>

LOW PRIORITY — Required field indicator:
- mobile_fields.vue: replace tooltip span with <abbr title="required"> pattern

LOW PRIORITY — Keyboard accessibility:
- templates_folders/edit.html.erb: tabindex="0" on folder toggle label

i18n: add download_options key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pull/599/head
Marcelo Paiva 3 weeks ago
parent c60b5f5284
commit 76f0fa7426

@ -54,19 +54,19 @@
v-if="field.type === 'image' && image" v-if="field.type === 'image' && image"
class="object-contain mx-auto" class="object-contain mx-auto"
:src="image.url" :src="image.url"
:alt="field.name || 'Image'" :alt="field.name || t('image')"
> >
<img <img
v-else-if="field.type === 'stamp' && stamp" v-else-if="field.type === 'stamp' && stamp"
class="object-contain mx-auto" class="object-contain mx-auto"
:src="stamp.url" :src="stamp.url"
:alt="field.name || 'Stamp'" :alt="field.name || t('stamp')"
> >
<img <img
v-else-if="field.type === 'kba' && kba" v-else-if="field.type === 'kba' && kba"
class="object-contain mx-auto" class="object-contain mx-auto"
:src="kba.url" :src="kba.url"
:alt="field.name || 'Knowledge-based authentication'" :alt="field.name || t('kba')"
> >
<div <div
v-else-if="field.type === 'signature' && signature" v-else-if="field.type === 'signature' && signature"
@ -176,6 +176,7 @@
v-if="submittable" v-if="submittable"
type="checkbox" type="checkbox"
:value="false" :value="false"
:aria-label="(field.title || field.name || fieldNames[field.type]) + (option?.value ? ': ' + option.value : '')"
class="aspect-square base-checkbox" class="aspect-square base-checkbox"
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }" :class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
:checked="!!modelValue && modelValue.includes(optionValue(option))" :checked="!!modelValue && modelValue.includes(optionValue(option))"

@ -106,10 +106,12 @@
<a <a
href="#" href="#"
:title="t('minimize')" :title="t('minimize')"
:aria-label="t('minimize')"
class="py-1.5 inline md:hidden" class="py-1.5 inline md:hidden"
@click.prevent="$emit('minimize')" @click.prevent="$emit('minimize')"
> >
<IconArrowsDiagonalMinimize2 <IconArrowsDiagonalMinimize2
aria-hidden="true"
:width="20" :width="20"
:height="20" :height="20"
/> />

@ -41,6 +41,7 @@
:required="field.required" :required="field.required"
:pattern="field.validation?.pattern" :pattern="field.validation?.pattern"
:placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`" :placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`"
:aria-label="showFieldNames && (field.name || field.title) ? undefined : (field.name || field.title || t('text_field'))"
type="text" type="text"
:name="`values[${field.uuid}]`" :name="`values[${field.uuid}]`"
@invalid="validationMessage ? $event.target.setCustomValidity(validationMessage) : ''" @invalid="validationMessage ? $event.target.setCustomValidity(validationMessage) : ''"
@ -56,6 +57,7 @@
class="base-textarea !text-2xl w-full" class="base-textarea !text-2xl w-full"
:placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`" :placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`"
:required="field.required" :required="field.required"
:aria-label="showFieldNames && (field.name || field.title) ? undefined : (field.name || field.title || t('text_field'))"
:name="`values[${field.uuid}]`" :name="`values[${field.uuid}]`"
@input="resizeTextarea" @input="resizeTextarea"
@focus="$emit('focus')" @focus="$emit('focus')"

@ -24,17 +24,22 @@
</span> </span>
<span <span
v-if="withButton" v-if="withButton"
role="button"
tabindex="0"
:aria-label="t('edit')"
class="relative inline" class="relative inline"
:class="{ 'peer-focus:hidden': hideIcon, 'peer-focus:invisible': !hideIcon }" :class="{ 'peer-focus:hidden': hideIcon, 'peer-focus:invisible': !hideIcon }"
@click="clickEdit"
@keydown.enter.prevent="clickEdit"
@keydown.space.prevent="clickEdit"
> >
<IconPencil <IconPencil
aria-hidden="true"
class="cursor-pointer flex-none opacity-0 group-hover/contenteditable-container:opacity-100 group-hover/contenteditable:opacity-100 align-middle pl-1" class="cursor-pointer flex-none opacity-0 group-hover/contenteditable-container:opacity-100 group-hover/contenteditable:opacity-100 align-middle pl-1"
:style="iconInline ? {} : { right: -(1.1 * iconWidth) + 'px' }" :style="iconInline ? {} : { right: -(1.1 * iconWidth) + 'px' }"
:title="t('edit')"
:class="{ invisible: !editable, 'absolute top-1/2 -translate-y-1/2': !iconInline || floatIcon, 'inline align-bottom': iconInline, 'left-0': floatIcon }" :class="{ invisible: !editable, 'absolute top-1/2 -translate-y-1/2': !iconInline || floatIcon, 'inline align-bottom': iconInline, 'left-0': floatIcon }"
:width="iconWidth + 4" :width="iconWidth + 4"
:stroke-width="iconStrokeWidth" :stroke-width="iconStrokeWidth"
@click="clickEdit"
/> />
</span> </span>
</div> </div>

@ -38,13 +38,12 @@
:width="20" :width="20"
/> />
{{ field.title || field.name }} {{ field.title || field.name }}
<span <abbr
v-if="defaultRequiredFields.includes(field)" v-if="defaultRequiredFields.includes(field)"
:data-tip="t('required')" :title="t('required')"
class="text-red-400 text-2xl tooltip tooltip-left h-6" class="text-red-400 text-2xl h-6 no-underline"
> aria-label="required"
* >*</abbr>
</span>
</a> </a>
</li> </li>
</template> </template>

@ -1,11 +1,11 @@
<form action="<%= root_path %>" method="get" id="templates_submissions_toggle" class="bg-base-200 px-1.5 rounded-xl py-1 whitespace-nowrap"> <form action="<%= root_path %>" method="get" id="templates_submissions_toggle" class="bg-base-200 px-1.5 rounded-xl py-1 whitespace-nowrap">
<toggle-cookies data-value="templates" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('templates') %>"> <toggle-cookies data-value="templates" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('templates') %>">
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9' : 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>"> <button class="<%= local_assigns[:selected] == 'submissions' ? 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9' : 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>" aria-label="<%= t('templates') %>">
<%= svg_icon('layout_grid', class: 'w-6 h-6 stroke-2') %> <%= svg_icon('layout_grid', class: 'w-6 h-6 stroke-2') %>
</button> </button>
</toggle-cookies> </toggle-cookies>
<toggle-cookies data-value="submissions" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('submissions') %>"> <toggle-cookies data-value="submissions" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('submissions') %>">
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9' : 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>"> <button class="<%= local_assigns[:selected] == 'submissions' ? 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9' : 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>" aria-label="<%= t('submissions') %>">
<%= svg_icon('layout_list', class: 'w-6 h-6 stroke-2') %> <%= svg_icon('layout_list', class: 'w-6 h-6 stroke-2') %>
</button> </button>
</toggle-cookies> </toggle-cookies>

@ -25,10 +25,10 @@
<% end %> <% end %>
<user-menu> <user-menu>
<div class="dropdown dropdown-end"> <div class="dropdown dropdown-end">
<label tabindex="0" class="cursor-pointer bg-base-content text-purple-300 rounded-full p-2 w-9 justify-center flex" role="button" aria-label="<%= t('user_menu') %>" aria-haspopup="menu" aria-expanded="false"> <label tabindex="0" class="cursor-pointer bg-base-content text-purple-300 rounded-full p-2 w-9 justify-center flex" role="button" aria-label="<%= t('user_menu') %>" aria-haspopup="menu" aria-expanded="false" aria-controls="user-menu-list">
<span class="text-sm align-text-top" aria-hidden="true"><%= current_user.initials %></span> <span class="text-sm align-text-top" aria-hidden="true"><%= current_user.initials %></span>
</label> </label>
<ul tabindex="-1" class="z-10 dropdown-content p-2 mt-2 shadow menu text-base bg-base-100 rounded-box min-w-[160px] text-right"> <ul id="user-menu-list" tabindex="-1" class="z-10 dropdown-content p-2 mt-2 shadow menu text-base bg-base-100 rounded-box min-w-[160px] text-right">
<li> <li>
<%= link_to settings_profile_index_path, class: 'flex items-center' do %> <%= link_to settings_profile_index_path, class: 'flex items-center' do %>
<%= svg_icon('adjustments', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> <%= svg_icon('adjustments', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>

@ -9,14 +9,17 @@
<%= form_for @encrypted_config, url: settings_storage_index_path, method: :post, html: { autocomplete: 'off', class: 'w-full' } do |f| %> <%= form_for @encrypted_config, url: settings_storage_index_path, method: :post, html: { autocomplete: 'off', class: 'w-full' } do |f| %>
<% options = [%w[Disk disk], %w[AWS aws_s3], %w[GCP google], %w[Azure azure]] %> <% options = [%w[Disk disk], %w[AWS aws_s3], %w[GCP google], %w[Azure azure]] %>
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="block relative"> <toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="block relative">
<ul class="items-center w-full text-sm font-medium text-gray-900 space-y-2 sm:space-y-0 sm:flex sm:space-x-2"> <fieldset>
<% options.each do |(label, val)| %> <legend class="sr-only"><%= t('storage') %></legend>
<li class="w-full text-sm font-medium flex items-center relative group py-3.5"> <ul class="items-center w-full text-sm font-medium text-gray-900 space-y-2 sm:space-y-0 sm:flex sm:space-x-2">
<%= f.radio_button :selected, val, checked: value['service'] == val, id: "#{val}_radio", data: { action: 'change:toggle-visible#trigger' }, class: 'base-radio ml-3 relative peer z-10' %> <% options.each do |(label, val)| %>
<%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'absolute border-neutral-focus border rounded-xl left-0 right-0 top-0 bottom-0 flex items-center justify-center group-hover:bg-neutral group-hover:text-white' %> <li class="w-full text-sm font-medium flex items-center relative group py-3.5">
</li> <%= f.radio_button :selected, val, checked: value['service'] == val, id: "#{val}_radio", data: { action: 'change:toggle-visible#trigger' }, class: 'base-radio ml-3 relative peer z-10' %>
<% end %> <%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'absolute border-neutral-focus border rounded-xl left-0 right-0 top-0 bottom-0 flex items-center justify-center group-hover:bg-neutral group-hover:text-white' %>
</ul> </li>
<% end %>
</ul>
</fieldset>
</toggle-visible> </toggle-visible>
<disable-hidden id="disk" class="block my-4 <%= 'hidden' if value['service'] != 'disk' %>"> <disable-hidden id="disk" class="block my-4 <%= 'hidden' if value['service'] != 'disk' %>">
<%= render 'disk_form', f: %> <%= render 'disk_form', f: %>

@ -20,14 +20,14 @@
<%= button_to button_title(title: t('unarchive'), disabled_with: t('unarchive')[0..-2], icon: svg_icon('rotate', class: 'w-6 h-6')), submission_unarchive_index_path(@submission), class: 'btn btn-primary btn-ghost text-base hidden md:flex' %> <%= button_to button_title(title: t('unarchive'), disabled_with: t('unarchive')[0..-2], icon: svg_icon('rotate', class: 'w-6 h-6')), submission_unarchive_index_path(@submission), class: 'btn btn-primary btn-ghost text-base hidden md:flex' %>
<% end %> <% end %>
<% if @submission.audit_trail.present? %> <% if @submission.audit_trail.present? %>
<a href="<%= ActiveStorage::Blob.proxy_url(@submission.audit_trail.blob, expires_at: 4.hours.from_now) %>" class="white-button" target="_blank"> <a href="<%= ActiveStorage::Blob.proxy_url(@submission.audit_trail.blob, expires_at: 4.hours.from_now) %>" class="white-button" target="_blank" aria-label="<%= t('audit_log') %>">
<%= svg_icon('external_link', class: 'w-6 h-6') %> <%= svg_icon('external_link', class: 'w-6 h-6') %>
<span class="hidden md:inline"><%= t('audit_log') %></span> <span class="hidden md:inline" aria-hidden="true"><%= t('audit_log') %></span>
</a> </a>
<% elsif signed_in? %> <% elsif signed_in? %>
<%= link_to submission_events_path(@submission), class: 'white-button', data: { turbo_frame: :modal } do %> <%= link_to submission_events_path(@submission), class: 'white-button', aria: { label: t('event_log') }, data: { turbo_frame: :modal } do %>
<%= svg_icon('logs', class: 'w-6 h-6') %> <%= svg_icon('logs', class: 'w-6 h-6') %>
<span class="hidden md:block"><%= t('event_log') %></span> <span class="hidden md:block" aria-hidden="true"><%= t('event_log') %></span>
<% end %> <% end %>
<% end %> <% end %>
<% if last_submitter %> <% if last_submitter %>
@ -45,8 +45,8 @@
</download-button> </download-button>
<% if is_all_completed && !is_combined_enabled %> <% if is_all_completed && !is_combined_enabled %>
<div class="dropdown dropdown-end"> <div class="dropdown dropdown-end">
<label tabindex="0" class="base-button !rounded-l-none !pl-1 !pr-2 !border-l-neutral-500"> <label tabindex="0" class="base-button !rounded-l-none !pl-1 !pr-2 !border-l-neutral-500" role="button" aria-haspopup="menu" aria-label="<%= t('download_options') %>">
<span class="text-sm align-text-top"> <span class="text-sm align-text-top" aria-hidden="true">
<%= svg_icon('chevron_down', class: 'w-6 h-6 flex-shrink-0 stroke-2') %> <%= svg_icon('chevron_down', class: 'w-6 h-6 flex-shrink-0 stroke-2') %>
</span> </span>
</label> </label>
@ -212,7 +212,7 @@
</div> </div>
<% if signed_in? && can?(:update, @submission) && submitter && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %> <% if signed_in? && can?(:update, @submission) && submitter && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %>
<span class="tooltip tooltip-left" data-tip="<%= t('edit') %>"> <span class="tooltip tooltip-left" data-tip="<%= t('edit') %>">
<%= link_to edit_submitter_path(submitter), class: 'shrink-0 inline md:hidden md:group-hover:inline', data: { turbo_frame: 'modal' } do %> <%= link_to edit_submitter_path(submitter), class: 'shrink-0 inline md:hidden md:group-hover:inline', aria: { label: "#{t('edit')} #{submitter.name || submitter.email || submitter.phone}" }, data: { turbo_frame: 'modal' } do %>
<%= svg_icon('pencil', class: 'w-5 h-5') %> <%= svg_icon('pencil', class: 'w-5 h-5') %>
<% end %> <% end %>
</span> </span>

@ -39,11 +39,11 @@
</div> </div>
<scroll-buttons class="fixed right-5 top-2 hidden md:flex gap-1 z-50 ease-in-out opacity-0 -translate-y-10"> <scroll-buttons class="fixed right-5 top-2 hidden md:flex gap-1 z-50 ease-in-out opacity-0 -translate-y-10">
<% if @form_configs[:with_decline] %> <% if @form_configs[:with_decline] %>
<label id="decline_button_scroll" for="<%= decline_modal_checkbox_uuid %>" class="btn btn-sm px-0" tabindex="0"> <label id="decline_button_scroll" for="<%= decline_modal_checkbox_uuid %>" class="btn btn-sm px-0" tabindex="0" aria-label="<%= t(:decline) %>">
<span class="min-[1366px]:inline hidden px-3"> <span class="min-[1366px]:inline hidden px-3" aria-hidden="true">
<%= t(:decline) %> <%= t(:decline) %>
</span> </span>
<span class="inline min-[1366px]:hidden px-2"> <span class="inline min-[1366px]:hidden px-2" aria-hidden="true">
<%= svg_icon('x', class: 'w-5 h-5') %> <%= svg_icon('x', class: 'w-5 h-5') %>
</span> </span>
</label> </label>

@ -32,35 +32,35 @@
<div class="space-y-1"> <div class="space-y-1">
<% if can?(:update, template) && !template.archived_at? && template.account_id == current_account.id %> <% if can?(:update, template) && !template.archived_at? && template.account_id == current_account.id %>
<span class="tooltip tooltip-left" data-tip="<%= t('move') %>"> <span class="tooltip tooltip-left" data-tip="<%= t('move') %>">
<a href="<%= edit_template_folder_path(template.id) %>" data-turbo-frame="modal" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle"> <a href="<%= edit_template_folder_path(template.id) %>" data-turbo-frame="modal" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle" aria-label="<%= "#{t('move')} - #{template.name}" %>">
<%= svg_icon('folder_share', class: 'w-4 h-4') %> <%= svg_icon('folder_share', class: 'w-4 h-4') %>
</a> </a>
</span> </span>
<% end %> <% end %>
<% if template.archived_at? && can?(:update, template) %> <% if template.archived_at? && can?(:update, template) %>
<span class="tooltip tooltip-left" data-tip="<%= t('restore') %>"> <span class="tooltip tooltip-left" data-tip="<%= t('restore') %>">
<%= button_to template_restore_index_path(template), class: 'btn btn-xs hover:btn-outline bg-base-200 btn-circle' do %> <%= button_to template_restore_index_path(template), class: 'btn btn-xs hover:btn-outline bg-base-200 btn-circle', aria: { label: "#{t('restore')} - #{template.name}" } do %>
<%= svg_icon('rotate', class: 'w-4 h-4 enabled') %> <%= svg_icon('rotate', class: 'w-4 h-4 enabled') %>
<%= svg_icon('loader', class: 'w-4 h-4 animate-spin disabled') %> <%= svg_icon('loader', class: 'w-4 h-4 animate-spin disabled') %>
<% end %> <% end %>
</span> </span>
<% elsif can?(:update, template) %> <% elsif can?(:update, template) %>
<span class="tooltip tooltip-left" data-tip="<%= t('edit') %>"> <span class="tooltip tooltip-left" data-tip="<%= t('edit') %>">
<a href="<%= edit_template_path(template) %>" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle"> <a href="<%= edit_template_path(template) %>" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle" aria-label="<%= "#{t('edit')} - #{template.name}" %>">
<%= svg_icon('pencil', class: 'w-4 h-4') %> <%= svg_icon('pencil', class: 'w-4 h-4') %>
</a> </a>
</span> </span>
<% end %> <% end %>
<% if can?(:create, template) %> <% if can?(:create, template) %>
<span class="tooltip tooltip-left" data-tip="<%= t('clone') %>"> <span class="tooltip tooltip-left" data-tip="<%= t('clone') %>">
<a href="<%= new_template_clone_path(template) %>" data-turbo-frame="modal" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle"> <a href="<%= new_template_clone_path(template) %>" data-turbo-frame="modal" class="btn btn-xs hover:btn-outline bg-base-200 btn-circle" aria-label="<%= "#{t('clone')} - #{template.name}" %>">
<%= svg_icon('copy', class: 'w-4 h-4') %> <%= svg_icon('copy', class: 'w-4 h-4') %>
</a> </a>
</span> </span>
<% end %> <% end %>
<% if can?(:destroy, template) %> <% if can?(:destroy, template) %>
<span class="tooltip tooltip-left" data-tip="<%= template.archived_at? ? t('delete') : t('archive') %>"> <span class="tooltip tooltip-left" data-tip="<%= template.archived_at? ? t('delete') : t('archive') %>">
<%= button_to template_path(template), data: template.archived_at? ? { turbo_confirm: t('template_deletion_is_irreversible_and_will_permanently_remove_all_associated_signed_documents_with_it_are_you_sure_') } : {}, params: { permanently: template.archived_at? }.compact_blank, method: :delete, class: 'btn btn-xs hover:btn-outline bg-base-200 btn-circle', aria_label: t('restore') do %> <%= button_to template_path(template), data: template.archived_at? ? { turbo_confirm: t('template_deletion_is_irreversible_and_will_permanently_remove_all_associated_signed_documents_with_it_are_you_sure_') } : {}, params: { permanently: template.archived_at? }.compact_blank, method: :delete, class: 'btn btn-xs hover:btn-outline bg-base-200 btn-circle', aria: { label: "#{template.archived_at? ? t('delete') : t('archive')} - #{template.name}" } do %>
<%= svg_icon(template.archived_at? ? 'trash' : 'archive', class: 'w-4 h-4 enabled') %> <%= svg_icon(template.archived_at? ? 'trash' : 'archive', class: 'w-4 h-4 enabled') %>
<%= svg_icon('loader', class: 'w-4 h-4 animate-spin disabled') %> <%= svg_icon('loader', class: 'w-4 h-4 animate-spin disabled') %>
<% end %> <% end %>

@ -21,7 +21,7 @@
</a> </a>
<% if can?(:update, template) %> <% if can?(:update, template) %>
<span class="pl-1 tooltip tooltip-right md:opacity-0 hover:opacity-100 peer-hover:opacity-100" data-tip="<%= t('move') %>"> <span class="pl-1 tooltip tooltip-right md:opacity-0 hover:opacity-100 peer-hover:opacity-100" data-tip="<%= t('move') %>">
<a href="<%= edit_template_folder_path(template.id, subfolder: @template.folder.parent_folder.present?) %>" data-turbo-frame="modal"> <a href="<%= edit_template_folder_path(template.id, subfolder: @template.folder.parent_folder.present?) %>" data-turbo-frame="modal" aria-label="<%= "#{t('move')} - #{template.name}" %>">
<%= svg_icon('pencil_share', class: 'w-5 h-5') %> <%= svg_icon('pencil_share', class: 'w-5 h-5') %>
</a> </a>
</span> </span>

@ -5,7 +5,7 @@
<%= f.hidden_field :parent_name, value: @template.folder.parent_folder&.name || @template.folder.name %> <%= f.hidden_field :parent_name, value: @template.folder.parent_folder&.name || @template.folder.name %>
<toggle-visible data-element-ids="<%= %w[folder_form subfolder_form].to_json %>" class="block relative" data-focus-id="name"> <toggle-visible data-element-ids="<%= %w[folder_form subfolder_form].to_json %>" class="block relative" data-focus-id="name">
<div class="flex items-center justify-between mb-2.5"> <div class="flex items-center justify-between mb-2.5">
<label for="is_root_folder" class="flex items-center tooltip tooltip-right pr-2 group" data-tip="<%= t('change_parent_folder') %>"> <label for="is_root_folder" class="flex items-center tooltip tooltip-right pr-2 group" data-tip="<%= t('change_parent_folder') %>" tabindex="0">
<%= check_box_tag :is_root_folder, 'folder_form', data: { action: 'change:toggle-visible#trigger' }, class: 'hidden' %> <%= check_box_tag :is_root_folder, 'folder_form', data: { action: 'change:toggle-visible#trigger' }, class: 'hidden' %>
<span class="flex items-center mt-1"> <span class="flex items-center mt-1">
<%= svg_icon('folder', class: 'w-5 h-5 flex-shrink-0 group-hover:hidden mr-1') %> <%= svg_icon('folder', class: 'w-5 h-5 flex-shrink-0 group-hover:hidden mr-1') %>

@ -369,6 +369,7 @@ en: &en
pdf_view: "PDF View" pdf_view: "PDF View"
text_view: "Text View" text_view: "Text View"
document_view_options: "Document view options" document_view_options: "Document view options"
download_options: "Download options"
text_view_disclaimer: "Text provided for accessibility. The PDF view is the authoritative document." text_view_disclaimer: "Text provided for accessibility. The PDF view is the authoritative document."
signing_fields_below: "Your signing fields are in the panel below." signing_fields_below: "Your signing fields are in the panel below."
powered_by: Powered by powered_by: Powered by

Loading…
Cancel
Save