Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions playground-vue/src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const components = [
'textarea',
'timeline',
'toast',
'toolbar',
'tooltip',
'tree'
]
Expand Down
1 change: 1 addition & 0 deletions playground/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const components = [
'textarea',
'timeline',
'toast',
'toolbar',
'tooltip',
'tree'
]
Expand Down
66 changes: 66 additions & 0 deletions playground/app/pages/components/toolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script setup lang="ts">
import theme from '#build/ui/toolbar'

const variants = Object.keys(theme.variants.variant)

const variant = ref(theme.defaultVariants.variant)
const title = ref('Toolbar Title')
</script>

<template>
<div class=" space-y-4">
<div class="space-x-2">
<UButtonGroup>
<UBadge color="neutral" variant="outline" size="lg" label="title" />

<UInput v-model="title" :highlight="false" />
</UButtonGroup>

<UButtonGroup>
<UBadge color="neutral" variant="outline" size="lg" label="variant" />

<USelect v-model="variant" :items="variants" />
</UButtonGroup>
</div>
<UToolbar :variant="variant">
<Placeholder class="w-full h-8" />
</UToolbar>

<UToolbar :variant="variant">
<template #left>
<Placeholder class="w-40 h-8" />
</template>
<template #center>
<Placeholder class="w-40 h-8" />
</template>
<template #right>
<Placeholder class="w-40 h-8" />
</template>
</UToolbar>

<UToolbar :variant="variant">
<template #left>
<Placeholder class="w-40 h-8" />
</template>
</UToolbar>

<UToolbar :variant="variant">
<template #center>
<Placeholder class="w-40 h-8" />
</template>
</UToolbar>

<UToolbar :variant="variant">
<template #right>
<Placeholder class="w-40 h-8" />
</template>
</UToolbar>

<UToolbar :title="title" />
<UToolbar :title="title" variant="outline" :ui="{ root: 'border-x-0' }" />
<UToolbar :title="title" variant="outline" class="border-0 border-b" />
<UToolbar :title="title" variant="soft" />
<UToolbar :title="title" variant="subtle" />
<UToolbar :title="title" variant="solid" />
</div>
</template>
69 changes: 69 additions & 0 deletions src/runtime/components/Toolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script lang="ts">
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/toolbar'
import type { ComponentConfig } from '../types/utils'

type Toolbar = ComponentConfig<typeof theme, AppConfig, 'toolbar'>

export interface ToolbarProps {
/**
* The element or component this component should render as.
* @defaultValue 'div'
*/
as?: any
/**
* @defaultValue 'outline'
*/
title?: string
variant?: Toolbar['variants']['variant']
class?: any
ui?: Toolbar['slots']
}
export interface ToolbarSlots {
default(props?: {}): any
title(props?: {}): any
left(props?: {}): any
right(props?: {}): any
center(props?: {}): any
}
</script>

<script setup lang="ts">
import { computed } from 'vue'
import { Primitive } from 'reka-ui'
import { useAppConfig } from '#imports'
import { tv } from '../utils/tv'

const props = defineProps<ToolbarProps>()
const slots = defineSlots<ToolbarSlots>()

const appConfig = useAppConfig() as Toolbar['AppConfig']

const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.toolbar || {}) })({
variant: props.variant
}))
</script>

<template>
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<slot>
<div :class="ui.left({ class: [props.ui?.left] })">
<slot name="left">
<div v-if="title || !!slots.title" :class="ui.title({ class: props.ui?.title })">
<slot name="title">
{{ title }}
</slot>
</div>
</slot>
</div>

<div :class="ui.center({ class: [props.ui?.center] })">
<slot name="center" />
</div>

<div :class="ui.right({ class: [props.ui?.right] })">
<slot name="right" />
</div>
</slot>
</Primitive>
</template>
1 change: 1 addition & 0 deletions src/runtime/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export * from '../components/Textarea.vue'
export * from '../components/Timeline.vue'
export * from '../components/Toast.vue'
export * from '../components/Toaster.vue'
export * from '../components/Toolbar.vue'
export * from '../components/Tooltip.vue'
export * from '../components/Tree.vue'
export * from './form'
Expand Down
1 change: 1 addition & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,6 @@ export { default as textarea } from './textarea'
export { default as timeline } from './timeline'
export { default as toast } from './toast'
export { default as toaster } from './toaster'
export { default as toolbar } from './toolbar'
export { default as tooltip } from './tooltip'
export { default as tree } from './tree'
29 changes: 29 additions & 0 deletions src/theme/toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export default {
slots: {
root: 'flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px]',
title: 'text-base text-pretty truncate font-semibold text-highlighted px-3',
left: 'flex items-center gap-1.5',
right: 'flex items-center gap-1.5',
center: 'flex items-center gap-1.5'
},
variants: {
variant: {
solid: {
root: 'bg-inverted text-inverted',
title: 'text-inverted'
},
outline: {
root: 'bg-default border border-default'
},
soft: {
root: 'bg-elevated/50'
},
subtle: {
root: 'bg-elevated/50 border border-default'
}
}
},
defaultVariants: {
variant: 'outline'
}
}
24 changes: 24 additions & 0 deletions test/components/Toolbar.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, it, expect } from 'vitest'
import Toolbar, { type ToolbarProps, type ToolbarSlots } from '../../src/runtime/components/Toolbar.vue'

Check failure on line 2 in test/components/Toolbar.spec.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 22)

Prefer using a top-level type-only import instead of inline type specifiers

Check failure on line 2 in test/components/Toolbar.spec.ts

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 22)

Prefer using a top-level type-only import instead of inline type specifiers
import ComponentRender from '../component-render'
import theme from '#build/ui/toolbar'

describe('Toolbar', () => {
const variants = Object.keys(theme.variants.variant) as any

it.each([
// Props
['with as', { props: { as: 'section' } }],
...variants.map((variant: string) => [`with variant ${variant}`, { props: { variant } }]),
['with class', { props: { class: 'border-0 border-b' } }],
['with ui', { props: { ui: { root: 'border-x-0' } } }],
// Slots
['with left slot', { slots: { left: () => 'Left slot' } }],
['with title slot', { slots: { title: () => 'Title slot' } }],
['with right slot', { slots: { right: () => 'Right slot' } }],
['with center slot', { slots: { center: () => 'Center slot' } }]
])('renders %s correctly', async (nameOrHtml: string, options: { props?: ToolbarProps, slots?: Partial<ToolbarSlots> }) => {
const html = await ComponentRender(nameOrHtml, options, Toolbar)
expect(html).toMatchSnapshot()
})
})
109 changes: 109 additions & 0 deletions test/components/__snapshots__/Toolbar-vue.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Toolbar > renders with as correctly 1`] = `
"<section class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</section>"
`;

exports[`Toolbar > renders with center slot correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5">Center slot</div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with class correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border-default border-0 border-b">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with left slot correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">Left slot</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with right slot correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5">Right slot</div>
</div>"
`;

exports[`Toolbar > renders with title slot correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">
<div class="text-base text-pretty truncate font-semibold text-highlighted px-3">Title slot</div>
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with ui correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default border-x-0">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with variant outline correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-default border border-default">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with variant soft correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-elevated/50">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with variant solid correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-inverted text-inverted">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;

exports[`Toolbar > renders with variant subtle correctly 1`] = `
"<div class="flex justify-between items-center shrink-0 no-wrap relative w-full px-3 gap-1.5 overflow-x-auto min-h-[49px] bg-elevated/50 border border-default">
<div class="flex items-center gap-1.5">
<!--v-if-->
</div>
<div class="flex items-center gap-1.5"></div>
<div class="flex items-center gap-1.5"></div>
</div>"
`;
Loading
Loading