aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorGravatar Corentin Thomasset <corentin.thomasset74@gmail.com> 2023-04-23 22:26:32 +0200
committerGravatar Corentin THOMASSET <corentin.thomasset74@gmail.com> 2023-04-23 22:43:06 +0200
commit92bd83536fd1ca84e71d27c3682153cc8eb27d84 (patch)
tree55bca29e778aa67dbb9d59f052e20e8433b87169 /src/ui
parente88c1d5f2c369e19b60af1f1d6424de74020dd2f (diff)
downloadit-tools-92bd83536fd1ca84e71d27c3682153cc8eb27d84.tar.gz
it-tools-92bd83536fd1ca84e71d27c3682153cc8eb27d84.tar.zst
it-tools-92bd83536fd1ca84e71d27c3682153cc8eb27d84.zip
feat(ui-lib): demo pages for c-lib components
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/c-button/c-button.demo.vue29
-rw-r--r--src/ui/c-button/c-button.theme.ts292
-rw-r--r--src/ui/c-button/c-button.vue5
-rw-r--r--src/ui/c-card/c-card.demo.vue13
-rw-r--r--src/ui/c-link/c-link.demo.vue12
-rw-r--r--src/ui/c-link/c-link.vue10
-rw-r--r--src/ui/color/color.models.test.ts40
-rw-r--r--src/ui/color/color.models.ts33
-rw-r--r--src/ui/demo/demo-wrapper.vue33
-rw-r--r--src/ui/demo/demo.routes.ts25
-rw-r--r--src/ui/theme/themes.ts23
11 files changed, 277 insertions, 238 deletions
diff --git a/src/ui/c-button/c-button.demo.vue b/src/ui/c-button/c-button.demo.vue
new file mode 100644
index 0000000..988659f
--- /dev/null
+++ b/src/ui/c-button/c-button.demo.vue
@@ -0,0 +1,29 @@
+<template>
+ <div v-for="buttonVariant of buttonVariants" :key="buttonVariant">
+ <h2>{{ _.capitalize(buttonVariant) }}</h2>
+
+ <c-button v-for="buttonType of buttonTypes" :key="buttonType" :variant="buttonVariant" :type="buttonType" mx-1>
+ Button
+ </c-button>
+
+ <c-button
+ v-for="buttonType of buttonTypes"
+ :key="buttonType"
+ :variant="buttonVariant"
+ :type="buttonType"
+ circle
+ mx-1
+ >
+ A
+ </c-button>
+ </div>
+</template>
+
+<script lang="ts" setup>
+import _ from 'lodash';
+
+const buttonVariants = ['basic', 'text'];
+const buttonTypes = ['default', 'primary'];
+</script>
+
+<style lang="less" scoped></style>
diff --git a/src/ui/c-button/c-button.theme.ts b/src/ui/c-button/c-button.theme.ts
index 2f25e6f..87ad89f 100644
--- a/src/ui/c-button/c-button.theme.ts
+++ b/src/ui/c-button/c-button.theme.ts
@@ -1,240 +1,76 @@
+import { darken, lighten } from '../color/color.models';
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,
- },
+const createState = ({
+ textColor,
+ backgroundColor,
+ hoverBackground,
+ hoveredTextColor = textColor,
+ pressedBackground,
+ pressedTextColor = textColor,
+}: {
+ textColor: string;
+ backgroundColor: string;
+ hoverBackground: string;
+ hoveredTextColor?: string;
+ pressedBackground: string;
+ pressedTextColor?: string;
+}) => ({
+ textColor,
+ backgroundColor,
+ hover: { textColor: hoveredTextColor, backgroundColor: hoverBackground },
+ pressed: { textColor: pressedTextColor, backgroundColor: pressedBackground },
+});
- pressed: {
- textColor: appThemes.dark.text.baseColor,
- backgroundColor: appThemes.dark.warning.colorPressed,
- },
+const createTheme = ({ style }: { style: 'light' | 'dark' }) => {
+ const theme = appThemes[style];
- outline: {
- color: appThemes.dark.warning.color,
- },
- },
- },
- },
- light: {
+ return {
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,
- },
- },
+ default: createState({
+ textColor: theme.text.baseColor,
+ backgroundColor: theme.default.color,
+ hoverBackground: theme.default.colorHover,
+ pressedBackground: theme.default.colorPressed,
+ }),
+ primary: createState({
+ textColor: theme.primary.color,
+ backgroundColor: theme.primary.colorFaded,
+ hoverBackground: lighten(theme.primary.colorFaded, 30),
+ pressedBackground: darken(theme.primary.colorFaded, 30),
+ }),
+ warning: createState({
+ textColor: theme.text.baseColor,
+ backgroundColor: theme.warning.color,
+ hoverBackground: theme.warning.colorHover,
+ pressedBackground: theme.warning.colorPressed,
+ }),
},
text: {
- default: {
- textColor: appThemes.light.text.baseColor,
+ default: createState({
+ textColor: theme.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,
+ hoverBackground: theme.default.colorHover,
+ pressedBackground: theme.default.colorPressed,
+ }),
+ primary: createState({
+ textColor: theme.primary.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,
- },
- },
+ hoverBackground: theme.primary.colorFaded,
+ pressedBackground: darken(theme.primary.colorFaded, 30),
+ }),
+ warning: createState({
+ textColor: theme.text.baseColor,
+ backgroundColor: theme.warning.color,
+ hoverBackground: theme.warning.colorHover,
+ pressedBackground: theme.warning.colorPressed,
+ }),
},
- },
+ };
+};
+
+export const { useTheme } = defineThemes({
+ dark: createTheme({ style: 'dark' }),
+ light: createTheme({ style: 'light' }),
});
diff --git a/src/ui/c-button/c-button.vue b/src/ui/c-button/c-button.vue
index f52a069..2cbc4fd 100644
--- a/src/ui/c-button/c-button.vue
+++ b/src/ui/c-button/c-button.vue
@@ -14,6 +14,7 @@
<script lang="ts" setup>
import type { RouteLocationRaw } from 'vue-router';
import { useTheme } from './c-button.theme';
+import { useAppTheme } from '../theme/themes';
const props = withDefaults(
defineProps<{
@@ -56,11 +57,11 @@ const tag = computed(() => {
}
return 'button';
});
+const appTheme = useAppTheme();
</script>
<style lang="less" scoped>
.c-button {
- margin: 0;
line-height: 1;
font-family: inherit;
font-size: inherit;
@@ -103,7 +104,7 @@ const tag = computed(() => {
}
&:focus {
- outline: 2px solid v-bind('variantTheme.outline.color');
+ outline: 1px solid v-bind('appTheme.primary.color');
}
&.disabled {
diff --git a/src/ui/c-card/c-card.demo.vue b/src/ui/c-card/c-card.demo.vue
new file mode 100644
index 0000000..6d81ee6
--- /dev/null
+++ b/src/ui/c-card/c-card.demo.vue
@@ -0,0 +1,13 @@
+<template>
+ <div>
+ <h2>Default</h2>
+
+ <c-card title="Title">
+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. Repudiandae ipsa reiciendis facilis officia nulla.
+ Laboriosam cumque molestias excepturi doloribus nulla nemo quod ratione rerum possimus. Excepturi nihil possimus
+ error itaque.
+ </c-card>
+ </div>
+</template>
+
+<script lang="ts" setup></script>
diff --git a/src/ui/c-link/c-link.demo.vue b/src/ui/c-link/c-link.demo.vue
new file mode 100644
index 0000000..a655f11
--- /dev/null
+++ b/src/ui/c-link/c-link.demo.vue
@@ -0,0 +1,12 @@
+<template>
+ <div>
+ <h2>Default</h2>
+ <c-link mx-1> Link </c-link>
+ </div>
+</template>
+
+<script lang="ts" setup>
+import CLink from './c-link.vue';
+</script>
+
+<style lang="less" scoped></style>
diff --git a/src/ui/c-link/c-link.vue b/src/ui/c-link/c-link.vue
index df10120..a7d1b83 100644
--- a/src/ui/c-link/c-link.vue
+++ b/src/ui/c-link/c-link.vue
@@ -16,7 +16,15 @@ const props = defineProps<{
const { href, to } = toRefs(props);
const theme = useTheme();
-const tag = computed(() => (href?.value ? 'a' : RouterLink));
+const tag = computed(() => {
+ if (href?.value) {
+ return 'a';
+ }
+ if (to?.value) {
+ return RouterLink;
+ }
+ return 'span';
+});
</script>
<style lang="less" scoped>
diff --git a/src/ui/color/color.models.test.ts b/src/ui/color/color.models.test.ts
new file mode 100644
index 0000000..dc59fa8
--- /dev/null
+++ b/src/ui/color/color.models.test.ts
@@ -0,0 +1,40 @@
+import { describe, test, expect } from 'vitest';
+import { darken, lighten, setOpacity } from './color.models';
+
+describe('color models', () => {
+ describe('lighten', () => {
+ test('lightens a color', () => {
+ expect(lighten('#000000', 10)).toBe('#0a0a0a');
+ expect(lighten('#000000', 20)).toBe('#141414');
+ expect(lighten('#ffffff', 30)).toBe('#ffffff');
+ });
+
+ test('lightens a color with alpha', () => {
+ expect(lighten('#00000080', 10)).toBe('#0a0a0a80');
+ expect(lighten('#00000080', 20)).toBe('#14141480');
+ expect(lighten('#ffffff80', 30)).toBe('#ffffff80');
+ });
+ });
+
+ describe('darken', () => {
+ test('darkens a color', () => {
+ expect(darken('#ffffff', 10)).toBe('#f5f5f5');
+ expect(darken('#ffffff', 20)).toBe('#ebebeb');
+ expect(darken('#000000', 30)).toBe('#000000');
+ });
+
+ test('darkens a color with alpha', () => {
+ expect(darken('#ffffff80', 10)).toBe('#f5f5f580');
+ });
+ });
+
+ describe('setOpacity', () => {
+ test('sets the opacity of a color', () => {
+ expect(setOpacity('#000000', 0.5)).toBe('#00000080');
+ });
+
+ test('sets the opacity of a color with alpha', () => {
+ expect(setOpacity('#00000000', 0.5)).toBe('#00000080');
+ });
+ });
+});
diff --git a/src/ui/color/color.models.ts b/src/ui/color/color.models.ts
new file mode 100644
index 0000000..5b4c79b
--- /dev/null
+++ b/src/ui/color/color.models.ts
@@ -0,0 +1,33 @@
+export { lighten, darken, setOpacity };
+
+const clampHex = (value: number) => Math.max(0, Math.min(255, Math.round(value)));
+
+function lighten(color: string, amount: number): string {
+ const alpha = color.length === 9 ? color.slice(7) : '';
+ const num = parseInt(color.slice(1, 7), 16);
+
+ const r = clampHex(((num >> 16) & 255) + amount);
+ const g = clampHex(((num >> 8) & 255) + amount);
+ const b = clampHex((num & 255) + amount);
+
+ return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}${alpha}`;
+}
+
+function darken(color: string, amount: number): string {
+ return lighten(color, -amount);
+}
+
+function setOpacity(color: string, opacity: number): string {
+ const alpha = clampHex(Math.round(opacity * 255))
+ .toString(16)
+ .padStart(2, '0');
+
+ if (color.length === 7) {
+ return `${color}${alpha}`;
+ }
+
+ if (color.length === 9) {
+ return `${color.slice(0, 7)}${alpha}`;
+ }
+ throw new Error('Invalid hex color');
+}
diff --git a/src/ui/demo/demo-wrapper.vue b/src/ui/demo/demo-wrapper.vue
new file mode 100644
index 0000000..cc16a00
--- /dev/null
+++ b/src/ui/demo/demo-wrapper.vue
@@ -0,0 +1,33 @@
+<template>
+ <div mt-2 w-full p-8>
+ <h1>c-lib components</h1>
+
+ <div flex>
+ <div w-30 b-r b-gray b-op-10 b-r-solid pr-4>
+ <c-button
+ v-for="{ name } of demoRoutes"
+ :key="name"
+ variant="text"
+ :to="{ name }"
+ w-full
+ important:justify-start
+ :type="route.name === name ? 'primary' : 'default'"
+ >
+ {{ name }}
+ </c-button>
+ </div>
+
+ <div flex-1 pl-4>
+ <router-view />
+ </div>
+ </div>
+ </div>
+</template>
+
+<script lang="ts" setup>
+import { demoRoutes } from './demo.routes';
+
+const route = useRoute();
+</script>
+
+<style lang="less" scoped></style>
diff --git a/src/ui/demo/demo.routes.ts b/src/ui/demo/demo.routes.ts
new file mode 100644
index 0000000..0e9a9e4
--- /dev/null
+++ b/src/ui/demo/demo.routes.ts
@@ -0,0 +1,25 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+const demoPages = import.meta.glob('../*/*.demo.vue');
+
+export const demoRoutes = Object.keys(demoPages).map((path) => {
+ const [, , fileName] = path.split('/');
+ const name = fileName.split('.').shift();
+
+ console.log(path);
+
+ return {
+ path: name,
+ name,
+ component: () => import(/* @vite-ignore */ path),
+ } as RouteRecordRaw;
+});
+
+export const routes = [
+ {
+ path: '/c-lib',
+ name: 'c-lib',
+ children: demoRoutes,
+ component: () => import('./demo-wrapper.vue'),
+ },
+];
diff --git a/src/ui/theme/themes.ts b/src/ui/theme/themes.ts
index eca63db..18b2c8d 100644
--- a/src/ui/theme/themes.ts
+++ b/src/ui/theme/themes.ts
@@ -3,16 +3,20 @@ import { defineThemes } from './theme.models';
export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({
light: {
text: {
- baseColor: 'rgb(51, 54, 57)',
- mutedColor: 'rgba(118, 124, 130)',
+ baseColor: '#333639',
+ mutedColor: '#767c82',
+ },
+ default: {
+ color: 'rgba(46, 51, 56, 0.05)',
+ colorHover: 'rgba(46, 51, 56, 0.09)',
+ colorPressed: 'rgba(46, 51, 56, 0.22)',
},
-
primary: {
color: '#18a058',
colorHover: '#1ea54c',
colorPressed: '#0C7A43',
+ colorFaded: '#18a0582f',
},
-
warning: {
color: '#f59e0b',
colorHover: '#f59e0b',
@@ -33,14 +37,19 @@ export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({
},
dark: {
text: {
- baseColor: 'rgba(255, 255, 255, 0.82)',
- mutedColor: 'rgba(255, 255, 255, 0.5)',
+ baseColor: '#ffffffd1',
+ mutedColor: '#ffffff80',
+ },
+ default: {
+ color: 'rgba(255, 255, 255, 0.08)',
+ colorHover: 'rgba(255, 255, 255, 0.12)',
+ colorPressed: 'rgba(255, 255, 255, 0.24)',
},
-
primary: {
color: '#1ea54c',
colorHover: '#36AD6A',
colorPressed: '#0C7A43',
+ colorFaded: '#18a0582f',
},
warning: {
color: '#f59e0b',