Skip to content

Commit

Permalink
Refine stories of UAvatar, UIcon and UDataList components
Browse files Browse the repository at this point in the history
  • Loading branch information
KinduD21 committed Feb 21, 2025
1 parent c43f4ee commit 6f6c0b0
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 102 deletions.
31 changes: 17 additions & 14 deletions src/ui.data-list/UDataList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const {
deleteIconAttrs,
editIconAttrs,
dragIconAttrs,
dragIconWrapperAttrs,
} = useUI<Config>(defaultConfig);
</script>

Expand Down Expand Up @@ -159,20 +160,22 @@ const {
<template #item="{ element }">
<div :id="element[valueKey]" v-bind="itemWrapperAttrs" :data-test="getDataTest('item')">
<div v-bind="itemAttrs" :data-test="getDataTest(`item-${element[valueKey]}`)">
<!--
@slot Use it to add something instead of the drag icon.
@binding {object} item
@binding {string} icon-name
-->
<slot name="drag" :item="element" :icon-name="config.defaults.dragIcon">
<UIcon
internal
color="gray"
variant="light"
:name="config.defaults.dragIcon"
v-bind="dragIconAttrs"
/>
</slot>
<div v-bind="dragIconWrapperAttrs">
<!--
@slot Use it to add something instead of the drag icon.
@binding {object} item
@binding {string} icon-name
-->
<slot name="drag" :item="element" :icon-name="config.defaults.dragIcon">
<UIcon
internal
color="gray"
variant="light"
:name="config.defaults.dragIcon"
v-bind="dragIconAttrs"
/>
</slot>
</div>

<div v-bind="isActive(element) ? labelAttrs : labelCrossedAttrs">
<!--
Expand Down
1 change: 1 addition & 0 deletions src/ui.data-list/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default /*tw*/ {
},
},
},
dragIconWrapper: "icon-drag cursor-move",
dragIcon: "{UIcon} {>dataListIcon} icon-drag cursor-move opacity-100",
label: {
base: "font-normal flex-auto pt-px",
Expand Down
39 changes: 17 additions & 22 deletions src/ui.data-list/storybook/docs.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
import { Markdown, Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
import { getSource } from "../../utils/storybook.ts";

import * as stories from "./stories.ts";
Expand All @@ -13,28 +13,23 @@ import defaultConfig from "../config.ts?raw"
<Stories of={stories} />

## Configuring items in a list
You can configure any item in a list by passing the following params.
You can configure any item in a `list` array by passing the following params:

<Source code={`
<UDataList :list="list" />
const list = [
{
id: 1, // unique item identifier
label: "Rent", // item label
children: [ // nested items
{ label: "Office", id: 11 },
{ label: "Shops", id: 12, children: [...] }, // children of subitems
],
isHiddenEdit: true, // hide edit button
isHiddenDelete: true, // hide delete button
isHiddenActions: true, // hide default and custom action buttons
isHiddenCustomActions: true, // hide only custom action buttons
isDisabledNesting: true, // disable nesting for the item
}
{...}
];
`} language="jsx" dark />
<Markdown>
{`
| Key name | Description | Type |
| ----------------------| --------------------------------------- | ---------------|
| id | Unique item identifier | String, Number |
| label | Item label | String |
| children | Nested items | Array |
| isActive | Option value | Boolean |
| isHiddenActions | Hide default and custom action buttons | Boolean |
| isHiddenCustomActions | Hide only custom action buttons | Boolean |
| isHiddenDelete | Hide delete button | Boolean |
| isHiddenEdit | Hide edit button | Boolean |
| isDisabledNesting | Disable nesting for the item | Boolean |
`}
</Markdown>

## Default config
<Source code={getSource(defaultConfig)} language="jsx" dark />
128 changes: 105 additions & 23 deletions src/ui.data-list/storybook/stories.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ref } from "vue";
import {
getArgTypes,
getSlotNames,
Expand All @@ -9,12 +10,17 @@ import UDataList from "../../ui.data-list/UDataList.vue";
import UIcon from "../../ui.image-icon/UIcon.vue";
import UButton from "../../ui.button/UButton.vue";
import URow from "../../ui.container-row/URow.vue";
import UBadge from "../../ui.text-badge/UBadge.vue";
import UAvatar from "../../ui.image-avatar/UAvatar.vue";
import UHeader from "../../ui.text-header/UHeader.vue";
import ULoader from "../../ui.loader/ULoader.vue";

import type { Meta, StoryFn } from "@storybook/vue3";
import type { Props } from "../types.ts";
import type { Props, DataListItem } from "../types.ts";

interface UDataListArgs extends Props {
slotTemplate?: string;
enum: "size";
}

export default {
Expand All @@ -24,25 +30,31 @@ export default {
args: {
list: [
{
label: "Salary",
label: "Expenses",
id: 1,
children: [
{ label: "IT", id: 1.1 },
{ label: "HR", id: 1.2 },
{ label: "C Level", id: 1.3 },
{ label: "Office Supplies", id: 1.1 },
{ label: "Travel & Lodging", id: 1.2 },
{ label: "Utilities", id: 1.3 },
],
},
{
label: "Rent",
label: "Revenue Streams",
id: 2,
children: [
{ label: "Office", id: 2.1 },
{ label: "Shops", id: 2.2 },
{ label: "Product Sales", id: 2.1 },
{ label: "Subscription Services", id: 2.2 },
{ label: "Consulting", id: 2.3 },
],
},
{
label: "Marketing",
label: "Departments",
id: 3,
children: [
{ label: "Engineering", id: 3.1 },
{ label: "Marketing", id: 3.2 },
{ label: "Finance", id: 3.3 },
],
},
],
},
Expand All @@ -57,19 +69,59 @@ export default {
} as Meta;

const DefaultTemplate: StoryFn<UDataListArgs> = (args: UDataListArgs) => ({
components: { UDataList, UIcon, URow, UButton },
components: { UDataList, UIcon, URow, UButton, UBadge, UAvatar, ULoader, UHeader },
setup() {
const slots = getSlotNames(UDataList.__name);

return { args, slots };
const avatars = [
"https://cdn-icons-png.flaticon.com/128/1999/1999625.png",
"https://cdn-icons-png.flaticon.com/128/4140/4140057.png",
"https://cdn-icons-png.flaticon.com/128/4140/4140047.png",
];

const list = ref(
args.list?.map((item, index) => ({
...item,
id: item.id,
avatar: avatars[index % avatars.length],
})),
);

function removeItem(targetItem: DataListItem) {
list.value = list.value?.filter((listItem) => listItem.id !== targetItem.id);

return alert(`Removed item: ${JSON.stringify(targetItem, null, 2)}`);
}

function editItem(targetItem: DataListItem) {
alert(`Edit item: ${JSON.stringify(targetItem, null, 2)}`);
}

return { args, slots, removeItem, editItem, list };
},
template: `
<UDataList v-bind="args">
<UDataList v-bind="args" :list="args.slotTemplate ? list : args.list">
${args.slotTemplate || getSlotsFragment("")}
</UDataList>
`,
});

const EnumVariantTemplate: StoryFn<UDataListArgs> = (args: UDataListArgs, { argTypes }) => ({
components: { URow, UDataList, UHeader },
setup() {
return {
args,
options: argTypes?.[args.enum]?.options,
};
},
template: `
<div v-for="(option, index) in options" :key="index">
<UHeader :label="option" size="xs" />
<UDataList v-bind="args" :[args.enum]="option" class="mb-4" />
</div>
`,
});

export const Default = DefaultTemplate.bind({});
Default.args = {};

Expand All @@ -79,18 +131,43 @@ EmptyState.args = {
emptyTitle: "The list is empty.",
emptyDescription: "There is no data in the list.",
};
EmptyState.parameters = {
docs: {
description: {
story:
"The `emptyTitle` and `emptyDescription` props are used to display a message when the list is empty.",
},
},
};

export const Nesting = DefaultTemplate.bind({});
Nesting.args = { nesting: true };

export const Size = EnumVariantTemplate.bind({});
Size.args = { enum: "size" };

export const SlotLabel = DefaultTemplate.bind({});
SlotLabel.args = {
slotTemplate: `
<template #label="{ item }">
<URow gap="xs" align="center">
{{ item.label }}
<UIcon name="check" color="green" size="sm" />
</URow>
<UBadge :label="item.label" />
</template>
`,
};

export const SlotEmpty = DefaultTemplate.bind({});
SlotEmpty.args = {
list: [],
emptyTitle: "Fetching data...",
emptyDescription: "Please wait until data is received.",
config: {
wrapper: "flex flex-col items-center justify-center py-10 gap-4",
},
slotTemplate: `
<template #empty="{ emptyTitle, emptyDescription }">
<ULoader loading size="lg" />
<UHeader :label="emptyTitle" size="xs" />
<p>{{ emptyDescription }}</p>
</template>
`,
};
Expand All @@ -99,34 +176,39 @@ export const SlotActions = DefaultTemplate.bind({});
SlotActions.args = {
slotTemplate: `
<template #actions>
<UIcon interactive name="star" color="red" />
<UButton label="Export" size="xs" />
</template>
`,
};

export const SlotDrag = DefaultTemplate.bind({});
SlotDrag.args = {
list: [
{ label: "John Doe (Engineering)", id: 1 },
{ label: "Michael Johnson (Finance)", id: 2 },
{ label: "Emma Smith (Marketing)", id: 3 },
],
slotTemplate: `
<template #drag>
<UIcon interactive name="swap_vert" size="sm" />
<template #drag="{ item }">
<UAvatar :src="item.avatar" rounded="full" />
</template>
`,
};

export const SlotDelete = DefaultTemplate.bind({});
SlotDelete.args = {
slotTemplate: `
<template #delete>
<UButton label="Delete" size="xs" variant="secondary" color="red" />
<template #delete="{ item }">
<UButton label="Delete" size="xs" variant="secondary" color="red" @click="removeItem(item)" />
</template>
`,
};

export const SlotEdit = DefaultTemplate.bind({});
SlotEdit.args = {
slotTemplate: `
<template #edit>
<UButton label="Edit" size="xs" variant="secondary" color="grayscale" />
<template #edit="{ item }">
<UButton label="Edit" size="xs" variant="secondary" color="grayscale" @click="editItem(item)" />
</template>
`,
};
1 change: 0 additions & 1 deletion src/ui.form-input-rating/storybook/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default {
component: UInputRating,
args: {
modelValue: 2,
label: "Rate your experience: ",
},
argTypes: {
...getArgTypes(UInputRating.__name),
Expand Down
Loading

0 comments on commit 6f6c0b0

Please sign in to comment.