Shortcuts.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <template>
  2. <AppSlideOver :show="show" @close="close()">
  3. <template #content>
  4. <div
  5. class="bg-primary border-dividerLight sticky top-0 z-10 flex items-center justify-between p-2 border-b"
  6. >
  7. <h3 class="heading ml-4">{{ t("app.shortcuts") }}</h3>
  8. <div class="flex">
  9. <ButtonSecondary svg="x" class="rounded" @click.native="close()" />
  10. </div>
  11. </div>
  12. <div class="bg-primary border-dividerLight border-b">
  13. <div class="flex flex-col mx-6 my-4">
  14. <input
  15. v-model="filterText"
  16. type="search"
  17. autocomplete="off"
  18. class="bg-primaryLight border-dividerLight focus-visible:border-divider flex w-full px-4 py-2 border rounded"
  19. :placeholder="`${t('action.search')}`"
  20. />
  21. </div>
  22. </div>
  23. <div
  24. v-if="filterText"
  25. class="divide-dividerLight hide-scrollbar flex flex-col flex-1 overflow-auto divide-y"
  26. >
  27. <div
  28. v-for="(map, mapIndex) in searchResults"
  29. :key="`map-${mapIndex}`"
  30. class="px-6 py-4 space-y-4"
  31. >
  32. <h1 class="text-secondaryDark font-semibold">
  33. {{ t(map.item.section) }}
  34. </h1>
  35. <AppShortcutsEntry
  36. v-for="(shortcut, index) in map.item.shortcuts"
  37. :key="`shortcut-${index}`"
  38. :shortcut="shortcut"
  39. />
  40. </div>
  41. <div
  42. v-if="searchResults.length === 0"
  43. class="text-secondaryLight flex flex-col items-center justify-center p-4"
  44. >
  45. <i class="material-icons pb-2 opacity-75">manage_search</i>
  46. <span class="text-center">
  47. {{ t("state.nothing_found") }} "{{ filterText }}"
  48. </span>
  49. </div>
  50. </div>
  51. <div
  52. v-else
  53. class="divide-dividerLight hide-scrollbar flex flex-col flex-1 overflow-auto divide-y"
  54. >
  55. <div
  56. v-for="(map, mapIndex) in mappings"
  57. :key="`map-${mapIndex}`"
  58. class="px-6 py-4 space-y-4"
  59. >
  60. <h1 class="text-secondaryDark font-semibold">
  61. {{ t(map.section) }}
  62. </h1>
  63. <AppShortcutsEntry
  64. v-for="(shortcut, shortcutIndex) in map.shortcuts"
  65. :key="`map-${mapIndex}-shortcut-${shortcutIndex}`"
  66. :shortcut="shortcut"
  67. />
  68. </div>
  69. </div>
  70. </template>
  71. </AppSlideOver>
  72. </template>
  73. <script setup lang="ts">
  74. import { computed, ref } from "@nuxtjs/composition-api"
  75. import Fuse from "fuse.js"
  76. import mappings from "~/helpers/shortcuts"
  77. import { useI18n } from "~/helpers/utils/composables"
  78. const t = useI18n()
  79. defineProps<{
  80. show: boolean
  81. }>()
  82. const options = {
  83. keys: ["shortcuts.label"],
  84. }
  85. const fuse = new Fuse(mappings, options)
  86. const filterText = ref("")
  87. const searchResults = computed(() => fuse.search(filterText.value))
  88. const emit = defineEmits<{
  89. (e: "close"): void
  90. }>()
  91. const close = () => {
  92. filterText.value = ""
  93. emit("close")
  94. }
  95. </script>
  96. <style lang="scss" scoped>
  97. .shortcut-key {
  98. @apply bg-dividerLight;
  99. @apply rounded;
  100. @apply ml-2;
  101. @apply py-1;
  102. @apply px-2;
  103. @apply inline-flex;
  104. }
  105. </style>