Skip to content

Commit

Permalink
feat(Breadcrumb): new component (#506)
Browse files Browse the repository at this point in the history
Co-authored-by: Eduard Aymerich <eduardaymerich@gmail.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
  • Loading branch information
3 people authored Nov 16, 2023
1 parent a975939 commit a35bfc7
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 2 deletions.
17 changes: 17 additions & 0 deletions docs/components/content/examples/BreadcrumbExampleBasic.vue
Original file line number Diff line number Diff line change
@@ -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>
20 changes: 20 additions & 0 deletions docs/components/content/examples/BreadcrumbExampleDefaultSlot.vue
Original file line number Diff line number Diff line change
@@ -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>
21 changes: 21 additions & 0 deletions docs/components/content/examples/BreadcrumbExampleDividerSlot.vue
Original file line number Diff line number Diff line change
@@ -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>
25 changes: 25 additions & 0 deletions docs/components/content/examples/BreadcrumbExampleIconSlot.vue
Original file line number Diff line number Diff line change
@@ -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>
16 changes: 16 additions & 0 deletions docs/content/1.getting-started/3.theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion docs/content/5.navigation/1.vertical-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
69 changes: 69 additions & 0 deletions docs/content/5.navigation/5.breadcrumb.md
Original file line number Diff line number Diff line change
@@ -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 changes: 84 additions & 0 deletions src/runtime/components/navigation/Breadcrumb.vue
Original file line number Diff line number Diff line change
@@ -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 changes: 7 additions & 0 deletions src/runtime/types/breadcrumb.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Link } from './link'

export interface BreadcrumbLink extends Link {
label: string
icon?: string
iconClass?: string
}
1 change: 1 addition & 0 deletions src/runtime/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
22 changes: 21 additions & 1 deletion src/runtime/ui.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
}
}
Expand Down Expand Up @@ -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 = {
Expand Down

1 comment on commit a35bfc7

@vercel
Copy link

@vercel vercel bot commented on a35bfc7 Nov 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ui – ./

ui-nuxt-js.vercel.app
ui-git-dev-nuxt-js.vercel.app
ui.nuxt.com

Please sign in to comment.