From c907ef760feda65f0a1cd604621936c85f067bff Mon Sep 17 00:00:00 2001 From: ofava Date: Wed, 29 Oct 2025 12:04:56 +0100 Subject: [PATCH 1/5] Add design tokens for typography, motion, color, elevation, and shape --- frontend/src/designTokens/designTokens.ts | 17 +++ .../src/designTokens/helpers/tokensToJson.ts | 123 +++++++++++++++ frontend/src/designTokens/index.ts | 3 + frontend/src/designTokens/tokens/color.ts | 140 ++++++++++++++++++ frontend/src/designTokens/tokens/elevation.ts | 40 +++++ .../designTokens/tokens/motion/duration.ts | 35 +++++ .../src/designTokens/tokens/motion/easing.ts | 29 ++++ .../src/designTokens/tokens/motion/index.ts | 3 + .../src/designTokens/tokens/motion/motion.ts | 16 ++ frontend/src/designTokens/tokens/shape.ts | 41 +++++ frontend/src/designTokens/tokens/state.ts | 31 ++++ .../designTokens/tokens/typography/index.ts | 3 + .../tokens/typography/typeface.ts | 23 +++ .../tokens/typography/typescale.ts | 136 +++++++++++++++++ .../tokens/typography/typography.ts | 18 +++ .../designTokens/tokens/typography/weight.ts | 37 +++++ 16 files changed, 695 insertions(+) create mode 100644 frontend/src/designTokens/designTokens.ts create mode 100644 frontend/src/designTokens/helpers/tokensToJson.ts create mode 100644 frontend/src/designTokens/index.ts create mode 100644 frontend/src/designTokens/tokens/color.ts create mode 100644 frontend/src/designTokens/tokens/elevation.ts create mode 100644 frontend/src/designTokens/tokens/motion/duration.ts create mode 100644 frontend/src/designTokens/tokens/motion/easing.ts create mode 100644 frontend/src/designTokens/tokens/motion/index.ts create mode 100644 frontend/src/designTokens/tokens/motion/motion.ts create mode 100644 frontend/src/designTokens/tokens/shape.ts create mode 100644 frontend/src/designTokens/tokens/state.ts create mode 100644 frontend/src/designTokens/tokens/typography/index.ts create mode 100644 frontend/src/designTokens/tokens/typography/typeface.ts create mode 100644 frontend/src/designTokens/tokens/typography/typescale.ts create mode 100644 frontend/src/designTokens/tokens/typography/typography.ts create mode 100644 frontend/src/designTokens/tokens/typography/weight.ts diff --git a/frontend/src/designTokens/designTokens.ts b/frontend/src/designTokens/designTokens.ts new file mode 100644 index 00000000..3c67a103 --- /dev/null +++ b/frontend/src/designTokens/designTokens.ts @@ -0,0 +1,17 @@ +import motion from './tokens/motion'; +import typography from './tokens/typography'; +import color from './tokens/color'; +import elevation from './tokens/elevation'; +import shape from './tokens/shape'; +import state from './tokens/state'; + +const designTokens = { + motion, + typography, + color, + elevation, + shape, + state, +}; + +export default designTokens; diff --git a/frontend/src/designTokens/helpers/tokensToJson.ts b/frontend/src/designTokens/helpers/tokensToJson.ts new file mode 100644 index 00000000..a316ce3c --- /dev/null +++ b/frontend/src/designTokens/helpers/tokensToJson.ts @@ -0,0 +1,123 @@ +/* eslint-disable @typescript-eslint/no-use-before-define */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import designTokens from '../designTokens'; +import type { Typeface } from '../tokens/typography/typeface'; +import type { TypeScale } from '../tokens/typography/typescale'; + +const outputFile = path.resolve('libs/shared/dist/designTokens.json'); + +type FontSize = [string, { lineHeight: string; fontWeight: string }]; + +type UnwrappedTokens = { + color: Record; + shape: Record; + elevation: Record; + state: Record; + motion: { + duration: Record; + easing: Record; + }; + typography: { + typeface: Record< + Typeface, + { + value: string; + } + >; + typeScale: Record< + TypeScale, + { + fontSize: string; + lineHeight: string; + fontWeight: string; + } + >; + weight: Record; + }; +}; + +/** + * Converts the design tokens to tailwind format and writes them to a JSON file. + */ +function designTokensToJson() { + // Ensure parent directory exists + fs.mkdirSync(path.dirname(outputFile), { recursive: true }); + + const tokens = unwrapValue(designTokens) as UnwrappedTokens; + + const fontSize = parseFontSize(tokens.typography.typeScale); + + const tailwindExtend = { + colors: tokens.color, + borderRadius: tokens.shape, + boxShadow: tokens.elevation, + opacity: tokens.state, + transitionDuration: tokens.motion?.duration, + transitionTimingFunction: tokens.motion?.easing, + fontFamily: tokens.typography?.typeface, + fontSize, + fontWeight: tokens.typography?.weight, + }; + + // Write or overwrite the file + fs.writeFileSync(outputFile, JSON.stringify(tailwindExtend, null, 2), { + flag: 'w', + }); + + console.log(`\x1b[32m✔ Design tokens JSON written to ${outputFile}\x1b[0m`); +} + +/** + * Recursively unwraps the `value` properties from the design tokens. + * @param {unknown} obj - The object to unwrap. + * @returns {unknown} The unwrapped object. + */ +function unwrapValue(obj: unknown): unknown { + if (!isRecord(obj)) { + return obj; + } + if (!isUndefined(obj.value)) { + return obj.value; + } + + return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, unwrapValue(value)])); +} + +/** + * Type guard to check if a value is a Record. + * @param {unknown} value - The value to check. + * @returns {boolean} True if the value is a Record, false otherwise. + */ +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null; +} + +/** + * Type guard to check if a value is undefined. + * @param {unknown} value - The value to check. + * @returns {boolean} True if the value is undefined, false otherwise. + */ +function isUndefined(value: unknown): value is undefined { + return typeof value === 'undefined'; +} + +/** + * Type guard to check if a value is a Record. + * @param {unknown} fontSizes - The value to check. + * @returns {boolean} True if the value is a Record, false otherwise. + */ +function parseFontSize( + fontSizes: Record +): Record { + return Object.entries(fontSizes).reduce( + (acc, [key, val]) => { + const { fontSize, lineHeight, fontWeight } = val; + acc[key] = [fontSize, { lineHeight, fontWeight }]; + return acc; + }, + {} as Record + ); +} + +designTokensToJson(); diff --git a/frontend/src/designTokens/index.ts b/frontend/src/designTokens/index.ts new file mode 100644 index 00000000..592014d7 --- /dev/null +++ b/frontend/src/designTokens/index.ts @@ -0,0 +1,3 @@ +import designTokens from './designTokens'; + +export default designTokens; diff --git a/frontend/src/designTokens/tokens/color.ts b/frontend/src/designTokens/tokens/color.ts new file mode 100644 index 00000000..c6cc329f --- /dev/null +++ b/frontend/src/designTokens/tokens/color.ts @@ -0,0 +1,140 @@ +/** + * Color Tokens + * + * These tokens define the core color system used throughout the interface. + * Each token represents a semantic purpose — rather than a specific hex value — + * allowing color changes to propagate consistently across the design system. + */ +const colors = { + primary: { + value: '#3E007E', + type: 'color', + description: 'Main brand color used for primary actions and highlights.', + }, + 'on-primary': { + value: '#FFFFFF', + type: 'color', + description: 'Foreground color used on primary surfaces.', + }, + 'primary-hover': { + value: '#3E007E2F', + type: 'color', + description: 'Main brand color for hovering.', + }, + + secondary: { + value: '#2F293B', + type: 'color', + description: 'Secondary brand color and accent.', + }, + 'on-secondary': { + value: '#FFFFFF', + type: 'color', + description: 'Foreground color used on secondary surfaces.', + }, + + tertiary: { + value: '#2A005E', + type: 'color', + description: 'Tertiary brand color and accent.', + }, + 'on-tertiary': { + value: '#FFFFFF', + type: 'color', + description: 'Foreground color used on tertiary surfaces.', + }, + + background: { + value: '#FFFFFF', + type: 'color', + description: 'Default background color for the interface.', + }, + darkGrey: { + value: '#202124', + type: 'color', + description: 'Dark grey color used for backgrounds and surfaces.', + }, + 'background-disabled': { + value: '#f5f5f5', + type: 'color', + description: 'Background color for disabled elements.', + }, + 'on-background': { + value: '#1E1925', + type: 'color', + description: 'Text or icon color used on background surfaces.', + }, + + surface: { + value: '#FCF8F8', + type: 'color', + description: 'Default surface color for cards and containers.', + }, + 'on-surface': { + value: '#000000', + type: 'color', + description: 'Text or icon color used on surface elements.', + }, + + error: { + value: '#600004', + type: 'color', + description: 'Color representing error states and critical messages.', + }, + 'on-error': { + value: '#FFFFFF', + type: 'color', + description: 'Foreground color for text/icons on error surfaces.', + }, + + warning: { + value: '#FCC723', + type: 'color', + description: 'Color representing warning states and cautionary messages.', + }, + 'on-warning': { + value: '#000000', + type: 'color', + description: 'Foreground color for text/icons on warning surfaces.', + }, + + success: { + value: '#2E8D32', + type: 'color', + description: 'Color representing success states and positive messages.', + }, + 'on-success': { + value: '#FFFFFF', + type: 'color', + description: 'Foreground color for text/icons on success surfaces.', + }, + + 'text-primary': { + value: '#333333', + type: 'color', + description: 'Primary text color used for main content and headings.', + }, + 'text-secondary': { + value: '#666666', + type: 'color', + description: 'Secondary text color used for subheadings and less prominent content.', + }, + + border: { + value: '#DDDDDD', + type: 'color', + description: 'Color used for borders and dividers between elements.', + }, + disabled: { + value: '#999999', + type: 'color', + description: 'Color used for disabled text and icons.', + }, + accent: { + value: '#2E7D32', + type: 'color', + description: 'Accent color used for highlights and interactive elements.', + }, +}; + +export default colors; diff --git a/frontend/src/designTokens/tokens/elevation.ts b/frontend/src/designTokens/tokens/elevation.ts new file mode 100644 index 00000000..87953367 --- /dev/null +++ b/frontend/src/designTokens/tokens/elevation.ts @@ -0,0 +1,40 @@ +/** + * Elevation Tokens + * + * These tokens define the shadow styles used to represent different levels of elevation + * in the design system. They help create a sense of depth and hierarchy among UI components. + */ +const elevation = { + level0: { + value: 'none', + type: 'shadow', + description: 'No elevation; flat surface.', + }, + level1: { + value: '0 1px 2px rgba(0,0,0,0.1)', + type: 'shadow', + description: 'Very low elevation for subtle depth effects.', + }, + level2: { + value: '0 2px 4px rgba(0,0,0,0.12)', + type: 'shadow', + description: 'Low elevation for cards and raised elements.', + }, + level3: { + value: '0 4px 6px rgba(0,0,0,0.14)', + type: 'shadow', + description: 'Moderate elevation for prominent components.', + }, + level4: { + value: '0 8px 12px rgba(0,0,0,0.16)', + type: 'shadow', + description: 'High elevation for floating elements.', + }, + level5: { + value: '0 12px 16px rgba(0,0,0,0.18)', + type: 'shadow', + description: 'Very high elevation for modal dialogs and overlays.', + }, +}; + +export default elevation; diff --git a/frontend/src/designTokens/tokens/motion/duration.ts b/frontend/src/designTokens/tokens/motion/duration.ts new file mode 100644 index 00000000..f4039f30 --- /dev/null +++ b/frontend/src/designTokens/tokens/motion/duration.ts @@ -0,0 +1,35 @@ +/** + * Duration Design Tokens + * + * This module defines standardized duration tokens for motion + * within the user interface, ensuring consistent timing + * for animations and transitions. + */ +const durations = { + instant: { + value: '50ms', + description: 'Used for immediate feedback like hover states or quick visual changes', + }, + quick: { + value: '100ms', + description: 'Used for fast interactions such as button presses or quick toggles', + }, + short: { + value: '150ms', + description: 'Used for small UI elements like tooltips or dropdowns', + }, + medium: { + value: '200ms', + description: 'Used for medium UI elements like cards or notifications', + }, + long: { + value: '300ms', + description: 'Used for larger UI elements like modals or side panels', + }, + extraLong: { + value: '500ms', + description: 'Used for complex animations like page transitions or full-screen overlays', + }, +}; + +export default durations; diff --git a/frontend/src/designTokens/tokens/motion/easing.ts b/frontend/src/designTokens/tokens/motion/easing.ts new file mode 100644 index 00000000..9021988a --- /dev/null +++ b/frontend/src/designTokens/tokens/motion/easing.ts @@ -0,0 +1,29 @@ +/** + * Motion Easing Tokens + * + * These tokens define the standard timing functions (easing curves) + * used to control the acceleration and deceleration of animations. + * Easing shapes the way elements move — giving interactions a sense + * of realism, weight, and responsiveness. + */ +const easing = { + standard: { + value: 'cubic-bezier(0.2, 0, 0, 1)', + description: 'Smooth and balanced easing — suitable for most UI animations and transitions.', + }, + accelerate: { + value: 'cubic-bezier(0.3, 0, 1, 1)', + description: 'Starts slow and speeds up — ideal for exiting or disappearing elements.', + }, + decelerate: { + value: 'cubic-bezier(0, 0, 0.3, 1)', + description: 'Starts fast and slows down — perfect for entering or appearing elements.', + }, + linear: { + value: 'linear', + description: + 'Constant speed from start to finish — useful for continuous or looping animations.', + }, +}; + +export default easing; diff --git a/frontend/src/designTokens/tokens/motion/index.ts b/frontend/src/designTokens/tokens/motion/index.ts new file mode 100644 index 00000000..f12e9c42 --- /dev/null +++ b/frontend/src/designTokens/tokens/motion/index.ts @@ -0,0 +1,3 @@ +import motion from './motion'; + +export default motion; diff --git a/frontend/src/designTokens/tokens/motion/motion.ts b/frontend/src/designTokens/tokens/motion/motion.ts new file mode 100644 index 00000000..fba222b4 --- /dev/null +++ b/frontend/src/designTokens/tokens/motion/motion.ts @@ -0,0 +1,16 @@ +/** + * Motion Design Tokens + * + * This module aggregates motion-related design tokens, + * specifically duration and easing, to standardize animation behaviors + * across the user interface. + */ +import duration from './duration'; +import easing from './easing'; + +const motion = { + duration, + easing, +}; + +export default motion; diff --git a/frontend/src/designTokens/tokens/shape.ts b/frontend/src/designTokens/tokens/shape.ts new file mode 100644 index 00000000..4826ed46 --- /dev/null +++ b/frontend/src/designTokens/tokens/shape.ts @@ -0,0 +1,41 @@ +/** + * Shape Tokens + * + * These tokens define the corner radius values used throughout the design system. + * They provide a consistent approach to rounding corners on various UI components, + * enhancing the overall visual coherence and user experience. + */ +const shape = { + none: { + value: '0px', + type: 'radius', + description: 'No rounding; sharp corners.', + }, + 'extra-small': { + value: '2px', + type: 'radius', + description: 'Minimal rounding for very subtle corner softening.', + }, + small: { + value: '4px', + type: 'radius', + description: 'Small corner radius for buttons and small components.', + }, + medium: { + value: '8px', + type: 'radius', + description: 'Default rounding for most UI elements.', + }, + large: { + value: '12px', + type: 'radius', + description: 'Larger rounding for cards and containers.', + }, + 'extra-large': { + value: '24px', + type: 'radius', + description: 'Significant rounding for prominent elements or modals.', + }, +}; + +export default shape; diff --git a/frontend/src/designTokens/tokens/state.ts b/frontend/src/designTokens/tokens/state.ts new file mode 100644 index 00000000..5f083969 --- /dev/null +++ b/frontend/src/designTokens/tokens/state.ts @@ -0,0 +1,31 @@ +/** + * State Tokens + * + * These tokens define the opacity levels used to represent different + * interaction states across the interface. They help convey feedback + * for hover, focus, pressed, and disabled states in a consistent manner. + */ +const state = { + 'hover-opacity': { + value: '0.08', + type: 'opacity', + description: 'Used to indicate hover state on interactive elements.', + }, + 'focus-opacity': { + value: '0.12', + type: 'opacity', + description: 'Used to indicate focus state on interactive elements.', + }, + 'pressed-opacity': { + value: '0.16', + type: 'opacity', + description: 'Used to indicate pressed state on interactive elements.', + }, + 'disabled-opacity': { + value: '0.38', + type: 'opacity', + description: 'Used to indicate that an element is disabled or inactive.', + }, +}; + +export default state; diff --git a/frontend/src/designTokens/tokens/typography/index.ts b/frontend/src/designTokens/tokens/typography/index.ts new file mode 100644 index 00000000..a6437c7d --- /dev/null +++ b/frontend/src/designTokens/tokens/typography/index.ts @@ -0,0 +1,3 @@ +import typography from './typography'; + +export default typography; diff --git a/frontend/src/designTokens/tokens/typography/typeface.ts b/frontend/src/designTokens/tokens/typography/typeface.ts new file mode 100644 index 00000000..ac91906e --- /dev/null +++ b/frontend/src/designTokens/tokens/typography/typeface.ts @@ -0,0 +1,23 @@ +/** + * Typeface Design Tokens + * + * This module defines the primary typeface used across the user interface. + * It specifies the font family along with a description of its intended use. + */ +const typeface = { + plain: { + value: "'Inter', sans-serif", + type: 'fontFamily', + description: 'Primary typeface for all text elements in the user interface.', + }, +}; + +export type Typeface = keyof typeof typeface; + +export type TypefaceProps = { + value: string | number; + type: 'fontFamily'; + description: string; +}; + +export default typeface as Record; diff --git a/frontend/src/designTokens/tokens/typography/typescale.ts b/frontend/src/designTokens/tokens/typography/typescale.ts new file mode 100644 index 00000000..67ea88d8 --- /dev/null +++ b/frontend/src/designTokens/tokens/typography/typescale.ts @@ -0,0 +1,136 @@ +/** + * Typography Type Scale Design Tokens + * + * This module defines a comprehensive type scale for typography, + * specifying font sizes, line heights, and font weights for various + * text elements such as labels, body text, titles, headlines, and display text. + * Each token includes a description to clarify its intended use. + */ +const typeScale = { + 'label-small': { + fontSize: { value: '0.6875rem', description: 'Equivalent to 11px' }, + lineHeight: { value: '1rem', description: 'Equivalent to 16px' }, + fontWeight: { value: 500, description: 'Medium weight for small labels' }, + }, + + 'label-medium': { + fontSize: { value: '0.75rem', description: 'Equivalent to 12px' }, + lineHeight: { value: '1rem', description: 'Equivalent to 16px' }, + fontWeight: { value: 500, description: 'Medium weight for medium labels' }, + }, + + 'label-large': { + fontSize: { value: '0.875rem', description: 'Equivalent to 14px' }, + lineHeight: { value: '1.25rem', description: 'Equivalent to 20px' }, + fontWeight: { value: 500, description: 'Medium weight for large labels' }, + }, + + 'body-small': { + fontSize: { value: '0.75rem', description: 'Equivalent to 12px' }, + lineHeight: { value: '1rem', description: 'Equivalent to 16px' }, + fontWeight: { + value: 400, + description: 'Regular weight for small body text', + }, + }, + + 'body-medium': { + fontSize: { value: '0.875rem', description: 'Equivalent to 14px' }, + lineHeight: { value: '1.25rem', description: 'Equivalent to 20px' }, + fontWeight: { + value: 400, + description: 'Regular weight for medium body text', + }, + }, + + 'body-large': { + fontSize: { value: '1rem', description: 'Equivalent to 16px' }, + lineHeight: { value: '1.5rem', description: 'Equivalent to 24px' }, + fontWeight: { + value: 400, + description: 'Regular weight for large body text', + }, + }, + + 'title-small': { + fontSize: { value: '0.875rem', description: 'Equivalent to 14px' }, + lineHeight: { value: '1.25rem', description: 'Equivalent to 20px' }, + fontWeight: { value: 500, description: 'Medium weight for small titles' }, + }, + + 'title-medium': { + fontSize: { value: '1rem', description: 'Equivalent to 16px' }, + lineHeight: { value: '1.5rem', description: 'Equivalent to 24px' }, + fontWeight: { value: 500, description: 'Medium weight for medium titles' }, + }, + + 'title-large': { + fontSize: { value: '1.375rem', description: 'Equivalent to ~22px' }, + lineHeight: { value: '1.75rem', description: 'Equivalent to 28px' }, + fontWeight: { value: 400, description: 'Regular weight for large titles' }, + }, + + 'headline-small': { + fontSize: { value: '1.5rem', description: 'Equivalent to 24px' }, + lineHeight: { value: '2rem', description: 'Equivalent to 32px' }, + fontWeight: { + value: 400, + description: 'Regular weight for small headlines', + }, + }, + + 'headline-medium': { + fontSize: { value: '1.75rem', description: 'Equivalent to 28px' }, + lineHeight: { value: '2.25rem', description: 'Equivalent to 36px' }, + fontWeight: { + value: 400, + description: 'Regular weight for medium headlines', + }, + }, + + 'headline-large': { + fontSize: { value: '2rem', description: 'Equivalent to 32px' }, + lineHeight: { value: '2.5rem', description: 'Equivalent to 40px' }, + fontWeight: { + value: 400, + description: 'Regular weight for large headlines', + }, + }, + + 'display-small': { + fontSize: { value: '2.25rem', description: 'Equivalent to 36px' }, + lineHeight: { value: '2.75rem', description: 'Equivalent to 44px' }, + fontWeight: { + value: 400, + description: 'Regular weight for small display text', + }, + }, + + 'display-medium': { + fontSize: { value: '2.8125rem', description: 'Equivalent to 45px' }, + lineHeight: { value: '3.25rem', description: 'Equivalent to 52px' }, + fontWeight: { + value: 400, + description: 'Regular weight for medium display text', + }, + }, + + 'display-large': { + fontSize: { value: '3.5625rem', description: 'Equivalent to 57px' }, + lineHeight: { value: '4rem', description: 'Equivalent to 64px' }, + fontWeight: { + value: 400, + description: 'Regular weight for large display text', + }, + }, +}; + +export type TypeScale = keyof typeof typeScale; + +export type TypeScaleProps = { + fontSize: { value: string; description: string }; + lineHeight: { value: string; description: string }; + fontWeight: { value: number; description: string }; +}; + +export default typeScale as Record; diff --git a/frontend/src/designTokens/tokens/typography/typography.ts b/frontend/src/designTokens/tokens/typography/typography.ts new file mode 100644 index 00000000..ddf5dcca --- /dev/null +++ b/frontend/src/designTokens/tokens/typography/typography.ts @@ -0,0 +1,18 @@ +/** + * Typography Tokens + * + * This module aggregates typography-related design tokens, including + * typefaces, type scales, and font weights. These tokens ensure + * consistent typographic styles across the user interface. + */ +import typeface from './typeface'; +import typeScale from './typescale'; +import weight from './weight'; + +const typography = { + typeface, + typeScale, + weight, +}; + +export default typography; diff --git a/frontend/src/designTokens/tokens/typography/weight.ts b/frontend/src/designTokens/tokens/typography/weight.ts new file mode 100644 index 00000000..900ca340 --- /dev/null +++ b/frontend/src/designTokens/tokens/typography/weight.ts @@ -0,0 +1,37 @@ +/** + * Typography Weight Design Tokens + * + * These tokens define the standard font weights used throughout + * the user interface. They provide a consistent typographic + * hierarchy by specifying regular, medium, and bold weights + * for various text elements. + */ +const weight = { + 'weight-regular': { + value: 400, + type: 'fontWeight', + description: 'Regular weight used for body text and general content.', + }, + + 'weight-medium': { + value: 500, + type: 'fontWeight', + description: 'Medium weight used for labels, subheadings, and emphasis.', + }, + + 'weight-bold': { + value: 700, + type: 'fontWeight', + description: 'Bold weight used for headings and important text elements.', + }, +}; + +export type Weight = keyof typeof weight; + +export type WeightProps = { + value: string | number; + type: 'fontWeight'; + description: string; +}; + +export default weight as Record; From 9b0074619dc96dbe28a030d81d18b77e8f1cde5c Mon Sep 17 00:00:00 2001 From: ofava Date: Wed, 29 Oct 2025 16:55:00 +0100 Subject: [PATCH 2/5] Compile tokens --- frontend/src/designTokens/designTokens.json | 179 ++++++++++++++++++ .../src/designTokens/helpers/tokensToJson.ts | 2 +- 2 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 frontend/src/designTokens/designTokens.json diff --git a/frontend/src/designTokens/designTokens.json b/frontend/src/designTokens/designTokens.json new file mode 100644 index 00000000..69e26509 --- /dev/null +++ b/frontend/src/designTokens/designTokens.json @@ -0,0 +1,179 @@ +{ + "colors": { + "primary": "#3E007E", + "on-primary": "#FFFFFF", + "primary-hover": "#3E007E2F", + "secondary": "#2F293B", + "on-secondary": "#FFFFFF", + "tertiary": "#2A005E", + "on-tertiary": "#FFFFFF", + "background": "#FFFFFF", + "darkGrey": "#202124", + "background-disabled": "#f5f5f5", + "on-background": "#1E1925", + "surface": "#FCF8F8", + "on-surface": "#000000", + "error": "#600004", + "on-error": "#FFFFFF", + "warning": "#FCC723", + "on-warning": "#000000", + "success": "#2E8D32", + "on-success": "#FFFFFF", + "text-primary": "#333333", + "text-secondary": "#666666", + "border": "#DDDDDD", + "disabled": "#999999", + "accent": "#2E7D32" + }, + "borderRadius": { + "none": "0px", + "extra-small": "2px", + "small": "4px", + "medium": "8px", + "large": "12px", + "extra-large": "24px" + }, + "boxShadow": { + "level0": "none", + "level1": "0 1px 2px rgba(0,0,0,0.1)", + "level2": "0 2px 4px rgba(0,0,0,0.12)", + "level3": "0 4px 6px rgba(0,0,0,0.14)", + "level4": "0 8px 12px rgba(0,0,0,0.16)", + "level5": "0 12px 16px rgba(0,0,0,0.18)" + }, + "opacity": { + "hover-opacity": "0.08", + "focus-opacity": "0.12", + "pressed-opacity": "0.16", + "disabled-opacity": "0.38" + }, + "transitionDuration": { + "instant": "50ms", + "quick": "100ms", + "short": "150ms", + "medium": "200ms", + "long": "300ms", + "extraLong": "500ms" + }, + "transitionTimingFunction": { + "standard": "cubic-bezier(0.2, 0, 0, 1)", + "accelerate": "cubic-bezier(0.3, 0, 1, 1)", + "decelerate": "cubic-bezier(0, 0, 0.3, 1)", + "linear": "linear" + }, + "fontFamily": { + "plain": "'Inter', sans-serif" + }, + "fontSize": { + "label-small": [ + "0.6875rem", + { + "lineHeight": "1rem", + "fontWeight": 500 + } + ], + "label-medium": [ + "0.75rem", + { + "lineHeight": "1rem", + "fontWeight": 500 + } + ], + "label-large": [ + "0.875rem", + { + "lineHeight": "1.25rem", + "fontWeight": 500 + } + ], + "body-small": [ + "0.75rem", + { + "lineHeight": "1rem", + "fontWeight": 400 + } + ], + "body-medium": [ + "0.875rem", + { + "lineHeight": "1.25rem", + "fontWeight": 400 + } + ], + "body-large": [ + "1rem", + { + "lineHeight": "1.5rem", + "fontWeight": 400 + } + ], + "title-small": [ + "0.875rem", + { + "lineHeight": "1.25rem", + "fontWeight": 500 + } + ], + "title-medium": [ + "1rem", + { + "lineHeight": "1.5rem", + "fontWeight": 500 + } + ], + "title-large": [ + "1.375rem", + { + "lineHeight": "1.75rem", + "fontWeight": 400 + } + ], + "headline-small": [ + "1.5rem", + { + "lineHeight": "2rem", + "fontWeight": 400 + } + ], + "headline-medium": [ + "1.75rem", + { + "lineHeight": "2.25rem", + "fontWeight": 400 + } + ], + "headline-large": [ + "2rem", + { + "lineHeight": "2.5rem", + "fontWeight": 400 + } + ], + "display-small": [ + "2.25rem", + { + "lineHeight": "2.75rem", + "fontWeight": 400 + } + ], + "display-medium": [ + "2.8125rem", + { + "lineHeight": "3.25rem", + "fontWeight": 400 + } + ], + "display-large": [ + "3.5625rem", + { + "lineHeight": "4rem", + "fontWeight": 400 + } + ] + }, + "fontWeight": { + "weight-regular": 400, + "weight-medium": 500, + "weight-bold": 700 + } +} \ No newline at end of file diff --git a/frontend/src/designTokens/helpers/tokensToJson.ts b/frontend/src/designTokens/helpers/tokensToJson.ts index a316ce3c..3e2802ac 100644 --- a/frontend/src/designTokens/helpers/tokensToJson.ts +++ b/frontend/src/designTokens/helpers/tokensToJson.ts @@ -5,7 +5,7 @@ import designTokens from '../designTokens'; import type { Typeface } from '../tokens/typography/typeface'; import type { TypeScale } from '../tokens/typography/typescale'; -const outputFile = path.resolve('libs/shared/dist/designTokens.json'); +const outputFile = path.resolve('frontend/src/designTokens/designTokens.json'); type FontSize = [string, { lineHeight: string; fontWeight: string }]; From 06588cb503931f005e1f4282c96dfa00c5d216a9 Mon Sep 17 00:00:00 2001 From: ofava Date: Wed, 29 Oct 2025 17:27:18 +0100 Subject: [PATCH 3/5] Copilot suggestions --- frontend/src/designTokens/helpers/tokensToJson.ts | 9 +++++---- frontend/src/designTokens/tokens/typography/typeface.ts | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/designTokens/helpers/tokensToJson.ts b/frontend/src/designTokens/helpers/tokensToJson.ts index 3e2802ac..403b0a1c 100644 --- a/frontend/src/designTokens/helpers/tokensToJson.ts +++ b/frontend/src/designTokens/helpers/tokensToJson.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ import * as fs from 'node:fs'; import * as path from 'node:path'; -import designTokens from '../designTokens'; +import designTokens from '../designTokens.ts'; import type { Typeface } from '../tokens/typography/typeface'; import type { TypeScale } from '../tokens/typography/typescale'; @@ -103,9 +103,10 @@ function isUndefined(value: unknown): value is undefined { } /** - * Type guard to check if a value is a Record. - * @param {unknown} fontSizes - The value to check. - * @returns {boolean} True if the value is a Record, false otherwise. + * Transforms font size objects into Tailwind CSS fontSize format. + * Converts each font size entry into a tuple with fontSize and associated properties. + * @param {Record} fontSizes - The font size objects to transform. + * @returns {Record} The transformed font sizes in Tailwind format. */ function parseFontSize( fontSizes: Record diff --git a/frontend/src/designTokens/tokens/typography/typeface.ts b/frontend/src/designTokens/tokens/typography/typeface.ts index ac91906e..bcdc1d15 100644 --- a/frontend/src/designTokens/tokens/typography/typeface.ts +++ b/frontend/src/designTokens/tokens/typography/typeface.ts @@ -15,7 +15,7 @@ const typeface = { export type Typeface = keyof typeof typeface; export type TypefaceProps = { - value: string | number; + value: string; type: 'fontFamily'; description: string; }; From f51c06e7d5adcf60b16e7a4b2e91f890793f3e6b Mon Sep 17 00:00:00 2001 From: ofava Date: Thu, 30 Oct 2025 09:16:36 +0100 Subject: [PATCH 4/5] Minor fix --- frontend/src/designTokens/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/designTokens/index.ts b/frontend/src/designTokens/index.ts index 592014d7..4fc6d19e 100644 --- a/frontend/src/designTokens/index.ts +++ b/frontend/src/designTokens/index.ts @@ -1,3 +1,3 @@ -import designTokens from './designTokens'; +import designTokens from './designTokens.ts'; export default designTokens; From a0fdc94899c9794214d55c2cda3afee366413e09 Mon Sep 17 00:00:00 2001 From: ofava Date: Thu, 30 Oct 2025 14:04:50 +0100 Subject: [PATCH 5/5] Ignore library in sonar --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index f5ea12bb..a1b0bb04 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,5 +11,5 @@ sonar.projectName=vonage-video-react-app # Encoding of the source code. Default is default system encoding sonar.sourceEncoding=UTF-8 # sonar.sources=src -sonar.exclusions=**/*.spec.tsx,**/*.spec.ts,**/*.test.ts,tests/**,node_modules/**,integration-tests/**,scripts/** +sonar.exclusions=**/*.spec.tsx,**/*.spec.ts,**/*.test.ts,tests/**,node_modules/**,integration-tests/**,scripts/**,frontend/src/designTokens/** sonar.javascript.lcov.reportPaths=**/coverage/lcov.info