feat(ui-lib): demo pages for c-lib components

This commit is contained in:
Corentin Thomasset 2023-04-23 22:26:32 +02:00 committed by Corentin THOMASSET
parent e88c1d5f2c
commit 92bd83536f
14 changed files with 294 additions and 248 deletions

View file

@ -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>

View file

@ -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,
},
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,
},
},
},
},
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 },
});
const createTheme = ({ style }: { style: 'light' | 'dark' }) => {
const theme = appThemes[style];
return {
basic: {
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: createState({
textColor: theme.text.baseColor,
backgroundColor: 'transparent',
hoverBackground: theme.default.colorHover,
pressedBackground: theme.default.colorPressed,
}),
primary: createState({
textColor: theme.primary.color,
backgroundColor: 'transparent',
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' }),
});

View file

@ -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 {

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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');
});
});
});

View file

@ -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');
}

View file

@ -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>

View file

@ -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'),
},
];

View file

@ -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',