mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-25 01:06:15 -04:00
refactor(ui): getting ride of naive ui buttons
This commit is contained in:
parent
df989e24b3
commit
c45bce36f9
44 changed files with 738 additions and 204 deletions
240
src/ui/c-button/c-button.theme.ts
Normal file
240
src/ui/c-button/c-button.theme.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
113
src/ui/c-button/c-button.vue
Normal file
113
src/ui/c-button/c-button.vue
Normal 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>
|
39
src/ui/c-link/c-link.theme.ts
Normal file
39
src/ui/c-link/c-link.theme.ts
Normal 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
49
src/ui/c-link/c-link.vue
Normal 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>
|
13
src/ui/theme/theme.models.ts
Normal file
13
src/ui/theme/theme.models.ts
Normal 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]);
|
||||
},
|
||||
};
|
||||
}
|
20
src/ui/theme/theme.store.ts
Normal file
20
src/ui/theme/theme.store.ts
Normal 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
37
src/ui/theme/themes.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue