daisy-ui-kit 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/components/-utils.ts +41 -0
- package/components/.DS_Store +0 -0
- package/components/Alert.vue +27 -0
- package/components/Artboard.vue +33 -0
- package/components/Avatar.vue +85 -0
- package/components/AvatarGroup.vue +19 -0
- package/components/Badge.vue +45 -0
- package/components/BottomNav.vue +27 -0
- package/components/Breadcrumbs.vue +7 -0
- package/components/Button.config.ts +26 -0
- package/components/Button.vue +112 -0
- package/components/ButtonGroup.vue +5 -0
- package/components/Card.vue +31 -0
- package/components/CardActions.vue +16 -0
- package/components/CardBody.vue +16 -0
- package/components/CardTitle.vue +16 -0
- package/components/Carousel.vue +26 -0
- package/components/CarouselItem.vue +5 -0
- package/components/Checkbox.vue +47 -0
- package/components/Code.vue +91 -0
- package/components/CodePreview.vue +28 -0
- package/components/CodeWrapper.vue +10 -0
- package/components/Collapse.vue +33 -0
- package/components/CollapseContent.vue +5 -0
- package/components/CollapseTitle.vue +5 -0
- package/components/Countdown.vue +16 -0
- package/components/CountdownTimers.vue +66 -0
- package/components/Counter.vue +15 -0
- package/components/Crumb.vue +5 -0
- package/components/DarkToggle.vue +11 -0
- package/components/DemoElement.vue +32 -0
- package/components/DemoExample.vue +23 -0
- package/components/Divider.vue +25 -0
- package/components/Drawer.vue +19 -0
- package/components/DrawerLayout.vue +35 -0
- package/components/DrawerLayoutContent.vue +11 -0
- package/components/Dropdown.vue +30 -0
- package/components/DropdownContent.vue +3 -0
- package/components/Flex.vue +146 -0
- package/components/FlexItem.vue +146 -0
- package/components/Footer.vue +25 -0
- package/components/FooterTitle.vue +17 -0
- package/components/FormControl.vue +5 -0
- package/components/Hero.vue +17 -0
- package/components/HeroContent.vue +17 -0
- package/components/HeroOverlay.vue +5 -0
- package/components/Home/AlternatingFeatureSections.vue +217 -0
- package/components/Home/CTA.vue +27 -0
- package/components/Home/Footer.vue +210 -0
- package/components/Home/GradientFeatureSections.vue +98 -0
- package/components/Home/Header.vue +174 -0
- package/components/Home/Hero.vue +52 -0
- package/components/Home/LogoCloud.vue +49 -0
- package/components/Home/StatsSection.vue +51 -0
- package/components/Home/Testimonial.vue +23 -0
- package/components/Indicator.vue +16 -0
- package/components/IndicatorItem.vue +37 -0
- package/components/InputGroup.vue +33 -0
- package/components/Kbd.vue +26 -0
- package/components/Label.vue +17 -0
- package/components/LabelText.vue +17 -0
- package/components/LabelTextAlt.vue +17 -0
- package/components/Link.vue +32 -0
- package/components/Logo.vue +8 -0
- package/components/Mask.config.ts +77 -0
- package/components/Mask.vue +15 -0
- package/components/Menu.vue +26 -0
- package/components/MenuItem.vue +17 -0
- package/components/MenuTitle.vue +14 -0
- package/components/MobileSidebar.vue +92 -0
- package/components/MockupCode.vue +4 -0
- package/components/Modal.vue +16 -0
- package/components/ModalAction.vue +5 -0
- package/components/ModalBox.vue +5 -0
- package/components/ModalWrapper.vue +32 -0
- package/components/NavButton.vue +22 -0
- package/components/Navbar.vue +17 -0
- package/components/NavbarCenter.vue +16 -0
- package/components/NavbarEnd.vue +16 -0
- package/components/NavbarStart.vue +16 -0
- package/components/Phone.vue +8 -0
- package/components/Progress.vue +44 -0
- package/components/Prose.vue +36 -0
- package/components/RadialProgress.vue +42 -0
- package/components/Radio.vue +63 -0
- package/components/RadioGroup.vue +41 -0
- package/components/Range.vue +49 -0
- package/components/RangeMeasure.vue +71 -0
- package/components/RangeMeasureTick.vue +62 -0
- package/components/Rating.vue +152 -0
- package/components/Select.vue +104 -0
- package/components/Sidebar.vue +89 -0
- package/components/SidebarMenuSection.vue +35 -0
- package/components/SigninForm.vue +47 -0
- package/components/Stack.vue +16 -0
- package/components/Stat.vue +5 -0
- package/components/StatActions.vue +5 -0
- package/components/StatDesc.vue +5 -0
- package/components/StatFigure.vue +5 -0
- package/components/StatTitle.vue +5 -0
- package/components/StatValue.vue +5 -0
- package/components/Stats.vue +5 -0
- package/components/Step.vue +36 -0
- package/components/Steps.vue +22 -0
- package/components/Swap.vue +60 -0
- package/components/Tab.vue +49 -0
- package/components/TabContent.vue +28 -0
- package/components/Tabs.vue +71 -0
- package/components/TabsManager.vue +37 -0
- package/components/Text.vue +179 -0
- package/components/TextArea.vue +53 -0
- package/components/TextInput.vue +64 -0
- package/components/Toast.vue +33 -0
- package/components/Toggle.vue +48 -0
- package/components/Tooltip.vue +49 -0
- package/components/UserMenu.vue +62 -0
- package/components/Window.vue +5 -0
- package/components/fixtures.ts +62 -0
- package/components/theme/Builder.vue +284 -0
- package/components/theme/Output.vue +70 -0
- package/components/theme/Picker.vue +39 -0
- package/components/theme/Preview.vue +1684 -0
- package/components/theme/Provider.vue +43 -0
- package/components/theme/Snooper.vue +41 -0
- package/components/theme/Swatch.vue +47 -0
- package/components/theme/custom-themes.ts +34 -0
- package/components/theme/theme-utils.ts +164 -0
- package/components/types.ts +7 -0
- package/index.ts +96 -0
- package/package.json +55 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const docsLinks = [{ label: 'Install', to: '/install' }]
|
|
3
|
+
const actions = [
|
|
4
|
+
{ label: 'Button', to: '/daisy-button' },
|
|
5
|
+
{ label: 'Dropdown', to: '/daisy-dropdown' },
|
|
6
|
+
{ label: 'Modal', to: '/daisy-modal', pendingDocs: true },
|
|
7
|
+
{ label: 'Swap', to: '/daisy-swap' },
|
|
8
|
+
]
|
|
9
|
+
const dataDisplay = [
|
|
10
|
+
{ label: 'Alert', to: '/daisy-alert' },
|
|
11
|
+
{ label: 'Avatar', to: '/daisy-avatar' },
|
|
12
|
+
{ label: 'AvatarGroup', to: '/daisy-avatar-group' },
|
|
13
|
+
{ label: 'Badge', to: '/daisy-badge' },
|
|
14
|
+
{ label: 'Card', to: '/daisy-card' },
|
|
15
|
+
{ label: 'Carousel', to: '/daisy-carousel' },
|
|
16
|
+
{ label: 'Collapse', to: '/daisy-collapse' },
|
|
17
|
+
{ label: 'Countdown', to: '/daisy-countdown' },
|
|
18
|
+
{ label: 'Kbd', to: '/daisy-kbd' },
|
|
19
|
+
{ label: 'Progress', to: '/daisy-progress' },
|
|
20
|
+
{ label: 'RadialProgress', to: '/daisy-radial-progress' },
|
|
21
|
+
{ label: 'Stat', to: '/daisy-stat' },
|
|
22
|
+
{ label: 'Table', to: '/daisy-table' },
|
|
23
|
+
{ label: 'Text', to: '/daisy-text' },
|
|
24
|
+
{ label: 'Tooltip', to: '/daisy-tooltip' },
|
|
25
|
+
{ label: 'Prose', to: '/daisy-prose' },
|
|
26
|
+
]
|
|
27
|
+
const dataInput = [
|
|
28
|
+
{ label: 'FormControl', to: '/daisy-form-control' },
|
|
29
|
+
{ label: 'Checkbox', to: '/daisy-form-checkbox' },
|
|
30
|
+
{ label: 'TextInput', to: '/daisy-form-text-input' },
|
|
31
|
+
{ label: 'Radio', to: '/daisy-form-radio' },
|
|
32
|
+
{ label: 'RadioGroup', to: '/daisy-form-radio-group' },
|
|
33
|
+
{ label: 'Range', to: '/daisy-form-range' },
|
|
34
|
+
{ label: 'Rating', to: '/daisy-form-rating' },
|
|
35
|
+
{ label: 'Select', to: '/daisy-form-select' },
|
|
36
|
+
{ label: 'Textarea', to: '/daisy-form-textarea' },
|
|
37
|
+
{ label: 'Toggle', to: '/daisy-form-toggle' },
|
|
38
|
+
]
|
|
39
|
+
const layout = [
|
|
40
|
+
{ label: 'Artboard', to: '/daisy-artboard' },
|
|
41
|
+
{ label: 'ButtonGroup', to: '/daisy-button-group' },
|
|
42
|
+
{ label: 'Divider', to: '/daisy-divider' },
|
|
43
|
+
{ label: 'Drawer', to: '/daisy-drawer' },
|
|
44
|
+
{ label: 'Flex', to: '/daisy-flex' },
|
|
45
|
+
{ label: 'Footer', to: '/daisy-footer' },
|
|
46
|
+
{ label: 'Hero', to: '/daisy-hero' },
|
|
47
|
+
{ label: 'Indicator', to: '/daisy-indicator' },
|
|
48
|
+
{ label: 'InputGroup', to: '/daisy-input-group' },
|
|
49
|
+
{ label: 'Mask', to: '/daisy-mask' },
|
|
50
|
+
{ label: 'Stack', to: '/daisy-stack' },
|
|
51
|
+
{ label: 'Toast', to: '/daisy-toast' },
|
|
52
|
+
]
|
|
53
|
+
const navigation = [
|
|
54
|
+
{ label: 'Breadcrumbs', to: '/daisy-breadcrumbs' },
|
|
55
|
+
{ label: 'BottomNav', to: '/daisy-bottom-nav' },
|
|
56
|
+
{ label: 'Link', to: '/daisy-link' },
|
|
57
|
+
{ label: 'Menu', to: '/daisy-menu' },
|
|
58
|
+
{ label: 'Navbar', to: '/daisy-navbar' },
|
|
59
|
+
{ label: 'Pagination', to: '/daisy-pagination' },
|
|
60
|
+
{ label: 'Steps', to: '/daisy-steps' },
|
|
61
|
+
{ label: 'Tabs', to: '/daisy-tabs' },
|
|
62
|
+
]
|
|
63
|
+
const mockup = [
|
|
64
|
+
{ label: 'Code', to: '/daisy-code' },
|
|
65
|
+
{ label: 'Phone', to: '/daisy-phone' },
|
|
66
|
+
{ label: 'Window', to: '/daisy-window' },
|
|
67
|
+
]
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<Drawer class="border-r border-r-base-300/30">
|
|
72
|
+
<!-- Sidebar component, swap this element with another sidebar if you like -->
|
|
73
|
+
<div class="relative pt-4 menu w-80 bg-base-100 text-base-content">
|
|
74
|
+
<NuxtLink to="/" class="fixed">
|
|
75
|
+
<Logo class="text-base-content" />
|
|
76
|
+
</NuxtLink>
|
|
77
|
+
|
|
78
|
+
<div class="pb-12 pl-2 mt-12 overflow-y-auto">
|
|
79
|
+
<SidebarMenuSection title="Docs" :links="docsLinks" />
|
|
80
|
+
<SidebarMenuSection title="Actions" :links="actions" />
|
|
81
|
+
<SidebarMenuSection title="Data Display" :links="dataDisplay" />
|
|
82
|
+
<SidebarMenuSection title="Data Input" :links="dataInput" />
|
|
83
|
+
<SidebarMenuSection title="Layout" :links="layout" />
|
|
84
|
+
<SidebarMenuSection title="Navigation" :links="navigation" />
|
|
85
|
+
<SidebarMenuSection title="Mockup" :links="mockup" />
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</Drawer>
|
|
89
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import FileTextIcon from '~icons/feather/file-text'
|
|
3
|
+
|
|
4
|
+
interface Link {
|
|
5
|
+
label: string
|
|
6
|
+
to: string
|
|
7
|
+
pending: boolean
|
|
8
|
+
pendingDocs: boolean
|
|
9
|
+
}
|
|
10
|
+
defineProps<{
|
|
11
|
+
title: string
|
|
12
|
+
links: Link[]
|
|
13
|
+
}>()
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<Menu compact class="p-2 mt-2">
|
|
18
|
+
<MenuTitle class="text-sm">
|
|
19
|
+
{{ title }}
|
|
20
|
+
</MenuTitle>
|
|
21
|
+
|
|
22
|
+
<MenuItem
|
|
23
|
+
v-for="link in links"
|
|
24
|
+
:key="link.label"
|
|
25
|
+
:class="{ 'opacity-30': link.pending }"
|
|
26
|
+
>
|
|
27
|
+
<NuxtLink :to="link.to" exact-active-class="active">
|
|
28
|
+
{{ link.label }}
|
|
29
|
+
<FileTextIcon v-if="link.pendingDocs" class="ml-2" />
|
|
30
|
+
</NuxtLink>
|
|
31
|
+
</MenuItem>
|
|
32
|
+
</Menu>
|
|
33
|
+
|
|
34
|
+
<hr class="opacity-10">
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { LockClosedIcon } from '@heroicons/vue/solid'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
components: {
|
|
6
|
+
LockClosedIcon,
|
|
7
|
+
},
|
|
8
|
+
}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="flex items-center justify-center min-h-full px-4 py-12 sm:px-6 lg:px-8">
|
|
13
|
+
<div class="w-full max-w-md space-y-8">
|
|
14
|
+
<div>
|
|
15
|
+
<img
|
|
16
|
+
class="w-auto h-24 mx-auto invert"
|
|
17
|
+
src="https://avatars.githubusercontent.com/u/85031756"
|
|
18
|
+
alt="Feathers Cloud"
|
|
19
|
+
>
|
|
20
|
+
<h2 class="mt-6 text-3xl font-extrabold text-center text-gray-900">
|
|
21
|
+
Sign in to your account
|
|
22
|
+
</h2>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="mt-8 space-y-6">
|
|
25
|
+
<a
|
|
26
|
+
type="button"
|
|
27
|
+
class="relative flex justify-center w-full px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md group hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
28
|
+
href="/api/auth/login"
|
|
29
|
+
>
|
|
30
|
+
<span class="absolute inset-y-0 left-0 flex items-center pl-3">
|
|
31
|
+
<LockClosedIcon
|
|
32
|
+
class="w-5 h-5 text-indigo-500 group-hover:text-indigo-400"
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
/>
|
|
35
|
+
</span>
|
|
36
|
+
Sign in
|
|
37
|
+
</a>
|
|
38
|
+
<div class="text-center">
|
|
39
|
+
or
|
|
40
|
+
<RouterLink to="/" class="text-blue-500">
|
|
41
|
+
Return to Home
|
|
42
|
+
</RouterLink>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineProps, withDefaults } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
is?: string
|
|
6
|
+
}
|
|
7
|
+
withDefaults(defineProps<Props>(), {
|
|
8
|
+
is: 'div',
|
|
9
|
+
})
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<component :is="is" class="stack">
|
|
14
|
+
<slot />
|
|
15
|
+
</component>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineProps } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
glyph?: string
|
|
6
|
+
|
|
7
|
+
color?: string
|
|
8
|
+
primary?: boolean
|
|
9
|
+
secondary?: boolean
|
|
10
|
+
accent?: boolean
|
|
11
|
+
neutral?: boolean
|
|
12
|
+
info?: boolean
|
|
13
|
+
success?: boolean
|
|
14
|
+
warning?: boolean
|
|
15
|
+
error?: boolean
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const classes = computed(() => {
|
|
19
|
+
return {
|
|
20
|
+
'step-primary': props.primary || props.color === 'primary',
|
|
21
|
+
'step-secondary': props.secondary || props.color === 'secondary',
|
|
22
|
+
'step-accent': props.accent || props.color === 'accent',
|
|
23
|
+
'step-neutral': props.neutral || props.color === 'neutral',
|
|
24
|
+
'step-info': props.info || props.color === 'info',
|
|
25
|
+
'step-success': props.success || props.color === 'success',
|
|
26
|
+
'step-warning': props.warning || props.color === 'warning',
|
|
27
|
+
'step-error': props.error || props.color === 'error',
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<li class="step" :class="classes" :data-content="glyph">
|
|
34
|
+
<slot />
|
|
35
|
+
</li>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineProps } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
vertical?: boolean
|
|
6
|
+
horizontal?: boolean
|
|
7
|
+
}
|
|
8
|
+
const props = defineProps<Props>()
|
|
9
|
+
|
|
10
|
+
const classes = computed(() => {
|
|
11
|
+
return {
|
|
12
|
+
'steps-vertical': props.vertical,
|
|
13
|
+
'steps-horizontal': props.horizontal,
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<ul class="steps" :class="classes">
|
|
20
|
+
<slot />
|
|
21
|
+
</ul>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineEmits, defineProps, nextTick, ref, watch } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
modelValue?: boolean | null
|
|
6
|
+
indeterminate?: boolean
|
|
7
|
+
rotate?: boolean
|
|
8
|
+
flip?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const props = defineProps<Props>()
|
|
12
|
+
const emit = defineEmits(['update:modelValue'])
|
|
13
|
+
const classes = computed(() => {
|
|
14
|
+
return {
|
|
15
|
+
'swap-rotate': props.rotate,
|
|
16
|
+
'swap-flip': props.flip,
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const checkbox = ref(null)
|
|
21
|
+
|
|
22
|
+
// Allow internal or external control
|
|
23
|
+
const isChecked = ref<any>(false)
|
|
24
|
+
watch(isChecked, val => emit('update:modelValue', val))
|
|
25
|
+
watch(
|
|
26
|
+
() => props.modelValue,
|
|
27
|
+
(val) => {
|
|
28
|
+
if (isChecked.value !== val)
|
|
29
|
+
isChecked.value = val
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
// When the indeterminate prop updates, manually update the checkbox element.
|
|
34
|
+
watch(
|
|
35
|
+
() => [props.indeterminate, checkbox.value],
|
|
36
|
+
([val]) => {
|
|
37
|
+
nextTick(() => {
|
|
38
|
+
if (checkbox.value != null)
|
|
39
|
+
(checkbox.value as any).indeterminate = val
|
|
40
|
+
isChecked.value = null
|
|
41
|
+
})
|
|
42
|
+
},
|
|
43
|
+
{ immediate: true },
|
|
44
|
+
)
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<label class="swap" :class="classes">
|
|
49
|
+
<input ref="checkbox" v-model="isChecked" type="checkbox">
|
|
50
|
+
<div class="swap-off">
|
|
51
|
+
<slot />
|
|
52
|
+
</div>
|
|
53
|
+
<div class="swap-on">
|
|
54
|
+
<slot name="swap" />
|
|
55
|
+
</div>
|
|
56
|
+
<div v-if="indeterminate" class="swap-indeterminate">
|
|
57
|
+
<slot name="indeterminate" />
|
|
58
|
+
</div>
|
|
59
|
+
</label>
|
|
60
|
+
</template>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineProps, inject, withDefaults } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
is?: string | Object | Function
|
|
6
|
+
name?: string
|
|
7
|
+
active?: boolean
|
|
8
|
+
|
|
9
|
+
variant?: 'bordered' | 'lifted'
|
|
10
|
+
bordered?: boolean
|
|
11
|
+
lifted?: boolean
|
|
12
|
+
|
|
13
|
+
size?: 'lg' | 'md' | 'sm' | 'xs'
|
|
14
|
+
lg?: boolean
|
|
15
|
+
md?: boolean
|
|
16
|
+
sm?: boolean
|
|
17
|
+
xs?: boolean
|
|
18
|
+
}
|
|
19
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
20
|
+
is: 'a',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const manager: any = inject('tabManager')
|
|
24
|
+
|
|
25
|
+
const classes = computed(() => {
|
|
26
|
+
return {
|
|
27
|
+
'tab-active': props.active || manager.currentTab === props.name,
|
|
28
|
+
|
|
29
|
+
'tab-lg': props.size === 'lg' || props.lg,
|
|
30
|
+
'tab-md': props.size === 'md' || props.md,
|
|
31
|
+
'tab-sm': props.size === 'sm' || props.sm,
|
|
32
|
+
'tab-xs': props.size === 'xs' || props.xs,
|
|
33
|
+
|
|
34
|
+
'tab-bordered': props.variant === 'bordered' || props.bordered,
|
|
35
|
+
'tab-lifted': props.variant === 'lifted' || props.lifted,
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<component
|
|
42
|
+
:is="is" class="tab" :class="classes" tabindex="0"
|
|
43
|
+
@click="() => (manager.currentTab = name)"
|
|
44
|
+
@keypress.enter="() => (manager.currentTab = name)"
|
|
45
|
+
>
|
|
46
|
+
<slot v-if="$slots.default" />
|
|
47
|
+
<span v-else>{{ name }}</span>
|
|
48
|
+
</component>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineProps, inject, withDefaults } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
is?: any
|
|
6
|
+
name: string
|
|
7
|
+
}
|
|
8
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
9
|
+
is: 'div',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const tabManager: any = inject('tabManager')
|
|
13
|
+
|
|
14
|
+
const isCurrentTab = computed(() => {
|
|
15
|
+
return tabManager.currentTab === props.name
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
if (!tabManager.currentTab) tabManager.currentTab = props.name
|
|
19
|
+
|
|
20
|
+
const existing = tabManager.tabs.find(t => t === props.name)
|
|
21
|
+
if (!existing) tabManager.tabs.push(props.name)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<component :is="is" v-show="isCurrentTab" class="tab-content">
|
|
26
|
+
<slot />
|
|
27
|
+
</component>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineProps, inject, withDefaults } from 'vue'
|
|
3
|
+
import Tab from './Tab.vue'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
is?: string | Object | Function
|
|
7
|
+
tabs: string[]
|
|
8
|
+
|
|
9
|
+
variant?: 'bordered' | 'lifted' | 'boxed' | 'inline-boxed'
|
|
10
|
+
bordered?: boolean
|
|
11
|
+
lifted?: boolean
|
|
12
|
+
boxed?: boolean
|
|
13
|
+
inlineBoxed?: boolean
|
|
14
|
+
|
|
15
|
+
size?: 'lg' | 'md' | 'sm' | 'xs'
|
|
16
|
+
lg?: boolean
|
|
17
|
+
md?: boolean
|
|
18
|
+
sm?: boolean
|
|
19
|
+
xs?: boolean
|
|
20
|
+
}
|
|
21
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
22
|
+
is: 'a',
|
|
23
|
+
tabs: [] as any,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const tabManager: any = inject('tabManager')
|
|
27
|
+
|
|
28
|
+
const _variant = computed(() => {
|
|
29
|
+
if (props.bordered || props.variant === 'bordered') return 'bordered'
|
|
30
|
+
if (props.lifted || props.variant === 'lifted') return 'lifted'
|
|
31
|
+
return undefined
|
|
32
|
+
})
|
|
33
|
+
const _size = computed(() => {
|
|
34
|
+
if (props.size) return props.size
|
|
35
|
+
if (props.lg) return 'lg'
|
|
36
|
+
if (props.md) return 'md'
|
|
37
|
+
if (props.sm) return 'sm'
|
|
38
|
+
if (props.xs) return 'xs'
|
|
39
|
+
return 'md'
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const classes = computed(() => {
|
|
43
|
+
return {
|
|
44
|
+
'tabs-boxed':
|
|
45
|
+
props.variant === 'boxed'
|
|
46
|
+
|| props.variant === 'inline-boxed'
|
|
47
|
+
|| props.boxed
|
|
48
|
+
|| props.inlineBoxed,
|
|
49
|
+
'inline-block': props.variant === 'inline-boxed' || props.inlineBoxed,
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<div class="tabs" :class="classes">
|
|
56
|
+
<slot v-if="$slots.default" />
|
|
57
|
+
<template v-for="tabName in tabs" v-else :key="tabName">
|
|
58
|
+
<Tab
|
|
59
|
+
:is="is"
|
|
60
|
+
:name="tabName"
|
|
61
|
+
:variant="_variant"
|
|
62
|
+
:size="_size"
|
|
63
|
+
:active="tabManager.currentTab === tabName"
|
|
64
|
+
@click="() => (tabManager.currentTab = tabName)"
|
|
65
|
+
>
|
|
66
|
+
{{ tabName }}
|
|
67
|
+
</Tab>
|
|
68
|
+
</template>
|
|
69
|
+
<div v-if="variant === 'lifted' || lifted" class="flex-1 cursor-default tab tab-lifted" />
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineEmits, defineProps, provide, reactive, watch } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
tab?: string
|
|
6
|
+
}
|
|
7
|
+
const props = defineProps<Props>()
|
|
8
|
+
const emit = defineEmits(['update:tab'])
|
|
9
|
+
|
|
10
|
+
const manager = reactive({
|
|
11
|
+
currentTab: props.tab,
|
|
12
|
+
tabs: [],
|
|
13
|
+
})
|
|
14
|
+
provide('tabManager', manager)
|
|
15
|
+
|
|
16
|
+
// If the tab changes from outside, update the internal value.
|
|
17
|
+
watch(
|
|
18
|
+
() => props.tab,
|
|
19
|
+
(val) => {
|
|
20
|
+
if (val !== manager.currentTab) manager.currentTab = val
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// If the internal tab value changes, update the tab
|
|
25
|
+
watch(
|
|
26
|
+
() => manager.currentTab,
|
|
27
|
+
(val) => {
|
|
28
|
+
if (val !== props.tab) emit('update:tab', val)
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="tabs-manager">
|
|
35
|
+
<slot />
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|