From abb83350418a5a52255e437f3e553f5786a251a1 Mon Sep 17 00:00:00 2001 From: Corentin THOMASSET Date: Tue, 31 Oct 2023 08:32:44 +0100 Subject: [PATCH] refactor(color-converter): improved color-converter UX (#701) --- .../color-converter.e2e.spec.ts | 23 +++ .../color-converter.models.test.ts | 13 ++ .../color-converter/color-converter.models.ts | 52 +++++++ src/tools/color-converter/color-converter.vue | 142 ++++++++++-------- 4 files changed, 167 insertions(+), 63 deletions(-) create mode 100644 src/tools/color-converter/color-converter.e2e.spec.ts create mode 100644 src/tools/color-converter/color-converter.models.test.ts create mode 100644 src/tools/color-converter/color-converter.models.ts diff --git a/src/tools/color-converter/color-converter.e2e.spec.ts b/src/tools/color-converter/color-converter.e2e.spec.ts new file mode 100644 index 00000000..6ab91d7a --- /dev/null +++ b/src/tools/color-converter/color-converter.e2e.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Tool - Color converter', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/color-converter'); + }); + + test('Has title', async ({ page }) => { + await expect(page).toHaveTitle('Color converter - IT Tools'); + }); + + test('Color is converted from its name to other formats', async ({ page }) => { + await page.getByTestId('input-name').fill('olive'); + + expect(await page.getByTestId('input-name').inputValue()).toEqual('olive'); + expect(await page.getByTestId('input-hex').inputValue()).toEqual('#808000'); + expect(await page.getByTestId('input-rgb').inputValue()).toEqual('rgb(128, 128, 0)'); + expect(await page.getByTestId('input-hsl').inputValue()).toEqual('hsl(60, 100%, 25%)'); + expect(await page.getByTestId('input-hwb').inputValue()).toEqual('hwb(60 0% 50%)'); + expect(await page.getByTestId('input-cmyk').inputValue()).toEqual('device-cmyk(0% 0% 100% 50%)'); + expect(await page.getByTestId('input-lch').inputValue()).toEqual('lch(52.15% 56.81 99.57)'); + }); +}); diff --git a/src/tools/color-converter/color-converter.models.test.ts b/src/tools/color-converter/color-converter.models.test.ts new file mode 100644 index 00000000..4261fed1 --- /dev/null +++ b/src/tools/color-converter/color-converter.models.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; +import { removeAlphaChannelWhenOpaque } from './color-converter.models'; + +describe('color-converter models', () => { + describe('removeAlphaChannelWhenOpaque', () => { + it('remove alpha channel of an hex color when it is opaque (alpha = 1)', () => { + expect(removeAlphaChannelWhenOpaque('#000000ff')).toBe('#000000'); + expect(removeAlphaChannelWhenOpaque('#ffffffFF')).toBe('#ffffff'); + expect(removeAlphaChannelWhenOpaque('#000000FE')).toBe('#000000FE'); + expect(removeAlphaChannelWhenOpaque('#00000000')).toBe('#00000000'); + }); + }); +}); diff --git a/src/tools/color-converter/color-converter.models.ts b/src/tools/color-converter/color-converter.models.ts new file mode 100644 index 00000000..030fd074 --- /dev/null +++ b/src/tools/color-converter/color-converter.models.ts @@ -0,0 +1,52 @@ +import { type Colord, colord } from 'colord'; +import { withDefaultOnError } from '@/utils/defaults'; +import { useValidation } from '@/composable/validation'; + +export { removeAlphaChannelWhenOpaque, buildColorFormat }; + +function removeAlphaChannelWhenOpaque(hexColor: string) { + return hexColor.replace(/^(#(?:[0-9a-f]{3}){1,2})ff$/i, '$1'); +} + +function buildColorFormat({ + label, + parse = value => colord(value), + format, + placeholder, + invalidMessage = `Invalid ${label.toLowerCase()} format.`, + type = 'text', +}: { + label: string + parse?: (value: string) => Colord + format: (value: Colord) => string + placeholder?: string + invalidMessage?: string + type?: 'text' | 'color-picker' +}) { + const value = ref(''); + + return { + type, + label, + parse: (v: string) => withDefaultOnError(() => parse(v), undefined), + format, + placeholder, + value, + validation: useValidation({ + source: value, + rules: [ + { + message: invalidMessage, + validator: v => withDefaultOnError(() => { + if (v === '') { + return true; + } + + return parse(v).isValid(); + }, false), + }, + ], + }), + + }; +} diff --git a/src/tools/color-converter/color-converter.vue b/src/tools/color-converter/color-converter.vue index 0b9909fa..a7d6139f 100644 --- a/src/tools/color-converter/color-converter.vue +++ b/src/tools/color-converter/color-converter.vue @@ -1,87 +1,103 @@