refactor(ui): getting ride of naive ui buttons

This commit is contained in:
Corentin Thomasset 2023-04-19 21:38:59 +02:00 committed by Corentin THOMASSET
parent df989e24b3
commit c45bce36f9
44 changed files with 738 additions and 204 deletions

View file

@ -0,0 +1,240 @@
import { defineThemes } from '../theme/theme.models';
import { appThemes } from '../theme/themes';
export const { useTheme } = defineThemes({
dark: {
basic: {
default: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.12)',
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.24)',
},
outline: {
color: appThemes.dark.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorPressed,
},
outline: {
color: appThemes.dark.warning.color,
},
},
},
text: {
default: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.12)',
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.82)',
},
outline: {
color: appThemes.dark.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorPressed,
},
outline: {
color: appThemes.dark.warning.color,
},
},
},
},
light: {
basic: {
default: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.05)',
hover: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.22)',
},
outline: {
color: appThemes.light.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.colorPressed,
},
outline: {
color: appThemes.light.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.colorPressed,
},
outline: {
color: appThemes.light.warning.color,
},
},
},
text: {
default: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.primary.color,
},
},
primary: {
textColor: appThemes.light.primary.color,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.primary.colorHover,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.primary.colorPressed,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.primary.color,
},
},
warning: {
textColor: appThemes.light.warning.color,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.warning.colorHover,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.warning.colorPressed,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.warning.color,
},
},
},
},
});

View file

@ -0,0 +1,113 @@
<template>
<component
:is="tag"
:href="href ?? to"
class="c-button"
:class="{ disabled, round, circle }"
:to="to"
@click="handleClick"
>
<slot />
</component>
</template>
<script lang="ts" setup>
import type { RouteLocationRaw } from 'vue-router';
import { useTheme } from './c-button.theme';
const props = withDefaults(
defineProps<{
type?: 'default' | 'primary';
variant?: 'basic' | 'text';
disabled?: boolean;
round?: boolean;
circle?: boolean;
href?: string;
to?: RouteLocationRaw;
}>(),
{
type: 'default',
variant: 'basic',
disabled: false,
round: false,
circle: false,
href: undefined,
to: undefined,
},
);
const { variant, disabled, round, circle, href, type, to } = toRefs(props);
const emits = defineEmits(['click']);
function handleClick(event: MouseEvent) {
if (!disabled.value) {
emits('click', event);
}
}
const theme = useTheme();
const variantTheme = computed(() => theme.value[variant.value][type.value]);
const tag = computed(() => {
if (href.value) {
return 'a';
}
if (to.value) {
return 'router-link';
}
return 'button';
});
</script>
<style lang="less" scoped>
.c-button {
margin: 0;
line-height: 1;
font-family: inherit;
font-size: inherit;
border: none;
text-align: center;
cursor: pointer;
text-decoration: none;
height: 34px;
font-weight: 400;
color: v-bind('variantTheme.textColor');
padding: 0 14px;
border-radius: 4px;
transition: background-color cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
background-color: v-bind('variantTheme.backgroundColor');
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
// outline-offset: 1px;
&.round {
border-radius: 100px;
}
&.circle {
border-radius: 40px;
width: 34px;
}
&:not(.disabled) {
&:hover {
background-color: v-bind('variantTheme.hover.backgroundColor');
}
&:active {
background-color: v-bind('variantTheme.pressed.backgroundColor');
}
}
&:focus {
outline: 2px solid v-bind('variantTheme.outline.color');
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
</style>

View file

@ -0,0 +1,39 @@
import { defineThemes } from '../theme/theme.models';
import { appThemes } from '../theme/themes';
export const { useTheme } = defineThemes({
dark: {
default: {
textColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
},
light: {
default: {
textColor: appThemes.light.primary.color,
hover: {
textColor: appThemes.light.primary.colorHover,
},
pressed: {
textColor: appThemes.light.primary.colorPressed,
},
outline: {
color: appThemes.light.primary.color,
},
},
},
});

49
src/ui/c-link/c-link.vue Normal file
View file

@ -0,0 +1,49 @@
<template>
<component :is="tag" :href="href ?? to" class="c-link" :to="to">
<slot />
</component>
</template>
<script lang="ts" setup>
import { RouterLink, type RouteLocationRaw } from 'vue-router';
import { useTheme } from './c-link.theme';
const props = defineProps<{
href?: string;
to?: RouteLocationRaw;
}>();
const { href, to } = toRefs(props);
const theme = useTheme();
const tag = computed(() => (href?.value ? 'a' : RouterLink));
</script>
<style lang="less" scoped>
.c-link {
line-height: inherit;
font-family: inherit;
font-size: inherit;
border: none;
cursor: pointer;
text-decoration: none;
font-weight: 400;
color: v-bind('theme.default.textColor');
border-radius: 4px;
transition: color cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
outline-offset: 1px;
&:hover {
color: v-bind('theme.default.hover.textColor');
}
&:active {
color: v-bind('theme.default.textColor');
}
&:focus {
color: v-bind('theme.default.outline.color');
}
}
</style>

View file

@ -0,0 +1,13 @@
import { useThemeStore } from './theme.store';
export { defineThemes };
function defineThemes<Theme>(themes: { light: Theme; dark: Theme }) {
return {
themes,
useTheme() {
const themeStore = useThemeStore();
return computed(() => themes[themeStore.themeType]);
},
};
}

View file

@ -0,0 +1,20 @@
import { defineStore } from 'pinia';
export const useThemeStore = defineStore('ui-theme', {
state: () => ({
themeType: useStorage<'dark' | 'light'>('ui-store:theme-type', 'dark') as Ref<'dark' | 'light'>,
}),
getters: {
isDarkTheme(): boolean {
return this.themeType === 'dark';
},
isLightTheme(): boolean {
return this.themeType === 'light';
},
},
actions: {
toggleTheme() {
this.themeType = this.isDarkTheme ? 'light' : 'dark';
},
},
});

37
src/ui/theme/themes.ts Normal file
View file

@ -0,0 +1,37 @@
import { defineThemes } from './theme.models';
export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({
light: {
text: {
baseColor: 'rgb(51, 54, 57)',
},
primary: {
color: '#18a058',
colorHover: '#1ea54c',
colorPressed: '#0C7A43',
},
warning: {
color: '#f59e0b',
colorHover: '#f59e0b',
colorPressed: '#f59e0b',
},
},
dark: {
text: {
baseColor: 'rgba(255, 255, 255, 0.82)',
},
primary: {
color: '#1ea54c',
colorHover: '#36AD6A',
colorPressed: '#0C7A43',
},
warning: {
color: '#f59e0b',
colorHover: '#f59e0b',
colorPressed: '#f59e0b',
},
},
});