Tabs.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <div
  3. class="flex flex-nowrap flex-1 h-full"
  4. :class="{ 'flex-col h-auto': !vertical }"
  5. >
  6. <div
  7. class="tabs hide-scrollbar relative"
  8. :class="[{ 'border-r border-dividerLight': vertical }, styles]"
  9. >
  10. <div class="flex flex-1">
  11. <div
  12. class="flex flex-1 justify-between"
  13. :class="{ 'flex-col': vertical }"
  14. >
  15. <div class="flex" :class="{ 'flex-col space-y-2 p-2': vertical }">
  16. <button
  17. v-for="(tab, index) in tabs"
  18. :key="`tab-${index}`"
  19. class="tab"
  20. :class="[{ active: tab.active }, { vertical: vertical }]"
  21. tabindex="0"
  22. :aria-label="tab.label"
  23. @keyup.enter="selectTab(tab)"
  24. @click="selectTab(tab)"
  25. >
  26. <SmartIcon v-if="tab.icon" class="svg-icons" :name="tab.icon" />
  27. <tippy
  28. v-if="vertical && tab.label"
  29. placement="left"
  30. theme="tooltip"
  31. :content="tab.label"
  32. />
  33. <span v-else-if="tab.label">{{ tab.label }}</span>
  34. <span v-if="tab.info && tab.info !== 'null'" class="tab-info">
  35. {{ tab.info }}
  36. </span>
  37. </button>
  38. </div>
  39. <div class="flex justify-center items-center">
  40. <slot name="actions"></slot>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. <div
  46. class="contents h-full w-full"
  47. :class="{
  48. '!flex flex-col flex-1 overflow-y-auto hide-scrollbar': vertical,
  49. }"
  50. >
  51. <slot></slot>
  52. </div>
  53. </div>
  54. </template>
  55. <script>
  56. import { defineComponent } from "@nuxtjs/composition-api"
  57. export default defineComponent({
  58. props: {
  59. styles: {
  60. type: String,
  61. default: "",
  62. },
  63. vertical: {
  64. type: Boolean,
  65. default: false,
  66. },
  67. },
  68. data() {
  69. return {
  70. tabs: [],
  71. }
  72. },
  73. mounted() {
  74. this.tabs = this.$children.filter(
  75. (child) => child.$options.name === "SmartTab"
  76. )
  77. },
  78. methods: {
  79. selectTab({ id }) {
  80. this.tabs.forEach((tab) => {
  81. tab.active = tab.id === id
  82. })
  83. this.$emit("tab-changed", id)
  84. },
  85. },
  86. })
  87. </script>
  88. <style scoped lang="scss">
  89. .tabs {
  90. @apply flex;
  91. @apply whitespace-nowrap;
  92. @apply overflow-auto;
  93. @apply flex-shrink-0;
  94. // &::after {
  95. // @apply absolute;
  96. // @apply inset-x-0;
  97. // @apply bottom-0;
  98. // @apply bg-dividerLight;
  99. // @apply z-1;
  100. // @apply h-0.5;
  101. // content: "";
  102. // }
  103. .tab {
  104. @apply relative;
  105. @apply flex;
  106. @apply flex-shrink-0;
  107. @apply items-center;
  108. @apply justify-center;
  109. @apply px-4 py-2;
  110. @apply text-secondary;
  111. @apply font-semibold;
  112. @apply cursor-pointer;
  113. @apply hover:text-secondaryDark;
  114. @apply focus:outline-none;
  115. @apply focus-visible:text-secondaryDark;
  116. .tab-info {
  117. @apply inline-flex;
  118. @apply items-center;
  119. @apply justify-center;
  120. @apply w-5;
  121. @apply h-4;
  122. @apply ml-2;
  123. @apply text-8px;
  124. @apply border border-divider;
  125. @apply rounded;
  126. @apply text-secondaryLight;
  127. }
  128. &::after {
  129. @apply absolute;
  130. @apply left-4;
  131. @apply right-4;
  132. @apply bottom-0;
  133. @apply bg-transparent;
  134. @apply z-2;
  135. @apply h-0.5;
  136. content: "";
  137. }
  138. &:focus::after {
  139. @apply bg-divider;
  140. }
  141. &.active {
  142. @apply text-secondaryDark;
  143. .tab-info {
  144. @apply text-secondary;
  145. @apply border-dividerDark;
  146. }
  147. &::after {
  148. @apply bg-accent;
  149. }
  150. }
  151. &.vertical {
  152. @apply p-2;
  153. @apply rounded;
  154. &:focus::after {
  155. @apply hidden;
  156. }
  157. &.active {
  158. @apply text-accent;
  159. .tab-info {
  160. @apply text-secondary;
  161. @apply border-dividerDark;
  162. }
  163. &::after {
  164. @apply hidden;
  165. }
  166. }
  167. }
  168. }
  169. }
  170. </style>