aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorGravatar Corentin Thomasset <corentin.thomasset74@gmail.com> 2023-04-19 21:38:59 +0200
committerGravatar Corentin THOMASSET <corentin.thomasset74@gmail.com> 2023-04-19 22:33:22 +0200
commitc45bce36f985a550d7bfad744099b601cb61e449 (patch)
tree2c5e186db857776a06879dce7529b5396de214b1 /src/ui
parentdf989e24b3937876f094301e33762677d604888a (diff)
downloadit-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.ts240
-rw-r--r--src/ui/c-button/c-button.vue113
-rw-r--r--src/ui/c-link/c-link.theme.ts39
-rw-r--r--src/ui/c-link/c-link.vue49
-rw-r--r--src/ui/theme/theme.models.ts13
-rw-r--r--src/ui/theme/theme.store.ts20
-rw-r--r--src/ui/theme/themes.ts37
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',
+ },
+ },
+});