feat: add scrollarea, nav menu

This commit is contained in:
zernonia 2023-09-04 11:30:01 +08:00
parent a0c08b2355
commit 56f473ccc1
14 changed files with 275 additions and 77 deletions

View File

@ -219,13 +219,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/menubar',
items: [],
},
// {
// title: "Navigation Menu",
// href: "#",
// label: "Soon",
// disabled: true,
// items: []
// },
{
title: 'Navigation Menu',
href: '/docs/components/navigation-menu',
items: [],
},
{
title: 'Popover',
href: '/docs/components/popover',
@ -241,13 +239,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/radio-group',
items: [],
},
// {
// title: "Scroll Area",
// href: "#",
// label: "Soon",
// disabled: true,
// items: []
// },
{
title: 'Scroll Area',
href: '/docs/components/scroll-area',
items: [],
},
{
title: 'Select',
href: '/docs/components/select',

View File

@ -138,26 +138,26 @@
* Lists
* -------------------------------------------------------------------------- */
.vp-doc ul,
.vp-doc ol {
.vp-doc ul:not(:where(.preview *)),
.vp-doc ol:not(:where(.preview *)) {
padding-left: 1.25rem;
margin: 16px 0;
}
.vp-doc ul {
.vp-doc ul:not(:where(.preview *)) {
list-style: disc;
}
.vp-doc ol {
.vp-doc ol:not(:where(.preview *)) {
list-style: decimal;
}
.vp-doc li + li {
.vp-doc li + li:not(:where(.preview *)) {
margin-top: 8px;
}
.vp-doc li > ol,
.vp-doc li > ul {
.vp-doc li > ol:not(:where(.preview *)),
.vp-doc li > ul:not(:where(.preview *)) {
margin: 8px 0 0;
}

View File

@ -0,0 +1,61 @@
---
title: Navigation Menu
description: A collection of links for navigating websites.
source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/registry/default/ui/navigation-menu
primitive: https://www.radix-vue.com/components/navigation-menu.html
---
<ComponentPreview name="NavigationMenuDemo" >
<<< ../../../lib/registry/default/examples/NavigationMenuDemo.vue
</ComponentPreview>
## Installation
```bash
npx shadcn-vue@latest add navigation-menu
```
<ManualInstall>
1. Install `radix-vue`:
```bash
npm install radix-vue
```
2. Copy and paste the component source files linked at the top of this page into your project.
</ManualInstall>
## Usage
```vue
<script setup lang="ts">
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
NavigationMenuViewport,
} from '@/lib/registry/default/ui/navigation-menu'
</script>
<template>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink>Link</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</template>
```

View File

@ -0,0 +1,110 @@
<script setup lang="ts">
import ListItem from './NavigationMenuDemoItem.vue'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from '@/lib/registry/default/ui/navigation-menu'
const components: { title: string; href: string; description: string }[] = [
{
title: 'Alert Dialog',
href: '/docs/primitives/alert-dialog',
description:
'A modal dialog that interrupts the user with important content and expects a response.',
},
{
title: 'Hover Card',
href: '/docs/primitives/hover-card',
description:
'For sighted users to preview content available behind a link.',
},
{
title: 'Progress',
href: '/docs/primitives/progress',
description:
'Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.',
},
{
title: 'Scroll-area',
href: '/docs/primitives/scroll-area',
description: 'Visually or semantically separates content.',
},
{
title: 'Tabs',
href: '/docs/primitives/tabs',
description:
'A set of layered sections of content—known as tab panels—that are displayed one at a time.',
},
{
title: 'Tooltip',
href: '/docs/primitives/tooltip',
description:
'A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.',
},
]
</script>
<template>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
<NavigationMenuContent>
<ul class="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<li class="row-span-3">
<NavigationMenuLink as-child>
<a
class="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
href="/"
>
<img src="https://www.radix-vue.com/logo.svg" class="h-6 w-6">
<div class="mb-2 mt-4 text-lg font-medium">
shadcn/ui
</div>
<p class="text-sm leading-tight text-muted-foreground">
Beautifully designed components built with Radix UI and
Tailwind CSS.
</p>
</a>
</NavigationMenuLink>
</li>
<ListItem href="/docs" title="Introduction">
Re-usable components built using Radix UI and Tailwind CSS.
</ListItem>
<ListItem href="/docs/installation" title="Installation">
How to install dependencies and structure your app.
</ListItem>
<ListItem href="/docs/primitives/typography" title="Typography">
Styles for headings, paragraphs, lists...etc
</ListItem>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
<NavigationMenuContent>
<ul class="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
<ListItem
v-for="component in components"
:key="component.title"
:title="component.title"
:href="component.href"
>
{{ component.description }}
</ListItem>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/docs" :class="navigationMenuTriggerStyle()">
Documentation
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</template>

View File

@ -0,0 +1,27 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import {
NavigationMenuLink,
} from '@/lib/registry/default/ui/navigation-menu'
defineProps<{ title?: string; href?: string }>()
</script>
<template>
<li>
<NavigationMenuLink as-child>
<a
:href="href"
:class="cn(
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
$attrs.class ?? '',
)"
>
<div class="text-sm font-medium leading-none">{{ title }}</div>
<p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
<slot />
</p>
</a>
</NavigationMenuLink>
</li>
</template>

View File

@ -3,8 +3,8 @@ import {
NavigationMenuRoot,
type NavigationMenuRootEmits,
type NavigationMenuRootProps,
NavigationMenuViewport,
} from 'radix-vue'
import NavigationMenuViewport from './NavigationMenuViewport.vue'
import { cn } from '@/lib/utils'
const props = defineProps<NavigationMenuRootProps & { class?: string }>()
@ -15,19 +15,10 @@ const emits = defineEmits<NavigationMenuRootEmits>()
<template>
<NavigationMenuRoot
v-bind="props"
:class="cn('relative z-10 flex w-full justify-center', props.class)"
:class="cn('relative z-10 flex max-w-max flex-1 items-center justify-center', props.class)"
@update:model-value="emits('update:modelValue', $event)"
>
<slot />
<div class="absolute top-full left-0 flex w-full justify-center">
<NavigationMenuViewport
:class="
cn(
'data-[state=open]:animate-scaleIn data-[state=closed]:animate-scaleOut relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full origin-[top_center] overflow-hidden bg-background rounded-lg border border-border shadow-md transition-[width,_height] duration-300 sm:w-[var(--radix-navigation-menu-viewport-width)]',
props.class,
)
"
/>
</div>
<NavigationMenuViewport />
</NavigationMenuRoot>
</template>

View File

@ -4,7 +4,7 @@ import {
type NavigationMenuContentEmits,
type NavigationMenuContentProps,
} from 'radix-vue'
import { cn } from '@/lib/utils'
import { cn, useEmitAsProps } from '@/lib/utils'
const props = defineProps<NavigationMenuContentProps & { class?: string }>()
@ -13,10 +13,10 @@ const emits = defineEmits<NavigationMenuContentEmits>()
<template>
<NavigationMenuContent
v-bind="props"
v-bind="{ ...props, ...useEmitAsProps(emits) }"
:class="
cn(
'data-[motion=from-start]:animate-enterFromLeft data-[motion=from-end]:animate-enterFromRight data-[motion=to-start]:animate-exitToLeft data-[motion=to-end]:animate-exitToRight absolute top-0 left-0 w-full sm:w-auto',
'left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ',
props.class,
)
"

View File

@ -0,0 +1,15 @@
<script setup lang="ts">
import { NavigationMenuIndicator, type NavigationMenuIndicatorProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<NavigationMenuIndicatorProps>()
</script>
<template>
<NavigationMenuIndicator
v-bind="props"
:class="cn('top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in', $attrs.class ?? '')"
>
<div class="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuIndicator>
</template>

View File

@ -4,14 +4,14 @@ import {
type NavigationMenuLinkEmits,
type NavigationMenuLinkProps,
} from 'radix-vue'
import { useEmitAsProps } from '@/lib/utils'
const props = defineProps<NavigationMenuLinkProps>()
const emits = defineEmits<NavigationMenuLinkEmits>()
</script>
<template>
<NavigationMenuLink v-bind="props" @select="emits('select', $event)">
<NavigationMenuLink v-bind="{ ...props, ...useEmitAsProps(emits) }">
<slot />
</NavigationMenuLink>
</template>

View File

@ -1,27 +0,0 @@
<script setup lang="ts">
import { NavigationMenuLink } from 'radix-vue'
const props = defineProps({
title: String,
href: String,
})
</script>
<template>
<li>
<NavigationMenuLink as-child>
<a
:href="props.href"
v-bind="$attrs"
class="focus:shadow-sm hover:bg-outline-hover block select-none rounded-sm p-3 text-sm leading-none no-underline outline-none transition-colors"
>
<div class="text-foreground mb-1 font-medium leading-4">
{{ props.title }}
</div>
<p class="text-muted my-0 leading-5">
<slot />
</p>
</a>
</NavigationMenuLink>
</li>
</template>

View File

@ -3,27 +3,19 @@ import {
NavigationMenuTrigger,
type NavigationMenuTriggerProps,
} from 'radix-vue'
import { cva } from 'class-variance-authority'
import { ChevronDown } from 'lucide-vue-next'
import { computed } from 'vue'
import { navigationMenuTriggerStyle } from '.'
import { cn } from '@/lib/utils'
const props = defineProps<NavigationMenuTriggerProps & { class?: string }>()
const navigationMenuTriggerStyle = computed(() => {
return cva(
'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-outline-hover hover:text-foreground focus:bg-outline-hover focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-outline-hover data-[state=open]:bg-outline-hover',
)
})
</script>
<template>
<NavigationMenuTrigger
:class="cn(navigationMenuTriggerStyle(), props.class)"
:class="cn(navigationMenuTriggerStyle(), 'group', props.class)"
v-bind="props"
>
<slot />
{{ " " }}
<ChevronDown
class="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
aria-hidden="true"

View File

@ -0,0 +1,23 @@
<script setup lang="ts">
import {
NavigationMenuViewport,
type NavigationMenuViewportProps,
} from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<NavigationMenuViewportProps>()
</script>
<template>
<div class="absolute left-0 top-full flex justify-center">
<NavigationMenuViewport
v-bind="props"
:class="
cn(
'origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
$attrs.class ?? '',
)
"
/>
</div>
</template>

View File

@ -1,7 +1,12 @@
import { cva } from 'class-variance-authority'
export { default as NavigationMenu } from './NavigationMenu.vue'
export { default as NavigationMenuList } from './NavigationMenuList.vue'
export { default as NavigationMenuItem } from './NavigationMenuItem.vue'
export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue'
export { default as NavigationMenuContent } from './NavigationMenuContent.vue'
export { default as NavigationMenuLink } from './NavigationMenuLink.vue'
export { default as NavigationMenuListItem } from './NavigationMenuListItem.vue'
export const navigationMenuTriggerStyle = cva(
'group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',
)

View File

@ -1,9 +1,14 @@
<script setup lang="ts">
import type { SelectRootEmits, SelectRootProps } from 'radix-vue'
import { SelectRoot } from 'radix-vue'
import { useEmitAsProps } from '@/lib/utils'
const props = defineProps<SelectRootProps>()
const emits = defineEmits<SelectRootEmits>()
</script>
<template>
<SelectRoot>
<SelectRoot v-bind="{ ...props, ...useEmitAsProps(emits) }">
<slot />
</SelectRoot>
</template>