From d07bae8600284a2014c3768ec80f34347ef5aa46 Mon Sep 17 00:00:00 2001 From: Georg Ekeberg Date: Mon, 3 Feb 2025 16:49:42 +0100 Subject: [PATCH] feat(ffe-datepicker)!: add semantic colors to components BREAKING CHANGE: Add semantic colors --- count-stories.js | 212 +++++++++++++++++++ packages/ffe-datepicker/less/calendar.less | 152 +++++++++---- packages/ffe-datepicker/less/dateinput.less | 57 +++-- packages/ffe-datepicker/less/datepicker.less | 1 - packages/ffe-datepicker/less/theme.less | 34 --- 5 files changed, 368 insertions(+), 88 deletions(-) create mode 100644 count-stories.js delete mode 100644 packages/ffe-datepicker/less/theme.less diff --git a/count-stories.js b/count-stories.js new file mode 100644 index 0000000000..19dfb767ca --- /dev/null +++ b/count-stories.js @@ -0,0 +1,212 @@ +const fs = require('fs'); +const path = require('path'); + +function countStoryFiles(directoryPath) { + const storyFiles = []; + const excludedStoryFiles = []; + const errors = []; + + // Folders to exclude + const excludeFolders = [ + 'ffe-buttons-react', + 'ffe-messages-react', + 'ffe-feedback-react', + 'ffe-chips-react', + 'ffe-core', + 'ffe-accordion-react', + 'ffe-datepicker-react', + ]; + + const colors = { + pink: '\x1b[38;5;218m', + blue: '\x1b[38;5;153m', + green: '\x1b[38;5;151m', + yellow: '\x1b[38;5;222m', + purple: '\x1b[38;5;183m', + cyan: '\x1b[38;5;159m', + reset: '\x1b[0m', + dim: '\x1b[2m', + bold: '\x1b[1m', + red: '\x1b[38;5;203m', + }; + + // Function to get color based on progress + function getProgressColor(progress) { + // Define color stops from red to yellow to green + const colorStops = [ + { percent: 0, color: '203' }, // Light red + { percent: 50, color: '222' }, // Light yellow + { percent: 100, color: '151' }, // Light green + ]; + + // Find the two color stops we're between + let start = colorStops[0]; + let end = colorStops[1]; + + for (let i = 0; i < colorStops.length - 1; i++) { + if ( + progress >= colorStops[i].percent && + progress <= colorStops[i + 1].percent + ) { + start = colorStops[i]; + end = colorStops[i + 1]; + break; + } + } + + // Calculate the color number based on progress between stops + const range = end.percent - start.percent; + const progressInRange = progress - start.percent; + const percentage = progressInRange / range; + + const startColor = parseInt(start.color); + const endColor = parseInt(end.color); + const color = Math.round( + startColor + (endColor - startColor) * percentage, + ); + + return `\x1b[38;5;${color}m`; + } + + function traverseExcludedDirectory(currentPath) { + try { + const files = fs.readdirSync(currentPath); + + for (const file of files) { + const filePath = path.join(currentPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory() && !file.startsWith('.')) { + traverseExcludedDirectory(filePath); + } else if (stats.isFile()) { + if (file.match(/\.stories\.(tsx|jsx)$/)) { + excludedStoryFiles.push({ + name: file, + path: filePath, + }); + } + } + } + } catch (error) { + errors.push(`Error accessing ${currentPath}: ${error.message}`); + } + } + + function traverseDirectory(currentPath) { + try { + const files = fs.readdirSync(currentPath); + + for (const file of files) { + const filePath = path.join(currentPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + // Check if it's an excluded folder at the root level + const isExcludedFolder = excludeFolders.includes(file); + + // Skip node_modules and hidden directories + if (file !== 'node_modules' && !file.startsWith('.')) { + // If it's an excluded folder, store its stories separately + if (isExcludedFolder) { + traverseExcludedDirectory(filePath); + } else { + traverseDirectory(filePath); + } + } + } else if (stats.isFile()) { + // Check if file matches story file pattern + if (file.match(/\.stories\.(tsx|jsx)$/)) { + storyFiles.push({ + name: file, + path: filePath, + }); + } + } + } + } catch (error) { + errors.push(`Error accessing ${currentPath}: ${error.message}`); + } + } + + traverseDirectory(directoryPath); + + // Calculate statistics + const totalStories = storyFiles.length + excludedStoryFiles.length; + const progressPercentage = ( + (excludedStoryFiles.length / totalStories) * + 100 + ).toFixed(1); + + // Print results + console.log( + `\n${colors.purple}${colors.bold} Storybook Story Files Analysis${colors.reset}`, + ); + console.log( + `${colors.dim}═══════════════════════════════${colors.reset}\n`, + ); + + console.log(`${colors.blue} Regular Story Files:${colors.reset}`); + storyFiles.forEach(file => { + console.log( + ` ${colors.dim}└─${colors.reset} ${colors.cyan}${file.name}${colors.reset} ${colors.dim}(${file.path})${colors.reset}`, + ); + }); + + console.log( + `\n${colors.pink} Progress on "Semantiske farger":${colors.reset}`, + ); + console.log(`${colors.dim}──────────────────────────────${colors.reset}`); + console.log( + ` ${colors.yellow}Stories in excluded folders: ${excludedStoryFiles.length}${colors.reset}`, + ); + console.log( + ` ${colors.yellow}Stories remaining: ${storyFiles.length}${colors.reset}`, + ); + console.log( + ` ${colors.green}Progress: ${progressPercentage}% complete${colors.reset}`, + ); + + // Create progress bar with gradient color + const progressColor = getProgressColor(parseFloat(progressPercentage)); + const progressBlocks = Math.floor(progressPercentage / 5); + const emptyBlocks = 20 - progressBlocks; + + console.log( + ` ${colors.bold}[${progressColor}${Array(progressBlocks) + .fill('█') + .join('')}${colors.dim}${Array(emptyBlocks) + .fill('░') + .join('')}${colors.reset}]`, + ); + + console.log(`\n${colors.purple} Summary:${colors.reset}`); + console.log(`${colors.dim}──────────────${colors.reset}`); + console.log( + ` ${colors.cyan}Total story files: ${totalStories}${colors.reset}`, + ); + console.log( + ` ${colors.cyan}Excluded folders: ${colors.dim}${excludeFolders.join(', ')}${colors.reset}`, + ); + + if (errors.length > 0) { + console.log(`\n${colors.yellow}⚠️ Errors encountered:${colors.reset}`); + errors.forEach(error => + console.log(` ${colors.red}❌ ${error}${colors.reset}`), + ); + } + + return { + totalFiles: storyFiles.length, + excludedFilesCount: excludedStoryFiles.length, + progressPercentage, + files: storyFiles, + excludedFiles: excludedStoryFiles, + errors, + }; +} + +// Get the directory path from command line argument, or use current directory +const targetDirectory = process.argv[2] || process.cwd(); + +// Run the counter +countStoryFiles(targetDirectory); diff --git a/packages/ffe-datepicker/less/calendar.less b/packages/ffe-datepicker/less/calendar.less index 079a4fb710..b4f6c5e34a 100644 --- a/packages/ffe-datepicker/less/calendar.less +++ b/packages/ffe-datepicker/less/calendar.less @@ -1,10 +1,11 @@ @import (reference) '@sb1/ffe-core/less/typography'; .ffe-calendar { - border: var(--ffe-g-border-width) solid var(--ffe-g-border-color); + border: 1px solid var(--ffe-color-foreground-default); border-radius: var(--ffe-g-border-radius); padding: var(--ffe-spacing-2xs); - background: var(--ffe-v-datepicker-bg-color); + background: var(--ffe-color-background-default); + color: var(--ffe-color-foreground); overflow-y: auto; &--datepicker { @@ -23,9 +24,11 @@ &__header { text-align: center; + color: var(--ffe-color-foreground-emphasis); padding: var(--ffe-spacing-sm) var(--ffe-spacing-2xs) var(--ffe-spacing-2xs); width: 100%; + margin-bottom: var(--ffe-spacing-xs); } &__header-inner-wrapper { @@ -34,8 +37,15 @@ align-items: center; } - &__month { + &__month, + &__title { padding-right: var(--ffe-spacing-xs); + color: var(--ffe-color-foreground-emphasis); + font-family: var(--ffe-g-font-heading-small); + font-size: var(--ffe-fontsize-h5); + display: inline-block; + vertical-align: middle; + margin-bottom: 0; } &__month-nav { @@ -65,23 +75,13 @@ &__icon-prev.ffe-icons, &__icon-next.ffe-icons { - color: var(--ffe-v-datepicker-icon-color); + color: var(--ffe-color-foreground-emphasis); } &__icon-next { transform: rotate(180deg); } - &__title { - font-family: var(--ffe-g-font-heading-small); - font-size: var(--ffe-fontsize-h5); - color: var(--ffe-v-datepicker-title-color); - display: inline-block; - vertical-align: middle; - min-width: 50%; - margin-bottom: 0; - } - &__accessible-text { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); @@ -100,8 +100,29 @@ &__weekday { .ffe-small-text(); - border-bottom: 1px solid var(--ffe-v-datepicker-weekday-border-color); - color: var(--ffe-v-datepicker-weekday-color); + color: var(--ffe-color-foreground-subtle); + } + + &__weekdays { + margin-bottom: var(--ffe-spacing-2xs); + } + + thead { + display: block; + border-bottom: 1px solid var(--ffe-color-foreground-emphasis); + margin-bottom: var(--ffe-spacing-2xs); + padding-bottom: var(--ffe-spacing-3xs); + } + + tr { + display: flex; + justify-content: space-between; + } + + td, + th { + flex: 1; + text-align: center; } &__day { @@ -114,41 +135,33 @@ .ffe-small-text(); font-size: 1rem; - background-color: var(--ffe-v-datepicker-bg-color); + background-color: var(); width: 2.1875rem; aspect-ratio: 1; - color: var(--ffe-v-datepicker-date-color); + color: var(--ffe-color-foreground-default); border-radius: 4px; display: inline-block; line-height: 2.1875; - border: 2px solid transparent; cursor: pointer; &--today { border: 1px solid var(--ffe-v-datepicker-date-color-today); } - &:focus { - border: 2px solid var(--ffe-v-datepicker-border-hover-color); - color: var(--ffe-v-datepicker-date-color-hover); - outline: none; - } - @media (hover: hover) and (pointer: fine) { &:hover { - border: 2px solid var(--ffe-v-datepicker-border-hover-color); - color: var(--ffe-v-datepicker-date-color-hover); + background: var(--ffe-color-fill-primary-hover); + color: var(--ffe-color-foreground-inverse); } } - &--focus { - border: 2px solid var(--ffe-v-datepicker-border-hover-color); - background: var(--ffe-v-datepicker-bg-color); + &:active { + background: var(--ffe-color-fill-primary-pressed); } &--selected { - background: var(--ffe-v-datepicker-border-hover-color); - color: var(--ffe-v-datepicker-bg-color); + background: var(--ffe-color-fill-primary-selected); + color: var(--ffe-color-foreground-inverse); @media (hover: hover) and (pointer: fine) { &:hover { @@ -157,12 +170,6 @@ } } - &--focus&--selected { - box-shadow: - 0 0 0 2px var(--ffe-v-datepicker-bg-color), - 0 0 0 4px var(--ffe-v-datepicker-border-hover-color); - } - &--disabled { color: var(--ffe-v-datepicker-date-color-disabled); @@ -185,3 +192,72 @@ } } } + +:root, +:host { + --ffe-v-datepicker-bg-color: var( + --ffe-color-component-form-input-fill-default + ); + --ffe-v-datepicker-border-hover-color: var( + --ffe-color-border-primary-hover + ); + --ffe-v-datepicker-icon-color: var(--ffe-color-foreground-interactive-link); + --ffe-v-datepicker-icon-color-hover: var( + --ffe-color-foreground-interactive-link-hover + ); + --ffe-v-datepicker-title-color: var(--ffe-color-foreground-default); + --ffe-v-datepicker-weekday-color: var(--ffe-color-foreground-subtle); + --ffe-v-datepicker-weekday-border-color: var( + --ffe-color-border-primary-subtle + ); + --ffe-v-datepicker-date-color: var(--ffe-color-foreground-default); + --ffe-v-datepicker-date-color-today: var( + --ffe-color-border-primary-emphasis + ); + --ffe-v-datepicker-date-color-hover: var(--ffe-color-fill-primary-hover); + --ffe-v-datepicker-date-color-focus: var( + --ffe-color-border-interactive-focus + ); + --ffe-v-datepicker-date-color-disabled: var(--ffe-color-foreground-subtle); + --ffe-v-datepicker-spinbutton-hover-color: var( + --ffe-color-surface-primary-default-hover + ); + + @media (prefers-color-scheme: dark) { + .regard-color-scheme-preference { + --ffe-v-datepicker-bg-color: var(--ffe-color-background-default); + --ffe-v-datepicker-border-hover-color: var( + --ffe-color-border-primary-hover + ); + --ffe-v-datepicker-icon-color: var( + --ffe-color-foreground-interactive-link + ); + --ffe-v-datepicker-icon-color-hover: var( + --ffe-color-foreground-interactive-link-hover + ); + --ffe-v-datepicker-title-color: var(--ffe-color-foreground-default); + --ffe-v-datepicker-weekday-color: var( + --ffe-color-foreground-subtle + ); + --ffe-v-datepicker-weekday-border-color: var( + --ffe-color-border-primary-subtle + ); + --ffe-v-datepicker-date-color: var(--ffe-color-foreground-default); + --ffe-v-datepicker-date-color-today: var( + --ffe-color-border-primary-emphasis + ); + --ffe-v-datepicker-date-color-hover: var( + --ffe-color-fill-primary-hover + ); + --ffe-v-datepicker-date-color-focus: var( + --ffe-color-border-interactive-focus + ); + --ffe-v-datepicker-date-color-disabled: var( + --ffe-color-foreground-subtle + ); + --ffe-v-datepicker-spinbutton-hover-color: var( + --ffe-color-surface-primary-default-hover + ); + } + } +} diff --git a/packages/ffe-datepicker/less/dateinput.less b/packages/ffe-datepicker/less/dateinput.less index be9c3de82f..637d875fc5 100644 --- a/packages/ffe-datepicker/less/dateinput.less +++ b/packages/ffe-datepicker/less/dateinput.less @@ -1,22 +1,29 @@ +.ffe-input-group { + > .ffe-form-label { + color: var(--ffe-color-foreground-default) !important; + } +} + .ffe-dateinput { position: relative; display: inline-block; grid-column: 1 e('/') 3; grid-row: 1 e('/') -1; min-width: 210px; + color: var(--ffe-color-foreground-default); &--full-width { display: block; } &:focus-within { - border: var(--ffe-g-border-width-focus) solid var(--ffe-g-primary-color); + border: 2px solid var(--ffe-color-border-interactive-focus); outline: none; & + .ffe-datepicker__button { @media (hover: hover) and (pointer: fine) { &:hover { - border: var(--ffe-g-border-width-focus) solid var(--ffe-g-primary-color); + border: 2px solid var(--ffe-color-border-interactive-focus); outline: none; } } @@ -26,33 +33,47 @@ &.ffe-input-field { display: flex; align-items: center; + border: 2px solid var(--ffe-color-border-primary-default); + background-color: var(--ffe-color-component-form-input-fill-default); + + @media (hover: hover) and (pointer: fine) { + &:hover, + &:has(+ .ffe-datepicker__button:hover) { + border-color: var(--ffe-color-border-primary-hover); + + & + .ffe-datepicker__button { + border-color: var(--ffe-color-border-primary-hover); + } + } + } &--invalid { - border: var(--ffe-g-border-width) solid var(--ffe-g-error-color); + border: 2px solid var(--ffe-color-border-feedback-critical); @media (hover: hover) and (pointer: fine) { &:hover { - border-color: var(--ffe-g-error-color); + border-color: var(--ffe-color-border-feedback-critical); } &:focus-within:hover { - border: var(--ffe-g-border-width-focus) solid var(--ffe-g-error-color); + border: 2px solid var(--ffe-color-border-feedback-critical); } } &:focus-within { - border: var(--ffe-g-border-width-focus) solid var(--ffe-g-error-color); + border: 2px solid var(--ffe-color-border-feedback-critical); outline: none; } & + .ffe-datepicker__button { &:focus-visible { - border-color: var(--ffe-g-error-color); + border-color: var(--ffe-color-border-feedback-critical); border-style: solid; } @media (hover: hover) and (pointer: fine) { &:hover { - border: var(--ffe-g-border-width-focus) solid var(--ffe-g-error-color); + border: 2px solid + var(--ffe-color-border-feedback-critical); outline: none; } } @@ -62,13 +83,15 @@ &__field { padding-block: var(--ffe-spacing-2xs); + color: var(--ffe-color-foreground-default); + background-color: transparent; &-year { min-width: 4ch; } &:focus { - background-color: var(--ffe-v-datepicker-spinbutton-hover-color); + background-color: transparent; outline: none; } @@ -92,8 +115,8 @@ } &__button { - background-color: transparent; - border: var(--ffe-g-border-width) solid transparent; + background-color: var(--ffe-color-background-default); + border: 2px solid var(--ffe-color-border-primary-default); grid-column: 2 e('/') 3; grid-row: 1 e('/') -1; outline: none; @@ -105,24 +128,28 @@ &:focus, &:active { - border: var(--ffe-g-border-width-focus) solid var(--ffe-v-datepicker-border-hover-color); + border: 2px solid var(--ffe-color-border-interactive-focus); } @media (hover: hover) and (pointer: fine) { &:hover { - border-color: var(--ffe-v-datepicker-border-hover-color); + border-color: var(--ffe-color-border-primary-hover); + + & ~ .ffe-input-field { + border-color: var(--ffe-color-border-primary-hover); + } } } } &__icon.ffe-icons { vertical-align: middle; - color: var(--ffe-v-datepicker-icon-color); + color: var(--ffe-color-foreground-interactive-link); transition: color var(--ffe-transition-duration) var(--ffe-ease); @media (hover: hover) and (pointer: fine) { &:hover { - color: var(--ffe-v-datepicker-icon-color-hover); + color: var(--ffe-color-foreground-interactive-link-hover); } } } diff --git a/packages/ffe-datepicker/less/datepicker.less b/packages/ffe-datepicker/less/datepicker.less index b9aba74ca1..7b31a0a36f 100644 --- a/packages/ffe-datepicker/less/datepicker.less +++ b/packages/ffe-datepicker/less/datepicker.less @@ -1,3 +1,2 @@ -@import 'theme'; @import 'dateinput'; @import 'calendar'; diff --git a/packages/ffe-datepicker/less/theme.less b/packages/ffe-datepicker/less/theme.less deleted file mode 100644 index e41517ccb1..0000000000 --- a/packages/ffe-datepicker/less/theme.less +++ /dev/null @@ -1,34 +0,0 @@ -:root, -:host { - --ffe-v-datepicker-bg-color: var(--ffe-farge-hvit); - --ffe-v-datepicker-border-hover-color: var(--ffe-g-primary-color); - --ffe-v-datepicker-icon-color: var(--ffe-g-primary-color); - --ffe-v-datepicker-icon-color-hover: var(--ffe-g-secondary-color); - --ffe-v-datepicker-title-color: var(--ffe-farge-svart); - --ffe-v-datepicker-weekday-color: var(--ffe-farge-moerkgraa); - --ffe-v-datepicker-weekday-border-color: var(--ffe-farge-lysgraa); - --ffe-v-datepicker-date-color: var(--ffe-g-text-color); - --ffe-v-datepicker-date-color-today: var(--ffe-farge-varmgraa); - --ffe-v-datepicker-date-color-hover: var(--ffe-farge-vann); - --ffe-v-datepicker-date-color-focus: var(--ffe-farge-vann); - --ffe-v-datepicker-date-color-disabled: var(--ffe-farge-varmgraa); - --ffe-v-datepicker-spinbutton-hover-color: var(--ffe-farge-frost-30); - - @media (prefers-color-scheme: dark) { - .regard-color-scheme-preference { - --ffe-v-datepicker-bg-color: var(--ffe-farge-svart); - --ffe-v-datepicker-border-hover-color: var(--ffe-g-primary-color); - --ffe-v-datepicker-icon-color: var(--ffe-g-primary-color); - --ffe-v-datepicker-icon-color-hover: var(--ffe-farge-vann-30); - --ffe-v-datepicker-title-color: var(--ffe-farge-vann-70); - --ffe-v-datepicker-weekday-color: var(--ffe-farge-graa); - --ffe-v-datepicker-weekday-border-color: var(--ffe-farge-varmgraa); - --ffe-v-datepicker-date-color: var(--ffe-farge-hvit); - --ffe-v-datepicker-date-color-today: var(--ffe-farge-graa); - --ffe-v-datepicker-date-color-hover: var(--ffe-farge-vann-70); - --ffe-v-datepicker-date-color-focus: var(--ffe-farge-vann-70); - --ffe-v-datepicker-date-color-disabled: var(--ffe-farge-graa); - --ffe-v-datepicker-spinbutton-hover-color: var(--ffe-farge-vann); - } - } -}