-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcore.pageTabs.component.vue
More file actions
79 lines (78 loc) · 2.33 KB
/
Copy pathcore.pageTabs.component.vue
File metadata and controls
79 lines (78 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<template>
<v-card
color="surface"
:flat="config.vuetify.theme.flat"
:class="config.vuetify.theme.rounded"
data-test="page-tabs"
>
<v-tabs
:model-value="modelValue"
color="primary"
:grow="grow"
@update:model-value="(v) => $emit('update:modelValue', v)"
>
<template v-for="tab in visibleTabs" :key="tab.value">
<v-tab :value="tab.value" class="text-none text-body-medium">
<v-icon v-if="tab.icon" :icon="tab.icon" size="small" class="mr-2"></v-icon>
{{ tab.label }}
</v-tab>
</template>
</v-tabs>
<v-divider></v-divider>
<v-window :model-value="modelValue">
<v-window-item
v-for="tab in visibleTabs"
:key="tab.value"
:value="tab.value"
>
<div class="pa-6">
<slot :name="tab.value"></slot>
</div>
</v-window-item>
</v-window>
</v-card>
</template>
<script>
/**
* @desc Reusable page-level tab strip. Wraps PageHeader-bounded
* pages (Account, Organization, Admin) so the tab styling +
* inset padding stay aligned with the sidenav across the app.
*
* Usage:
* <PageTabs v-model="tab" :tabs="tabs">
* <template #profile> ... </template>
* <template #organizations> ... </template>
* </PageTabs>
*
* Each `tab` is { value, label, icon?, visible? }. When `visible`
* is false, the entry is omitted from the strip (used for
* permission-gated tabs like Subscriptions).
*
* `config` is injected via Vue globalProperties (same pattern as
* CoreDatatable) — provides `config.vuetify.theme.flat` and
* `config.vuetify.theme.rounded` for surface-consistent card styling.
*/
export default {
name: 'CorePageTabs',
props: {
modelValue: { type: String, required: true },
tabs: {
type: Array,
required: true,
validator: (arr) => arr.every((t) => t && typeof t.value === 'string' && typeof t.label === 'string'),
},
grow: { type: Boolean, default: false },
},
emits: ['update:modelValue'],
computed: {
/**
* Returns only tabs where `visible` is not explicitly false.
* Tabs without a `visible` key are shown by default.
* @returns {Array<{value: string, label: string, icon?: string, visible?: boolean}>}
*/
visibleTabs() {
return this.tabs.filter((t) => t.visible !== false);
},
},
};
</script>