diff --git a/packages/@n8n/stylelint-config/README.md b/packages/@n8n/stylelint-config/README.md new file mode 100644 index 00000000000..d68af1dccd7 --- /dev/null +++ b/packages/@n8n/stylelint-config/README.md @@ -0,0 +1,357 @@ +# @n8n/stylelint-config + +Stylelint configuration for n8n projects with custom CSS variable naming convention enforcement. + +## Features + +- Pre-configured stylelint rules for SCSS/Sass and Vue files +- Custom CSS variable naming convention based on the [proposal.md](../../../proposal.md) +- Automatic enforcement via pre-commit hooks +- CI/CD integration + +## Installation + +This package is already configured in n8n frontend packages. To use it in a new package: + +```json +{ + "devDependencies": { + "@n8n/stylelint-config": "workspace:*" + } +} +``` + +## Usage + +Create a `stylelint.config.mjs` file: + +```javascript +import { baseConfig } from '@n8n/stylelint-config/base'; + +export default baseConfig; +``` + +Add scripts to your `package.json`: + +```json +{ + "scripts": { + "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache", + "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache" + } +} +``` + +## CSS Variable Naming Convention + +The `@n8n/css-var-naming` rule enforces a structured naming pattern for CSS custom properties (variables). + +### Pattern Structure + +``` +--[namespace--][component[--part]--]property--value[--variant][--state][--mode][--media] +``` + +**Required groups:** +- `property`: Property name from vocabulary (color, background, spacing, etc.) +- `value`: Semantic name or scale value + +**Optional groups (in order):** +- `namespace`: `n8n`, `chat`, or `p` (for primitives) +- `component`: Component name (e.g., `button`, `input`) +- `part`: Sub-component (e.g., `menu`, `tab`, `arrow`) +- `variant`: Visual style (e.g., `solid`, `outline`, `ghost`) +- `state`: Interaction state (e.g., `hover`, `active`, `focus`, `disabled`) +- `mode`: Theme/environment (e.g., `light`, `dark`, `hc`) +- `media`: Breakpoint (e.g., `sm`, `md`, `lg`) + +### Rules + +1. **Pattern**: Double dash `--` between groups, single dash `-` within groups (kebab-case) +2. **Case**: Lowercase alphanumerics only +3. **Groups**: Minimum 2, maximum 8 groups +4. **Order**: Groups must follow the canonical order shown above + +### Valid Examples + +```css +/* Global tokens */ +--color--primary: #0d6efd; +--spacing--md: 20px; +--text-color--muted: #888; + +/* With namespace */ +--n8n--color--primary: #0d6efd; +--chat--button--background--primary: #0d6efd; +--p--color--primary-500: #0d6efd; +--p--color--gray-740: #2e3440; + +/* Component tokens */ +--button--background--primary: #0d6efd; +--button--text-color--on-primary: #fff; +--tabs--tab--text-color--muted: #888; + +/* With states */ +--button--background--primary--hover: #0b5ed7; +--input--border-color--primary--focus: blue; + +/* With variants */ +--button--background--primary--solid: #0d6efd; +--button--background--primary--outline: transparent; + +/* With variants and states */ +--button--background--primary--solid--hover: #0b5ed7; +--button--background--primary--outline--focus: rgba(13, 110, 253, 0.5); + +/* With modes */ +--color--primary--dark: #66a3ff; +--background--surface--dark: #000; + +/* Complex patterns */ +--n8n--button--background--primary--solid--hover--dark: #0a58ca; +``` + +### Invalid Examples + +```css +/* ❌ Single dash between groups */ +--color-primary: #0d6efd; + +/* ❌ Only one group */ +--primary: #0d6efd; + +/* ❌ Uppercase letters */ +--Color--Primary: #0d6efd; + +/* ❌ Missing property from vocabulary */ +--button--main--primary: #0d6efd; + +/* ❌ Invalid value (too short) */ +--color--xyz: #0d6efd; + +/* ❌ Wrong order (state before variant) */ +--button--background--primary--hover--solid: #0d6efd; + +/* ❌ Missing required property */ +--p--gray-740: #2e3440; +``` + +## Property Vocabulary + +The following properties are recognized: + +| Property | CSS Mapping | Description | +|----------|-------------|-------------| +| `color` | `color` | Text/element color | +| `text-color` | `color` | Text-specific color | +| `background` | `background-color` | Background color | +| `border-color` | `border-color` | Border color | +| `border-width` | `border-width` | Border width | +| `icon-color` | `fill`/`stroke` | Icon color | +| `radius` | `border-radius` | Border radius | +| `shadow` | `box-shadow` | Box shadow | +| `spacing` | `margin`/`padding` | Spacing scale | +| `font-size` | `font-size` | Font size | +| `font-weight` | `font-weight` | Font weight | +| `line-height` | `line-height` | Line height | +| `z` | `z-index` | Z-index | +| `duration` | `transition-duration` | Animation duration | +| `easing` | `transition-timing-function` | Animation easing | +| `outline-color` | `outline-color` | Outline color | +| `outline-width` | `outline-width` | Outline width | + +## Value Types + +### Semantic Values + +Use semantic names for values when possible: + +- **Colors**: `primary`, `secondary`, `success`, `warning`, `danger`, `info`, `muted`, `surface`, `on-primary`, `on-surface` +- **Variants**: `solid`, `outline`, `ghost`, `link`, `soft`, `subtle` +- **States**: `hover`, `active`, `focus`, `focus-visible`, `visited`, `disabled`, `selected`, `checked`, `invalid`, `opened`, `closed`, `loading` +- **Modes**: `light`, `dark`, `hc` (high-contrast), `rtl`, `print` + +### Scale Values + +Use scale values for sizes and spacing: + +- **Size scales**: `none`, `2xs`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl` +- **Special**: `pill`, `full` +- **Font weights**: `regular`, `medium`, `semibold`, `bold` +- **Numeric scales**: `primary-100`, `primary-500`, `danger-700` + +### Custom Values + +Descriptive value names with 4+ characters are also accepted: +- `base`, `thin`, `thick`, `fast`, `slow`, `modal`, `tooltip`, `purple`, `teal` + +## Usage in CSS/SCSS/Vue + +### Global Tokens + +Define global design tokens in a central location: + +```scss +:root { + --color--primary: #0d6efd; + --color--secondary: #6c757d; + --spacing--sm: 8px; + --spacing--md: 16px; + --spacing--lg: 24px; +} +``` + +### Component Tokens + +Create component-specific tokens that reference globals: + +```scss +:root { + --button--background--primary: var(--color--primary); + --button--text-color--on-primary: #ffffff; + --button--radius--md: var(--radius--md); + --button--padding--md: var(--spacing--md); +} +``` + +### Usage in Components + +```scss +.button { + background: var(--button--background--primary); + color: var(--button--text-color--on-primary); + border-radius: var(--button--radius--md); + padding: var(--button--padding--md); + + &:hover { + background: var(--button--background--primary--hover); + } +} +``` + +### Theming + +Override variables for different themes: + +```scss +:root { + --color--primary: #0d6efd; + --color--surface: #ffffff; + --button--background--primary: var(--color--primary); +} + +:root[data-theme="dark"] { + --color--primary: #66a3ff; + --color--surface: #0f1115; + /* button tokens automatically update through var() references */ +} +``` + +### Namespaced Tokens + +Use namespaces for cross-app libraries: + +```scss +/* In @n8n/design-system */ +:root { + --n8n--color--primary: #ff6d5a; + --n8n--button--background--primary: var(--n8n--color--primary); +} + +/* In @n8n/chat */ +:root { + --chat--color--primary: #0d6efd; + --chat--button--background--primary: var(--chat--color--primary); +} +``` + +## CI/CD Integration + +The stylelint rule runs automatically in: + +1. **Pre-commit hooks** (via lefthook): + - Validates CSS variables before commit + - Auto-fixes issues when possible + +2. **GitHub Actions CI**: + - Runs on all pull requests + - Blocks merging if violations are found + +## Development + +### Running Tests + +```bash +cd packages/@n8n/stylelint-config +pnpm test +``` + +### Building + +```bash +pnpm build +``` + +### Testing the Rule + +```bash +# Test on a specific file +pnpm stylelint "path/to/file.scss" --config stylelint.config.mjs + +# Test with auto-fix +pnpm stylelint "path/to/file.scss" --fix --config stylelint.config.mjs +``` + +## Troubleshooting + +### Common Issues + +**Issue**: Rule not being applied +- **Solution**: Make sure package is built: `pnpm build` + +**Issue**: Too many violations in existing codebase +- **Solution**: Use `--fix` to auto-fix pattern issues, or add `/* stylelint-disable @n8n/css-var-naming */` temporarily + +**Issue**: False positive for a valid pattern +- **Solution**: Check the pattern follows the canonical structure. If it's a legitimate case, please file an issue. + +### Disabling the Rule + +To disable for a specific line: +```css +/* stylelint-disable-next-line @n8n/css-var-naming */ +--legacy-var-name: value; +``` + +To disable for a file: +```css +/* stylelint-disable @n8n/css-var-naming */ +``` + +To disable in config (not recommended): +```javascript +export default { + ...baseConfig, + rules: { + ...baseConfig.rules, + '@n8n/css-var-naming': null, + }, +}; +``` + +## References + +- [Stylelint Documentation](https://stylelint.io/) +- [n8n Design System](../frontend/@n8n/design-system/) + +## Contributing + +When modifying the rule: + +1. Update the rule in `src/rules/css-var-naming.ts` +2. Add/update tests in `src/rules/css-var-naming.test.ts` +3. Run tests: `pnpm test` +4. Build: `pnpm build` +5. Update this README if needed + +All tests must pass before submitting changes. diff --git a/packages/@n8n/stylelint-config/jest.config.cjs b/packages/@n8n/stylelint-config/jest.config.cjs new file mode 100644 index 00000000000..d14f2d60c69 --- /dev/null +++ b/packages/@n8n/stylelint-config/jest.config.cjs @@ -0,0 +1,7 @@ +/** @type {import('jest').Config} */ +module.exports = { + ...require('../../../jest.config'), + transform: { + '^.+\\.ts$': ['ts-jest', { isolatedModules: false }], + }, +}; diff --git a/packages/@n8n/stylelint-config/package.json b/packages/@n8n/stylelint-config/package.json index b4a7bac620e..00e12b9ffc1 100644 --- a/packages/@n8n/stylelint-config/package.json +++ b/packages/@n8n/stylelint-config/package.json @@ -7,6 +7,13 @@ "./base": { "default": "./dist/configs/base.js", "types": "./dist/configs/base.d.ts" + }, + "./rules": { + "default": "./dist/rules/index.js", + "types": "./dist/rules/index.d.ts" + }, + "./formatter-summary": { + "default": "./dist/formatter-summary.js" } }, "scripts": { @@ -15,6 +22,8 @@ "dev": "pnpm watch", "format": "biome format --write .", "format:check": "biome ci .", + "test": "jest", + "test:dev": "jest --watch", "typecheck": "tsc --noEmit", "watch": "tsc --watch" }, diff --git a/packages/@n8n/stylelint-config/src/configs/base.ts b/packages/@n8n/stylelint-config/src/configs/base.ts index 00f4f5a503f..24ebce337e1 100644 --- a/packages/@n8n/stylelint-config/src/configs/base.ts +++ b/packages/@n8n/stylelint-config/src/configs/base.ts @@ -1,11 +1,13 @@ import type { Config } from 'stylelint'; +import { cssVarNaming } from '../rules/index.js'; export const baseConfig: Config = { // TODO: Extending with standard config requires a lot of manual fixes but would be great to have // extends: 'stylelint-config-standard-scss', // Basic SCSS support with essential rules - plugins: ['stylelint-scss'], + plugins: ['stylelint-scss', cssVarNaming], rules: { + '@n8n/css-var-naming': [true, { severity: 'warning' }], 'no-empty-source': true, // Basic syntax and consistency rules diff --git a/packages/@n8n/stylelint-config/src/formatter-summary.ts b/packages/@n8n/stylelint-config/src/formatter-summary.ts new file mode 100644 index 00000000000..33dcbc3f60e --- /dev/null +++ b/packages/@n8n/stylelint-config/src/formatter-summary.ts @@ -0,0 +1,54 @@ +/** + * Custom stylelint formatter that outputs a summary by package + * @type {import('stylelint').Formatter} + */ +export default function formatter(results) { + const packageStats = new Map(); + let totalWarnings = 0; + let totalErrors = 0; + + for (const result of results) { + if (result.warnings.length === 0) continue; + + // Extract package name from file path + const match = result.source.match(/packages\/([^/]+\/[^/]+)/); + const packageName = match ? match[1] : 'unknown'; + + if (!packageStats.has(packageName)) { + packageStats.set(packageName, { warnings: 0, errors: 0 }); + } + + const stats = packageStats.get(packageName); + + for (const warning of result.warnings) { + if (warning.severity === 'error') { + stats.errors++; + totalErrors++; + } else { + stats.warnings++; + totalWarnings++; + } + } + } + + if (packageStats.size === 0) { + return '✓ No style issues found\n'; + } + + let output = '\n📊 Style Lint Summary:\n'; + output += '─'.repeat(50) + '\n'; + + for (const [packageName, stats] of packageStats) { + const parts = []; + if (stats.errors > 0) parts.push(`${stats.errors} error${stats.errors > 1 ? 's' : ''}`); + if (stats.warnings > 0) parts.push(`${stats.warnings} warning${stats.warnings > 1 ? 's' : ''}`); + + output += ` ${packageName}: ${parts.join(', ')}\n`; + } + + output += '─'.repeat(50) + '\n'; + output += ` Total: ${totalErrors} error${totalErrors !== 1 ? 's' : ''}, ${totalWarnings} warning${totalWarnings !== 1 ? 's' : ''}\n`; + output += '\n'; + + return output; +} diff --git a/packages/@n8n/stylelint-config/src/rules/css-var-naming.test.ts b/packages/@n8n/stylelint-config/src/rules/css-var-naming.test.ts new file mode 100644 index 00000000000..0ee5f14b2e0 --- /dev/null +++ b/packages/@n8n/stylelint-config/src/rules/css-var-naming.test.ts @@ -0,0 +1,644 @@ +import { lint } from 'stylelint'; +import plugin from './css-var-naming'; + +const config = { + plugins: [plugin], + rules: { + '@n8n/css-var-naming': true, + }, +}; + +async function lintCSS(code: string) { + const result = await lint({ + code, + config, + }); + return result.results[0]; +} + +describe('css-var-naming rule', () => { + describe('namespace validation', () => { + it('should accept valid n8n namespace', async () => { + const namespacePattern = ` + :root { + --n8n--color--primary: #0d6efd; + --n8n--button--background--primary: #0d6efd; + --n8n--button--background--primary--hover: #0b5ed7; + --n8n--text-color--muted: #888; + } + `; + const result = await lintCSS(namespacePattern); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept valid chat namespace', async () => { + const namespacePattern = ` + :root { + --chat--color--primary: #0d6efd; + --chat--button--background--primary: #0d6efd; + --chat--text-color--base: #333; + } + `; + const result = await lintCSS(namespacePattern); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept valid p namespace for primitives', async () => { + const namespacePattern = ` + :root { + --p--color--primary: #0d6efd; + --p--color--primary-500: #0d6efd; + --p--spacing--md: 20px; + --p--color--gray-740: #2e3440; + } + `; + const result = await lintCSS(namespacePattern); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept variables without namespace', async () => { + const noNamespace = ` + :root { + --color--primary: #0d6efd; + --button--background--primary: #0d6efd; + } + `; + const result = await lintCSS(noNamespace); + expect(result.warnings).toHaveLength(0); + }); + + it('should allow non-namespace first groups (components)', async () => { + // Note: The rule doesn't strictly enforce namespace validation + // It only recognizes 'n8n' and 'chat' as namespaces for property checking + // Other first groups are treated as components, which is valid + const componentFirst = ` + :root { + --button--background--primary: #0d6efd; + --tabs--tab--color--base: #333; + } + `; + const result = await lintCSS(componentFirst); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept namespace with component and states', async () => { + const complexNamespace = ` + :root { + --n8n--button--background--primary--solid--hover: #0b5ed7; + --chat--input--border-color--primary--focus: blue; + } + `; + const result = await lintCSS(complexNamespace); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept namespace with all 8 groups', async () => { + const maxGroups = ` + :root { + --n8n--button--part--text-color--primary--solid--hover--dark: #000; + } + `; + const result = await lintCSS(maxGroups); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('basic pattern validation', () => { + it('should accept valid patterns with double dashes between groups', async () => { + const validPatterns = ` + :root { + --color--primary: #0d6efd; + --text-color--muted: #5b6270; + --background--surface: #ffffff; + --spacing--md: 20px; + --font-size--lg: 18px; + } + `; + const result = await lintCSS(validPatterns); + expect(result.warnings).toHaveLength(0); + }); + + it('should reject patterns with single dash between groups', async () => { + const invalidPattern = ` + :root { + --color-primary: #0d6efd; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must follow pattern'), + }); + }); + + it('should reject patterns with only one group', async () => { + const invalidPattern = ` + :root { + --primary: #0d6efd; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must follow pattern'), + }); + }); + + it('should reject patterns with uppercase letters', async () => { + const invalidPattern = ` + :root { + --Color--Primary: #0d6efd; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + }); + + it('should reject patterns with underscores', async () => { + const invalidPattern = ` + :root { + --color_primary: #0d6efd; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + }); + + it('should reject patterns with more than 8 groups', async () => { + const invalidPattern = ` + :root { + --a--b--c--d--e--f--g--h--i: value; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + // The pattern is rejected by the basic regex first + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must follow pattern'), + }); + }); + + it('should reject because missing required property', async () => { + const invalidPattern = ` + :root { + --p--gray-740: #2e3440; + } + `; + const result = await lintCSS(invalidPattern); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must include a valid property from vocabulary'), + }); + }); + }); + + describe('property vocabulary validation', () => { + it('should accept variables with valid property names', async () => { + const validProperties = ` + :root { + --color--primary: #0d6efd; + --text-color--base: #333; + --background--light: #fff; + --border-color--primary: #ddd; + --border-width--thin: 1px; + --icon-color--muted: #888; + --radius--md: 4px; + --shadow--sm: 0 1px 2px rgba(0,0,0,0.1); + --spacing--lg: 24px; + --font-size--md: 16px; + --font-weight--bold: 600; + --line-height--normal: 1.5; + --z--modal: 1000; + --duration--fast: 200ms; + --easing--ease-out: ease-out; + --outline-color--focus: blue; + --outline-width--thick: 2px; + } + `; + const result = await lintCSS(validProperties); + expect(result.warnings).toHaveLength(0); + }); + + it('should reject variables without valid property names', async () => { + const invalidProperty = ` + :root { + --primary--value: #0d6efd; + } + `; + const result = await lintCSS(invalidProperty); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('valid property from vocabulary'), + }); + }); + + it('should reject variables with synonym properties', async () => { + const invalidProperty = ` + :root { + --bg--primary: #fff; + } + `; + const result = await lintCSS(invalidProperty); + expect(result.warnings.length).toBeGreaterThan(0); + }); + }); + + describe('component tokens', () => { + it('should accept component-level tokens', async () => { + const componentTokens = ` + :root { + --button--background--primary: #0d6efd; + --button--text-color--on-primary: #fff; + --button--border-color--outline: #ddd; + --card--radius--md: 8px; + --tabs--tab--text-color--muted: #888; + --select--menu--background--dark: #000; + --tooltip--arrow--color--primary: #333; + } + `; + const result = await lintCSS(componentTokens); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept component with part tokens', async () => { + const componentPartTokens = ` + :root { + --tabs--tab--background--surface: #fff; + --select--menu--shadow--lg: 0 4px 8px rgba(0,0,0,0.1); + --tooltip--arrow--border-color--primary: #ddd; + } + `; + const result = await lintCSS(componentPartTokens); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('states validation', () => { + it('should accept valid state modifiers', async () => { + const stateModifiers = ` + :root { + --button--background--primary--hover: #0b5ed7; + --button--background--primary--active: #0a58ca; + --button--background--primary--focus: #0d6efd; + --button--background--primary--focus-visible: #0d6efd; + --button--background--primary--disabled: #ccc; + --input--border-color--primary--invalid: red; + --checkbox--background--primary--checked: #0d6efd; + --select--background--surface--opened: #fff; + --accordion--background--surface--closed: #f5f5f5; + --button--background--primary--loading: #999; + } + `; + const result = await lintCSS(stateModifiers); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept link-specific states', async () => { + const linkStates = ` + :root { + --link--text-color--primary--visited: purple; + --link--text-color--primary--hover: blue; + } + `; + const result = await lintCSS(linkStates); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('variants validation', () => { + it('should accept valid variant modifiers', async () => { + const variantModifiers = ` + :root { + --button--background--primary--solid: #0d6efd; + --button--background--primary--outline: transparent; + --button--background--primary--ghost: transparent; + --button--background--primary--link: transparent; + --button--background--primary--soft: #e7f1ff; + --button--background--primary--subtle: #f0f8ff; + } + `; + const result = await lintCSS(variantModifiers); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept variants with states (variant before state)', async () => { + const variantWithState = ` + :root { + --button--background--primary--solid--hover: #0b5ed7; + --button--background--primary--outline--active: #0a58ca; + --button--background--primary--ghost--focus: rgba(13, 110, 253, 0.1); + } + `; + const result = await lintCSS(variantWithState); + expect(result.warnings).toHaveLength(0); + }); + + it('should reject when state comes before variant', async () => { + const invalidOrder = ` + :root { + --button--background--primary--hover--solid: #0b5ed7; + } + `; + const result = await lintCSS(invalidOrder); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Variant should come before state'), + }); + }); + }); + + describe('modes validation', () => { + it('should accept valid mode modifiers', async () => { + const modeModifiers = ` + :root { + --color--primary--dark: #66a3ff; + --color--primary--light: #0d6efd; + --background--surface--dark: #000; + --background--surface--light: #fff; + --text-color--base--hc: #000; + --spacing--md--rtl: 20px; + --color--primary--print: #000; + } + `; + const result = await lintCSS(modeModifiers); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('media/breakpoint validation', () => { + it('should accept valid media breakpoint modifiers', async () => { + const mediaModifiers = ` + :root { + --spacing--md--sm: 16px; + --spacing--md--md: 20px; + --spacing--md--lg: 24px; + --spacing--md--xl: 32px; + --spacing--md--2xl: 40px; + } + `; + const result = await lintCSS(mediaModifiers); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('semantic values', () => { + it('should accept semantic color values', async () => { + const semanticValues = ` + :root { + --color--primary: #0d6efd; + --color--secondary: #6c757d; + --color--success: #28a745; + --color--warning: #ffc107; + --color--danger: #dc3545; + --color--info: #17a2b8; + --color--muted: #6c757d; + --color--surface: #fff; + --color--on-primary: #fff; + --color--on-surface: #000; + } + `; + const result = await lintCSS(semanticValues); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept scale values', async () => { + const scaleValues = ` + :root { + --spacing--2xs: 2px; + --spacing--xs: 4px; + --spacing--sm: 8px; + --spacing--md: 16px; + --spacing--lg: 24px; + --spacing--xl: 32px; + --spacing--2xl: 48px; + --spacing--3xl: 64px; + --radius--none: 0; + --radius--sm: 2px; + --radius--md: 4px; + --radius--lg: 8px; + --radius--xl: 12px; + --radius--pill: 9999px; + --radius--full: 100%; + --font-weight--regular: 400; + --font-weight--medium: 500; + --font-weight--semibold: 600; + --font-weight--bold: 700; + } + `; + const result = await lintCSS(scaleValues); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept descriptive value names (4+ chars)', async () => { + const descriptiveValues = ` + :root { + --color--purple: #800080; + --text-color--base: #333; + --border-width--thin: 1px; + --z--modal: 1000; + --duration--fast: 200ms; + } + `; + const result = await lintCSS(descriptiveValues); + expect(result.warnings).toHaveLength(0); + }); + + it('should reject very short value names (<4 chars)', async () => { + const shortValue = ` + :root { + --spacing--xxx: 20px; + } + `; + const result = await lintCSS(shortValue); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('too short'), + }); + }); + + it('should accept color shades with numbers', async () => { + const colorShades = ` + :root { + --color--primary-500: #0d6efd; + --color--primary-100: #e7f1ff; + --color--danger-700: #a02622; + } + `; + const result = await lintCSS(colorShades); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept component names as values', async () => { + const componentValues = ` + :root { + --button--background--surface: #fff; + --tooltip--text-color--on-surface: #000; + } + `; + const result = await lintCSS(componentValues); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('var() references validation', () => { + it('should validate CSS variables in var() references', async () => { + const varReferences = ` + .button { + background: var(--button--background--primary); + color: var(--button--text-color--on-primary); + border-color: var(--button--border-color--outline); + } + `; + const result = await lintCSS(varReferences); + expect(result.warnings).toHaveLength(0); + }); + + it('should reject invalid CSS variables in var() references', async () => { + const invalidVarReferences = ` + .button { + background: var(--button-background); + } + `; + const result = await lintCSS(invalidVarReferences); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must follow pattern'), + }); + }); + + it('should reject invalid CSS variables with unknown property in var() references', async () => { + const invalidVarReferences = ` + .button { + background: var(--button--unknown); + } + `; + const result = await lintCSS(invalidVarReferences); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Must include a valid property'), + }); + }); + + it('should reject invalid CSS variables with mixed order in var() references', async () => { + const invalidVarReferences = ` + .button { + background: var(--button--background--primary--hover--solid); + } + `; + const result = await lintCSS(invalidVarReferences); + expect(result.warnings.length).toBeGreaterThan(0); + expect(result.warnings[0]).toMatchObject({ + text: expect.stringContaining('Invalid CSS variable'), + }); + }); + + it('should accept var() with fallback values', async () => { + const varWithFallback = ` + .button { + background: var(--button--background--primary, var(--color--primary)); + border-radius: var(--button--radius--md, var(--radius--md)); + } + `; + const result = await lintCSS(varWithFallback); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('complex real-world examples from proposal', () => { + it('should accept all examples from proposal section 6', async () => { + const proposalExamples = ` + .button { + background: var(--button--background--primary); + color: var(--button--text-color--on-primary); + border-color: var(--button--border-color--ghost); + border-radius: var(--button--radius--md, var(--radius--md)); + box-shadow: var(--button--shadow--sm, var(--shadow--sm)); + } + + .button:hover { + background: var(--button--background--primary--hover); + } + + .input:focus-visible { + outline-color: var(--input--outline-color--focus-visible, var(--color--primary)); + } + + .card { + background: var(--card--background--surface, var(--color--surface)); + box-shadow: var(--card--shadow--lg, var(--shadow--lg)); + } + `; + const result = await lintCSS(proposalExamples); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept theming example from proposal', async () => { + const themingExample = ` + :root { + --color--primary: #0d6efd; + --color--surface: #ffffff; + --text-color--muted: #5b6270; + --button--background--primary: var(--color--primary); + --button--text-color--on-primary: #ffffff; + } + + :root[data-theme="dark"] { + --color--primary: #66a3ff; + --color--surface: #0f1115; + --text-color--muted: #9aa3b2; + } + `; + const result = await lintCSS(themingExample); + expect(result.warnings).toHaveLength(0); + }); + }); + + describe('edge cases', () => { + it('should accept variables with numbers in groups', async () => { + const numbersInGroups = ` + :root { + --color--primary-500: #0d6efd; + --color--primary-shade-50: #0b5ed7; + --color--primary-tint-50: #6ea8fe; + --spacing--2xs: 2px; + --font-size--2xl: 28px; + } + `; + const result = await lintCSS(numbersInGroups); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept kebab-case within groups', async () => { + const kebabCase = ` + :root { + --text-color--on-primary: #fff; + --outline-color--focus-visible: blue; + --font-weight--semi-bold: 600; + } + `; + const result = await lintCSS(kebabCase); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept minimum valid pattern (2 groups)', async () => { + const minimumPattern = ` + :root { + --color--primary: #0d6efd; + --spacing--md: 20px; + } + `; + const result = await lintCSS(minimumPattern); + expect(result.warnings).toHaveLength(0); + }); + + it('should accept maximum valid pattern (8 groups)', async () => { + const maximumPattern = ` + :root { + --namespace--component--part--text-color--primary--solid--hover--dark: #000; + } + `; + const result = await lintCSS(maximumPattern); + expect(result.warnings).toHaveLength(0); + }); + }); +}); diff --git a/packages/@n8n/stylelint-config/src/rules/css-var-naming.ts b/packages/@n8n/stylelint-config/src/rules/css-var-naming.ts new file mode 100644 index 00000000000..54015e4d11a --- /dev/null +++ b/packages/@n8n/stylelint-config/src/rules/css-var-naming.ts @@ -0,0 +1,280 @@ +import stylelint from 'stylelint'; +import type { Rule } from 'stylelint'; + +const ruleName = '@n8n/css-var-naming'; + +const messages = stylelint.utils.ruleMessages(ruleName, { + rejected: (variable: string, reason: string) => `Invalid CSS variable "${variable}": ${reason}`, +}); + +const meta = { + url: 'https://github.com/n8n-io/n8n', +}; + +// Reserved vocabulary from proposal.md +const PROPERTY_VOCABULARY = new Set([ + 'color', + 'text-color', + 'background', + 'border-color', + 'border-width', + 'icon-color', + 'radius', + 'shadow', + 'spacing', + 'font-size', + 'font-weight', + 'line-height', + 'z', + 'duration', + 'easing', + 'outline-color', + 'outline-width', +]); + +const STATES = new Set([ + 'hover', + 'active', + 'focus', + 'focus-visible', + 'visited', + 'disabled', + 'selected', + 'checked', + 'invalid', + 'opened', + 'closed', + 'loading', +]); + +const VARIANTS = new Set(['solid', 'outline', 'ghost', 'link', 'soft', 'subtle']); + +const MODES = new Set(['light', 'dark', 'hc', 'rtl', 'print']); + +const MEDIA = new Set(['sm', 'md', 'lg', 'xl', '2xl']); + +// Allowed namespaces +const NAMESPACES = new Set(['n8n', 'chat', 'p']); + +// Semantic values and scales +const SEMANTIC_VALUES = new Set([ + 'primary', + 'secondary', + 'success', + 'warning', + 'danger', + 'info', + 'muted', + 'surface', + 'on-primary', + 'on-surface', +]); + +const SCALE_VALUES = new Set([ + 'none', + '2xs', + 'xs', + 'sm', + 'md', + 'lg', + 'xl', + '2xl', + '3xl', + 'pill', + 'full', + 'regular', + 'medium', + 'semibold', + 'bold', +]); + +// Regex for basic validation +const BASIC_PATTERN = /^--[a-z0-9]+(?:-[a-z0-9]+)*(?:--[a-z0-9]+(?:-[a-z0-9]+)*){1,7}$/; + +interface ValidationResult { + valid: boolean; + reason?: string; +} + +function validateCssVariable(variable: string): ValidationResult { + // Basic pattern check + if (!BASIC_PATTERN.test(variable)) { + return { + valid: false, + reason: + 'Must follow pattern: --[group]--[group]--... with lowercase alphanumerics and single dash within groups', + }; + } + + // Split into groups (drop first empty element from leading --) + const groups = variable.slice(2).split('--'); + + // Check group count (2-8 groups) + if (groups.length < 2) { + return { + valid: false, + reason: 'Must have at least 2 groups separated by double dashes (--property--value minimum)', + }; + } + + if (groups.length > 8) { + return { + valid: false, + reason: 'Must have at most 8 groups (too many segments)', + }; + } + + // Check each group for invalid characters + for (const group of groups) { + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(group)) { + return { + valid: false, + reason: `Group "${group}" contains invalid characters. Use only lowercase letters, numbers, and single dash within groups`, + }; + } + } + + // Check if first group is a namespace, and if so, validate it + const firstGroup = groups[0]; + let startIndex = 0; + + // If first group is a valid namespace, skip it for property validation + if (NAMESPACES.has(firstGroup)) { + startIndex = 1; + } + + // Validate property vocabulary (should be in the variable somewhere after namespace) + const hasValidProperty = groups.slice(startIndex).some((group) => PROPERTY_VOCABULARY.has(group)); + if (!hasValidProperty) { + return { + valid: false, + reason: `Must include a valid property from vocabulary: ${Array.from(PROPERTY_VOCABULARY).join(', ')}`, + }; + } + + // Find the property index to validate what comes after it + const propertyIndex = groups + .slice(startIndex) + .findIndex((group) => PROPERTY_VOCABULARY.has(group)); + const absolutePropertyIndex = startIndex + propertyIndex; + + // The group after property should be a value (semantic or scale) + if (absolutePropertyIndex + 1 < groups.length) { + const valueGroup = groups[absolutePropertyIndex + 1]; + + // Check if this is a known modifier (variant, state, mode, media) + const isModifier = + VARIANTS.has(valueGroup) || + STATES.has(valueGroup) || + MODES.has(valueGroup) || + MEDIA.has(valueGroup); + + // If it's not a modifier, validate it's a semantic or scale value + // We use a permissive approach: reject only clearly invalid patterns + if (!isModifier) { + const isValidValue = + SEMANTIC_VALUES.has(valueGroup) || + SCALE_VALUES.has(valueGroup) || + // Allow color shades like "primary-500", "shade-50", "tint-50" + /^[a-z]+-\d+$/.test(valueGroup) || + // Allow descriptive names (4+ chars) - these are likely intentional semantic names + valueGroup.length >= 4; + + if (!isValidValue) { + return { + valid: false, + reason: `Value "${valueGroup}" is too short. Use semantic values (${Array.from(SEMANTIC_VALUES).slice(0, 5).join(', ')}...) or scale values (${Array.from(SCALE_VALUES).slice(0, 5).join(', ')}...). See proposal for full list.`, + }; + } + } + } + + // Check for states/variants/modes in appropriate positions (optional validation) + const lastGroup = groups[groups.length - 1]; + + // If last group is a state/mode/media, that's valid + if (STATES.has(lastGroup) || MODES.has(lastGroup) || MEDIA.has(lastGroup)) { + // Valid pattern + return { valid: true }; + } + + // Check if we have variants in reasonable positions + const hasVariant = groups.some((group) => VARIANTS.has(group)); + const hasState = groups.some((group) => STATES.has(group)); + + // If we have both variant and state, variant should come before state + if (hasVariant && hasState) { + const variantIndex = groups.findIndex((group) => VARIANTS.has(group)); + const stateIndex = groups.findIndex((group) => STATES.has(group)); + if (variantIndex > stateIndex) { + return { + valid: false, + reason: + 'Variant should come before state (e.g., --button--background--primary--solid--hover)', + }; + } + } + + return { valid: true }; +} + +const ruleFunction: Rule = (primary, secondaryOptions, context) => { + return (root, result) => { + const validOptions = stylelint.utils.validateOptions(result, ruleName, { + actual: primary, + }); + + if (!validOptions) { + return; + } + + root.walkDecls((decl) => { + const prop = decl.prop; + + // Only check CSS custom properties (variables) + if (!prop.startsWith('--')) { + return; + } + + const validation = validateCssVariable(prop); + + if (!validation.valid) { + stylelint.utils.report({ + message: messages.rejected(prop, validation.reason!), + node: decl, + result, + ruleName, + }); + } + }); + + // Also check variable usage in var() functions + root.walkDecls((decl) => { + const value = decl.value; + + // Find all var() references + const varPattern = /var\((--[a-z0-9-]+)/g; + let match; + + while ((match = varPattern.exec(value)) !== null) { + const variable = match[1]; + const validation = validateCssVariable(variable); + + if (!validation.valid) { + stylelint.utils.report({ + message: messages.rejected(variable, validation.reason!), + node: decl, + result, + ruleName, + }); + } + } + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; +ruleFunction.meta = meta; + +export default stylelint.createPlugin(ruleName, ruleFunction); diff --git a/packages/@n8n/stylelint-config/src/rules/index.ts b/packages/@n8n/stylelint-config/src/rules/index.ts new file mode 100644 index 00000000000..15f743135c1 --- /dev/null +++ b/packages/@n8n/stylelint-config/src/rules/index.ts @@ -0,0 +1 @@ +export { default as cssVarNaming } from './css-var-naming.js'; diff --git a/packages/extensions/insights/package.json b/packages/extensions/insights/package.json index aaae518cde5..e033e2e56fd 100644 --- a/packages/extensions/insights/package.json +++ b/packages/extensions/insights/package.json @@ -32,8 +32,8 @@ "dev": "vite", "lint": "eslint src --quiet", "lint:fix": "eslint src --fix", - "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache", - "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache", + "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache --custom-formatter $(pwd)/../../../packages/@n8n/stylelint-config/dist/formatter-summary.js", + "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache --custom-formatter $(pwd)/../../../packages/@n8n/stylelint-config/dist/formatter-summary.js", "typecheck": "vue-tsc --noEmit", "build:backend": "tsup", "build:frontend": "vite build", diff --git a/packages/frontend/@n8n/chat/package.json b/packages/frontend/@n8n/chat/package.json index 964196da41d..0a036e964ef 100644 --- a/packages/frontend/@n8n/chat/package.json +++ b/packages/frontend/@n8n/chat/package.json @@ -12,8 +12,8 @@ "typecheck": "vue-tsc --noEmit", "lint": "eslint src --quiet", "lint:fix": "eslint src --fix", - "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache", - "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache", + "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache --custom-formatter ../../../../packages/@n8n/stylelint-config/dist/formatter-summary.js", + "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache --custom-formatter $(pwd)/../../../../packages/@n8n/stylelint-config/dist/formatter-summary.js", "format": "biome format --write src .storybook && prettier --write src/ --ignore-path ../../../../.prettierignore", "format:check": "biome ci src .storybook && prettier --check src/ --ignore-path ../../../../.prettierignore", "storybook": "storybook dev -p 6006 --no-open", diff --git a/packages/frontend/@n8n/design-system/package.json b/packages/frontend/@n8n/design-system/package.json index 368431b4faf..99b5f8f2f8a 100644 --- a/packages/frontend/@n8n/design-system/package.json +++ b/packages/frontend/@n8n/design-system/package.json @@ -19,8 +19,8 @@ "format:check": "biome ci . && prettier --check . --ignore-path ../../../../.prettierignore", "lint": "eslint src --quiet", "lint:fix": "eslint src --fix", - "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache", - "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache" + "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache --custom-formatter \"$(pwd)/../../../../packages/@n8n/stylelint-config/dist/formatter-summary.js\"", + "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache --custom-formatter $(pwd)/../../../../packages/@n8n/stylelint-config/dist/formatter-summary.js" }, "devDependencies": { "@n8n/eslint-config": "workspace:*", diff --git a/packages/frontend/@n8n/design-system/src/css/_primitives.scss b/packages/frontend/@n8n/design-system/src/css/_primitives.scss index a0ca851747b..3742c32ab8f 100644 --- a/packages/frontend/@n8n/design-system/src/css/_primitives.scss +++ b/packages/frontend/@n8n/design-system/src/css/_primitives.scss @@ -4,132 +4,132 @@ // Tokens should be used instead in components and other UI elements @mixin primitives { - --h-gray: 220; + --p--color--gray: 220; // Gray - --p-gray-820: hsl(var(--h-gray), 1%, 18%); - --p-gray-800: hsl(var(--h-gray), 1%, 20%); - --p-gray-780: hsl(var(--h-gray), 1%, 22%); - --p-gray-740: hsl(var(--h-gray), 2%, 26%); - --p-gray-710: hsl(var(--h-gray), 2%, 29%); - --p-gray-670: hsl(var(--h-gray), 2%, 33%); - --p-gray-540: hsl(var(--h-gray), 4%, 46%); - --p-gray-490: hsl(var(--h-gray), 3%, 51%); - --p-gray-420: hsl(var(--h-gray), 4%, 58%); - --p-gray-320: hsl(var(--h-gray), 10%, 68%); - --p-gray-200: hsl(var(--h-gray), 18%, 80%); - --p-gray-120: hsl(var(--h-gray), 25%, 88%); - --p-gray-070: hsl(var(--h-gray), 32%, 93%); - --p-gray-040: hsl(var(--h-gray), 40%, 96%); - --p-gray-030: hsl(var(--h-gray), 43%, 97%); - --p-gray-025: hsl(var(--h-gray), 50%, 97.5%); - --p-gray-010: hsl(var(--h-gray), 50%, 99%); - --p-white: hsl(var(--h-gray), 50%, 100%); + --p--color--gray-820: hsl(var(--p--color--gray), 1%, 18%); + --p--color--gray-800: hsl(var(--p--color--gray), 1%, 20%); + --p--color--gray-780: hsl(var(--p--color--gray), 1%, 22%); + --p--color--gray-740: hsl(var(--p--color--gray), 2%, 26%); + --p--color--gray-710: hsl(var(--p--color--gray), 2%, 29%); + --p--color--gray-670: hsl(var(--p--color--gray), 2%, 33%); + --p--color--gray-540: hsl(var(--p--color--gray), 4%, 46%); + --p--color--gray-490: hsl(var(--p--color--gray), 3%, 51%); + --p--color--gray-420: hsl(var(--p--color--gray), 4%, 58%); + --p--color--gray-320: hsl(var(--p--color--gray), 10%, 68%); + --p--color--gray-200: hsl(var(--p--color--gray), 18%, 80%); + --p--color--gray-120: hsl(var(--p--color--gray), 25%, 88%); + --p--color--gray-070: hsl(var(--p--color--gray), 32%, 93%); + --p--color--gray-040: hsl(var(--p--color--gray), 40%, 96%); + --p--color--gray-030: hsl(var(--p--color--gray), 43%, 97%); + --p--color--gray-025: hsl(var(--p--color--gray), 50%, 97.5%); + --p--color--gray-010: hsl(var(--p--color--gray), 50%, 99%); + --p--color--white: hsl(var(--p--color--gray), 50%, 100%); // Gray alpha - --p-gray-320-a-010: hsla(var(--h-gray), 10%, 68%, 0.1); - --p-gray-70-a-010: hsla(var(--h-gray), 32%, 93%, 0.1); + --p--color--gray-320-a-010: hsla(var(--p--color--gray), 10%, 68%, 0.1); + --p--color--gray-70-a-010: hsla(var(--p--color--gray), 32%, 93%, 0.1); // White alpha - --p-white-a-075: hsla(var(--h-gray), 50%, 100%, 0.75); - --p-white-a-030: hsla(var(--h-gray), 50%, 100%, 0.3); - --p-white-a-025: hsla(var(--h-gray), 50%, 100%, 0.25); - --p-white-a-020: hsla(var(--h-gray), 50%, 100%, 0.2); - --p-white-a-015: hsla(var(--h-gray), 50%, 100%, 0.15); - --p-white-a-010: hsla(var(--h-gray), 50%, 100%, 0.1); + --p--color--white-a-075: hsla(var(--p--color--gray), 50%, 100%, 0.75); + --p--color--white-a-030: hsla(var(--p--color--gray), 50%, 100%, 0.3); + --p--color--white-a-025: hsla(var(--p--color--gray), 50%, 100%, 0.25); + --p--color--white-a-020: hsla(var(--p--color--gray), 50%, 100%, 0.2); + --p--color--white-a-015: hsla(var(--p--color--gray), 50%, 100%, 0.15); + --p--color--white-a-010: hsla(var(--p--color--gray), 50%, 100%, 0.1); // Primary color - --h-primary: 7; - --s-primary: 100%; - --l-primary: 68%; + --p--color--primary-h: 7; + --p--color--primary-s: 100%; + --p--color--primary-l: 68%; - --p-color-primary-420: hsl(7, 85%, 58%); - --p-color-primary-320: hsl(7, 100%, 68%); // Base - --p-color-primary-220: hsl(7, 100%, 78%); - --p-color-primary-120: hsl(7, 100%, 88%); - --p-color-primary-070: hsl(7, 100%, 93%); - --p-color-primary-050: hsl(7, 100%, 95%); - --p-color-primary-030: hsl(7, 100%, 98%); + --p--color--primary-420: hsl(7, 85%, 58%); + --p--color--primary-320: hsl(7, 100%, 68%); // Base + --p--color--primary-220: hsl(7, 100%, 78%); + --p--color--primary-120: hsl(7, 100%, 88%); + --p--color--primary-070: hsl(7, 100%, 93%); + --p--color--primary-050: hsl(7, 100%, 95%); + --p--color--primary-030: hsl(7, 100%, 98%); - --p-color-primary-320-a-010: hsla(7, 100%, 68%, 0.1); - --p-color-primary-320-a-035: hsla(7, 100%, 68%, 0.35); - --p-color-primary-320-a-050: hsla(7, 100%, 68%, 0.5); + --p--color--primary-320-a-010: hsla(7, 100%, 68%, 0.1); + --p--color--primary-320-a-035: hsla(7, 100%, 68%, 0.35); + --p--color--primary-320-a-050: hsla(7, 100%, 68%, 0.5); // Secondary color - --p-color-secondary-720: hsl(247, 24%, 28%); - --p-color-secondary-570: hsl(247, 49%, 43%); - --p-color-secondary-470: hsl(247, 49%, 53%); // Base - --p-color-secondary-370: hsl(247, 49%, 63%); - --p-color-secondary-270: hsl(247, 49%, 73%); - --p-color-secondary-170: hsl(247, 49%, 83%); - --p-color-secondary-070: hsl(247, 49%, 93%); + --p--color--secondary-720: hsl(247, 24%, 28%); + --p--color--secondary-570: hsl(247, 49%, 43%); + --p--color--secondary-470: hsl(247, 49%, 53%); // Base + --p--color--secondary-370: hsl(247, 49%, 63%); + --p--color--secondary-270: hsl(247, 49%, 73%); + --p--color--secondary-170: hsl(247, 49%, 83%); + --p--color--secondary-070: hsl(247, 49%, 93%); - --p-color-secondary-470-a-010: hsla(247, 49%, 53%, 0.1); - --p-color-secondary-470-a-025: hsla(247, 49%, 53%, 0.25); + --p--color--secondary-470-a-010: hsla(247, 49%, 53%, 0.1); + --p--color--secondary-470-a-025: hsla(247, 49%, 53%, 0.25); // Color Alternate A - --p-color-alt-a-800: hsl(150, 45%, 20%); - --p-color-alt-a-700: hsl(150, 53%, 30%); - --p-color-alt-a-600: hsl(150, 60%, 40%); // Base - --p-color-alt-a-300: hsl(150, 60%, 70%); - --p-color-alt-a-200: hsl(150, 60%, 80%); - --p-color-alt-a-100: hsl(150, 60%, 90%); - --p-color-alt-a-050: hsl(150, 60%, 95%); + --p--color--alt-a-800: hsl(150, 45%, 20%); + --p--color--alt-a-700: hsl(150, 53%, 30%); + --p--color--alt-a-600: hsl(150, 60%, 40%); // Base + --p--color--alt-a-300: hsl(150, 60%, 70%); + --p--color--alt-a-200: hsl(150, 60%, 80%); + --p--color--alt-a-100: hsl(150, 60%, 90%); + --p--color--alt-a-050: hsl(150, 60%, 95%); - --p-color-alt-a-600-a-015: hsla(150, 60%, 40%, 0.15); - --p-color-alt-a-600-a-025: hsla(150, 60%, 40%, 0.25); + --p--color--alt-a-600-a-015: hsla(150, 60%, 40%, 0.15); + --p--color--alt-a-600-a-025: hsla(150, 60%, 40%, 0.25); // Color Alternate B - --p-color-alt-b-780: hsl(36, 42%, 22%); - --p-color-alt-b-680: hsl(36, 42%, 32%); - --p-color-alt-b-530: hsl(36, 77%, 47%); - --p-color-alt-b-430: hsl(36, 77%, 57%); // Base - --p-color-alt-b-280: hsl(36, 77%, 72%); - --p-color-alt-b-180: hsl(36, 77%, 82%); - --p-color-alt-b-130: hsl(36, 77%, 87%); - --p-color-alt-b-030: hsl(36, 77%, 97%); + --p--color--alt-b-780: hsl(36, 42%, 22%); + --p--color--alt-b-680: hsl(36, 42%, 32%); + --p--color--alt-b-530: hsl(36, 77%, 47%); + --p--color--alt-b-430: hsl(36, 77%, 57%); // Base + --p--color--alt-b-280: hsl(36, 77%, 72%); + --p--color--alt-b-180: hsl(36, 77%, 82%); + --p--color--alt-b-130: hsl(36, 77%, 87%); + --p--color--alt-b-030: hsl(36, 77%, 97%); - --p-color-alt-b-430-a-020: hsla(36, 77%, 57%, 0.2); + --p--color--alt-b-430-a-020: hsla(36, 77%, 57%, 0.2); // Color Alternate C - --p-color-alt-c-730: hsl(355, 43%, 27%); - --p-color-alt-c-630: hsl(355, 53%, 37%); - --p-color-alt-c-580: hsl(355, 83%, 42%); - --p-color-alt-c-480: hsl(355, 83%, 52%); // Base - --p-color-alt-c-330: hsl(355, 83%, 67%); - --p-color-alt-c-230: hsl(355, 83%, 77%); - --p-color-alt-c-180: hsl(355, 83%, 82%); - --p-color-alt-c-080: hsl(355, 83%, 92%); - --p-color-alt-c-030: hsl(355, 83%, 97%); + --p--color--alt-c-730: hsl(355, 43%, 27%); + --p--color--alt-c-630: hsl(355, 53%, 37%); + --p--color--alt-c-580: hsl(355, 83%, 42%); + --p--color--alt-c-480: hsl(355, 83%, 52%); // Base + --p--color--alt-c-330: hsl(355, 83%, 67%); + --p--color--alt-c-230: hsl(355, 83%, 77%); + --p--color--alt-c-180: hsl(355, 83%, 82%); + --p--color--alt-c-080: hsl(355, 83%, 92%); + --p--color--alt-c-030: hsl(355, 83%, 97%); - --p-color-alt-c-480-a-020: hsla(355, 83%, 52%, 0.2); - --p-color-alt-c-480-a-010: hsla(355, 83%, 52%, 0.1); + --p--color--alt-c-480-a-020: hsla(355, 83%, 52%, 0.2); + --p--color--alt-c-480-a-010: hsla(355, 83%, 52%, 0.1); // Color Alternate D - --p-color-alt-d-780: hsl(46, 45%, 22%); - --p-color-alt-d-680: hsl(46, 45%, 32%); - --p-color-alt-d-230: hsl(46, 100%, 77%); - --p-color-alt-d-080: hsl(46, 100%, 92%); // Base + --p--color--alt-d-780: hsl(46, 45%, 22%); + --p--color--alt-d-680: hsl(46, 45%, 32%); + --p--color--alt-d-230: hsl(46, 100%, 77%); + --p--color--alt-d-080: hsl(46, 100%, 92%); // Base // Color Alternate E - --p-color-alt-e-780: hsl(210, 47%, 22%); - --p-color-alt-e-680: hsl(210, 57%, 32%); - --p-color-alt-e-580: hsl(210, 67%, 42%); - --p-color-alt-e-530: hsl(210, 67%, 47%); - --p-color-alt-e-430: hsl(210, 67%, 57%); // Base - --p-color-alt-e-180: hsl(210, 67%, 82%); - --p-color-alt-e-080: hsl(210, 67%, 92%); + --p--color--alt-e-780: hsl(210, 47%, 22%); + --p--color--alt-e-680: hsl(210, 57%, 32%); + --p--color--alt-e-580: hsl(210, 67%, 42%); + --p--color--alt-e-530: hsl(210, 67%, 47%); + --p--color--alt-e-430: hsl(210, 67%, 57%); // Base + --p--color--alt-e-180: hsl(210, 67%, 82%); + --p--color--alt-e-080: hsl(210, 67%, 92%); // Color Alternate F - --p-color-alt-f-560: hsl(147, 83%, 44%); // Base + --p--color--alt-f-560: hsl(147, 83%, 44%); // Base // Color Alternate G - --p-color-alt-g-700: hsl(247, 10%, 30%); // Base + --p--color--alt-g-700: hsl(247, 10%, 30%); // Base - --p-color-alt-g-700-a-075: hsla(247, 10%, 30%, 0.75); + --p--color--alt-g-700-a-075: hsla(247, 10%, 30%, 0.75); // Color Alternate H - Used for errors in dark mode - --p-color-alt-h-310: hsl(355, 100%, 69%); // Base + --p--color--alt-h-310: hsl(355, 100%, 69%); // Base } :root { diff --git a/packages/frontend/@n8n/design-system/src/css/_tokens.dark.scss b/packages/frontend/@n8n/design-system/src/css/_tokens.dark.scss index 210c860811d..53a8ad64c77 100644 --- a/packages/frontend/@n8n/design-system/src/css/_tokens.dark.scss +++ b/packages/frontend/@n8n/design-system/src/css/_tokens.dark.scss @@ -2,7 +2,7 @@ @mixin theme { // Primary tokens - --color-danger: var(--p-color-alt-h-310); + --color-danger: var(--p--color--alt-h-310); // Diff colors (dark theme overrides) --diff-new: #38cb7a; @@ -16,27 +16,27 @@ --diff-del-faint: #4d3e3d; // Text - --color-text-dark: var(--p-gray-040); - --color-text-base: var(--p-gray-200); - --color-text-light: var(--p-gray-320); - --color-text-lighter: var(--p-gray-740); - --color-text-xlight: var(--p-gray-820); - --color-text-danger: var(--p-color-alt-c-330); + --color-text-dark: var(--p--color--gray-040); + --color-text-base: var(--p--color--gray-200); + --color-text-light: var(--p--color--gray-320); + --color-text-lighter: var(--p--color--gray-740); + --color-text-xlight: var(--p--color--gray-820); + --color-text-danger: var(--p--color--alt-c-330); // Foreground - --color-foreground-xdark: var(--p-gray-200); - --color-foreground-dark: var(--p-gray-420); - --color-foreground-base: var(--p-gray-670); - --color-foreground-light: var(--p-gray-740); - --color-foreground-xlight: var(--p-gray-820); + --color-foreground-xdark: var(--p--color--gray-200); + --color-foreground-dark: var(--p--color--gray-420); + --color-foreground-base: var(--p--color--gray-670); + --color-foreground-light: var(--p--color--gray-740); + --color-foreground-xlight: var(--p--color--gray-820); // Background - --color-background-dark: var(--p-gray-070); - --color-background-medium: var(--p-gray-540); - --color-background-base: var(--p-gray-670); - --color-background-light-base: var(--p-gray-780); - --color-background-light: var(--p-gray-820); - --color-background-xlight: var(--p-gray-740); + --color-background-dark: var(--p--color--gray-070); + --color-background-medium: var(--p--color--gray-540); + --color-background-base: var(--p--color--gray-670); + --color-background-light-base: var(--p--color--gray-780); + --color-background-light: var(--p--color--gray-820); + --color-background-xlight: var(--p--color--gray-740); --box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.2), 0 0 6px rgba(0, 0, 0, 0.1); --box-shadow-dark: 0 2px 4px rgba(0, 0, 0, 0.2), 0 0 6px rgba(0, 0, 0, 0.2); @@ -72,20 +72,20 @@ ); // LangChain - --color-lm-chat-messages-background: var(--p-gray-820); - --color-lm-chat-bot-background: var(--p-gray-740); - --color-lm-chat-bot-border: var(--p-gray-490); - --color-lm-chat-user-background: var(--p-color-alt-a-700); - --color-lm-chat-user-border: var(--p-color-alt-a-600); + --color-lm-chat-messages-background: var(--p--color--gray-820); + --color-lm-chat-bot-background: var(--p--color--gray-740); + --color-lm-chat-bot-border: var(--p--color--gray-490); + --color-lm-chat-user-background: var(--p--color--alt-a-700); + --color-lm-chat-user-border: var(--p--color--alt-a-600); // Canvas - --color-canvas-background: var(--p-gray-820); - --color-canvas-background-h: var(--h-gray); // Used for connectors labels background + --color-canvas-background: var(--p--color--gray-820); + --color-canvas-background-h: var(--p--color--gray); // Used for connectors labels background --color-canvas-background-s: 1%; --color-canvas-background-l: 18%; - --color-canvas-dot: var(--p-gray-670); - --color-canvas-read-only-line: var(--p-gray-800); - --color-canvas-selected: var(--p-white-a-025); + --color-canvas-dot: var(--p--color--gray-670); + --color-canvas-read-only-line: var(--p--color--gray-800); + --color-canvas-selected: var(--p--color--white-a-025); --color-canvas-selected-transparent: var(--color-canvas-selected); --color-canvas-label-background: hsla( var(--color-canvas-background-h), @@ -95,43 +95,43 @@ ); // Nodes - --color-node-background: var(--p-gray-740); - --color-node-executing-background: var(--p-gray-670); - --color-node-executing-other-background: var(--p-gray-670); - --color-node-pinned-border: var(--p-color-secondary-370); - --node-type-main-color: var(--p-gray-420); + --color-node-background: var(--p--color--gray-740); + --color-node-executing-background: var(--p--color--gray-670); + --color-node-executing-other-background: var(--p--color--gray-670); + --color-node-pinned-border: var(--p--color--secondary-370); + --node-type-main-color: var(--p--color--gray-420); // Sticky - --color-sticky-background: var(--p-color-alt-d-780); - --color-sticky-border: var(--p-color-alt-d-680); - --color-sticky-font: var(--p-gray-040); - --color-sticky-code-font: var(--p-color-secondary-170); - --color-sticky-code-background: var(--p-gray-70-a-010); + --color-sticky-background: var(--p--color--alt-d-780); + --color-sticky-border: var(--p--color--alt-d-680); + --color-sticky-font: var(--p--color--gray-040); + --color-sticky-code-font: var(--p--color--secondary-170); + --color-sticky-code-background: var(--p--color--gray-70-a-010); - --color-sticky-background-1: var(--p-color-alt-d-780); - --color-sticky-border-1: var(--p-color-alt-d-680); - --color-sticky-background-2: var(--p-color-alt-b-780); - --color-sticky-border-2: var(--p-color-alt-b-680); - --color-sticky-background-3: var(--p-color-alt-c-730); - --color-sticky-border-3: var(--p-color-alt-c-630); - --color-sticky-background-4: var(--p-color-alt-a-800); - --color-sticky-border-4: var(--p-color-alt-a-700); - --color-sticky-background-5: var(--p-color-alt-e-780); - --color-sticky-border-5: var(--p-color-alt-e-680); - --color-sticky-background-6: var(--p-color-secondary-720); - --color-sticky-border-6: var(--p-color-secondary-570); - --color-sticky-background-7: var(--p-gray-740); - --color-sticky-border-7: var(--p-gray-670); + --color-sticky-background-1: var(--p--color--alt-d-780); + --color-sticky-border-1: var(--p--color--alt-d-680); + --color-sticky-background-2: var(--p--color--alt-b-780); + --color-sticky-border-2: var(--p--color--alt-b-680); + --color-sticky-background-3: var(--p--color--alt-c-730); + --color-sticky-border-3: var(--p--color--alt-c-630); + --color-sticky-background-4: var(--p--color--alt-a-800); + --color-sticky-border-4: var(--p--color--alt-a-700); + --color-sticky-background-5: var(--p--color--alt-e-780); + --color-sticky-border-5: var(--p--color--alt-e-680); + --color-sticky-background-6: var(--p--color--secondary-720); + --color-sticky-border-6: var(--p--color--secondary-570); + --color-sticky-background-7: var(--p--color--gray-740); + --color-sticky-border-7: var(--p--color--gray-670); // NodeIcon - --color-node-icon-gray: var(--p-gray-120); - --color-node-icon-black: var(--p-gray-010); + --color-node-icon-gray: var(--p--color--gray-120); + --color-node-icon-black: var(--p--color--gray-010); --color-node-icon-blue: #898fff; --color-node-icon-light-blue: #58abff; --color-node-icon-dark-blue: #7ba7ff; - --color-node-icon-orange-red: var(--p-color-primary-320); + --color-node-icon-orange-red: var(--p--color--primary-320); --color-node-icon-pink-red: #f85d82; - --color-node-icon-red: var(--p-color-alt-h-310); + --color-node-icon-red: var(--p--color--alt-h-310); --color-node-icon-light-green: #20b69e; --color-node-icon-green: #38cb7a; --color-node-icon-dark-green: #86decc; @@ -139,19 +139,19 @@ --color-node-icon-crimson: #f188a2; // Expressions, autocomplete, infobox - --color-valid-resolvable-foreground: var(--p-color-alt-a-300); - --color-valid-resolvable-background: var(--p-color-alt-a-600-a-025); - --color-invalid-resolvable-foreground: var(--p-color-alt-c-230); - --color-invalid-resolvable-background: var(--p-color-alt-c-480-a-020); + --color-valid-resolvable-foreground: var(--p--color--alt-a-300); + --color-valid-resolvable-background: var(--p--color--alt-a-600-a-025); + --color-invalid-resolvable-foreground: var(--p--color--alt-c-230); + --color-invalid-resolvable-background: var(--p--color--alt-c-480-a-020); --color-pending-resolvable-foreground: var(--color-text-base); - --color-pending-resolvable-background: var(--p-gray-70-a-010); - --color-expression-editor-background: var(--p-gray-800); - --color-expression-editor-modal-background: var(--p-gray-800); - --color-expression-syntax-example: var(--p-gray-670); - --color-autocomplete-item-selected: var(--p-color-secondary-270); - --color-autocomplete-section-header-border: var(--p-gray-540); - --color-infobox-background: var(--p-gray-780); - --color-infobox-examples-border-color: var(--p-gray-670); + --color-pending-resolvable-background: var(--p--color--gray-70-a-010); + --color-expression-editor-background: var(--p--color--gray-800); + --color-expression-editor-modal-background: var(--p--color--gray-800); + --color-expression-syntax-example: var(--p--color--gray-670); + --color-autocomplete-item-selected: var(--p--color--secondary-270); + --color-autocomplete-section-header-border: var(--p--color--gray-540); + --color-infobox-background: var(--p--color--gray-780); + --color-infobox-examples-border-color: var(--p--color--gray-670); // Code --color-code-tags-string: #9ecbff; @@ -168,97 +168,97 @@ --color-code-tags-heading: #79b8ff; --color-code-tags-invalid: #f97583; --color-code-tags-comment: #6a737d; - --color-json-default: var(--p-color-secondary-270); + --color-json-default: var(--p--color--secondary-270); --color-json-null: var(--color-danger); - --color-json-boolean: var(--p-color-alt-a-600); - --color-json-number: var(--p-color-alt-a-600); - --color-json-string: var(--p-color-secondary-270); + --color-json-boolean: var(--p--color--alt-a-600); + --color-json-number: var(--p--color--alt-a-600); + --color-json-string: var(--p--color--secondary-270); --color-json-key: var(--color-text-dark); - --color-json-brackets: var(--p-gray-670); - --color-json-brackets-hover: var(--p-color-alt-e-430); - --color-json-line: var(--p-gray-200); + --color-json-brackets: var(--p--color--gray-670); + --color-json-brackets-hover: var(--p--color--alt-e-430); + --color-json-line: var(--p--color--gray-200); --color-json-highlight: var(--color-background-base); - --color-code-background: var(--p-gray-820); - --color-code-background-readonly: var(--p-gray-740); - --color-code-lineHighlight: var(--p-gray-320-a-010); - --color-code-foreground: var(--p-gray-070); - --color-code-caret: var(--p-gray-010); + --color-code-background: var(--p--color--gray-820); + --color-code-background-readonly: var(--p--color--gray-740); + --color-code-lineHighlight: var(--p--color--gray-320-a-010); + --color-code-foreground: var(--p--color--gray-070); + --color-code-caret: var(--p--color--gray-010); --color-code-selection: #3392ff44; --color-code-selection-highlight: #17e5e633; - --color-code-gutter-background: var(--p-gray-820); - --color-code-gutter-foreground: var(--p-gray-320); - --color-code-gutter-foreground-active: var(--p-gray-010); - --color-code-indentation-marker: var(--p-gray-740); - --color-code-indentation-marker-active: var(--p-gray-670); - --color-line-break: var(--p-gray-420); - --color-code-line-break: var(--p-color-secondary-370); + --color-code-gutter-background: var(--p--color--gray-820); + --color-code-gutter-foreground: var(--p--color--gray-320); + --color-code-gutter-foreground-active: var(--p--color--gray-010); + --color-code-indentation-marker: var(--p--color--gray-740); + --color-code-indentation-marker-active: var(--p--color--gray-670); + --color-line-break: var(--p--color--gray-420); + --color-code-line-break: var(--p--color--secondary-370); // Tag - --tag-background-color: var(--p-gray-670); - --tag-background-hover-color: var(--p-gray-540); - --tag-border-color: var(--p-gray-710); - --tag-border-hover-color: var(--p-gray-670); + --tag-background-color: var(--p--color--gray-670); + --tag-background-hover-color: var(--p--color--gray-540); + --tag-border-color: var(--p--color--gray-710); + --tag-border-hover-color: var(--p--color--gray-670); --tag-text-color: var(--color-text-dark); // Variables - --color-variables-usage-font: var(--p-color-alt-a-300); - --color-variables-usage-syntax-bg: var(--p-color-alt-a-600-a-025); + --color-variables-usage-font: var(--p--color--alt-a-300); + --color-variables-usage-syntax-bg: var(--p--color--alt-a-600-a-025); // Button primary - --color-button-primary-focus-outline: var(--p-color-primary-320-a-035); - --color-button-primary-disabled-font: var(--p-white-a-030); + --color-button-primary-focus-outline: var(--p--color--primary-320-a-035); + --color-button-primary-disabled-font: var(--p--color--white-a-030); --color-button-primary-disabled-border: transparent; - --color-button-primary-disabled-background: var(--p-color-primary-320-a-050); + --color-button-primary-disabled-background: var(--p--color--primary-320-a-050); // Button secondary - --color-button-secondary-font: var(--p-gray-070); + --color-button-secondary-font: var(--p--color--gray-070); --color-button-secondary-border: var(--color-foreground-base); --color-button-secondary-background: var(--color-background-light); - --color-button-secondary-hover-active-focus-font: var(--p-color-primary-220); + --color-button-secondary-hover-active-focus-font: var(--p--color--primary-220); --color-button-secondary-hover-background: var(--color-background-light); - --color-button-secondary-active-focus-background: var(--p-color-primary-320-a-010); - --color-button-secondary-focus-outline: var(--p-color-primary-320-a-035); - --color-button-secondary-disabled-font: var(--p-white-a-030); + --color-button-secondary-active-focus-background: var(--p--color--primary-320-a-010); + --color-button-secondary-focus-outline: var(--p--color--primary-320-a-035); + --color-button-secondary-disabled-font: var(--p--color--white-a-030); --color-button-secondary-disabled-border: var(--color-foreground-base); // Button highlight - --color-button-highlight-font: var(--prim-gray-320); + --color-button-highlight-font: var(--p--color--gray-320); --color-button-highlight-border: transparent; --color-button-highlight-background: transparent; - --color-button-highlight-hover-active-focus-font: var(--prim-color-primary-tint-100); - --color-button-highlight-hover-active-focus-border: var(--prim-gray-670); - --color-button-highlight-hover-background: var(--prim-gray-670); - --color-button-highlight-active-focus-background: var(--prim-gray-670); - --color-button-highlight-focus-outline: var(--prim-gray-670); - --color-button-highlight-disabled-font: var(--prim-gray-0-a-010); + --color-button-highlight-hover-active-focus-font: var(--p--color--primary-420); + --color-button-highlight-hover-active-focus-border: var(--p--color--gray-670); + --color-button-highlight-hover-background: var(--p--color--gray-670); + --color-button-highlight-active-focus-background: var(--p--color--gray-670); + --color-button-highlight-focus-outline: var(--p--color--gray-670); + --color-button-highlight-disabled-font: var(--p--color--white-a-010); --color-button-highlight-disabled-border: transparent; // Button success, warning, danger - --color-button-danger-font: var(--p-white); + --color-button-danger-font: var(--p--color--white); --color-button-danger-border: transparent; - --color-button-danger-focus-outline: var(--p-color-alt-c-230); - --color-button-danger-disabled-font: var(--p-white-a-025); + --color-button-danger-focus-outline: var(--p--color--alt-c-230); + --color-button-danger-disabled-font: var(--p--color--white-a-025); --color-button-danger-disabled-border: transparent; - --color-button-danger-disabled-background: var(--p-color-alt-c-480-a-020); + --color-button-danger-disabled-background: var(--p--color--alt-c-480-a-020); // Text button - --color-text-button-secondary-font: var(--p-gray-320); + --color-text-button-secondary-font: var(--p--color--gray-320); // Node Creator Button --color-button-node-creator-border-font: var(--color-button-secondary-font); --color-button-node-creator-hover-font: var(--color-button-secondary-hover-active-focus-font); - --color-button-node-creator-hover-border: var(--p-color-primary-320); - --color-button-node-creator-background: var(--p-color-primary-320-a-010); + --color-button-node-creator-hover-border: var(--p--color--primary-320); + --color-button-node-creator-background: var(--p--color--primary-320-a-010); // Table - --color-table-header-background: var(--p-gray-740); - --color-table-row-background: var(--p-gray-820); - --color-table-row-even-background: var(--p-gray-800); - --color-table-row-hover-background: var(--p-gray-740); + --color-table-header-background: var(--p--color--gray-740); + --color-table-row-background: var(--p--color--gray-820); + --color-table-row-even-background: var(--p--color--gray-800); + --color-table-row-hover-background: var(--p--color--gray-740); --color-table-row-highlight-background: var(--color-warning-tint-1); // Notification - --color-notification-background: var(--p-gray-740); + --color-notification-background: var(--p--color--gray-740); // Execution --execution-card-background: var(--color-foreground-light); @@ -266,61 +266,61 @@ --execution-selector-background: var(--color-background-dark); --execution-selector-text: var(--color-text-xlight); --execution-select-all-text: var(--color-text-base); - --execution-card-text-waiting: var(--p-color-secondary-370); + --execution-card-text-waiting: var(--p--color--secondary-370); // NDV - --color-run-data-background: var(--p-gray-800); - --color-ndvv2-run-data-background: var(--p-gray-800); - --color-ndv-droppable-parameter: var(--p-color-primary-320); - --color-ndv-droppable-parameter-background: var(--p-color-primary-320-a-010); - --color-ndv-droppable-parameter-active-background: var(--p-color-alt-a-600-a-015); - --color-ndv-back-font: var(--p-white); + --color-run-data-background: var(--p--color--gray-800); + --color-ndvv2-run-data-background: var(--p--color--gray-800); + --color-ndv-droppable-parameter: var(--p--color--primary-320); + --color-ndv-droppable-parameter-background: var(--p--color--primary-320-a-010); + --color-ndv-droppable-parameter-active-background: var(--p--color--alt-a-600-a-015); + --color-ndv-back-font: var(--p--color--white); // Notice - --color-notice-warning-border: var(--p-color-alt-b-180); - --color-notice-warning-background: var(--p-color-alt-b-430-a-020); - --color-notice-font: var(--p-white); + --color-notice-warning-border: var(--p--color--alt-b-180); + --color-notice-warning-background: var(--p--color--alt-b-430-a-020); + --color-notice-font: var(--p--color--white); // Callout - --color-callout-info-border: var(--p-gray-670); - --color-callout-info-background: var(--p-gray-740); - --color-callout-info-font: var(--p-white); + --color-callout-info-border: var(--p--color--gray-670); + --color-callout-info-background: var(--p--color--gray-740); + --color-callout-info-font: var(--p--color--white); --color-callout-success-border: var(--color-success); - --color-callout-success-background: var(--p-color-alt-a-800); - --color-callout-success-font: var(--p-white); + --color-callout-success-background: var(--p--color--alt-a-800); + --color-callout-success-font: var(--p--color--white); --color-callout-warning-border: var(--color-warning); - --color-callout-warning-background: var(--p-color-alt-b-780); - --color-callout-warning-font: var(--p-white); + --color-callout-warning-background: var(--p--color--alt-b-780); + --color-callout-warning-font: var(--p--color--white); --color-callout-danger-border: var(--color-danger); - --color-callout-danger-background: var(--p-color-alt-c-730); - --color-callout-danger-font: var(--p-white); + --color-callout-danger-background: var(--p--color--alt-c-730); + --color-callout-danger-font: var(--p--color--white); --color-callout-danger-icon: var(--color-danger); --color-callout-secondary-border: var(--color-secondary); - --color-callout-secondary-background: var(--p-color-secondary-470-a-025); - --color-callout-secondary-font: var(--p-white); + --color-callout-secondary-background: var(--p--color--secondary-470-a-025); + --color-callout-secondary-font: var(--p--color--white); // Dialogs and overlays - --color-dialog-background: var(--p-gray-800); - --color-dialog-overlay-background: var(--p-color-alt-g-700-a-075); - --color-dialog-overlay-background-dark: var(--p-color-alt-g-700-a-075); + --color-dialog-background: var(--p--color--gray-800); + --color-dialog-overlay-background: var(--p--color--alt-g-700-a-075); + --color-dialog-overlay-background-dark: var(--p--color--alt-g-700-a-075); // Avatar - --color-avatar-font: var(--p-white); + --color-avatar-font: var(--p--color--white); // NPS Survey - --color-nps-survey-background: var(--p-gray-740); - --color-nps-survey-font: var(--p-white); + --color-nps-survey-background: var(--p--color--gray-740); + --color-nps-survey-font: var(--p--color--white); // Switch (Activation, boolean) - --color-switch-background: var(--p-gray-820); - --color-switch-border-color: var(--p-gray-670); - --color-switch-toggle: var(--p-gray-040); + --color-switch-background: var(--p--color--gray-820); + --color-switch-border-color: var(--p--color--gray-670); + --color-switch-toggle: var(--p--color--gray-040); // Action Dropdown --color-action-dropdown-item-active-background: var(--color-background-xlight); // Input Triple - --color-background-input-triple: var(--p-gray-800); + --color-background-input-triple: var(--p--color--gray-800); // Node error --color-node-error-output-text-color: var(--color-danger); @@ -331,7 +331,7 @@ --color-mfa-lose-access-text-color: var(--color-danger); // Text highlight - --color-text-highlight-background: var(--p-color-alt-d-680); + --color-text-highlight-background: var(--p--color--alt-d-680); // AI --node-type-background-l: 20%; @@ -503,8 +503,8 @@ ); // Various - --color-info-tint-1: var(--p-gray-420); - --color-info-tint-2: var(--p-gray-740); + --color-info-tint-1: var(--p--color--gray-420); + --color-info-tint-2: var(--p--color--gray-740); --border-color-base: var(--color-foreground-base); --border-color-light: var(--color-foreground-light); --border-base: var(--border-width-base) var(--border-style-base) var(--color-foreground-base); @@ -515,18 +515,18 @@ var(--node-type-supplemental-label-color-l) ); --color-configurable-node-name: var(--color-text-dark); - --color-secondary-link: var(--p-color-secondary-270); - --color-secondary-link-hover: var(--p-color-secondary-370); + --color-secondary-link: var(--p--color--secondary-270); + --color-secondary-link-hover: var(--p--color--secondary-370); // Params --color-icon-base: var(--color-text-light); - --color-icon-hover: var(--p-color-primary-320); + --color-icon-hover: var(--p--color--primary-320); - --color-menu-background: var(--p-gray-740); - --color-menu-hover-background: var(--p-gray-670); - --color-menu-active-background: var(--p-gray-670); + --color-menu-background: var(--p--color--gray-740); + --color-menu-hover-background: var(--p--color--gray-670); + --color-menu-active-background: var(--p--color--gray-670); /* Ag Grid */ - --grid-row-selected-background: var(--p-color-secondary-720); + --grid-row-selected-background: var(--p--color--secondary-720); } body[data-theme='dark'] { diff --git a/packages/frontend/@n8n/design-system/src/css/_tokens.scss b/packages/frontend/@n8n/design-system/src/css/_tokens.scss index ae8a7de40bb..e579c24c91c 100644 --- a/packages/frontend/@n8n/design-system/src/css/_tokens.scss +++ b/packages/frontend/@n8n/design-system/src/css/_tokens.scss @@ -1,46 +1,46 @@ @use 'sass:math'; @mixin theme { - --color-primary-h: var(--h-primary); - --color-primary-s: var(--s-primary); - --color-primary-l: 68%; + --color-primary-h: var(--p--color--primary-h); + --color-primary-s: var(--p--color--primary-s); + --color-primary-l: var(--p--color--primary-l); // Primary tokens // Primary - --color-primary-shade-1: var(--p-color-primary-420); - --color-primary: var(--p-color-primary-320); - --color-primary-tint-1: var(--p-color-primary-120); - --color-primary-tint-2: var(--p-color-primary-070); - --color-primary-tint-3: var(--p-color-primary-030); + --color-primary-shade-1: var(--p--color--primary-420); + --color-primary: var(--p--color--primary-320); + --color-primary-tint-1: var(--p--color--primary-120); + --color-primary-tint-2: var(--p--color--primary-070); + --color-primary-tint-3: var(--p--color--primary-030); // Secondary - --color-secondary-shade-1: var(--p-color-secondary-570); - --color-secondary: var(--p-color-secondary-470); - --color-secondary-tint-1: var(--p-color-secondary-170); - --color-secondary-tint-3: var(--p-color-secondary-070); + --color-secondary-shade-1: var(--p--color--secondary-570); + --color-secondary: var(--p--color--secondary-470); + --color-secondary-tint-1: var(--p--color--secondary-170); + --color-secondary-tint-3: var(--p--color--secondary-070); // Success - --color-success-shade-1: var(--p-color-alt-a-700); - --color-success: var(--p-color-alt-a-600); - --color-success-light: var(--p-color-alt-a-300); - --color-success-light-2: var(--p-color-alt-a-200); - --color-success-tint-1: var(--p-color-alt-a-100); - --color-success-tint-2: var(--p-color-alt-a-050); + --color-success-shade-1: var(--p--color--alt-a-700); + --color-success: var(--p--color--alt-a-600); + --color-success-light: var(--p--color--alt-a-300); + --color-success-light-2: var(--p--color--alt-a-200); + --color-success-tint-1: var(--p--color--alt-a-100); + --color-success-tint-2: var(--p--color--alt-a-050); // Warning - --color-warning-shade-1: var(--p-color-alt-b-530); - --color-warning: var(--p-color-alt-b-430); - --color-warning-tint-1: var(--p-color-alt-b-180); - --color-warning-tint-2: var(--p-color-alt-b-030); + --color-warning-shade-1: var(--p--color--alt-b-530); + --color-warning: var(--p--color--alt-b-430); + --color-warning-tint-1: var(--p--color--alt-b-180); + --color-warning-tint-2: var(--p--color--alt-b-030); // Danger - --color-danger-shade-1: var(--p-color-alt-c-580); - --color-danger: var(--p-color-alt-c-480); - --color-danger-light: var(--p-color-alt-c-330); - --color-danger-light-2: var(--p-color-alt-c-230); - --color-danger-tint-1: var(--p-color-alt-c-080); - --color-danger-tint-2: var(--p-color-alt-c-030); + --color-danger-shade-1: var(--p--color--alt-c-580); + --color-danger: var(--p--color--alt-c-480); + --color-danger-light: var(--p--color--alt-c-330); + --color-danger-light-2: var(--p--color--alt-c-230); + --color-danger-tint-1: var(--p--color--alt-c-080); + --color-danger-tint-2: var(--p--color--alt-c-030); // Diff colors --diff-new: #0eab54; @@ -54,45 +54,45 @@ --diff-del-faint: #ffedec; // Text - --color-text-dark: var(--p-gray-740); - --color-text-base: var(--p-gray-540); - --color-text-light: var(--p-gray-420); - --color-text-lighter: var(--p-gray-120); - --color-text-xlight: var(--p-white); - --color-text-danger: var(--p-color-alt-c-480); + --color-text-dark: var(--p--color--gray-740); + --color-text-base: var(--p--color--gray-540); + --color-text-light: var(--p--color--gray-420); + --color-text-lighter: var(--p--color--gray-120); + --color-text-xlight: var(--p--color--white); + --color-text-danger: var(--p--color--alt-c-480); // Foreground - --color-foreground-xdark: var(--p-gray-490); - --color-foreground-dark: var(--p-gray-200); - --color-foreground-base: var(--p-gray-120); - --color-foreground-light: var(--p-gray-070); - --color-foreground-xlight: var(--p-white); + --color-foreground-xdark: var(--p--color--gray-490); + --color-foreground-dark: var(--p--color--gray-200); + --color-foreground-base: var(--p--color--gray-120); + --color-foreground-light: var(--p--color--gray-070); + --color-foreground-xlight: var(--p--color--white); // Background - --color-background-dark: var(--p-gray-820); - --color-background-medium: var(--p-gray-120); - --color-background-base: var(--p-gray-040); - --color-background-light-base: var(--p-gray-025); - --color-background-light: var(--p-gray-010); - --color-background-xlight: var(--p-white); + --color-background-dark: var(--p--color--gray-820); + --color-background-medium: var(--p--color--gray-120); + --color-background-base: var(--p--color--gray-040); + --color-background-light-base: var(--p--color--gray-025); + --color-background-light: var(--p--color--gray-010); + --color-background-xlight: var(--p--color--white); // Secondary tokens // LangChain --color-lm-chat-messages-background: var(--color-background-base); - --color-lm-chat-bot-background: var(--p-white); - --color-lm-chat-user-background: var(--p-color-alt-a-600); + --color-lm-chat-bot-background: var(--p--color--white); + --color-lm-chat-user-background: var(--p--color--alt-a-600); --color-lm-chat-user-color: var(--color-text-xlight); // Canvas - --color-canvas-background: var(--p-gray-010); - --color-canvas-background-h: var(--h-gray); // Used for connectors labels background + --color-canvas-background: var(--p--color--gray-010); + --color-canvas-background-h: var(--p--color--gray); // Used for connectors labels background --color-canvas-background-s: 47%; --color-canvas-background-l: 99%; - --color-canvas-dot: var(--p-gray-120); - --color-canvas-read-only-line: var(--p-gray-030); - --color-canvas-selected: var(--p-gray-070); - --color-canvas-selected-transparent: hsla(var(--h-gray), 47%, 30%, 0.1); + --color-canvas-dot: var(--p--color--gray-120); + --color-canvas-read-only-line: var(--p--color--gray-030); + --color-canvas-selected: var(--p--color--gray-070); + --color-canvas-selected-transparent: hsla(var(--p--color--gray), 47%, 30%, 0.1); --color-canvas-label-background: hsla( var(--color-canvas-background-h), var(--color-canvas-background-s), @@ -106,29 +106,29 @@ --color-node-executing-other-background: var(--color-primary-tint-3); --color-node-pinned-border: var(--color-secondary); --color-node-running-border: var(--color-primary); - --node-type-main-color: var(--p-gray-490); + --node-type-main-color: var(--p--color--gray-490); // Sticky - --color-sticky-background: var(--p-color-alt-d-080); - --color-sticky-border: var(--p-color-alt-d-230); - --color-sticky-font: var(--p-gray-740); + --color-sticky-background: var(--p--color--alt-d-080); + --color-sticky-border: var(--p--color--alt-d-230); + --color-sticky-font: var(--p--color--gray-740); --color-sticky-code-font: var(--color-secondary); --color-sticky-code-background: var(--color-background-base); --color-sticky-background-1: var(--color-sticky-background); --color-sticky-border-1: var(--color-sticky-border); - --color-sticky-background-2: var(--p-color-alt-b-130); - --color-sticky-border-2: var(--p-color-alt-b-280); - --color-sticky-background-3: var(--p-color-alt-c-080); - --color-sticky-border-3: var(--p-color-alt-c-180); - --color-sticky-background-4: var(--p-color-alt-a-100); - --color-sticky-border-4: var(--p-color-alt-a-300); - --color-sticky-background-5: var(--p-color-alt-e-080); - --color-sticky-border-5: var(--p-color-alt-e-180); - --color-sticky-background-6: var(--p-color-secondary-070); - --color-sticky-border-6: var(--p-color-secondary-170); - --color-sticky-background-7: var(--p-gray-010); - --color-sticky-border-7: var(--p-gray-120); + --color-sticky-background-2: var(--p--color--alt-b-130); + --color-sticky-border-2: var(--p--color--alt-b-280); + --color-sticky-background-3: var(--p--color--alt-c-080); + --color-sticky-border-3: var(--p--color--alt-c-180); + --color-sticky-background-4: var(--p--color--alt-a-100); + --color-sticky-border-4: var(--p--color--alt-a-300); + --color-sticky-background-5: var(--p--color--alt-e-080); + --color-sticky-border-5: var(--p--color--alt-e-180); + --color-sticky-background-6: var(--p--color--secondary-070); + --color-sticky-border-6: var(--p--color--secondary-170); + --color-sticky-background-7: var(--p--color--gray-010); + --color-sticky-border-7: var(--p--color--gray-120); // AI Assistant --color-askAssistant-button-background-gradient: linear-gradient( @@ -173,15 +173,15 @@ ); // NodeIcon - --color-node-icon-gray: var(--p-gray-420); - --color-node-icon-black: var(--p-gray-780); + --color-node-icon-gray: var(--p--color--gray-420); + --color-node-icon-black: var(--p--color--gray-780); --color-node-icon-blue: #3a42e9; --color-node-icon-light-blue: #5fabf7; --color-node-icon-dark-blue: #353f6e; --color-node-icon-orange: #ff965a; --color-node-icon-orange-red: #ff6d5a; --color-node-icon-pink-red: #ea4b71; - --color-node-icon-red: var(--p-color-alt-c-480); + --color-node-icon-red: var(--p--color--alt-c-480); --color-node-icon-light-green: #31c4ab; --color-node-icon-green: #108e49; --color-node-icon-dark-green: #157562; @@ -190,15 +190,15 @@ --color-node-icon-crimson: #724; // Expressions, autocomplete, infobox - --color-valid-resolvable-foreground: var(--p-color-alt-a-600); - --color-valid-resolvable-background: var(--p-color-alt-a-100); - --color-invalid-resolvable-foreground: var(--p-color-alt-c-480); - --color-invalid-resolvable-background: var(--p-color-alt-c-030); + --color-valid-resolvable-foreground: var(--p--color--alt-a-600); + --color-valid-resolvable-background: var(--p--color--alt-a-100); + --color-invalid-resolvable-foreground: var(--p--color--alt-c-480); + --color-invalid-resolvable-background: var(--p--color--alt-c-030); --color-pending-resolvable-foreground: var(--color-text-base); - --color-pending-resolvable-background: var(--p-gray-040); - --color-expression-editor-background: var(--p-white); + --color-pending-resolvable-background: var(--p--color--gray-040); + --color-expression-editor-background: var(--p--color--white); --color-expression-editor-modal-background: var(--color-background-base); - --color-expression-syntax-example: var(--p-gray-040); + --color-expression-syntax-example: var(--p--color--gray-040); --color-autocomplete-item-selected: var(--color-secondary); --color-autocomplete-section-header-border: var(--color-foreground-light); --color-infobox-background: var(--color-background-light-base); @@ -219,38 +219,38 @@ --color-code-tags-heading: #005cc5; --color-code-tags-invalid: #cb2431; --color-code-tags-comment: #6a737d; - --color-json-default: var(--p-color-secondary-570); - --color-json-null: var(--p-color-alt-c-480); - --color-json-boolean: var(--p-color-alt-a-600); - --color-json-number: var(--p-color-alt-a-600); - --color-json-string: var(--p-color-secondary-570); - --color-json-key: var(--p-gray-670); - --color-json-brackets: var(--p-gray-670); - --color-json-brackets-hover: var(--p-color-alt-e-430); - --color-json-line: var(--p-gray-200); + --color-json-default: var(--p--color--secondary-570); + --color-json-null: var(--p--color--alt-c-480); + --color-json-boolean: var(--p--color--alt-a-600); + --color-json-number: var(--p--color--alt-a-600); + --color-json-string: var(--p--color--secondary-570); + --color-json-key: var(--p--color--gray-670); + --color-json-brackets: var(--p--color--gray-670); + --color-json-brackets-hover: var(--p--color--alt-e-430); + --color-json-line: var(--p--color--gray-200); --color-json-highlight: var(--color-background-base); - --color-code-background: var(--p-white); - --color-code-background-readonly: var(--p-gray-040); - --color-code-lineHighlight: var(--p-gray-320-a-010); - --color-code-foreground: var(--p-gray-670); - --color-code-caret: var(--p-gray-820); + --color-code-background: var(--p--color--white); + --color-code-background-readonly: var(--p--color--gray-040); + --color-code-lineHighlight: var(--p--color--gray-320-a-010); + --color-code-foreground: var(--p--color--gray-670); + --color-code-caret: var(--p--color--gray-820); --color-code-selection: #0366d625; --color-code-selection-highlight: #34d05840; - --color-code-gutter-background: var(--p-white); - --color-code-gutter-foreground: var(--p-gray-320); - --color-code-gutter-foreground-active: var(--p-gray-670); - --color-code-indentation-marker: var(--p-gray-070); - --color-code-indentation-marker-active: var(--p-gray-200); - --color-line-break: var(--p-gray-320); - --color-code-line-break: var(--p-color-secondary-270); + --color-code-gutter-background: var(--p--color--white); + --color-code-gutter-foreground: var(--p--color--gray-320); + --color-code-gutter-foreground-active: var(--p--color--gray-670); + --color-code-indentation-marker: var(--p--color--gray-070); + --color-code-indentation-marker-active: var(--p--color--gray-200); + --color-line-break: var(--p--color--gray-320); + --color-code-line-break: var(--p--color--secondary-270); // Tag --tag-height: 20px; --tag-padding: 0 var(--spacing-4xs); - --tag-background-color: var(--p-gray-040); - --tag-background-hover-color: var(--p-gray-070); - --tag-border-color: var(--p-gray-070); - --tag-border-hover-color: var(--p-gray-120); + --tag-background-color: var(--p--color--gray-040); + --tag-background-hover-color: var(--p--color--gray-070); + --tag-border-color: var(--p--color--gray-070); + --tag-border-hover-color: var(--p--color--gray-120); --tag-border-radius: var(--border-radius-base); --tag-text-color: var(--color-text-base); --tag-font-size: var(--font-size-2xs); @@ -262,61 +262,61 @@ --color-variables-usage-syntax-bg: var(--color-success-tint-2); // Button primary - --color-button-primary-font: var(--p-white); - --color-button-primary-border: var(--p-color-primary-320); - --color-button-primary-background: var(--p-color-primary-320); - --color-button-primary-hover-active-border: var(--p-color-primary-420); - --color-button-primary-hover-active-focus-background: var(--p-color-primary-420); - --color-button-primary-focus-outline: var(--p-color-primary-320-a-035); - --color-button-primary-disabled-font: var(--p-white-a-075); - --color-button-primary-disabled-border: var(--p-color-primary-120); - --color-button-primary-disabled-background: var(--p-color-primary-120); + --color-button-primary-font: var(--p--color--white); + --color-button-primary-border: var(--p--color--primary-320); + --color-button-primary-background: var(--p--color--primary-320); + --color-button-primary-hover-active-border: var(--p--color--primary-420); + --color-button-primary-hover-active-focus-background: var(--p--color--primary-420); + --color-button-primary-focus-outline: var(--p--color--primary-320-a-035); + --color-button-primary-disabled-font: var(--p--color--white-a-075); + --color-button-primary-disabled-border: var(--p--color--primary-120); + --color-button-primary-disabled-background: var(--p--color--primary-120); // Button secondary - --color-button-secondary-font: var(--p-gray-670); - --color-button-secondary-border: var(--p-gray-320); - --color-button-secondary-background: var(--p-white); - --color-button-secondary-hover-active-focus-font: var(--p-color-primary-420); - --color-button-secondary-hover-active-focus-border: var(--p-color-primary-320); - --color-button-secondary-hover-background: var(--p-color-primary-030); - --color-button-secondary-active-focus-background: var(--p-color-primary-050); - --color-button-secondary-focus-outline: var(--p-gray-120); - --color-button-secondary-disabled-font: var(--p-gray-200); - --color-button-secondary-disabled-border: var(--p-gray-200); + --color-button-secondary-font: var(--p--color--gray-670); + --color-button-secondary-border: var(--p--color--gray-320); + --color-button-secondary-background: var(--p--color--white); + --color-button-secondary-hover-active-focus-font: var(--p--color--primary-420); + --color-button-secondary-hover-active-focus-border: var(--p--color--primary-320); + --color-button-secondary-hover-background: var(--p--color--primary-030); + --color-button-secondary-active-focus-background: var(--p--color--primary-050); + --color-button-secondary-focus-outline: var(--p--color--gray-120); + --color-button-secondary-disabled-font: var(--p--color--gray-200); + --color-button-secondary-disabled-border: var(--p--color--gray-200); // Button highlight - --color-button-highlight-font: var(--p-gray-670); + --color-button-highlight-font: var(--p--color--gray-670); --color-button-highlight-border: transparent; --color-button-highlight-background: transparent; - --color-button-highlight-hover-active-focus-font: var(--p-color-primary-shade-100); - --color-button-highlight-hover-active-focus-border: var(--p-gray-40); - --color-button-highlight-hover-background: var(--p-gray-40); - --color-button-highlight-active-focus-background: var(--p-gray-40); - --color-button-highlight-focus-outline: var(--p-gray-40); - --color-button-highlight-disabled-font: var(--p-gray-120); + --color-button-highlight-hover-active-focus-font: var(--p--color--primary-420); + --color-button-highlight-hover-active-focus-border: var(--p--color--gray-040); + --color-button-highlight-hover-background: var(--p--color--gray-040); + --color-button-highlight-active-focus-background: var(--p--color--gray-040); + --color-button-highlight-focus-outline: var(--p--color--gray-040); + --color-button-highlight-disabled-font: var(--p--color--gray-120); --color-button-highlight-disabled-border: transparent; --color-button-highlight-disabled-background: transparent; // Button success, warning, danger - --color-button-success-font: var(--p-white); - --color-button-success-disabled-font: var(--p-white-a-075); + --color-button-success-font: var(--p--color--white); + --color-button-success-disabled-font: var(--p--color--white-a-075); --color-button-warning-font: var(--color-text-xlight); - --color-button-warning-disabled-font: var(--p-white-a-075); + --color-button-warning-disabled-font: var(--p--color--white-a-075); --color-button-danger-font: var(--color-text-xlight); --color-button-danger-border: var(--color-danger); --color-button-danger-focus-outline: var(--color-danger-tint-1); - --color-button-danger-disabled-font: var(--p-white-a-075); + --color-button-danger-disabled-font: var(--p--color--white-a-075); --color-button-danger-disabled-border: var(--color-danger-tint-1); --color-button-danger-disabled-background: var(--color-danger-tint-1); // Text button - --color-text-button-secondary-font: var(--p-gray-670); + --color-text-button-secondary-font: var(--p--color--gray-670); // Node Creator Button - --color-button-node-creator-border-font: var(--p-gray-540); - --color-button-node-creator-hover-font: var(--p-color-primary-320); - --color-button-node-creator-hover-border: var(--p-color-primary-320); - --color-button-node-creator-background: var(--p-white); + --color-button-node-creator-border-font: var(--p--color--gray-540); + --color-button-node-creator-hover-font: var(--p--color--primary-320); + --color-button-node-creator-hover-border: var(--p--color--primary-320); + --color-button-node-creator-background: var(--p--color--white); // Table --color-table-header-background: var(--color-background-base); @@ -329,12 +329,12 @@ --color-notification-background: var(--color-background-xlight); // Execution - --execution-card-border-new: var(--p-gray-200); - --execution-card-border-success: var(--p-color-alt-a-300); - --execution-card-border-error: var(--p-color-alt-c-230); - --execution-card-border-waiting: var(--p-color-secondary-170); - --execution-card-border-running: var(--p-color-alt-b-180); - --execution-card-border-unknown: var(--p-gray-120); + --execution-card-border-new: var(--p--color--gray-200); + --execution-card-border-success: var(--p--color--alt-a-300); + --execution-card-border-error: var(--p--color--alt-c-230); + --execution-card-border-waiting: var(--p--color--secondary-170); + --execution-card-border-running: var(--p--color--alt-b-180); + --execution-card-border-unknown: var(--p--color--gray-120); --execution-card-background: var(--color-foreground-xlight); --execution-card-background-hover: var(--color-foreground-light); --execution-card-text-waiting: var(--color-secondary); @@ -343,12 +343,12 @@ --execution-select-all-text: var(--color-danger); // NDV - --color-run-data-background: var(--p-gray-070); - --color-ndvv2-run-data-background: var(--p-gray-040); + --color-run-data-background: var(--p--color--gray-070); + --color-ndvv2-run-data-background: var(--p--color--gray-040); --color-ndv-droppable-parameter: var(--color-secondary); - --color-ndv-droppable-parameter-background: var(--p-color-secondary-470-a-010); - --color-ndv-droppable-parameter-active-background: var(--p-color-alt-a-600-a-015); - --color-ndv-back-font: var(--p-white); + --color-ndv-droppable-parameter-background: var(--p--color--secondary-470-a-010); + --color-ndv-droppable-parameter-active-background: var(--p--color--alt-a-600-a-015); + --color-ndv-back-font: var(--p--color--white); // Notice --color-notice-warning-border: var(--color-warning-tint-1); @@ -378,29 +378,29 @@ --color-callout-secondary-icon: var(--color-secondary); // Dialogs and overlays - --color-dialog-background: var(--p-white); - --color-dialog-overlay-background: var(--p-white-a-075); - --color-dialog-overlay-background-dark: var(--p-color-alt-g-700-a-075); - --color-block-ui-overlay: var(--p-gray-820); + --color-dialog-background: var(--p--color--white); + --color-dialog-overlay-background: var(--p--color--white-a-075); + --color-dialog-overlay-background-dark: var(--p--color--alt-g-700-a-075); + --color-block-ui-overlay: var(--p--color--gray-820); // Avatar --color-avatar-font: var(--color-text-xlight); // NPS Survey - --color-nps-survey-background: var(--p-gray-740); - --color-nps-survey-font: var(--p-white); + --color-nps-survey-background: var(--p--color--gray-740); + --color-nps-survey-font: var(--p--color--white); // Action Dropdown --color-action-dropdown-item-active-background: var(--color-background-base); // Switch (Activation, boolean) - --color-switch-background: var(--p-gray-420); - --color-switch-active-background: var(--p-color-alt-f-560); + --color-switch-background: var(--p--color--gray-420); + --color-switch-active-background: var(--p--color--alt-f-560); --color-switch-border-color: transparent; - --color-switch-toggle: var(--p-white); + --color-switch-toggle: var(--p--color--white); // Feature Request - --color-feature-request-font: var(--p-white); + --color-feature-request-font: var(--p--color--white); // Input Triple --color-background-input-triple: var(--color-background-light); @@ -410,14 +410,14 @@ // MFA Recovery codes --color-mfa-recovery-code-background: var(--color-background-base); - --color-mfa-recovery-code-color: var(--p-gray-490); + --color-mfa-recovery-code-color: var(--p--color--gray-490); --color-mfa-lose-access-text-color: var(--color-danger); // Text highlight - --color-text-highlight-background: var(--p-color-alt-d-230); + --color-text-highlight-background: var(--p--color--alt-d-230); // MFA Modal - --color-qr-code-border: var(--p-gray-010); + --color-qr-code-border: var(--p--color--gray-010); // AI --node-type-background-l: 95%; @@ -589,22 +589,22 @@ ); // Various - --color-avatar-accent-1: var(--p-gray-120); - --color-avatar-accent-2: var(--p-color-alt-e-530); - --color-info: var(--p-gray-420); - --color-info-tint-1: var(--p-gray-120); - --color-info-tint-2: var(--p-gray-040); - --color-grey: var(--p-gray-200); - --color-light-grey: var(--p-gray-120); - --color-neutral: var(--p-gray-490); + --color-avatar-accent-1: var(--p--color--gray-120); + --color-avatar-accent-2: var(--p--color--alt-e-530); + --color-info: var(--p--color--gray-420); + --color-info-tint-1: var(--p--color--gray-120); + --color-info-tint-2: var(--p--color--gray-040); + --color-grey: var(--p--color--gray-200); + --color-light-grey: var(--p--color--gray-120); + --color-neutral: var(--p--color--gray-490); --color-configurable-node-name: var(--color-text-dark); --color-secondary-link: var(--color-secondary); --color-secondary-link-hover: var(--color-secondary-shade-1); // Menu - --color-menu-background: var(--p-white); - --color-menu-hover-background: var(--p-gray-120); - --color-menu-active-background: var(--p-gray-120); + --color-menu-background: var(--p--color--white); + --color-menu-hover-background: var(--p--color--gray-120); + --color-menu-active-background: var(--p--color--gray-120); // Generated Color Shades from 50 to 950 // Not yet used in design system @@ -694,10 +694,10 @@ // Params --color-icon-base: var(--color-text-light); - --color-icon-hover: var(--p-color-primary-320); + --color-icon-hover: var(--p--color--primary-320); /* Ag Grid */ - --grid-row-selected-background: var(--p-color-secondary-070); + --grid-row-selected-background: var(--p--color--secondary-070); --grid-cell-editing-border: 2px solid var(--color-secondary); } diff --git a/packages/frontend/@n8n/design-system/src/styleguide/colorsprimitives.stories.ts b/packages/frontend/@n8n/design-system/src/styleguide/colorsprimitives.stories.ts index 38cd38e9502..e2e19c34f62 100644 --- a/packages/frontend/@n8n/design-system/src/styleguide/colorsprimitives.stories.ts +++ b/packages/frontend/@n8n/design-system/src/styleguide/colorsprimitives.stories.ts @@ -22,39 +22,39 @@ const Template = }); export const Gray = Template( - "", + "", ); export const Primary = Template( - "", + "", ); export const Secondary = Template( - "", + "", ); export const AlternateA = Template( - "", + "", ); export const AlternateB = Template( - "", + "", ); export const AlternateC = Template( - "", + "", ); export const AlternateD = Template( - "", + "", ); export const AlternateE = Template( - "", + "", ); -export const AlternateF = Template(''); +export const AlternateF = Template(''); -export const AlternateG = Template(''); +export const AlternateG = Template(''); -export const AlternateH = Template(''); +export const AlternateH = Template(''); diff --git a/packages/frontend/editor-ui/package.json b/packages/frontend/editor-ui/package.json index 612e97d1067..538acd4ce0f 100644 --- a/packages/frontend/editor-ui/package.json +++ b/packages/frontend/editor-ui/package.json @@ -15,8 +15,8 @@ "dev": "pnpm serve", "lint": "eslint src --quiet", "lint:fix": "eslint src --fix", - "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache", - "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache", + "lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache --custom-formatter ../../@n8n/stylelint-config/dist/formatter-summary.js", + "lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache --custom-formatter ../../@n8n/stylelint-config/dist/formatter-summary.js", "format": "biome format --write . && prettier --write . --ignore-path ../../../.prettierignore", "format:check": "biome ci . && prettier --check . --ignore-path ../../../.prettierignore", "serve": "cross-env VUE_APP_URL_BASE_API=http://localhost:5678/ vite --host 0.0.0.0 --port 8080 dev", diff --git a/packages/frontend/editor-ui/src/components/MainHeader/MainHeader.vue b/packages/frontend/editor-ui/src/components/MainHeader/MainHeader.vue index 0e5007ee6a3..ac37ef6e42a 100644 --- a/packages/frontend/editor-ui/src/components/MainHeader/MainHeader.vue +++ b/packages/frontend/editor-ui/src/components/MainHeader/MainHeader.vue @@ -342,7 +342,7 @@ function hideGithubButton() { cursor: pointer; &:hover { - color: var(--p-color-primary-420); + color: var(--p--color--primary-420); } } .github-button-container { diff --git a/packages/frontend/editor-ui/src/components/ParameterInputOverrides/FromAiOverrideButton.vue b/packages/frontend/editor-ui/src/components/ParameterInputOverrides/FromAiOverrideButton.vue index 14403952599..fd7949ff6b7 100644 --- a/packages/frontend/editor-ui/src/components/ParameterInputOverrides/FromAiOverrideButton.vue +++ b/packages/frontend/editor-ui/src/components/ParameterInputOverrides/FromAiOverrideButton.vue @@ -46,7 +46,7 @@ const emit = defineEmits<{ svg { // ensure enough contrast in both light and dark mode - color: var(--p-gray-200); + color: var(--p--color--gray-200); } } } diff --git a/packages/frontend/editor-ui/src/features/dataTable/components/dataGrid/DataTableTable.vue b/packages/frontend/editor-ui/src/features/dataTable/components/dataGrid/DataTableTable.vue index 2737e0c4c8b..0932430a7cd 100644 --- a/packages/frontend/editor-ui/src/features/dataTable/components/dataGrid/DataTableTable.vue +++ b/packages/frontend/editor-ui/src/features/dataTable/components/dataGrid/DataTableTable.vue @@ -235,7 +235,7 @@ defineExpose({ // AG Grid style overrides --ag-foreground-color: var(--color-text-base); --ag-cell-text-color: var(--color-text-dark); - --ag-accent-color: var(--p-color-secondary-470); + --ag-accent-color: var(--p--color--secondary-470); --ag-row-hover-color: var(--color-background-light-base); --ag-background-color: var(--color-background-xlight); --ag-border-color: var(--border-color-base); @@ -252,7 +252,7 @@ defineExpose({ --ag-cell-horizontal-padding: var(--spacing-2xs); --ag-header-height: calc(var(--ag-grid-size) * 0.8 + 32px); --ag-header-column-border-height: 100%; - --ag-range-selection-border-color: var(--p-color-secondary-470); + --ag-range-selection-border-color: var(--p--color--secondary-470); --ag-input-padding-start: var(--spacing-2xs); --ag-input-background-color: var(--color-text-xlight); --ag-focus-shadow: none;