diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 20e4a7e..840fc87 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -2,6 +2,7 @@ import type { Preview, VueRenderer } from '@storybook/vue3' import { withThemeByClassName } from '@storybook/addon-themes' import '../src/main.css' +import './storybook.css' const preview: Preview = { parameters: { diff --git a/.storybook/storybook.css b/.storybook/storybook.css new file mode 100644 index 0000000..e5a4660 --- /dev/null +++ b/.storybook/storybook.css @@ -0,0 +1,9 @@ +.sb-show-main.sb-main-padded { + /* remove default padding from component area */ + padding: 0; +} + +#storybook-root { + /* set background color according to theme */ + @apply h-screen bg-gray-50 dark:bg-gray-900; +} diff --git a/src/components/NeCard.vue b/src/components/NeCard.vue new file mode 100644 index 0000000..2711e5c --- /dev/null +++ b/src/components/NeCard.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/components/NeDropdown.vue b/src/components/NeDropdown.vue new file mode 100644 index 0000000..bb52f03 --- /dev/null +++ b/src/components/NeDropdown.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/main.ts b/src/main.ts index 26e8225..7bb2ff1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,6 +22,8 @@ export { default as NeTableBody } from '@/components/NeTableBody.vue' export { default as NeTableRow } from '@/components/NeTableRow.vue' export { default as NeTableCell } from '@/components/NeTableCell.vue' export { default as NeCombobox } from '@/components/NeCombobox.vue' +export { default as NeDropdown } from '@/components/NeDropdown.vue' +export { default as NeCard } from '@/components/NeCard.vue' // types export type { NeComboboxOption } from '@/components/NeCombobox.vue' diff --git a/stories/NeCard.stories.ts b/stories/NeCard.stories.ts new file mode 100644 index 0000000..6356b06 --- /dev/null +++ b/stories/NeCard.stories.ts @@ -0,0 +1,222 @@ +// Copyright (C) 2024 Nethesis S.r.l. +// SPDX-License-Identifier: GPL-3.0-or-later + +import type { Meta, StoryObj } from '@storybook/vue3' +import { NeCard, NeTooltip, NeButton } from '../src/main' +import { faHeart } from '@fortawesome/free-solid-svg-icons' +import { library } from '@fortawesome/fontawesome-svg-core' + +library.add(faHeart) + +const meta = { + title: 'Visual/NeCard', + component: NeCard, + tags: ['autodocs'], + args: { + title: 'Card title', + description: '', + icon: [], + loading: false, + skeletonLines: 4, + errorTitle: '', + errorDescription: '', + menuItems: [], + alternateBackground: false + } +} satisfies Meta + +export default meta +type Story = StoryObj + +const defaultTemplate = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' + +export const Default: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: {} +} + +const titleSlotTemplate = ` + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +` + +export const TitleSlot: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: titleSlotTemplate + }), + args: { title: '' } +} + +export const WithDescription: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: { description: 'Card description' } +} + +export const WithIcon: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: { icon: ['fas', 'heart'] } +} + +export const Loading: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: { loading: true } +} + +export const Error: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: { + errorTitle: 'Cannot retrieve data', + errorDescription: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' + } +} + +const templateWithTooltip = + '\ + \ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\ + ' + +export const WithTooltip: Story = { + render: (args) => ({ + components: { NeCard, NeTooltip }, + setup() { + return { args } + }, + template: templateWithTooltip + }), + args: {} +} + +export const WithMenu: Story = { + render: (args) => ({ + components: { NeCard }, + setup() { + return { args } + }, + template: defaultTemplate + }), + args: { + menuItems: [ + { + id: 'edit', + label: 'Edit' + }, + { + id: 'delete', + label: 'Delete', + danger: true + } + ] + } +} + +const templateWithTopRightSlot = ` + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +` + +export const WithTopRightSlot: Story = { + render: (args) => ({ + components: { NeCard, NeButton }, + setup() { + return { args } + }, + template: templateWithTopRightSlot + }), + args: {} +} + +export const WithMenuAndTopRightSlot: Story = { + render: (args) => ({ + components: { NeCard, NeButton }, + setup() { + return { args } + }, + template: templateWithTopRightSlot + }), + args: { + menuItems: [ + { + id: 'edit', + label: 'Edit' + }, + { + id: 'delete', + label: 'Delete', + danger: true + } + ] + } +} + +const alternateBackgroundTemplate = ` +
+
+ Alternate background is useful to get contrast when the card is placed in a container with the same background as the default card background +
+ + Card with default background + + + Card with alternate background + +
` + +export const AlternateBackground: Story = { + render: (args) => ({ + components: { NeCard, NeButton }, + setup() { + return { args } + }, + template: alternateBackgroundTemplate + }), + args: { + alternateBackground: true + } +} diff --git a/stories/NeDropdown.stories.ts b/stories/NeDropdown.stories.ts new file mode 100644 index 0000000..8518641 --- /dev/null +++ b/stories/NeDropdown.stories.ts @@ -0,0 +1,116 @@ +// Copyright (C) 2024 Nethesis S.r.l. +// SPDX-License-Identifier: GPL-3.0-or-later + +import type { Meta, StoryObj } from '@storybook/vue3' + +import { NeDropdown, NeButton } from '../src/main' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faPenToSquare as fasPenToSquare } from '@fortawesome/free-solid-svg-icons' +import { faFloppyDisk as fasFloppyDisk } from '@fortawesome/free-solid-svg-icons' +import { faTrashCan as fasTrashCan } from '@fortawesome/free-solid-svg-icons' +import { faCopy as fasCopy } from '@fortawesome/free-solid-svg-icons' +import { faChevronDown as fasChevronDown } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' + +library.add(fasPenToSquare) +library.add(fasFloppyDisk) +library.add(fasTrashCan) +library.add(fasCopy) +library.add(fasChevronDown) + +const meta = { + title: 'Visual/NeDropdown', + component: NeDropdown, + tags: ['autodocs'], + args: { + items: [ + { + id: 'edit', + label: 'Edit', + icon: 'pen-to-square', + iconStyle: 'fas', + action: () => {} + }, + { + id: 'copy', + label: 'Copy', + icon: 'copy', + iconStyle: 'fas', + action: () => {} + }, + { + id: 'save', + label: 'Save', + icon: 'floppy-disk', + iconStyle: 'fas', + action: () => {}, + disabled: true + }, + { + id: 'divider1' + }, + { + id: 'delete', + label: 'Delete', + icon: 'trash-can', + iconStyle: 'fas', + danger: true, + action: () => {} + } + ], + alignToRight: false, + openMenuAriaLabel: 'Open menu' + } +} satisfies Meta + +export default meta +type Story = StoryObj + +const template = '' + +export const Default: Story = { + render: (args) => ({ + components: { NeDropdown }, + setup() { + return { args } + }, + template: template + }), + args: {} +} + +const alignToRightTemplate = '' + +export const AlignToRight: Story = { + render: (args) => ({ + components: { NeDropdown }, + setup() { + return { args } + }, + template: alignToRightTemplate + }), + args: { alignToRight: true } +} + +const withSlotTemplate = + '\ + \ + ' + +export const WithSlot: Story = { + render: (args) => ({ + components: { NeDropdown, NeButton, FontAwesomeIcon }, + setup() { + return { args } + }, + template: withSlotTemplate + }), + args: {} +}