mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-03 04:27:53 +00:00
feat: Add the update design for the button component (#10257)
Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
19
.eslintrc.js
19
.eslintrc.js
@@ -12,6 +12,19 @@ module.exports = {
|
|||||||
'vitest-globals/env': true,
|
'vitest-globals/env': true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.story.vue'],
|
||||||
|
rules: {
|
||||||
|
'vue/no-undef-components': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignorePatterns: ['Variant', 'Story'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// Story files can have static strings, it doesn't need to handle i18n always.
|
||||||
|
'vue/no-bare-strings-in-template': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
plugins: ['html', 'prettier'],
|
plugins: ['html', 'prettier'],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
@@ -223,11 +236,5 @@ module.exports = {
|
|||||||
globals: {
|
globals: {
|
||||||
bus: true,
|
bus: true,
|
||||||
vi: true,
|
vi: true,
|
||||||
// beforeEach: true,
|
|
||||||
// afterEach: true,
|
|
||||||
// test: true,
|
|
||||||
// describe: true,
|
|
||||||
// it: true,
|
|
||||||
// expect: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
126
app/javascript/dashboard/components-next/button/Button.story.vue
Normal file
126
app/javascript/dashboard/components-next/button/Button.story.vue
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<script setup>
|
||||||
|
import Button from './Button.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Story title="Components/Button" :layout="{ type: 'grid', width: '400' }">
|
||||||
|
<Variant title="Default">
|
||||||
|
<div class="p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default Button" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Disabled">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Disabled" disabled />
|
||||||
|
<Button label="Disabled" variant="outline" disabled />
|
||||||
|
<Button label="Disabled" disabled icon="delete" variant="outline" />
|
||||||
|
<Button
|
||||||
|
label="Disabled"
|
||||||
|
disabled
|
||||||
|
icon="delete"
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Disabled"
|
||||||
|
disabled
|
||||||
|
icon="delete"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Disabled"
|
||||||
|
disabled
|
||||||
|
icon="delete"
|
||||||
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Disabled with icon">
|
||||||
|
<div class="p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Disabled Button" icon="emoji-add" disabled />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Different variant">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default" variant="default" />
|
||||||
|
<Button label="Destructive" variant="destructive" />
|
||||||
|
<Button label="Outline" variant="outline" />
|
||||||
|
<Button label="Secondary" variant="secondary" />
|
||||||
|
<Button label="Ghost" variant="ghost" />
|
||||||
|
<Button label="Link" variant="link" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Different variant with icon only">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button icon="emoji-add" variant="default" />
|
||||||
|
<Button icon="emoji-add" variant="destructive" />
|
||||||
|
<Button icon="emoji-add" variant="outline" />
|
||||||
|
<Button icon="emoji-add" variant="secondary" />
|
||||||
|
<Button icon="emoji-add" variant="ghost" />
|
||||||
|
<Button icon="emoji-add" variant="link" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Different size">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default" />
|
||||||
|
<Button label="Large" size="lg" />
|
||||||
|
<Button label="Small" size="sm" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Different text variant">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default" text-variant="default" variant="outline" />
|
||||||
|
<Button label="Success" text-variant="success" variant="outline" />
|
||||||
|
<Button label="Warning" text-variant="warning" variant="outline" />
|
||||||
|
<Button label="Danger" text-variant="danger" variant="outline" />
|
||||||
|
<Button label="Info" text-variant="info" variant="outline" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Button with left icon with different sizes and icon only">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default" icon="emoji-add" icon-position="left" />
|
||||||
|
<Button
|
||||||
|
label="Default LG"
|
||||||
|
icon="emoji-add"
|
||||||
|
icon-position="left"
|
||||||
|
size="lg"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Default SM"
|
||||||
|
icon="emoji-add"
|
||||||
|
icon-position="left"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<Button icon="emoji-add" size="icon" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Button with right icon with different sizes and icon only">
|
||||||
|
<div class="flex flex-wrap gap-2 p-4 bg-white dark:bg-slate-900">
|
||||||
|
<Button label="Default" icon="emoji-add" icon-position="right" />
|
||||||
|
<Button
|
||||||
|
label="Default LG"
|
||||||
|
icon="emoji-add"
|
||||||
|
icon-position="right"
|
||||||
|
size="lg"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Default SM"
|
||||||
|
icon="emoji-add"
|
||||||
|
icon-position="right"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<Button icon="emoji-add" size="icon" />
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
</Story>
|
||||||
|
</template>
|
||||||
130
app/javascript/dashboard/components-next/button/Button.vue
Normal file
130
app/javascript/dashboard/components-next/button/Button.vue
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
type: String,
|
||||||
|
default: 'default',
|
||||||
|
validator: value =>
|
||||||
|
[
|
||||||
|
'default',
|
||||||
|
'destructive',
|
||||||
|
'outline',
|
||||||
|
'secondary',
|
||||||
|
'ghost',
|
||||||
|
'link',
|
||||||
|
].includes(value),
|
||||||
|
},
|
||||||
|
textVariant: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
validator: value =>
|
||||||
|
['', 'default', 'success', 'warning', 'danger', 'info'].includes(value),
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'default',
|
||||||
|
validator: value => ['default', 'sm', 'lg', 'icon'].includes(value),
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
iconPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'left',
|
||||||
|
validator: value => ['left', 'right'].includes(value),
|
||||||
|
},
|
||||||
|
iconLib: {
|
||||||
|
type: String,
|
||||||
|
default: 'fluent',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['click']);
|
||||||
|
|
||||||
|
const buttonVariants = {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
'bg-woot-500 dark:bg-woot-500 text-white dark:text-white hover:bg-woot-600 dark:hover:bg-woot-600',
|
||||||
|
destructive:
|
||||||
|
'bg-ruby-700 dark:bg-ruby-700 text-white dark:text-white hover:bg-ruby-800 dark:hover:bg-ruby-800',
|
||||||
|
outline:
|
||||||
|
'border border-slate-200 dark:border-slate-700/50 hover:border-slate-300 dark:hover:border-slate-600',
|
||||||
|
secondary:
|
||||||
|
'bg-slate-50 text-slate-900 dark:bg-slate-700/50 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-600',
|
||||||
|
ghost:
|
||||||
|
'text-slate-900 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800',
|
||||||
|
link: 'text-woot-500 underline-offset-4 hover:underline dark:hover:underline',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: 'h-10 px-4 py-2',
|
||||||
|
sm: 'h-8 px-3',
|
||||||
|
lg: 'h-11 px-4',
|
||||||
|
icon: 'h-auto w-auto px-2',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
default:
|
||||||
|
'!text-woot-500 dark:!text-woot-500 hover:!text-woot-600 dark:hover:!text-woot-600',
|
||||||
|
success:
|
||||||
|
'!text-green-500 dark:!text-green-500 hover:!text-green-600 dark:hover:!text-green-600',
|
||||||
|
warning:
|
||||||
|
'!text-amber-600 dark:!text-amber-600 hover:!text-amber-600 dark:hover:!text-amber-600',
|
||||||
|
danger:
|
||||||
|
'!text-ruby-700 dark:!text-ruby-700 hover:!text-ruby-800 dark:hover:!text-ruby-800',
|
||||||
|
info: '!text-slate-500 dark:!text-slate-400 hover:!text-slate-600 dark:hover:!text-slate-500',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonClasses = computed(() => {
|
||||||
|
const classes = [
|
||||||
|
buttonVariants.variant[props.variant],
|
||||||
|
buttonVariants.size[props.size],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (props.textVariant && buttonVariants.text[props.textVariant]) {
|
||||||
|
classes.push(buttonVariants.text[props.textVariant]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes.join(' ');
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconSize = computed(() => {
|
||||||
|
if (props.size === 'sm') return 16;
|
||||||
|
if (props.size === 'lg') return 20;
|
||||||
|
return 18;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
emit('click');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
:class="buttonClasses"
|
||||||
|
class="inline-flex items-center justify-center h-10 min-w-0 gap-2 text-sm font-medium transition-all duration-200 ease-in-out rounded-lg disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<FluentIcon
|
||||||
|
v-if="icon && iconPosition === 'left'"
|
||||||
|
:icon="icon"
|
||||||
|
:size="iconSize"
|
||||||
|
:icon-lib="iconLib"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
/>
|
||||||
|
<span v-if="label" class="min-w-0 truncate">{{ label }}</span>
|
||||||
|
<FluentIcon
|
||||||
|
v-if="icon && iconPosition === 'right'"
|
||||||
|
:icon="icon"
|
||||||
|
:size="iconSize"
|
||||||
|
:icon-lib="iconLib"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user