-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(entities-shared): create shared empty state component [KHCP-1435…
…5] (#1850) * feat(entities-shared): create shared empty state component [KHCP-14355] * fix(*): fix imports and styles * fix(*): fix card styles * fix(*): card children styles * fix(*): card children styles * fix(*): emit event on learning hub button click and slot icon for feature card * fix(*): add icons to features * fix(*): apply pr feedback * fix(*): apply pr feedback
- Loading branch information
Showing
9 changed files
with
360 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
packages/entities/entities-shared/docs/entity-empty-state.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# EntityEmptyState.vue | ||
|
||
An empty state component that displays title, description, and optionally pricing, action button, learn more, and a set of features cards. Used for engaging and onboarding new users with rich information and context. | ||
|
||
- [Requirements](#requirements) | ||
- [Usage](#usage) | ||
- [Install](#install) | ||
- [Props](#props) | ||
- [Usage example](#usage-example) | ||
- [TypeScript interfaces](#typescript-interfaces) | ||
|
||
## Requirements | ||
|
||
- `vue` must be initialized in the host application | ||
- `@kong/kongponents` must be added as a `dependency` in the host application, globally available via the Vue Plugin installation, and the package's style imports must be added in the app entry file. [See here for instructions on installing Kongponents](https://kongponents.konghq.com/#globally-install-all-kongponents). | ||
|
||
## Usage | ||
|
||
### Install | ||
|
||
[See instructions for installing the `@kong-ui-public/entities-shared` package.](../README.md#install) | ||
|
||
### Props | ||
|
||
#### `title` | ||
|
||
- type: `String` | ||
- required: `true` | ||
|
||
Title for the empty state. | ||
|
||
#### `description` | ||
|
||
- type: `String` | ||
- default: `''` | ||
|
||
Description for the empty state. | ||
|
||
#### `pricing` | ||
|
||
- type: `String` | ||
- default: `` | ||
|
||
If provided, will display pricing information for transparency. | ||
|
||
#### `actionButtonText` | ||
|
||
- type: `String` | ||
- default: `` | ||
|
||
If provided, a CTA button will show with text and icon typically, for creating an entity. | ||
|
||
#### `learnMoreLink` | ||
|
||
- type: `Boolean` | ||
- default: false | ||
|
||
If provided, will show the Learning Hub button for the entity. | ||
|
||
#### `features` | ||
|
||
- type: `Array` | ||
- default: `[]` | ||
|
||
If provided, will display card for each feature of that entity, along with an icon, a title and a short description. | ||
|
||
### Usage example | ||
|
||
Please refer to the [sandbox](../src/components/entity-empty-state/EntityEmptyState.vue). | ||
|
||
## TypeScript interfaces | ||
|
||
TypeScript interfaces [are available here](https://github.com/Kong/public-ui-components/blob/main/packages/entities/entities-shared/src/types/entity-empty-state.ts) and can be directly imported into your host application. The following type interfaces are available for import: | ||
|
||
```ts | ||
import type { EmptyStateFeature } from '@kong-ui-public/entities-shared' | ||
``` |
47 changes: 47 additions & 0 deletions
47
packages/entities/entities-shared/sandbox/pages/EntityEmptyStatePage.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<template> | ||
<div class="sandbox-container"> | ||
<main> | ||
<h3>Entity empty state</h3> | ||
<EntityEmptyState | ||
action-button-text="Create a gateway" | ||
description="Lorem ipsum dolor sit amet consectetur adipisicing elit. Id quidem aperiam similique vitae beatae. Repellat quam voluptas vitae, maxime consequuntur praesentium suscipit. Numquam aliquid nulla vel esse accusantium reiciendis error?" | ||
:features="features" | ||
learn-more-link | ||
pricing="Lorem ipsum dolor sit amet consectetur adipisicing elit." | ||
title="Gateway Manager" | ||
@create-button-clicked="console.log('create button clicked')" | ||
@learning-hub-button-clicked="console.log('learning hub button clicked')" | ||
> | ||
<template #icon> | ||
<RuntimesIcon /> | ||
</template> | ||
</EntityEmptyState> | ||
</main> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { EntityEmptyState } from '../../src' | ||
import { RuntimesIcon } from '@kong/icons' | ||
const features = [ | ||
{ | ||
iconVariant: 'deploy', | ||
title: 'First', | ||
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Id quidem aperiam similique vitae beatae', | ||
}, | ||
{ | ||
iconVariant: 'plug', | ||
title: 'Second', | ||
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Id quidem aperiam similique vitae beatae', | ||
}, { | ||
iconVariant: 'chartData', | ||
title: 'Third ', | ||
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Id quidem aperiam similique vitae beatae', | ||
}, { | ||
iconVariant: 'analytics', | ||
title: 'Fourth', | ||
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Id quidem aperiam similique vitae beatae', | ||
}, | ||
] | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
216 changes: 216 additions & 0 deletions
216
packages/entities/entities-shared/src/components/entity-empty-state/EntityEmptyState.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
<template> | ||
<div class="kong-ui-public-entity-empty-state"> | ||
<div v-if="$slots.image"> | ||
<slot name="image" /> | ||
</div> | ||
<div class="entity-empty-state-content"> | ||
<div | ||
v-if="title || $slots.title || $slots['title-after']" | ||
class="entity-empty-state-title" | ||
> | ||
<slot name="title" /> | ||
<div :title="title"> | ||
{{ title }} | ||
</div> | ||
<span v-if="$slots['title-after']"> | ||
<slot name="title-after" /> | ||
</span> | ||
</div> | ||
<div | ||
v-if="description || $slots.default" | ||
class="entity-empty-state-description" | ||
> | ||
<slot name="default"> | ||
<p> | ||
{{ description }} | ||
</p> | ||
</slot> | ||
</div> | ||
<div | ||
v-if="pricing" | ||
class="entity-empty-state-pricing" | ||
> | ||
<p> | ||
<b>{{ t('emptyState.pricingTitle') }}</b> <slot name="pricing"> | ||
{{ pricing }} | ||
</slot> | ||
</p> | ||
</div> | ||
</div> | ||
<div | ||
v-if="$slots.message" | ||
class="entity-empty-state-message" | ||
> | ||
<slot name="message" /> | ||
</div> | ||
<div class="entity-empty-state-action"> | ||
<KButton | ||
v-if="actionButtonText || $slots.action" | ||
appearance="primary" | ||
size="large" | ||
@click="$emit('create-button-clicked')" | ||
> | ||
<AddIcon /> | ||
{{ actionButtonText }} | ||
</KButton> | ||
<KButton | ||
v-if="learnMoreLink" | ||
appearance="secondary" | ||
size="large" | ||
@click="$emit('learning-hub-button-clicked')" | ||
> | ||
<BookIcon decorative /> | ||
{{ t('emptyState.learnMore') }} | ||
</KButton> | ||
</div> | ||
<div class="entity-empty-state-card-container"> | ||
<template | ||
v-for="feature in features" | ||
:key="feature" | ||
> | ||
<KCard class="entity-empty-state-card"> | ||
<template #title> | ||
<component | ||
:is="getEntityIcon(feature.iconVariant)" | ||
:color="KUI_COLOR_TEXT_NEUTRAL_STRONGER" | ||
:size="KUI_ICON_SIZE_40" | ||
/> | ||
<div class="card-title"> | ||
{{ feature.title }} | ||
</div> | ||
</template> | ||
{{ feature.description }} | ||
</KCard> | ||
</template> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { type PropType } from 'vue' | ||
import { KButton } from '@kong/kongponents' | ||
import { BookIcon, AddIcon, DeployIcon, PlugIcon, ChartDataIcon, AnalyticsIcon } from '@kong/icons' | ||
import composables from '../../composables' | ||
import type { EmptyStateFeature } from 'src/types/entity-empty-state' | ||
import { KUI_ICON_SIZE_40, KUI_COLOR_TEXT_NEUTRAL_STRONGER } from '@kong/design-tokens' | ||
const getEntityIcon = (iconType: string): object => { | ||
switch (iconType) { | ||
case 'deploy': | ||
return DeployIcon | ||
case 'plug': | ||
return PlugIcon | ||
case 'chartData': | ||
return ChartDataIcon | ||
case 'analytics': | ||
return AnalyticsIcon | ||
default: | ||
return BookIcon | ||
} | ||
} | ||
defineProps({ | ||
title: { | ||
type: String, | ||
required: true, | ||
}, | ||
description: { | ||
type: String, | ||
required: true, | ||
}, | ||
pricing: { | ||
type: String, | ||
default: '', | ||
}, | ||
actionButtonText: { | ||
type: String, | ||
default: '', | ||
}, | ||
learnMoreLink: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
features: { | ||
type: Array as PropType<EmptyStateFeature[]>, | ||
default: () => [], | ||
}, | ||
}) | ||
defineEmits(['create-button-clicked', 'learning-hub-button-clicked']) | ||
const { i18n: { t } } = composables.useI18n() | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
.kong-ui-public-entity-empty-state { | ||
align-items: center; | ||
background-color: $kui-color-background; | ||
box-sizing: border-box; | ||
display: flex; | ||
flex-direction: column; | ||
font-family: $kui-font-family-text; | ||
gap: $kui-space-100; | ||
padding: $kui-space-130 $kui-space-150; | ||
width: 100%; | ||
.entity-empty-state-content { | ||
align-items: center; | ||
display: flex; | ||
flex-direction: column; | ||
gap: $kui-space-40; | ||
text-align: center; | ||
width: 100%; | ||
.entity-empty-state-title { | ||
color: $kui-color-text; | ||
font-size: $kui-font-size-70; | ||
font-weight: $kui-font-weight-bold; | ||
line-height: $kui-line-height-60; | ||
} | ||
} | ||
.entity-empty-state-description, .entity-empty-state-pricing { | ||
color: $kui-color-text-neutral-strong; | ||
font-size: $kui-font-size-30; | ||
font-weight: $kui-font-weight-regular; | ||
line-height: $kui-line-height-30; | ||
max-width: 640px; // limit width so the description stays readable if it is too long | ||
p { | ||
margin: $kui-space-30; | ||
} | ||
} | ||
.entity-empty-state-action { | ||
align-items: center; | ||
display: flex; | ||
gap: $kui-space-50; | ||
} | ||
.entity-empty-state-card-container { | ||
display: grid !important; | ||
gap: $kui-space-60; | ||
grid-template-columns: auto auto !important; | ||
.entity-empty-state-card { | ||
background-color: $kui-color-background-neutral-weakest; | ||
border: $kui-border-width-10 solid $kui-color-border; | ||
border-radius: $kui-border-radius-30; | ||
color: $kui-color-text-neutral-weak; | ||
gap: $kui-space-60; | ||
height: 160px; | ||
padding: $kui-space-80; | ||
width: 312px; | ||
:deep(.card-title) { | ||
font-size: $kui-font-size-30; | ||
font-weight: $kui-font-weight-semibold; | ||
} | ||
:deep(.card-content) { | ||
color: $kui-color-text-neutral; | ||
} | ||
} | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
packages/entities/entities-shared/src/types/entity-empty-state.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface EmptyStateFeature { | ||
iconVariant: string, | ||
title: string, | ||
description: string | ||
} |
Oops, something went wrong.