Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
7 changes: 7 additions & 0 deletions .changeset/blue-dryers-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@storefront-ui/react': minor
'@storefront-ui/vue': minor
'@storefront-ui/shared': minor
---

Added SfBadge component in react and vue
97 changes: 97 additions & 0 deletions apps/docs/components/components/badge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
layout: AtomLayout
hideBreadcrumbs: true
---

# Badge

::: slot usage

## Examples

### Basic usage

The badge component must be wrapped with a container that has `class="relative"`. You must provide such a container by yourself, but it gives you the flexibility to put the badge wherever you want. Bagde comes with a "dot" variant, which hides the content. When given content is of type number (or string that could be parsed to number), you can set a maximum limit of that number using `max` prop.

<Showcase showcase-name="Badge/BadgeBasic">
<!-- vue -->
<<<../../preview/nuxt/pages/showcases/Badge/BadgeBasic.vue
<!-- end vue -->
<!-- react -->
<<<../../preview/next/pages/showcases/Badge/BadgeBasic.tsx#source
<!-- end react -->
</Showcase>

### Placement

You can align the Badge in every corner of the container.

<Showcase showcase-name="Badge/BadgePlacement">
<!-- vue -->
<<<../../preview/nuxt/pages/showcases/Badge/BadgePlacement.vue
<!-- end vue -->
<!-- react -->
<<<../../preview/next/pages/showcases/Badge/BadgePlacement.tsx#source
<!-- end react -->
</Showcase>

### Custom outline

A nifty effect that makes the Badge a bit more attractive is to add an outline that separates the Badge from an element.

<Showcase showcase-name="Badge/BadgeOutline">
<!-- vue -->
<<<../../preview/nuxt/pages/showcases/Badge/BadgeOutline.vue
<!-- end vue -->
<!-- react -->
<<<../../preview/next/pages/showcases/Badge/BadgeOutline.tsx#source
<!-- end react -->
</Showcase>

### Avatars

A common use case for the Badge is to place it on a user's avatar.

<Showcase showcase-name="Badge/BadgeAvatar">
<!-- vue -->
<<<../../preview/nuxt/pages/showcases/Badge/BadgeAvatar.vue
<!-- end vue -->
<!-- react -->
<<<../../preview/next/pages/showcases/Badge/BadgeAvatar.tsx#source
<!-- end react -->
</Showcase>

## Playground

<Generate style="height: 380px" />

:::

::: slot api

## Props

| Prop name | Type | Default value | Possible values |
| ----------- | ------------------ | ------------- | ------------------------------------------------------ |
| `content` | `string | number` | |
Comment thread
aniamusial marked this conversation as resolved.
| `max` | `number` | `99` | |
| `placement` | `SfBadgePlacement` | `top-right` | `top-right`, `top-left`, `bottom-right`, `bottom-left` |
| `variant` | `SfBadgeVariant` | `standard` | `standard`, `dot` |

:::

::: slot source
<SourceCode>

<!-- vue -->

<<<../../../packages/sfui/frameworks/vue/components/SfBadge/SfBadge.vue

<!-- end vue -->
<!-- react -->

<<<../../../packages/sfui/frameworks/react/components/SfBadge/SfBadge.tsx

<!-- end react -->
</SourceCode>
:::
58 changes: 58 additions & 0 deletions apps/preview/next/pages/examples/SfBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { SfBadge, SfButton, SfIconShoppingCart, SfBadgePlacement, SfBadgeVariant } from '@storefront-ui/react';
import { prepareControls } from '../../components/utils/Controls';
import ComponentExample from '../../components/utils/ComponentExample';
import { ExamplePageLayout } from '../examples';

function Example() {
const { state, controls } = prepareControls(
[
{
type: 'text',
modelName: 'content',
description: 'Content to display in the badge.',
propType: 'string | number',
},
{
type: 'text',
modelName: 'max',
description: 'Maximum number of counter to show.',
propType: 'number',
propDefaultValue: '99',
},
{
type: 'select',
modelName: 'variant',
description: 'Badge can have content or be a simple dot.',
options: Object.values(SfBadgeVariant),
propType: 'SfBadgeVariant',
propDefaultValue: 'standard',
},
{
type: 'select',
modelName: 'placement',
description: 'Position of the badge relatively to a container.',
options: Object.values(SfBadgePlacement),
propType: 'SfBadgePlacement',
propDefaultValue: 'top-right',
},
],
{
content: '1',
max: 99,
variant: SfBadgeVariant.standard,
placement: SfBadgePlacement['top-right'],
},
);

return (
<ComponentExample controls={{ state, controls }}>
<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge {...state.get} max={Number(state.get.max)} />
</SfButton>
</ComponentExample>
);
}

Example.getLayout = ExamplePageLayout;
export default Example;
25 changes: 25 additions & 0 deletions apps/preview/next/pages/showcases/Badge/BadgeAvatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ShowcasePageLayout } from '../../showcases';
// #region source
import { SfBadge } from '@storefront-ui/react';

export default function BadgeAvatar() {
return (
<ul>
<li className="flex items-center mb-2">
<div className="relative">
<img src="http://localhost:3100/@assets/woman_avatar.png" alt="Avatar of a woman" width={36} height={36} />
<SfBadge variant="dot" placement="bottom-right" className="!bg-primary-600 outline outline-white" />
</div>
</li>
<li className="flex items-center">
<div className="relative">
<img src="http://localhost:3100/@assets/woman_avatar.png" alt="Avatar of a woman" width={36} height={36} />
<SfBadge variant="dot" placement="bottom-right" className="!bg-neutral-600 outline outline-white" />
</div>
</li>
</ul>
);
}

// #endregion source
BadgeAvatar.getLayout = ShowcasePageLayout;
32 changes: 32 additions & 0 deletions apps/preview/next/pages/showcases/Badge/BadgeBasic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ShowcasePageLayout } from '../../showcases';
// #region source
import { SfBadge, SfButton, SfIconShoppingCart } from '@storefront-ui/react';

export default function BadgeBasic() {
return (
<div className="flex gap-3">
<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={10} />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={10000} />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content="New" />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge variant="dot" />
</SfButton>
</div>
);
}

// #endregion source
BadgeBasic.getLayout = ShowcasePageLayout;
34 changes: 34 additions & 0 deletions apps/preview/next/pages/showcases/Badge/BadgeOutline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ShowcasePageLayout } from '../../showcases';
// #region source
import { SfBadge, SfButton, SfIconShoppingCart } from '@storefront-ui/react';

export default function BadgeOutline() {
return (
<div className="flex gap-3">
<div className="p-3 bg-white">
<SfButton className="group relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge
content={100}
max={99}
className="outline outline-white group-hover:outline-primary-100 group-active:outline-primary-200"
/>
</SfButton>
</div>

<div className="p-3 bg-primary-700">
<SfButton className="group relative hover:bg-primary-800 active:bg-primary-900" square variant="tertiary">
<SfIconShoppingCart className="text-white" />
<SfBadge
content={100}
max={99}
className="outline outline-primary-700 bg-white !text-neutral-900 group-hover:outline-primary-800 group-active:outline-primary-900"
/>
</SfButton>
</div>
</div>
);
}

// #endregion source
BadgeOutline.getLayout = ShowcasePageLayout;
32 changes: 32 additions & 0 deletions apps/preview/next/pages/showcases/Badge/BadgePlacement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ShowcasePageLayout } from '../../showcases';
// #region source
import { SfBadge, SfButton, SfIconShoppingCart } from '@storefront-ui/react';

export default function BadgePlacement() {
return (
<div className="flex gap-3">
<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={100} max={99} placement="top-right" />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={100} max={99} placement="bottom-right" />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={100} max={99} placement="top-left" />
</SfButton>

<SfButton className="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge content={100} max={99} placement="bottom-left" />
</SfButton>
</div>
);
}

// #endregion source
BadgePlacement.getLayout = ShowcasePageLayout;
68 changes: 68 additions & 0 deletions apps/preview/nuxt/pages/examples/SfBadge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<ComponentExample :controls-attrs="controlsAttrs">
<SfButton class="relative" square variant="tertiary">
<SfIconShoppingCart />
<SfBadge v-bind="state" :max="Number(state.max)" />
</SfButton>
</ComponentExample>
</template>

<script lang="ts">
import { ref } from 'vue';
import { SfBadge, SfBadgePlacement, SfBadgeVariant, SfButton, SfIconShoppingCart } from '@storefront-ui/vue';
import { prepareControls } from '../../components/utils/Controls.vue';
import ComponentExample from '../../components/utils/ComponentExample.vue';

export default {
name: 'SfBadgeExample',
components: {
ComponentExample,
SfBadge,
SfButton,
SfIconShoppingCart,
},
setup() {
return {
...prepareControls(
[
{
type: 'text',
modelName: 'content',
description: 'Content to display in the badge.',
propType: 'string | number',
},
{
type: 'text',
modelName: 'max',
description: 'Maximum number of counter to show.',
propType: 'number',
propDefaultValue: '99',
},
{
type: 'select',
modelName: 'variant',
description: 'Badge can have content or be a simple dot.',
options: Object.values(SfBadgeVariant),
propType: 'SfBadgeVariant',
propDefaultValue: 'standard',
},
{
type: 'select',
modelName: 'placement',
description: 'Position of the badge relatively to a container.',
options: Object.values(SfBadgePlacement),
propType: 'SfBadgePlacement',
propDefaultValue: 'top-right',
},
],
{
content: ref('1'),
max: ref(99),
variant: ref(SfBadgeVariant.standard),
placement: ref(SfBadgePlacement['top-right']),
},
),
};
},
};
</script>
20 changes: 20 additions & 0 deletions apps/preview/nuxt/pages/showcases/Badge/BadgeAvatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<ul>
<li class="flex items-center mb-2">
<div class="relative">
<img src="http://localhost:3100/@assets/woman_avatar.png" alt="Avatar of a woman" :width="36" :height="36" />
<SfBadge variant="dot" placement="bottom-right" class="!bg-primary-600 outline outline-white" />
</div>
</li>
<li class="flex items-center">
<div class="relative">
<img src="http://localhost:3100/@assets/woman_avatar.png" alt="Avatar of a woman" :width="36" :height="36" />
<SfBadge variant="dot" placement="bottom-right" class="!bg-neutral-600 outline outline-white" />
</div>
</li>
</ul>
</template>

<script lang="ts" setup>
import { SfBadge } from '@storefront-ui/vue';
</script>
Loading