diff --git a/packages/docs/src/data/nav.json b/packages/docs/src/data/nav.json index 64a5a2a71cc..ad3ca42ad22 100644 --- a/packages/docs/src/data/nav.json +++ b/packages/docs/src/data/nav.json @@ -226,6 +226,10 @@ { "title": "sparklines", "subfolder": "components" + }, + { + "title": "empty-states", + "subfolder": "components" } ] }, diff --git a/packages/docs/src/examples/v-empty-state/usage.vue b/packages/docs/src/examples/v-empty-state/usage.vue new file mode 100644 index 00000000000..bed5c48336c --- /dev/null +++ b/packages/docs/src/examples/v-empty-state/usage.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/docs/src/pages/en/components/empty-states.md b/packages/docs/src/pages/en/components/empty-states.md new file mode 100644 index 00000000000..05d4dba12b9 --- /dev/null +++ b/packages/docs/src/pages/en/components/empty-states.md @@ -0,0 +1,36 @@ +--- +emphasized: true +meta: + title: Empty states + description: The empty state component is used to indicate that a list is empty or that no search results were found. + keywords: empty state, no results, no data, no items, no content, no records, no information, no search results +related: + - /components/buttons/ + - /components/icons/ + - /components/avatars/ +features: + report: true + spec: https://m2.material.io/design/communication/empty-states.html +--- + +# Empty states + +The `v-empty-state` component is used to indicate that a list is empty or that no search results were found. + + + +## Usage + +A basic empty state is composed of a title and a description. It can also include an icon and a button. + + + + + +## API + +| Component | Description | +| - | - | +| [v-empty-state](/api/v-empty-state/) | Primary Component | + + diff --git a/packages/vuetify/src/labs/VEmptyState/VEmptyState.sass b/packages/vuetify/src/labs/VEmptyState/VEmptyState.sass new file mode 100644 index 00000000000..2bc44c055b7 --- /dev/null +++ b/packages/vuetify/src/labs/VEmptyState/VEmptyState.sass @@ -0,0 +1,20 @@ +@use './variables' as * + +.v-empty-state + min-height: 100% + display: flex + align-items: center + justify-content: center + flex-direction: column + +.v-empty-state__title + font-size: $empty-state-title-font-size + +.v-empty-state__subtitle + font-size: $empty-state-subtitle-font-size + +.v-empty-state__text + font-size: $empty-state-text-font-size + +.v-empty-state__content + padding: $empty-state-content-padding diff --git a/packages/vuetify/src/labs/VEmptyState/VEmptyState.tsx b/packages/vuetify/src/labs/VEmptyState/VEmptyState.tsx new file mode 100644 index 00000000000..2a7dd2ca4b4 --- /dev/null +++ b/packages/vuetify/src/labs/VEmptyState/VEmptyState.tsx @@ -0,0 +1,124 @@ +// Styles +import './VEmptyState.sass' + +// Components +import { VAvatar } from '@/components/VAvatar' +import { VDefaultsProvider } from '@/components/VDefaultsProvider' +import { VIcon } from '@/components/VIcon' + +// Composables +import { makeSizeProps } from '@/composables/size' +import { makeComponentProps } from '@/composables/component' +import { makeThemeProps, provideTheme } from '@/composables/theme' +import { IconValue } from '@/composables/icons' + +// Utility +import { genericComponent, propsFactory, useRender } from '@/util' +import { useBackgroundColor } from '@/composables/color' +import { toRef } from 'vue' + +// Types + +export type VEmptyStateSlots = { + default: void + media: void +} + +export const makeVEmptyStateProps = propsFactory({ + avatar: String, + color: String, + icon: IconValue, + title: String, + subtitle: String, + text: String, + + ...makeComponentProps(), + ...makeSizeProps({ size: '25%' }), + ...makeThemeProps(), +}, 'VEmptyState') + +export const VEmptyState = genericComponent()({ + name: 'VEmptyState', + + props: makeVEmptyStateProps(), + + setup (props, { slots }) { + const { themeClasses } = provideTheme(props) + const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(toRef(props, 'color')) + + useRender(() => ( +
+ { !slots.media ? ( + <> + { props.avatar ? ( + + ) : props.icon ? ( + + ) : undefined } + + ) : ( + + { slots.media() } + + )} + + + { props.title && ( +
+ { props.title } +
+ )} + + { props.subtitle && ( +
+ { props.subtitle } +
+ )} + + { props.text && ( +
+ { props.text } +
+ )} + + { slots.default && ( +
+ { slots.default() } +
+ )} +
+ )) + + return {} + }, +}) + +export type VEmptyState = InstanceType diff --git a/packages/vuetify/src/labs/VEmptyState/_variables.scss b/packages/vuetify/src/labs/VEmptyState/_variables.scss new file mode 100644 index 00000000000..462d8239a54 --- /dev/null +++ b/packages/vuetify/src/labs/VEmptyState/_variables.scss @@ -0,0 +1,4 @@ +$empty-state-title-font-size: 4rem !default; +$empty-state-subtitle-font-size: 2rem !default; +$empty-state-text-font-size: .875rem !default; +$empty-state-content-padding: 24px 0 !default; diff --git a/packages/vuetify/src/labs/VEmptyState/index.ts b/packages/vuetify/src/labs/VEmptyState/index.ts new file mode 100644 index 00000000000..b07cb7066b1 --- /dev/null +++ b/packages/vuetify/src/labs/VEmptyState/index.ts @@ -0,0 +1 @@ +export { VEmptyState } from './VEmptyState' diff --git a/packages/vuetify/src/labs/components.ts b/packages/vuetify/src/labs/components.ts index 537e82f098b..c0e9a648c6f 100644 --- a/packages/vuetify/src/labs/components.ts +++ b/packages/vuetify/src/labs/components.ts @@ -2,3 +2,4 @@ export * from './VConfirmEdit' export * from './VCalendar' export * from './VPicker' export * from './VSparkline' +export * from './VEmptyState'