Skip to content

Commit

Permalink
feat: adds the badge components
Browse files Browse the repository at this point in the history
  • Loading branch information
gokh4nozturk authored and Gökhan Öztürk committed Sep 12, 2022
1 parent d52bc8a commit 268501f
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 0 deletions.
132 changes: 132 additions & 0 deletions src/components/Badge/Badge.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';

import Badge from './Badge.vue';
import Icon from '../Icon/Icon.vue';
import IconList from '../Shared/IconList.js';
export const icons = [null, ...Object.keys(IconList.solid)];

export const defaultArgs = {
placement: {
control: {
type: 'select',
options: ['right', 'bottom', 'left'],
},
defaultValue: 'right',
},
bgColor: {
control: {
type: 'color',
},
defaultValue: '#2dd4bf',
},
size: {
control: {
type: 'select',
options: ['small', 'medium', 'large'],
},
defaultValue: 'medium',
},
square: {
control: {
type: 'boolean',
},
defaultValue: false,
},
overlap: {
control: {
type: 'boolean',
},
defaultValue: false,
},
hover: {
control: {
type: 'boolean',
},
defaultValue: false,
},
icon: {
control: {
type: 'select',
options: icons,
},
defaultValue: icons[0],
},
color: {
control: {
type: 'color',
},
defaultValue: '#000',
},
content: {
control: {
type: 'text',
},
defaultValue: '',
},
onClick: {
action: 'click',
},
};

<Meta
title="Components/Badge"
component={Badge}
argTypes={{ ...defaultArgs }}
/>

export const Default = (args) => ({
components: { Badge, Icon },
setup() {
return { args };
},
template: `
<Badge v-bind="args">
<Icon name="CubeIcon" size="24" />
</Badge>
`,
});

# Badges

<Canvas>
<Story
name="Right"
argTypes={{ ...Default.argTypes }}
args={{ placement: 'right' }}
>
{Default.bind({})}
</Story>
<Story
name="Left"
argTypes={{ ...Default.argTypes }}
args={{ placement: 'left' }}
>
{Default.bind({})}
</Story>
<Story
name="Bottom"
argTypes={{ ...Default.argTypes }}
args={{ placement: 'bottom' }}
>
{Default.bind({})}
</Story>
<Story name="Hover" argTypes={{ ...Default.argTypes }} args={{ hover: true }}>
{Default.bind({})}
</Story>
<Story
name="With Icon"
argTypes={{ ...Default.argTypes }}
args={{ icon: 'XCircleIcon' }}
>
{Default.bind({})}
</Story>
<Story
name="With Content"
argTypes={{ ...Default.argTypes }}
args={{ content: '1' }}
>
{Default.bind({})}
</Story>
</Canvas>

<ArgsTable story="Right" />
71 changes: 71 additions & 0 deletions src/components/Badge/Badge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script setup lang="ts">
import './badge.css';
import { defineProps, defineEmits, computed } from 'vue';
import Icon from '../Icon/Icon.vue';
export interface BadgeProps {
placement?: 'right' | 'bottom' | 'left';
bgColor?: string;
color?: string;
size?: 'small' | 'medium' | 'large';
square?: boolean;
overlap?: boolean;
hover?: boolean;
icon?: string;
content?: string | number;
}
const props = withDefaults(defineProps<BadgeProps>(), {
placement: 'right',
bgColor: '#2dd4bf',
color: '#fff',
size: 'medium',
square: false,
overlap: false,
hover: false,
icon: '',
content: '',
});
const emit = defineEmits(['click']);
const classes = computed(() => {
return {
badge: true,
badge__content: props.content,
[`badge__content--${props.size}`]: props.size,
[`badge--${props.placement}`]: props.placement,
[`badge--${props.bgColor}`]: props.bgColor,
[`badge--${props.size}`]: props.size,
'badge--overlap': props.overlap,
'badge--square': props.square,
'badge--hover': props.hover,
};
});
const styles = computed(() => {
return {
backgroundColor: props.bgColor,
color: props.color,
};
});
const iconSize = computed(() => {
return {
small: '10px',
medium: '12px',
large: '14px',
}[props.size];
});
const onClick = () => emit('click');
</script>
<template>
<div class="wrapper group">
<div v-if="!props.icon" :style="styles" :class="classes" @click="onClick">
{{ props.content }}
</div>
<Icon
:name="`${props.icon}`"
:class="classes"
:color="props.color"
:size="iconSize"
@click="onClick"
/>
<slot />
</div>
</template>
53 changes: 53 additions & 0 deletions src/components/Badge/badge.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@tailwind components;

.wrapper {
@apply font-sans relative max-w-max p-2;
}

.badge {
@apply h-3 w-3 absolute z-50 rounded-full;
}

.badge--right {
@apply top-0 right-0;
}

.badge--left {
@apply top-0 left-0;
}

.badge--bottom {
@apply right-0 bottom-0;
}

.badge--overlap {
@apply top-1 right-1;
}

.badge--square {
@apply rounded-none;
}

.badge--hover {
@apply opacity-0 group-hover:opacity-100 transition-opacity duration-300;
}

.badge__content {
@apply grid place-items-center leading-none text-xs text-white font-bold h-3.5 w-3.5;
}

.badge--small {
@apply h-2 w-2;
}

.badge__content--small {
font-size: 8px;
}

.badge--large {
@apply h-4 w-4;
}

.badge__content--large {
font-size: 1rem;
}
22 changes: 22 additions & 0 deletions src/components/Badge/badge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';

import { mount } from '@vue/test-utils';
import Badge from './Badge.vue';

describe('Badge', () => {
it('renders properly', () => {
const wrapper = mount(Badge, {
props: {
placement: 'right',
size: 'small',
content: '1',
},
});
console.log();

expect(wrapper.element.classList.contains('badge'));
expect(wrapper.element.classList.contains('badge--right'));
expect(wrapper.element.classList.contains('badge--small'));
expect(wrapper.element.innerHTML.includes('1'));
});
});

0 comments on commit 268501f

Please # to comment.