diff options
author | 2023-04-19 21:38:59 +0200 | |
---|---|---|
committer | 2023-04-19 22:33:22 +0200 | |
commit | c45bce36f985a550d7bfad744099b601cb61e449 (patch) | |
tree | 2c5e186db857776a06879dce7529b5396de214b1 /src/ui | |
parent | df989e24b3937876f094301e33762677d604888a (diff) | |
download | it-tools-c45bce36f985a550d7bfad744099b601cb61e449.tar.gz it-tools-c45bce36f985a550d7bfad744099b601cb61e449.tar.zst it-tools-c45bce36f985a550d7bfad744099b601cb61e449.zip |
refactor(ui): getting ride of naive ui buttons
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/c-button/c-button.theme.ts | 240 | ||||
-rw-r--r-- | src/ui/c-button/c-button.vue | 113 | ||||
-rw-r--r-- | src/ui/c-link/c-link.theme.ts | 39 | ||||
-rw-r--r-- | src/ui/c-link/c-link.vue | 49 | ||||
-rw-r--r-- | src/ui/theme/theme.models.ts | 13 | ||||
-rw-r--r-- | src/ui/theme/theme.store.ts | 20 | ||||
-rw-r--r-- | src/ui/theme/themes.ts | 37 |
7 files changed, 511 insertions, 0 deletions
diff --git a/src/ui/c-button/c-button.theme.ts b/src/ui/c-button/c-button.theme.ts new file mode 100644 index 0000000..2f25e6f --- /dev/null +++ b/src/ui/c-button/c-button.theme.ts @@ -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, + }, + }, + }, + }, +}); diff --git a/src/ui/c-button/c-button.vue b/src/ui/c-button/c-button.vue new file mode 100644 index 0000000..a179cc2 --- /dev/null +++ b/src/ui/c-button/c-button.vue @@ -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> diff --git a/src/ui/c-link/c-link.theme.ts b/src/ui/c-link/c-link.theme.ts new file mode 100644 index 0000000..2d90bc0 --- /dev/null +++ b/src/ui/c-link/c-link.theme.ts @@ -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, + }, + }, + }, +}); diff --git a/src/ui/c-link/c-link.vue b/src/ui/c-link/c-link.vue new file mode 100644 index 0000000..df10120 --- /dev/null +++ b/src/ui/c-link/c-link.vue @@ -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> diff --git a/src/ui/theme/theme.models.ts b/src/ui/theme/theme.models.ts new file mode 100644 index 0000000..850afe9 --- /dev/null +++ b/src/ui/theme/theme.models.ts @@ -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]); + }, + }; +} diff --git a/src/ui/theme/theme.store.ts b/src/ui/theme/theme.store.ts new file mode 100644 index 0000000..e2457fc --- /dev/null +++ b/src/ui/theme/theme.store.ts @@ -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'; + }, + }, +}); diff --git a/src/ui/theme/themes.ts b/src/ui/theme/themes.ts new file mode 100644 index 0000000..94c87f6 --- /dev/null +++ b/src/ui/theme/themes.ts @@ -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', + }, + }, +}); |