Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ If you want to use the helpers used in some components you need to copy the `src
- Progress
- Pagination
- Dropdown Menu
- Table
- Stepper
- Navigation Menu
- (More components coming soon)

## Contributing
Expand Down
45 changes: 45 additions & 0 deletions src/components/navigation-menus/NavigationMenu01.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script setup lang="ts">
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle
} from '@/components/ui/NavigationMenu'

const components = [
{ title: 'Alert Dialog', description: 'A modal dialog that interrupts the user with content.' },
{ title: 'Hover Card', description: 'For sighted users to preview content behind a link.' },
{ title: 'Progress', description: 'Displays an indicator showing completion progress.' },
{ title: 'Tabs', description: 'Layered sections of content shown one at a time.' }
]
</script>

<template>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
<NavigationMenuContent>
<ul class="grid w-[340px] gap-1 p-2 md:grid-cols-2">
<li v-for="component in components" :key="component.title">
<NavigationMenuLink href="#">
<div class="text-sm font-medium text-foreground">{{ component.title }}</div>
<p class="line-clamp-2 text-xs text-muted-foreground">
{{ component.description }}
</p>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink :class="navigationMenuTriggerStyle()" href="#">
Documentation
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</template>
23 changes: 23 additions & 0 deletions src/components/navigation-menus/NavigationMenu02.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
navigationMenuTriggerStyle
} from '@/components/ui/NavigationMenu'

const links = ['Home', 'Features', 'Pricing', 'About']
</script>

<template>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem v-for="link in links" :key="link">
<NavigationMenuLink :class="navigationMenuTriggerStyle()" href="#">
{{ link }}
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</template>
33 changes: 33 additions & 0 deletions src/components/steppers/Stepper01.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import {
Stepper,
StepperItem,
StepperIndicator,
StepperSeparator,
StepperTrigger
} from '@/components/ui/Stepper'
import { Check as CheckIcon } from 'lucide-vue-next'

const steps = [1, 2, 3, 4]
</script>

<template>
<Stepper :default-value="2" class="w-full max-w-xs">
<StepperItem
v-for="step in steps"
:key="step"
:step="step"
class="flex-1 last:flex-initial"
>
<StepperTrigger>
<StepperIndicator>
<CheckIcon
class="hidden size-4 group-data-[state=completed]/step:block"
/>
<span class="group-data-[state=completed]/step:hidden">{{ step }}</span>
</StepperIndicator>
</StepperTrigger>
<StepperSeparator v-if="step !== steps.length" />
</StepperItem>
</Stepper>
</template>
59 changes: 59 additions & 0 deletions src/components/steppers/Stepper02.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script setup lang="ts">
import {
Stepper,
StepperItem,
StepperIndicator,
StepperSeparator,
StepperTitle,
StepperTrigger
} from '@/components/ui/Stepper'
import Button from '@/components/ui/Button.vue'
import { Check as CheckIcon } from 'lucide-vue-next'
import { ref } from 'vue'

const steps = [
{ step: 1, title: 'Account' },
{ step: 2, title: 'Profile' },
{ step: 3, title: 'Confirm' }
]

const current = ref(1)
</script>

<template>
<div class="flex w-full max-w-md flex-col gap-6">
<Stepper v-model="current">
<StepperItem
v-for="item in steps"
:key="item.step"
:step="item.step"
class="flex-1 last:flex-initial"
>
<StepperTrigger>
<StepperIndicator>
<CheckIcon class="hidden size-4 group-data-[state=completed]/step:block" />
<span class="group-data-[state=completed]/step:hidden">{{ item.step }}</span>
</StepperIndicator>
<StepperTitle class="hidden sm:block">{{ item.title }}</StepperTitle>
</StepperTrigger>
<StepperSeparator v-if="item.step !== steps.length" />
</StepperItem>
</Stepper>

<div class="flex justify-between gap-2">
<Button
variant="outline"
:disabled="current === 1"
@click="current = Math.max(1, current - 1)"
>
Previous
</Button>
<Button
:disabled="current === steps.length"
@click="current = Math.min(steps.length, current + 1)"
>
Next
</Button>
</div>
</div>
</template>
40 changes: 40 additions & 0 deletions src/components/tables/Table01.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script setup lang="ts">
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from '@/components/ui/Table'

const invoices = [
{ invoice: 'INV001', status: 'Paid', method: 'Credit Card', amount: '$250.00' },
{ invoice: 'INV002', status: 'Pending', method: 'PayPal', amount: '$150.00' },
{ invoice: 'INV003', status: 'Unpaid', method: 'Bank Transfer', amount: '$350.00' },
{ invoice: 'INV004', status: 'Paid', method: 'Credit Card', amount: '$450.00' }
]
</script>

<template>
<div class="w-full max-w-md">
<Table>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">{{ invoice.invoice }}</TableCell>
<TableCell>{{ invoice.status }}</TableCell>
<TableCell>{{ invoice.method }}</TableCell>
<TableCell class="text-right">{{ invoice.amount }}</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
</template>
50 changes: 50 additions & 0 deletions src/components/tables/Table02.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow
} from '@/components/ui/Table'
import Badge from '@/components/ui/Badge.vue'

const invoices = [
{ invoice: 'INV001', status: 'success', label: 'Paid', amount: '$250.00' },
{ invoice: 'INV002', status: 'warning', label: 'Pending', amount: '$150.00' },
{ invoice: 'INV003', status: 'error', label: 'Unpaid', amount: '$350.00' },
{ invoice: 'INV004', status: 'success', label: 'Paid', amount: '$450.00' }
] as const
</script>

<template>
<div class="w-full max-w-lg">
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">{{ invoice.invoice }}</TableCell>
<TableCell>
<Badge :variant="invoice.status">{{ invoice.label }}</Badge>
</TableCell>
<TableCell class="text-right">{{ invoice.amount }}</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colspan="2">Total</TableCell>
<TableCell class="text-right">$1,200.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</template>
30 changes: 30 additions & 0 deletions src/components/ui/NavigationMenu/NavigationMenu.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { reactiveOmit } from '@vueuse/core'
import {
NavigationMenuRoot,
type NavigationMenuRootEmits,
type NavigationMenuRootProps,
useForwardPropsEmits
} from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import NavigationMenuViewport from './NavigationMenuViewport.vue'

const props = defineProps<NavigationMenuRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<NavigationMenuRootEmits>()

const delegatedProps = reactiveOmit(props, 'class')
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
<NavigationMenuRoot
v-bind="forwarded"
:class="
cn('relative z-10 flex max-w-max flex-1 items-center justify-center', props.class)
"
>
<slot />
<NavigationMenuViewport />
</NavigationMenuRoot>
</template>
31 changes: 31 additions & 0 deletions src/components/ui/NavigationMenu/NavigationMenuContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { reactiveOmit } from '@vueuse/core'
import {
NavigationMenuContent,
type NavigationMenuContentEmits,
type NavigationMenuContentProps,
useForwardPropsEmits
} from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = defineProps<NavigationMenuContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<NavigationMenuContentEmits>()

const delegatedProps = reactiveOmit(props, 'class')
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
<NavigationMenuContent
v-bind="forwarded"
:class="
cn(
'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
)
"
>
<slot />
</NavigationMenuContent>
</template>
26 changes: 26 additions & 0 deletions src/components/ui/NavigationMenu/NavigationMenuIndicator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { reactiveOmit } from '@vueuse/core'
import { NavigationMenuIndicator, type NavigationMenuIndicatorProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = defineProps<NavigationMenuIndicatorProps & { class?: HTMLAttributes['class'] }>()

const delegatedProps = reactiveOmit(props, 'class')
</script>

<template>
<NavigationMenuIndicator
v-bind="delegatedProps"
: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',
props.class
)
"
>
<div
class="relative top-[60%] size-2 rotate-45 rounded-tl-sm bg-border shadow-md"
/>
</NavigationMenuIndicator>
</template>
16 changes: 16 additions & 0 deletions src/components/ui/NavigationMenu/NavigationMenuItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { reactiveOmit } from '@vueuse/core'
import { NavigationMenuItem, type NavigationMenuItemProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = defineProps<NavigationMenuItemProps & { class?: HTMLAttributes['class'] }>()

const delegatedProps = reactiveOmit(props, 'class')
</script>

<template>
<NavigationMenuItem v-bind="delegatedProps" :class="cn('relative', props.class)">
<slot />
</NavigationMenuItem>
</template>
Loading
Loading