mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 20:19:34 +01:00
feat(Breadcrumb): new component (#506)
Co-authored-by: Eduard Aymerich <eduardaymerich@gmail.com> Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a97593985c
commit
a35bfc7343
17
docs/components/content/examples/BreadcrumbExampleBasic.vue
Normal file
17
docs/components/content/examples/BreadcrumbExampleBasic.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
const links = [{
|
||||
label: 'Home',
|
||||
icon: 'i-heroicons-home',
|
||||
to: '/'
|
||||
}, {
|
||||
label: 'Navigation',
|
||||
icon: 'i-heroicons-square-3-stack-3d'
|
||||
}, {
|
||||
label: 'Breadcrumb',
|
||||
icon: 'i-heroicons-link'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UBreadcrumb :links="links" />
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
const links = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
label: 'Navigation'
|
||||
}, {
|
||||
label: 'Breadcrumb'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UBreadcrumb :links="links">
|
||||
<template #default="{ link, isActive, index }">
|
||||
<UBadge :color="isActive ? 'primary' : 'gray'" class="rounded-full">
|
||||
{{ index + 1 }}. {{ link.label }}
|
||||
</UBadge>
|
||||
</template>
|
||||
</UBreadcrumb>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
const links = [{
|
||||
label: 'Home',
|
||||
icon: 'i-heroicons-home',
|
||||
to: '/'
|
||||
}, {
|
||||
label: 'Navigation',
|
||||
icon: 'i-heroicons-square-3-stack-3d'
|
||||
}, {
|
||||
label: 'Breadcrumb',
|
||||
icon: 'i-heroicons-link'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UBreadcrumb :links="links" :ui="{ ol: 'gap-x-3', li: 'gap-x-3' }">
|
||||
<template #divider>
|
||||
<span class="w-8 h-1 rounded-full bg-gray-300 dark:bg-gray-700" />
|
||||
</template>
|
||||
</UBreadcrumb>
|
||||
</template>
|
||||
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
const links = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
label: 'Navigation'
|
||||
}, {
|
||||
label: 'Breadcrumb'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UBreadcrumb :links="links" :divider="null" :ui="{ ol: 'gap-x-3' }">
|
||||
<template #icon="{ link, index, isActive }">
|
||||
<UAvatar
|
||||
:alt="(index + 1 ).toString()"
|
||||
:ui="{
|
||||
background: isActive ? 'bg-primary-500 dark:bg-primary-400' : undefined,
|
||||
placeholder: isActive ? 'text-white dark:text-gray-900' : !!link.to ? 'group-hover:text-gray-700 dark:group-hover:text-gray-200' : ''
|
||||
}"
|
||||
size="xs"
|
||||
/>
|
||||
</template>
|
||||
</UBreadcrumb>
|
||||
</template>
|
||||
@@ -369,13 +369,29 @@ export default defineAppConfig({
|
||||
},
|
||||
pagination: {
|
||||
default: {
|
||||
firstButton: {
|
||||
icon: 'i-octicon-chevron-left-24'
|
||||
},
|
||||
prevButton: {
|
||||
icon: 'i-octicon-arrow-left-24'
|
||||
},
|
||||
nextButton: {
|
||||
icon: 'i-octicon-arrow-right-24'
|
||||
},
|
||||
lastButton: {
|
||||
icon: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
accordion: {
|
||||
default: {
|
||||
openIcon: 'i-octicon-chevron-down-24'
|
||||
}
|
||||
},
|
||||
breadcrumb: {
|
||||
default: {
|
||||
divider: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ Pass an array to the `links` prop of the VerticalNavigation component. Each link
|
||||
|
||||
- `label` - The label of the link.
|
||||
- `icon` - The icon of the link.
|
||||
- `iconClass` - The class of the icon of the link.
|
||||
- `iconClass` - The class of the icon link.
|
||||
- `avatar` - The avatar of the link. You can pass all the props of the [Avatar](/elements/avatar) component.
|
||||
- `badge` - A badge to display next to the label.
|
||||
- `click` - The click handler of the link.
|
||||
|
||||
69
docs/content/5.navigation/5.breadcrumb.md
Normal file
69
docs/content/5.navigation/5.breadcrumb.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Breadcrumb
|
||||
description: A list of links that indicate the current page's location within a navigational hierarchy.
|
||||
navigation:
|
||||
badge: New
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Pass an array to the `links` prop of the Breadcrumb component. Each link can have the following properties:
|
||||
|
||||
- `label` - The label of the link.
|
||||
- `icon` - The icon of the link.
|
||||
- `iconClass` - The class of the icon link.
|
||||
|
||||
You can also pass any property from the [NuxtLink](https://nuxt.com/docs/api/components/nuxt-link#props) component such as `to`, `exact`, etc.
|
||||
|
||||
:component-example{component="breadcrumb-example-basic"}
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
A `span` will be rendered instead of a link when the `to` property is not defined.
|
||||
::
|
||||
|
||||
## Divider
|
||||
|
||||
Use the `divider` prop to customize the divider between each link, it can be **an icon or a string**. You can change it globally in `ui.breadcrumb.default.divider`. Defaults to `i-heroicons-chevron-right-20-solid`.
|
||||
|
||||
You can set the prop to `null` to hide the divider. Additionally, you can customize it using the [`divider`](#divider-1) slot.
|
||||
|
||||
::component-card
|
||||
---
|
||||
baseProps:
|
||||
links:
|
||||
- label: Home
|
||||
to: /
|
||||
- label: Navigation
|
||||
- label: Breadcrumb
|
||||
props:
|
||||
divider: '/'
|
||||
---
|
||||
::
|
||||
|
||||
## Slots
|
||||
|
||||
### `default`
|
||||
|
||||
Use the `#default` slot to customize the link label. You will have access to the `link`, `index` and `isActive` properties in the slot scope.
|
||||
|
||||
:component-example{component="breadcrumb-example-default-slot"}
|
||||
|
||||
### `icon`
|
||||
|
||||
Use the `#icon` slot to customize the link icon. You will have access to the `link`, `index` and `isActive` properties in the slot scope.
|
||||
|
||||
:component-example{component="breadcrumb-example-icon-slot"}
|
||||
|
||||
### `divider`
|
||||
|
||||
Use the `divider` slot to customize the divider of the Breadcrumb.
|
||||
|
||||
:component-example{component="breadcrumb-example-divider-slot"}
|
||||
|
||||
## Props
|
||||
|
||||
:component-props
|
||||
|
||||
## Config
|
||||
|
||||
:component-preset
|
||||
84
src/runtime/components/navigation/Breadcrumb.vue
Normal file
84
src/runtime/components/navigation/Breadcrumb.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<nav aria-label="Breadcrumb" :class="ui.wrapper" v-bind="attrs">
|
||||
<ol :class="ui.ol">
|
||||
<li v-for="(link, index) in links" :key="index" :class="ui.li">
|
||||
<ULink
|
||||
as="span"
|
||||
:class="[ui.base, index === links.length - 1 ? ui.active : !!link.to ? ui.inactive : '']"
|
||||
v-bind="omit(link, ['label', 'icon', 'iconClass'])"
|
||||
:aria-current="index === links.length - 1 ? 'page' : undefined"
|
||||
>
|
||||
<slot name="icon" :link="link" :index="index" :is-active="index === links.length - 1">
|
||||
<UIcon
|
||||
v-if="link.icon"
|
||||
:name="link.icon"
|
||||
:class="[ui.icon.base, index === links.length - 1 ? ui.icon.active : !!link.to ? ui.icon.inactive : '', link.iconClass]"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<slot :link="link" :index="index" :is-active="index === links.length - 1">
|
||||
{{ link.label }}
|
||||
</slot>
|
||||
</ULink>
|
||||
|
||||
<slot v-if="index < links.length - 1" name="divider">
|
||||
<template v-if="divider">
|
||||
<UIcon v-if="divider.startsWith('i-')" :name="divider" :class="ui.divider.base" role="presentation" />
|
||||
<span v-else role="presentation">{{ divider }}</span>
|
||||
</template>
|
||||
</slot>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRef } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import ULink from '../elements/Link.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig, omit } from '../../utils'
|
||||
import type { BreadcrumbLink, Strategy } from '../../types'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
import { breadcrumb } from '#ui/ui.config'
|
||||
|
||||
const config = mergeConfig<typeof breadcrumb>(appConfig.ui.strategy, appConfig.ui.breadcrumb, breadcrumb)
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
UIcon,
|
||||
ULink
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
links: {
|
||||
type: Array as PropType<BreadcrumbLink[]>,
|
||||
default: () => []
|
||||
},
|
||||
divider: {
|
||||
type: String,
|
||||
default: () => config.default.divider
|
||||
},
|
||||
class: {
|
||||
type: [String, Object, Array] as PropType<any>,
|
||||
default: undefined
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const { ui, attrs } = useUI('breadcrumb', toRef(props, 'ui'), config, toRef(props, 'class'))
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
attrs,
|
||||
omit
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
7
src/runtime/types/breadcrumb.d.ts
vendored
Normal file
7
src/runtime/types/breadcrumb.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Link } from './link'
|
||||
|
||||
export interface BreadcrumbLink extends Link {
|
||||
label: string
|
||||
icon?: string
|
||||
iconClass?: string
|
||||
}
|
||||
1
src/runtime/types/index.d.ts
vendored
1
src/runtime/types/index.d.ts
vendored
@@ -1,6 +1,7 @@
|
||||
export * from './accordion'
|
||||
export * from './avatar'
|
||||
export * from './badge'
|
||||
export * from './breadcrumb'
|
||||
export * from './button'
|
||||
export * from './clipboard'
|
||||
export * from './command-palette'
|
||||
|
||||
@@ -1124,7 +1124,7 @@ export const pagination = {
|
||||
nextButton: {
|
||||
color: 'white',
|
||||
class: 'rtl:[&_span:last-child]:rotate-180',
|
||||
icon: 'i-heroicons-chevron-right-20-solid '
|
||||
icon: 'i-heroicons-chevron-right-20-solid'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1163,6 +1163,26 @@ export const tabs = {
|
||||
}
|
||||
}
|
||||
|
||||
export const breadcrumb = {
|
||||
wrapper: 'relative',
|
||||
ol: 'flex items-center gap-x-1.5',
|
||||
li: 'flex items-center gap-x-1.5 text-gray-500 dark:text-gray-400 text-sm',
|
||||
base: 'flex items-center gap-x-1.5 group font-semibold',
|
||||
icon: {
|
||||
base: 'flex-shrink-0 w-4 h-4',
|
||||
active: '',
|
||||
inactive: ''
|
||||
},
|
||||
divider: {
|
||||
base: 'flex-shrink-0 w-5 h-5'
|
||||
},
|
||||
active: 'text-primary-500 dark:text-primary-400',
|
||||
inactive: ' hover:text-gray-700 dark:hover:text-gray-200',
|
||||
default: {
|
||||
divider: 'i-heroicons-chevron-right-20-solid'
|
||||
}
|
||||
}
|
||||
|
||||
// Overlays
|
||||
|
||||
export const modal = {
|
||||
|
||||
Reference in New Issue
Block a user