| 
1 | 1 | <script setup>  | 
2 |  | -import { ref, computed, useSlots } from 'vue'  | 
 | 2 | +import { ref, computed, useSlots, onMounted, watch, nextTick } from 'vue'  | 
3 | 3 | 
  | 
4 | 4 | const slots = useSlots()  | 
5 | 5 | const tabKeys = Object.keys(slots)  | 
6 | 6 | const activeTab = ref(tabKeys[0] ?? '')  | 
7 | 7 | const currentTab = computed(() => activeTab.value)  | 
 | 8 | +const wrapperRef = ref(null)  | 
 | 9 | +
  | 
 | 10 | +function formatKey(key) {  | 
 | 11 | +  return key.replace(/[__]/g, ' ')  | 
 | 12 | +}  | 
 | 13 | +
  | 
 | 14 | +// Display select  | 
 | 15 | +onMounted(() => {  | 
 | 16 | +  const hash = decodeURIComponent(window.location.hash.slice(1))  | 
 | 17 | +  if (tabKeys.includes(hash)) {  | 
 | 18 | +    activeTab.value = hash  | 
 | 19 | +
  | 
 | 20 | +    nextTick(() => {  | 
 | 21 | +      const el = wrapperRef.value  | 
 | 22 | +      if (el) {  | 
 | 23 | +        const offset = 80  | 
 | 24 | +        const top = el.getBoundingClientRect().top + window.scrollY - offset  | 
 | 25 | +        window.scrollTo({ top, behavior: 'smooth' })  | 
 | 26 | +      }  | 
 | 27 | +    })  | 
 | 28 | +  }  | 
 | 29 | +})  | 
 | 30 | +
  | 
 | 31 | +watch(activeTab, (newVal) => {  | 
 | 32 | +  if (newVal) {  | 
 | 33 | +    history.replaceState(null, '', `#${encodeURIComponent(newVal)}`)  | 
 | 34 | +  }  | 
 | 35 | +})  | 
8 | 36 | </script>  | 
9 | 37 | 
  | 
10 | 38 | <template>  | 
11 |  | -  <div class="table-tabs mt-8 border rounded-lg overflow-hidden text-sm">  | 
12 |  | -    <div class="bg-gray-50 flex justify-between items-center border-b">  | 
13 |  | -<!--  <span class="font-medium text-gray-700">Optional Text:span>   -->  | 
 | 39 | +  <div  | 
 | 40 | +    ref="wrapperRef"  | 
 | 41 | +    class="table-tabs mt-8 border rounded-lg overflow-hidden text-sm scroll-mt-24"  | 
 | 42 | +    :id="activeTab"  | 
 | 43 | +  >  | 
 | 44 | +    <div class="bg-gray-50 flex justify-between items-center border-b px-4 py-2">  | 
 | 45 | +<!--      <span class="font-medium text-gray-700">Optional Text:</span>   -->  | 
14 | 46 |       <select  | 
15 | 47 |         v-model="activeTab"  | 
16 | 48 |         class="bg-white text-gray-800 text-sm rounded border-gray-300 focus:outline-none focus:ring-1 focus:ring-blue-500"  | 
17 | 49 |       >  | 
18 | 50 |         <option v-for="key in tabKeys" :key="key" :value="key">  | 
19 |  | -          {{ key }}  | 
 | 51 | +          {{ formatKey(key) }}  | 
20 | 52 |         </option>  | 
21 | 53 |       </select>  | 
22 | 54 |     </div>  | 
23 | 55 | 
  | 
24 |  | -    <div class="tab-content prose prose-sm max-w-none">  | 
 | 56 | +    <div class="tab-content prose prose-sm max-w-none p-4">  | 
25 | 57 |       <slot :name="currentTab" />  | 
26 | 58 |     </div>  | 
27 | 59 |   </div>  | 
28 | 60 | </template>  | 
29 | 61 | 
  | 
30 |  | -
  | 
 | 
0 commit comments