Browse Source

Maintenance: Improve display of overflowing text in select fields.

Dusan Vuckovic 1 year ago
parent
commit
70ccb4dda9

+ 1 - 1
app/frontend/apps/desktop/components/CommonInputSearch/CommonInputSearch.vue

@@ -76,7 +76,7 @@ export default {
       name="search"
       decorative
     />
-    <div class="relative grow inline-flex">
+    <div class="relative grow inline-flex overflow-clip">
       <input
         ref="filterInput"
         v-model="filter"

+ 1 - 1
app/frontend/apps/desktop/components/CommonSelect/CommonSelect.vue

@@ -301,7 +301,7 @@ const duration = VITE_TEST_MODE ? undefined : { enter: 300, leave: 200 }
         v-if="showDropdown"
         id="common-select"
         ref="dropdownElement"
-        class="fixed z-10 flex antialiased"
+        class="fixed z-10 min-h-9 flex antialiased"
         :style="dropdownStyle"
       >
         <div

+ 14 - 10
app/frontend/apps/desktop/components/CommonSelect/CommonSelectItem.vue

@@ -30,11 +30,13 @@ const select = (option: SelectOption) => {
 
 const label = computed(() => {
   const { option } = props
-  if (props.noLabelTranslate) {
-    return option.label
-  }
 
-  return i18n.t(option.label, ...(option.labelPlaceholder || []))
+  if (props.noLabelTranslate) return option.label || option.value.toString()
+
+  return (
+    i18n.t(option.label, ...(option.labelPlaceholder || [])) ||
+    option.value.toString()
+  )
 })
 </script>
 
@@ -61,7 +63,7 @@ const label = computed(() => {
       size="xs"
       decorative
       :name="selected ? 'check-square' : 'square'"
-      class="fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
     />
     <CommonIcon
       v-if="option.icon"
@@ -71,14 +73,15 @@ const label = computed(() => {
         'fill-stone-200 dark:fill-neutral-500': option.disabled,
       }"
       decorative
-      class="fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
     />
     <span
       v-if="filter"
       :class="{
         'text-stone-200 dark:text-neutral-500': option.disabled,
       }"
-      class="grow"
+      class="grow truncate"
+      :title="label"
       v-html="(option as MatchedSelectOption).matchedLabel"
     />
     <span
@@ -86,13 +89,14 @@ const label = computed(() => {
       :class="{
         'text-stone-200 dark:text-neutral-500': option.disabled,
       }"
-      class="grow"
+      class="grow truncate"
+      :title="label"
     >
-      {{ label || option.value }}
+      {{ label }}
     </span>
     <CommonIcon
       v-if="!multiple"
-      class="fill-stone-200 dark:fill-neutral-500 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-stone-200 dark:fill-neutral-500 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
       :class="{
         invisible: !selected,
         'fill-gray-100 dark:fill-neutral-400': option.disabled,

+ 27 - 11
app/frontend/apps/desktop/components/Form/fields/FieldSelect/FieldSelectInput.vue

@@ -210,17 +210,25 @@ setupMissingOrDisabledOptionHandling()
               <CommonIcon
                 v-if="getSelectedOptionIcon(selectedValue)"
                 :name="getSelectedOptionIcon(selectedValue)"
-                class="fill-gray-100 dark:fill-neutral-400"
+                class="shrink-0 fill-gray-100 dark:fill-neutral-400"
                 size="xs"
                 decorative
               />
-              {{
-                getSelectedOptionLabel(selectedValue) ||
-                i18n.t('%s (unknown)', selectedValue)
-              }}
+              <span
+                class="line-clamp-3"
+                :title="
+                  getSelectedOptionLabel(selectedValue) ||
+                  i18n.t('%s (unknown)', selectedValue)
+                "
+              >
+                {{
+                  getSelectedOptionLabel(selectedValue) ||
+                  i18n.t('%s (unknown)', selectedValue)
+                }}
+              </span>
               <CommonIcon
                 :aria-label="i18n.t('Unselect Option')"
-                class="fill-stone-200 dark:fill-neutral-500 hover:fill-black dark:hover:fill-white focus-visible:outline focus-visible:rounded-sm focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
+                class="shrink-0 fill-stone-200 dark:fill-neutral-500 hover:fill-black dark:hover:fill-white focus-visible:outline focus-visible:rounded-sm focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
                 name="x-lg"
                 size="xs"
                 role="button"
@@ -252,14 +260,22 @@ setupMissingOrDisabledOptionHandling()
             <CommonIcon
               v-if="getSelectedOptionIcon(currentValue)"
               :name="getSelectedOptionIcon(currentValue)"
-              class="fill-gray-100 dark:fill-neutral-400"
+              class="shrink-0 fill-gray-100 dark:fill-neutral-400"
               size="tiny"
               decorative
             />
-            {{
-              getSelectedOptionLabel(currentValue) ||
-              i18n.t('%s (unknown)', currentValue)
-            }}
+            <span
+              class="line-clamp-3"
+              :title="
+                getSelectedOptionLabel(currentValue) ||
+                i18n.t('%s (unknown)', currentValue)
+              "
+            >
+              {{
+                getSelectedOptionLabel(currentValue) ||
+                i18n.t('%s (unknown)', currentValue)
+              }}
+            </span>
           </div>
         </div>
         <CommonIcon

+ 15 - 5
app/frontend/apps/desktop/components/Form/fields/FieldTreeSelect/FieldTreeSelectInput.vue

@@ -280,14 +280,19 @@ setupMissingOrDisabledOptionHandling()
               <CommonIcon
                 v-if="getSelectedOptionIcon(selectedValue)"
                 :name="getSelectedOptionIcon(selectedValue)"
-                class="fill-gray-100 dark:fill-neutral-400"
+                class="shrink-0 fill-gray-100 dark:fill-neutral-400"
                 size="xs"
                 decorative
               />
-              {{ getSelectedOptionFullPath(selectedValue) }}
+              <span
+                class="line-clamp-3"
+                :title="getSelectedOptionFullPath(selectedValue)"
+              >
+                {{ getSelectedOptionFullPath(selectedValue) }}
+              </span>
               <CommonIcon
                 :aria-label="i18n.t('Unselect Option')"
-                class="fill-stone-200 dark:fill-neutral-500 hover:fill-black dark:hover:fill-white focus-visible:outline focus-visible:rounded-sm focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
+                class="shrink-0 fill-stone-200 dark:fill-neutral-500 hover:fill-black dark:hover:fill-white focus-visible:outline focus-visible:rounded-sm focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
                 name="x-lg"
                 size="xs"
                 role="button"
@@ -319,11 +324,16 @@ setupMissingOrDisabledOptionHandling()
             <CommonIcon
               v-if="getSelectedOptionIcon(currentValue)"
               :name="getSelectedOptionIcon(currentValue)"
-              class="fill-gray-100 dark:fill-neutral-400"
+              class="shrink-0 fill-gray-100 dark:fill-neutral-400"
               size="tiny"
               decorative
             />
-            {{ getSelectedOptionFullPath(currentValue) }}
+            <span
+              class="line-clamp-3"
+              :title="getSelectedOptionFullPath(currentValue)"
+            >
+              {{ getSelectedOptionFullPath(currentValue) }}
+            </span>
           </div>
         </div>
         <CommonIcon

+ 1 - 1
app/frontend/apps/desktop/components/Form/fields/FieldTreeSelect/FieldTreeSelectInputDropdown.vue

@@ -407,7 +407,7 @@ const duration = VITE_TEST_MODE ? undefined : { enter: 300, leave: 200 }
         v-if="showDropdown"
         id="field-tree-select-input-dropdown"
         ref="dropdownElement"
-        class="fixed z-10 flex antialiased"
+        class="fixed z-10 min-h-9 flex antialiased"
         :style="dropdownStyle"
       >
         <div

+ 14 - 9
app/frontend/apps/desktop/components/Form/fields/FieldTreeSelect/FieldTreeSelectInputDropdownItem.vue

@@ -39,9 +39,12 @@ const select = (option: FlatSelectOption) => {
 const label = computed(() => {
   const { option } = props
 
-  if (props.noLabelTranslate) return option.label
+  if (props.noLabelTranslate) return option.label || option.value.toString()
 
-  return i18n.t(option.label, ...(option.labelPlaceholder || []))
+  return (
+    i18n.t(option.label, ...(option.labelPlaceholder || [])) ||
+    option.value.toString()
+  )
 })
 
 const goToNextPage = (option: FlatSelectOption, noFocus?: boolean) => {
@@ -72,7 +75,7 @@ const goToNextPage = (option: FlatSelectOption, noFocus?: boolean) => {
       size="xs"
       decorative
       :name="selected ? 'check-square' : 'square'"
-      class="fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
     />
     <CommonIcon
       v-if="option.icon"
@@ -82,14 +85,15 @@ const goToNextPage = (option: FlatSelectOption, noFocus?: boolean) => {
         'fill-stone-200 dark:fill-neutral-500': option.disabled,
       }"
       decorative
-      class="fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-gray-100 dark:fill-neutral-400 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
     />
     <span
       v-if="filter"
       :class="{
         'text-stone-200 dark:text-neutral-500': option.disabled,
       }"
-      class="grow"
+      class="grow truncate"
+      :title="label"
       v-html="(option as MatchedFlatSelectOption).matchedPath"
     />
     <span
@@ -97,13 +101,14 @@ const goToNextPage = (option: FlatSelectOption, noFocus?: boolean) => {
       :class="{
         'text-stone-200 dark:text-neutral-500': option.disabled,
       }"
-      class="grow"
+      :title="label"
+      class="grow truncate"
     >
-      {{ label || option.value }}
+      {{ label }}
     </span>
     <CommonIcon
       v-if="!multiple"
-      class="fill-stone-200 dark:fill-neutral-500 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
+      class="shrink-0 fill-stone-200 dark:fill-neutral-500 group-hover:fill-black dark:group-hover:fill-white group-focus:fill-white"
       :class="{
         invisible: !selected,
         'fill-gray-100 dark:fill-neutral-400': option.disabled,
@@ -114,7 +119,7 @@ const goToNextPage = (option: FlatSelectOption, noFocus?: boolean) => {
     />
     <div
       v-if="option.hasChildren && !filter"
-      class="group/nav p-2.5 -me-2 flex-nowrap items-center justify-center gap-x-2.5 rounded-[5px] hover:bg-blue-800 group-focus:hover:bg-blue-600 dark:group-focus:hover:bg-blue-900"
+      class="group/nav shrink-0 p-2.5 -me-2 flex-nowrap items-center justify-center gap-x-2.5 rounded-[5px] hover:bg-blue-800 group-focus:hover:bg-blue-600 dark:group-focus:hover:bg-blue-900"
       :aria-label="$t('Has submenu')"
       role="button"
       tabindex="-1"

+ 10 - 3
app/frontend/apps/desktop/pages/home/views/Playground.vue

@@ -2,7 +2,7 @@
 <!-- eslint-disable zammad/zammad-detect-translatable-string -->
 
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, ref } from 'vue'
 import CommonAlert from '#shared/components/CommonAlert/CommonAlert.vue'
 import CommonButton from '#desktop/components/CommonButton/CommonButton.vue'
 import Form from '#shared/components/Form/Form.vue'
@@ -15,6 +15,12 @@ const alphabetOptions = computed(() =>
   })),
 )
 
+const longOption = ref({
+  value: 999,
+  label:
+    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, nullam pulvinar nunc sapien, vitae malesuada justo interdum feugiat, mauris odio, mattis et malesuada quis, vulputate vitae enim',
+})
+
 const treeselectOptions = [
   {
     value: 0,
@@ -42,6 +48,7 @@ const treeselectOptions = [
         value: 5,
         label: 'Item 2',
         children: [
+          ...[longOption.value],
           {
             value: 6,
             label: 'Item IV',
@@ -113,7 +120,7 @@ const formSchema = [
     label: 'Single select',
     clearable: true,
     props: {
-      options: alphabetOptions.value,
+      options: [...alphabetOptions.value, ...[longOption.value]],
     },
   },
   {
@@ -123,7 +130,7 @@ const formSchema = [
     clearable: true,
     props: {
       multiple: true,
-      options: alphabetOptions.value,
+      options: [...alphabetOptions.value, ...[longOption.value]],
     },
   },
   {