From 7f743cfca429583502ef92c8cf5a9566e8fe9fdf Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 19:35:47 +0100 Subject: [PATCH 01/55] refactor: introduce NamingConvention type and update related interfaces for consistency --- src/types/app.ts | 2 ++ src/types/configurations.ts | 2 -- src/types/events.ts | 9 +++------ src/ui/App.tsx | 5 +++-- src/ui/services/CreatePalette.tsx | 5 +++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/types/app.ts b/src/types/app.ts index 088ec919..a5c8b6b0 100644 --- a/src/types/app.ts +++ b/src/types/app.ts @@ -70,6 +70,8 @@ export type PriorityContext = export type ThirdParty = 'COOLORS' | 'REALTIME_COLORS' | 'COLOUR_LOVERS' +export type NamingConvention = 'ONES' | 'TENS' | 'HUNDREDS' + export type Easing = 'LINEAR' | 'EASE_IN' | 'EASE_OUT' | 'EASE_IN_OUT' export interface ImportUrl { diff --git a/src/types/configurations.ts b/src/types/configurations.ts index 087de696..2824fbb5 100644 --- a/src/types/configurations.ts +++ b/src/types/configurations.ts @@ -50,8 +50,6 @@ export interface ScaleConfiguration { [key: string]: number } -export type NamingConventionConfiguration = 'ONES' | 'TENS' | 'HUNDREDS' - export interface ColorConfiguration { name: string description: string diff --git a/src/types/events.ts b/src/types/events.ts index 88ef0af3..ed36fff6 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -1,8 +1,5 @@ -import { Easing, EditorType } from './app' -import { - ColorSpaceConfiguration, - NamingConventionConfiguration, -} from './configurations' +import { Easing, EditorType, NamingConvention } from './app' +import { ColorSpaceConfiguration } from './configurations' export interface EditorEvent { editor: EditorType @@ -43,7 +40,7 @@ export interface ScaleEvent { | 'SWITCH_BASE' | 'SWITCH_CUSTOM' | 'OPEN_KEYBOARD_SHORTCUTS' - | NamingConventionConfiguration + | NamingConvention | Easing } diff --git a/src/ui/App.tsx b/src/ui/App.tsx index c77fd857..d96fb42f 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -11,6 +11,7 @@ import { EditorType, HighlightDigest, Language, + NamingConvention, PlanStatus, PriorityContext, Service, @@ -24,7 +25,6 @@ import { DatesConfiguration, ExportConfiguration, ExtractOfPaletteConfiguration, - NamingConventionConfiguration, PresetConfiguration, PublicationConfiguration, ScaleConfiguration, @@ -66,7 +66,8 @@ export interface AppStates { name: string description: string preset: PresetConfiguration - namingConvention: NamingConventionConfiguration + namingConvention: NamingConvention + distributionEasing: Easing scale: ScaleConfiguration colors: Array colorSpace: ColorSpaceConfiguration diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index 78f46ccc..d69bf597 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -8,12 +8,12 @@ import { Context, ContextItem, Language, + NamingConvention, PlanStatus, ThirdParty, } from '../../types/app' import { ColorSpaceConfiguration, - NamingConventionConfiguration, PresetConfiguration, ScaleConfiguration, SourceColorConfiguration, @@ -38,7 +38,8 @@ interface CreatePaletteProps { name: string description: string preset: PresetConfiguration - namingConvention: NamingConventionConfiguration + namingConvention: NamingConvention + distributionEasing: Easing scale: ScaleConfiguration colorSpace: ColorSpaceConfiguration visionSimulationMode: VisionSimulationModeConfiguration From 59158ec57a125ad7a84599734e827cf9091ebd3a Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 19:37:43 +0100 Subject: [PATCH 02/55] refactor: update distributionEasing and namingConvention types for consistency across components --- src/ui/App.tsx | 2 ++ src/ui/contexts/Scale.tsx | 17 +++++++++++------ src/ui/services/CreatePalette.tsx | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index d96fb42f..6d6963a8 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -16,6 +16,7 @@ import { PriorityContext, Service, TrialStatus, + Easing, } from '../types/app' import { AlgorithmVersionConfiguration, @@ -142,6 +143,7 @@ export default class App extends PureComponent< preset: presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset, namingConvention: 'ONES', + distributionEasing: 'LINEAR', scale: {}, colors: [], colorSpace: 'LCH', diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index 1d89f1ae..eb4ebc0e 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -14,9 +14,14 @@ import { PureComponent } from 'preact/compat' import React from 'react' import { locals } from '../../content/locals' -import { Easing, EditorType, Language, PlanStatus } from '../../types/app' import { - NamingConventionConfiguration, + Easing, + EditorType, + Language, + NamingConvention, + PlanStatus, +} from '../../types/app' +import { PresetConfiguration, ScaleConfiguration, SourceColorConfiguration, @@ -39,7 +44,8 @@ interface ScaleProps { sourceColors?: Array hasPreset: boolean preset: PresetConfiguration - namingConvention: NamingConventionConfiguration + namingConvention: NamingConvention + distributionEasing: Easing scale?: ScaleConfiguration actions?: string userIdentity: UserConfiguration @@ -60,7 +66,6 @@ interface ScaleProps { } interface ScaleStates { - distributionEasing: Easing isTipsOpen: boolean } @@ -70,6 +75,7 @@ export default class Scale extends PureComponent { static defaultProps: Partial = { namingConvention: 'ONES', + distributionEasing: 'LINEAR', } static features = (planStatus: PlanStatus) => ({ @@ -136,7 +142,6 @@ export default class Scale extends PureComponent { ) as DispatchProcess, } this.state = { - distributionEasing: 'LINEAR', isTipsOpen: false, } } @@ -501,7 +506,7 @@ export default class Scale extends PureComponent { action: this.customHandler, }, ]} - selected={this.state.distributionEasing} + selected={this.props.distributionEasing} parentClassName="controls" pin="BOTTOM" isBlocked={Scale.features( diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index d69bf597..7839ea6b 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -7,6 +7,7 @@ import { uid } from 'uid' import { Context, ContextItem, + Easing, Language, NamingConvention, PlanStatus, From 0f103cf6c0b8bc33ae9c5f22a90d56ca19c20791 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 19:41:17 +0100 Subject: [PATCH 03/55] refactor: update Slider component types and templates for enhanced functionality --- src/ui/components/Slider.tsx | 62 +++++++++++++++++++++++------- src/ui/contexts/Scale.tsx | 73 ++++++++++++++++-------------------- 2 files changed, 80 insertions(+), 55 deletions(-) diff --git a/src/ui/components/Slider.tsx b/src/ui/components/Slider.tsx index 9a30870f..dbb72840 100644 --- a/src/ui/components/Slider.tsx +++ b/src/ui/components/Slider.tsx @@ -18,7 +18,7 @@ interface SliderProps { stops: Array hasPreset: boolean presetName: string - type: 'EQUAL' | 'CUSTOM' + type: 'PRE_EDIT' | 'EDIT' | 'FULLY_EDIT' min?: number max?: number scale?: ScaleConfiguration @@ -299,16 +299,7 @@ export default class Slider extends Component { } // Templates - Equal = () => { - palette.min = this.props.min - palette.max = this.props.max - palette.scale = doLightnessScale( - this.props.stops, - palette.min ?? 0, - palette.max ?? 100, - true, - this.props.distributionEasing - ) + PreEdit = () => { return (
{Object.entries(palette.scale).map((lightness) => ( @@ -325,7 +316,49 @@ export default class Slider extends Component { ) } - Custom = () => { + Edit = () => { + palette.scale = this.props.scale ?? {} + return ( +
+ {Object.entries(this.props.scale ?? {}).map( + (lightness, index, original) => ( + ) => { + this.onShiftRight(e.target as HTMLElement, e.metaKey, e.ctrlKey) + }} + onShiftLeft={(e: React.KeyboardEvent) => { + this.onShiftLeft(e.target as HTMLElement, e.metaKey, e.ctrlKey) + }} + onMouseDown={(e: React.MouseEvent) => { + this.onGrab(e) + ;(e.target as HTMLElement).focus() + }} + onValidStopValue={(stopId, e) => this.validHandler(stopId, e)} + /> + ) + )} +
+ ) + } + + FullyEdit = () => { palette.scale = this.props.scale ?? {} return (
{ render() { return (
- {this.props.type === 'EQUAL' && } - {this.props.type === 'CUSTOM' && } + {this.props.type === 'PRE_EDIT' && } + {this.props.type === 'EDIT' && } + {this.props.type === 'FULLY_EDIT' && }
) } diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index eb4ebc0e..ea1ac09d 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -751,38 +751,17 @@ export default class Scale extends PureComponent { this.props.planStatus ).SCALE_CONFIGURATION.isActive()} > - {this.props.preset.isDistributed && - Object.keys(this.props.scale ?? {}).length === 0 ? ( - - ) : ( - - )} + { this.props.planStatus ).SCALE_CONFIGURATION.isActive()} > - + {this.props.preset.id === 'CUSTOM' ? ( + + ) : ( + + )} Date: Tue, 10 Dec 2024 19:45:50 +0100 Subject: [PATCH 04/55] refactor: streamline state management in Slider and Scale --- src/ui/App.tsx | 132 +++++++++++------- src/ui/contexts/CommunityPalettes.tsx | 1 - src/ui/contexts/Scale.tsx | 191 ++++++++++++++++++-------- src/ui/contexts/Source.tsx | 1 + src/ui/services/CreatePalette.tsx | 2 +- 5 files changed, 218 insertions(+), 109 deletions(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 6d6963a8..7c121f23 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -59,6 +59,7 @@ import EditPalette from './services/EditPalette' import TransferPalette from './services/TransferPalette' import './stylesheets/app-components.css' import './stylesheets/app.css' +import doLightnessScale from '../utils/doLightnessScale' export interface AppStates { service: Service @@ -154,7 +155,7 @@ export default class App extends PureComponent< lightColor: '#FFFFFF', darkColor: '#000000', }, - algorithmVersion: 'v1', + algorithmVersion: 'v2', screenshot: null, dates: { createdAt: '', @@ -211,6 +212,15 @@ export default class App extends PureComponent< componentDidMount = async () => { setTimeout(() => this.setState({ isLoaded: true }), 1000) + this.setState({ + scale: doLightnessScale( + this.state.preset.scale, + this.state.preset.min, + this.state.preset.max, + this.state.preset.isDistributed, + this.props.distributionEasing + ), + }) fetch( `${announcementsWorkerUrl}/?action=get_version&database_id=${process.env.REACT_APP_NOTION_ANNOUNCEMENTS_ID}` ) @@ -354,65 +364,82 @@ export default class App extends PureComponent< }) const updateWhileEmptySelection = () => { + if (isPaletteSelected) { + const preset = + presets.find((preset) => preset.id === 'MATERIAL') ?? + defaultPreset + + this.setState({ + id: '', + name: '', + description: '', + preset: preset, + scale: doLightnessScale( + preset.scale, + preset.min, + preset.max, + preset.isDistributed, + this.props.distributionEasing + ), + colorSpace: 'LCH', + visionSimulationMode: 'NONE', + view: 'PALETTE_WITH_PROPERTIES', + textColorsTheme: { + lightColor: '#FFFFFF', + darkColor: '#000000', + }, + algorithmVersion: 'v2', + screenshot: null, + dates: { + createdAt: '', + updatedAt: '', + publishedAt: '', + }, + publicationStatus: { + isPublished: false, + isShared: false, + }, + creatorIdentity: { + creatorFullName: '', + creatorAvatar: '', + creatorId: '', + }, + priorityContainerContext: (() => { + if (this.state.priorityContainerContext === 'PUBLICATION') + return 'EMPTY' + else return this.state.priorityContainerContext + })(), + onGoingStep: 'selection empty', + }) + palette.name = '' + palette.description = '' + palette.preset = defaultPreset + palette.colorSpace = 'LCH' + palette.visionSimulationMode = 'NONE' + palette.view = 'PALETTE_WITH_PROPERTIES' + palette.textColorsTheme = { + lightColor: '#FFFFFF', + darkColor: '#000000', + } + } this.setState({ service: 'CREATE', sourceColors: this.state.sourceColors.filter( (sourceColor: SourceColorConfiguration) => sourceColor.source !== 'CANVAS' ), - id: '', - name: '', - description: '', - preset: - presets.find((preset) => preset.id === 'MATERIAL') ?? - defaultPreset, - namingConvention: 'ONES', - scale: {}, - colorSpace: 'LCH', - visionSimulationMode: 'NONE', - view: 'PALETTE_WITH_PROPERTIES', - textColorsTheme: { - lightColor: '#FFFFFF', - darkColor: '#000000', - }, - algorithmVersion: 'v1', - screenshot: null, - dates: { - createdAt: '', - updatedAt: '', - publishedAt: '', - }, - publicationStatus: { - isPublished: false, - isShared: false, - }, - creatorIdentity: { - creatorFullName: '', - creatorAvatar: '', - creatorId: '', - }, - priorityContainerContext: (() => { - if (this.state.priorityContainerContext === 'PUBLICATION') - return 'EMPTY' - else return this.state.priorityContainerContext - })(), onGoingStep: 'selection empty', }) - palette.name = '' - palette.description = '' - palette.preset = defaultPreset - palette.colorSpace = 'LCH' - palette.visionSimulationMode = 'NONE' - palette.view = 'PALETTE_WITH_PROPERTIES' - palette.textColorsTheme = { - lightColor: '#FFFFFF', - darkColor: '#000000', - } + isPaletteSelected = false } const updateWhileColorSelected = () => { if (isPaletteSelected) { + const preset = + presets.find((preset) => preset.id === 'MATERIAL') ?? + defaultPreset + this.setState({ id: '', name: '', @@ -420,8 +447,13 @@ export default class App extends PureComponent< preset: presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset, - namingConvention: 'ONES', - scale: {}, + scale: doLightnessScale( + preset.scale, + preset.min, + preset.max, + preset.isDistributed, + this.props.distributionEasing + ), colorSpace: 'LCH', visionSimulationMode: 'NONE', view: 'PALETTE_WITH_PROPERTIES', @@ -429,7 +461,7 @@ export default class App extends PureComponent< lightColor: '#FFFFFF', darkColor: '#000000', }, - algorithmVersion: 'v1', + algorithmVersion: 'v2', screenshot: null, dates: { createdAt: '', diff --git a/src/ui/contexts/CommunityPalettes.tsx b/src/ui/contexts/CommunityPalettes.tsx index 893c6b3d..f83371a6 100644 --- a/src/ui/contexts/CommunityPalettes.tsx +++ b/src/ui/contexts/CommunityPalettes.tsx @@ -79,7 +79,6 @@ export default class CommunityPalettes extends PureComponent< return actions[this.props.status]?.() } - // Lifecycle componentDidUpdate = (prevProps: Readonly): void => { if (prevProps.palettesList.length !== this.props.palettesList.length) this.setState({ diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index ea1ac09d..b472c5cf 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -59,6 +59,7 @@ interface ScaleProps { onAddStop?: React.Dispatch> onRemoveStop?: React.Dispatch> onChangeNamingConvention?: React.Dispatch> + onChangeDistributionEasing?: React.Dispatch> onCreatePalette?: () => void onSyncLocalStyles?: () => void onSyncLocalVariables?: () => void @@ -176,6 +177,7 @@ export default class Scale extends PureComponent { const onUpdatingStop = () => { this.scaleMessage.isEditedInRealTime = true + this.props.onChangeScale() if (!this.props.hasPreset) this.dispatch.scale.on.status = true } @@ -190,10 +192,25 @@ export default class Scale extends PureComponent { } presetsHandler = (e: Event) => { + const scale = (preset: PresetConfiguration) => + doLightnessScale( + preset.scale ?? [], + preset.min ?? 0, + preset.max ?? 100, + preset.isDistributed ?? true, + this.props.distributionEasing + ) + const setMaterialDesignPreset = () => { + const preset = + presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'MATERIAL'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -208,9 +225,15 @@ export default class Scale extends PureComponent { } const setMaterial3Preset = () => { + const preset = + presets.find((preset) => preset.id === 'MATERIAL_3') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'MATERIAL_3'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -225,9 +248,15 @@ export default class Scale extends PureComponent { } const setTailwindPreset = () => { + const preset = + presets.find((preset) => preset.id === 'TAILWIND') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'TAILWIND'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -242,9 +271,15 @@ export default class Scale extends PureComponent { } const setAntDesignPreset = () => { + const preset = + presets.find((preset) => preset.id === 'ANT') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'ANT'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -259,9 +294,15 @@ export default class Scale extends PureComponent { } const setAdsPreset = () => { + const preset = + presets.find((preset) => preset.id === 'ADS') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'ADS'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -276,9 +317,15 @@ export default class Scale extends PureComponent { } const setAdsNeutralPreset = () => { + const preset = + presets.find((preset) => preset.id === 'ADS_NEUTRAL') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'ADS_NEUTRAL'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -293,9 +340,15 @@ export default class Scale extends PureComponent { } const setCarbonPreset = () => { + const preset = + presets.find((preset) => preset.id === 'CARBON') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'CARBON'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -310,9 +363,15 @@ export default class Scale extends PureComponent { } const setBasePreset = () => { + const preset = + presets.find((preset) => preset.id === 'BASE') ?? defaultPreset + + palette.preset = preset + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'BASE'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -327,9 +386,24 @@ export default class Scale extends PureComponent { } const setCustomPreset = () => { + const preset = + presets.find((preset) => preset.id === 'CUSTOM') ?? defaultPreset + const newScale = preset?.scale.map((stop, index) => { + if (this.props.namingConvention === 'TENS') return (index + 1) * 10 + else if (this.props.namingConvention === 'HUNDREDS') + return (index + 1) * 100 + return (index + 1) * 1 + }) + + preset.scale = newScale ?? [] + palette.preset = preset + palette.min = preset.min + palette.max = preset.max + palette.scale = scale(preset) + this.props.onChangePreset?.({ - preset: presets.find((preset) => preset.id === 'CUSTOM'), - scale: {}, + preset: preset, + scale: scale(preset), onGoingStep: 'preset changed', }) @@ -360,68 +434,71 @@ export default class Scale extends PureComponent { } customHandler = (e: Event) => { - const scale = this.props.preset?.['scale'] ?? [1, 2] + const stops = this.props.preset?.['scale'] ?? [1, 2] + const preset = + presets.find((preset) => preset.id === 'CUSTOM') ?? defaultPreset + const scale = (stps = stops) => + doLightnessScale( + stps, + palette.min ?? 0, + palette.max ?? 100, + true, + this.props.distributionEasing + ) const addStop = () => { - if (scale.length < 24) { - scale.push(scale.slice(-1)[0] + scale[0]) + if (stops.length < 24) { + stops.push(stops.slice(-1)[0] + stops[0]) + preset.scale = stops + palette.scale = scale() + this.props.onAddStop?.({ - preset: { - name: presets.find((preset) => preset.id === 'CUSTOM')?.name ?? '', - scale: scale, - min: palette.min ?? 0, - max: palette.max ?? 100, - isDistributed: true, - id: 'CUSTOM', - }, - scale: {}, + preset: preset, + scale: scale(), }) } } const removeStop = () => { - if (scale.length > 2) { - scale.pop() + if (stops.length > 2) { + stops.pop() + preset.scale = stops + palette.scale = scale() + this.props.onRemoveStop?.({ - preset: { - name: presets.find((preset) => preset.id === 'CUSTOM')?.name ?? '', - scale: scale, - min: palette.min ?? 0, - max: palette.max ?? 100, - isDistributed: true, - id: 'CUSTOM', - }, - scale: {}, + preset: preset, + scale: scale(), }) } } const changeNamingConvention = () => { + const preset = + presets.find((preset) => preset.id === 'CUSTOM') ?? defaultPreset const option = (e.target as HTMLInputElement).dataset - .value as NamingConventionConfiguration + .value as NamingConvention + const newStops = stops.map((stop, index) => { + if (option === 'TENS') return (index + 1) * 10 + else if (option === 'HUNDREDS') return (index + 1) * 100 + return (index + 1) * 1 + }) + + preset.scale = newStops + palette.scale = scale(newStops) + palette.preset = preset this.props.onChangeNamingConvention?.({ namingConvention: option, - preset: { - name: presets.find((preset) => preset.id === 'CUSTOM')?.name ?? '', - scale: scale.map((stop, index) => { - if (option === 'TENS') return (index + 1) * 10 - else if (option === 'HUNDREDS') return (index + 1) * 100 - return (index + 1) * 1 - }), - min: palette.min ?? 0, - max: palette.max ?? 100, - isDistributed: true, - id: 'CUSTOM', - }, - scale: {}, + preset: preset, + scale: scale(newStops), }) } const changeDistributionEasing = () => { - const value = (e.target as HTMLElement).dataset.value as Easing + const value = + ((e.target as HTMLElement).dataset.value as Easing) ?? 'LINEAR' - this.setState({ + this.props.onChangeDistributionEasing?.({ distributionEasing: value, }) diff --git a/src/ui/contexts/Source.tsx b/src/ui/contexts/Source.tsx index 339d44eb..c42a9be9 100644 --- a/src/ui/contexts/Source.tsx +++ b/src/ui/contexts/Source.tsx @@ -24,6 +24,7 @@ import Actions from '../modules/Actions' import Preview from '../modules/Preview' import Explore from './Explore' import Overview from './Overview' +import { palette } from '../../utils/palettePackage' interface SourceProps { sourceColors: Array diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index 7839ea6b..29683c26 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -24,7 +24,6 @@ import { } from '../../types/configurations' import { TextColorsThemeHexModel } from '../../types/models' import { UserSession } from '../../types/user' -import doLightnessScale from '../../utils/doLightnessScale' import { trackActionEvent } from '../../utils/eventsTracker' import { palette } from '../../utils/palettePackage' import { setContexts } from '../../utils/setContexts' @@ -199,6 +198,7 @@ export default class CreatePalette extends PureComponent< onAddStop={this.props.onCustomPreset} onRemoveStop={this.props.onCustomPreset} onChangeNamingConvention={this.props.onCustomPreset} + onChangeDistributionEasing={this.props.onCustomPreset} onChangeScale={this.slideHandler} onCreatePalette={this.onCreatePalette} /> From e755a7f2f0109a5a52f6fb1cdf4d781209ab70de Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 19:47:39 +0100 Subject: [PATCH 05/55] refactor: Knob and Slider to use React hooks ans state management --- src/ui/components/Knob.tsx | 25 ++++++++--- src/ui/components/Slider.tsx | 62 +++++++++++++-------------- src/ui/contexts/Scale.tsx | 2 +- src/ui/handlers/shiftLeftStop.ts | 4 +- src/ui/handlers/shiftRightStop.ts | 4 +- src/ui/stylesheets/app-components.css | 10 ----- 6 files changed, 57 insertions(+), 50 deletions(-) diff --git a/src/ui/components/Knob.tsx b/src/ui/components/Knob.tsx index ff110878..0a4c7714 100644 --- a/src/ui/components/Knob.tsx +++ b/src/ui/components/Knob.tsx @@ -11,6 +11,7 @@ interface KnobProps { min?: string max?: string canBeTyped: boolean + isDisplayed: boolean onShiftRight?: React.KeyboardEventHandler onShiftLeft?: React.KeyboardEventHandler onDelete?: React.KeyboardEventHandler @@ -23,16 +24,18 @@ interface KnobProps { ) => void } -interface States { +interface KnobStates { isStopInputOpen: boolean + isTooltipOpen: boolean stopInputValue: string | number } -export default class Knob extends PureComponent { +export default class Knob extends PureComponent { constructor(props: KnobProps) { super(props) this.state = { isStopInputOpen: false, + isTooltipOpen: false, stopInputValue: this.props.value, } } @@ -91,12 +94,12 @@ export default class Knob extends PureComponent {
n) .join(' ')} style={{ left: `${this.props.value}%` }} + data-lightness={this.props.id} tabIndex={0} onKeyDown={(e) => this.keyboardHandler( @@ -105,11 +108,21 @@ export default class Knob extends PureComponent { ) } onMouseDown={this.props.onMouseDown} + onMouseEnter={() => this.setState({ isTooltipOpen: true })} + onMouseLeave={(e) => { + const isFocused = document.activeElement === e.target + if (isFocused) this.setState({ isTooltipOpen: true }) + else this.setState({ isTooltipOpen: false }) + }} + onFocus={() => this.setState({ isTooltipOpen: true })} + onBlur={() => this.setState({ isTooltipOpen: false })} onClick={(e) => this.clickHandler(e)} > -
- {this.transformStopValue(this.props.value)} -
+ {(this.props.isDisplayed || this.state.isTooltipOpen) && ( +
+ {this.transformStopValue(this.props.value)} +
+ )} {this.state.isStopInputOpen && (
void } -export default class Slider extends Component { +interface SliderStates { + isTooltipDisplay: Array +} + +export default class Slider extends Component { + constructor(props: SliderProps) { + super(props) + this.state = { + isTooltipDisplay: Array(this.props.stops?.length).fill(false), + } + } + // Handlers validHandler = ( stopId: string, @@ -80,7 +91,7 @@ export default class Slider extends Component { ) stops.forEach((stop) => this.updateLightnessScaleEntry( - stop.classList[1], + stop.dataset.lightness as string, parseFloat(stop.style.left.replace('%', '')) ) ) @@ -171,17 +182,13 @@ export default class Slider extends Component { } if (e.ctrlKey === false && e.metaKey === false && e.shiftKey === false) - stops.forEach( - (stop) => ((stop.children[0] as HTMLElement).style.display = 'none') - ) + this.setState({ + isTooltipDisplay: Array(stops.length).fill(false), + }) stop.style.left = doMap(offset, 0, rangeWidth, 0, 100).toFixed(1) + '%' // Update lightness scale - this.updateStopTooltip( - tooltip, - parseFloat(doMap(offset, 0, rangeWidth, 0, 100).toFixed(1)) - ) update() this.props.onChange('UPDATING') } @@ -195,9 +202,9 @@ export default class Slider extends Component { document.onmouseup = null stop.onmouseup = null stop.style.zIndex = '1' - stops.forEach( - (stop) => ((stop.children[0] as HTMLElement).style.display = 'none') - ) + this.setState({ + isTooltipDisplay: Array(stops.length).fill(false), + }) update() this.props.onChange('RELEASED') @@ -248,13 +255,6 @@ export default class Slider extends Component { palette.scale[key] = parseFloat(value.toFixed(1)) } - updateStopTooltip = (tooltip: HTMLElement, value: number | string) => { - tooltip.style.display = 'block' - if (typeof value === 'string') - tooltip.textContent = value === '100.0' ? '100' : value - else tooltip.textContent = value === 100 ? '100' : value?.toFixed(1) - } - distributeStops = ( type: string, value: number, @@ -270,13 +270,12 @@ export default class Slider extends Component { true, this.props.distributionEasing ) - stops.forEach((stop) => { - stop.style.left = palette.scale[stop.classList[1]] + '%' - this.updateStopTooltip( - stop.childNodes[0] as HTMLElement, - parseFloat(palette.scale[stop.classList[1]].toFixed(1)) - ) + stop.style.left = palette.scale[stop.dataset.lightness as string] + '%' + }) + + this.setState({ + isTooltipDisplay: Array(stops.length).fill(true), }) } @@ -291,10 +290,10 @@ export default class Slider extends Component { if (stop !== src) stop.style.left = parseFloat(doMap(shift, 0, width, 0, 100).toFixed(1)) + '%' - this.updateStopTooltip( - stop.childNodes[0] as HTMLElement, - parseFloat(doMap(shift, 0, width, 0, 100).toFixed(1)) - ) + }) + + this.setState({ + isTooltipDisplay: this.state.isTooltipDisplay.fill(true), }) } @@ -302,13 +301,14 @@ export default class Slider extends Component { PreEdit = () => { return (
- {Object.entries(palette.scale).map((lightness) => ( + {Object.entries(this.props.scale ?? {}).map((lightness, index) => ( ) => this.onGrab(e)} /> ))} @@ -337,7 +337,6 @@ export default class Slider extends Component { ? '100' : (original[index - 1][1] - safeGap).toString() } - position={index} canBeTyped={!this.props.hasPreset} isDisplayed={this.state.isTooltipDisplay[index]} onShiftRight={(e: React.KeyboardEvent) => { @@ -395,6 +394,7 @@ export default class Slider extends Component { : (original[index - 1][1] - safeGap).toString() } canBeTyped={!this.props.hasPreset} + isDisplayed={this.state.isTooltipDisplay[index]} onShiftRight={(e: React.KeyboardEvent) => { this.onShiftRight(e.target as HTMLElement, e.metaKey, e.ctrlKey) }} diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index b472c5cf..72b81ecc 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -32,7 +32,7 @@ import { ActionsList, DispatchProcess } from '../../types/models' import features from '../../config' import doLightnessScale from '../../utils/doLightnessScale' import { trackScaleManagementEvent } from '../../utils/eventsTracker' -import { palette, presets } from '../../utils/palettePackage' +import { defaultPreset, palette, presets } from '../../utils/palettePackage' import type { AppStates } from '../App' import Feature from '../components/Feature' import Slider from '../components/Slider' diff --git a/src/ui/handlers/shiftLeftStop.ts b/src/ui/handlers/shiftLeftStop.ts index b7df6e91..a419aef7 100644 --- a/src/ui/handlers/shiftLeftStop.ts +++ b/src/ui/handlers/shiftLeftStop.ts @@ -14,7 +14,9 @@ const shiftLeftStop = ( stopsList.push(stop) }) - const selectedKnobIndex = stopsList.indexOf(selectedKnob.classList[1]), + const selectedKnobIndex = stopsList.indexOf( + selectedKnob.dataset.lightness as string + ), newLightnessScale = scale, currentStopValue: number = newLightnessScale[stopsList[selectedKnobIndex]], nextStopValue: number = diff --git a/src/ui/handlers/shiftRightStop.ts b/src/ui/handlers/shiftRightStop.ts index 39e4feaa..27bc1ee1 100644 --- a/src/ui/handlers/shiftRightStop.ts +++ b/src/ui/handlers/shiftRightStop.ts @@ -14,7 +14,9 @@ const shiftRightStop = ( stopsList.push(stop) }) - const selectedKnobIndex = stopsList.indexOf(selectedKnob.classList[1]), + const selectedKnobIndex = stopsList.indexOf( + selectedKnob.dataset.lightness as string + ), newLightnessScale = scale, currentStopValue: number = newLightnessScale[stopsList[selectedKnobIndex]], nextStopValue: number = diff --git a/src/ui/stylesheets/app-components.css b/src/ui/stylesheets/app-components.css index 596c5e07..f19a3719 100644 --- a/src/ui/stylesheets/app-components.css +++ b/src/ui/stylesheets/app-components.css @@ -127,11 +127,6 @@ div.slider .slider__knob--editing { outline: none; } -div.slider .slider__knob:focus .slider__tooltip, -div.slider .slider__knob--selected .slider__tooltip { - display: block !important; -} - div.slider .slider__knob:active .slider__label, div.slider .slider__knob:focus .slider__label, div.slider .slider__knob--selected .slider__label { @@ -195,11 +190,6 @@ div.slider .slider__tooltip { top: calc(var(--size-xsmall) * -1); text-align: center; user-select: none; - display: none; -} - -div.slider .slider__knob:hover .slider__tooltip { - display: block !important; } div.slider .slider__tooltip:after { From c8577fafd6c5124ccb6eba36524c5e6cf1fbb1c2 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 19:53:48 +0100 Subject: [PATCH 06/55] feat: upgrade Preview reactivity and display --- src/ui/App.tsx | 7 ++----- src/ui/contexts/Scale.tsx | 5 ++++- src/ui/contexts/Settings.tsx | 5 ++++- src/ui/contexts/Source.tsx | 5 ++++- src/ui/modules/Preview.tsx | 12 ++++++++---- src/ui/services/EditPalette.tsx | 5 ++++- src/ui/stylesheets/app.css | 2 +- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 7c121f23..f66a456e 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,7 +1,7 @@ import { Consent, ConsentConfiguration } from '@a_ng_d/figmug-ui' import { FeatureStatus } from '@a_ng_d/figmug-utils' import 'figma-plugin-ds/dist/figma-plugin-ds.css' -import { PureComponent } from 'preact/compat' +import { Component, PureComponent } from 'preact/compat' import React from 'react' import checkConnectionStatus from '../bridges/checks/checkConnectionStatus' @@ -101,10 +101,7 @@ export interface AppStates { let isPaletteSelected = false -export default class App extends PureComponent< - Record, - AppStates -> { +export default class App extends Component, AppStates> { static features = (planStatus: PlanStatus) => ({ CREATE: new FeatureStatus({ features: features, diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index 72b81ecc..f26b7a37 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -905,7 +905,10 @@ export default class Scale extends PureComponent { - +
) diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index cde599dd..93d5062e 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -531,7 +531,10 @@ export default class Settings extends PureComponent< this.props.planStatus ).PREVIEW.isActive()} > - + ) : ( diff --git a/src/ui/contexts/Source.tsx b/src/ui/contexts/Source.tsx index c42a9be9..3e3a38d9 100644 --- a/src/ui/contexts/Source.tsx +++ b/src/ui/contexts/Source.tsx @@ -141,7 +141,10 @@ export default class Source extends PureComponent { - + ) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index 46042a40..cf79c569 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -1,18 +1,22 @@ import chroma from 'chroma-js' import * as blinder from 'color-blind' import { Hsluv } from 'hsluv' -import { PureComponent } from 'preact/compat' +import { Component } from 'preact/compat' import React from 'react' -import { SourceColorConfiguration } from '../../types/configurations' +import { + ScaleConfiguration, + SourceColorConfiguration, +} from '../../types/configurations' import { RgbModel } from '../../types/models' import { palette } from '../../utils/palettePackage' interface PreviewProps { sourceColors: Array | [] + scale: ScaleConfiguration } -export default class Preview extends PureComponent { +export default class Preview extends Component { static defaultProps = { sourceColors: [], } @@ -82,7 +86,7 @@ export default class Preview extends PureComponent { className="preview__row" key={index} > - {Object.values(palette.scale) + {Object.values(this.props.scale) .reverse() .map((scale, index) => (
{ +export default class EditPalette extends PureComponent< + EditPaletteProps, + EditPaletteStates +> { themesMessage: ThemesMessage contexts: Array themesRef: React.RefObject diff --git a/src/ui/stylesheets/app.css b/src/ui/stylesheets/app.css index 8ab4e5b2..122c6478 100644 --- a/src/ui/stylesheets/app.css +++ b/src/ui/stylesheets/app.css @@ -223,5 +223,5 @@ div.about__links { .preview__cell { flex: 1; overflow: hidden; - height: var(--size-xxxsmall); + height: var(--size-medium); } From 0a3f231e93278be9935af082abe4958b2d39f9e8 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 20:03:39 +0100 Subject: [PATCH 07/55] fix: reset scale after unselecting palette --- src/ui/App.tsx | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index f66a456e..6e8ebe8c 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,7 +1,7 @@ import { Consent, ConsentConfiguration } from '@a_ng_d/figmug-ui' import { FeatureStatus } from '@a_ng_d/figmug-utils' import 'figma-plugin-ds/dist/figma-plugin-ds.css' -import { Component, PureComponent } from 'preact/compat' +import { Component } from 'preact/compat' import React from 'react' import checkConnectionStatus from '../bridges/checks/checkConnectionStatus' @@ -365,19 +365,20 @@ export default class App extends Component, AppStates> { const preset = presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset + const scale = doLightnessScale( + preset.scale, + preset.min, + preset.max, + preset.isDistributed, + this.props.distributionEasing + ) this.setState({ id: '', name: '', description: '', preset: preset, - scale: doLightnessScale( - preset.scale, - preset.min, - preset.max, - preset.isDistributed, - this.props.distributionEasing - ), + scale: scale, colorSpace: 'LCH', visionSimulationMode: 'NONE', view: 'PALETTE_WITH_PROPERTIES', @@ -411,6 +412,7 @@ export default class App extends Component, AppStates> { palette.name = '' palette.description = '' palette.preset = defaultPreset + palette.scale = scale palette.colorSpace = 'LCH' palette.visionSimulationMode = 'NONE' palette.view = 'PALETTE_WITH_PROPERTIES' @@ -436,6 +438,13 @@ export default class App extends Component, AppStates> { const preset = presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset + const scale = doLightnessScale( + preset.scale, + preset.min, + preset.max, + preset.isDistributed, + this.props.distributionEasing + ) this.setState({ id: '', @@ -444,13 +453,7 @@ export default class App extends Component, AppStates> { preset: presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset, - scale: doLightnessScale( - preset.scale, - preset.min, - preset.max, - preset.isDistributed, - this.props.distributionEasing - ), + scale: scale, colorSpace: 'LCH', visionSimulationMode: 'NONE', view: 'PALETTE_WITH_PROPERTIES', @@ -485,6 +488,7 @@ export default class App extends Component, AppStates> { palette.preset = presets.find((preset) => preset.id === 'MATERIAL') ?? defaultPreset + palette.scale = scale palette.colorSpace = 'LCH' palette.visionSimulationMode = 'NONE' palette.view = 'PALETTE_WITH_PROPERTIES' From 1d88e8a3cf842f14fc9ca86d0fe264f885a35fc3 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 20:03:48 +0100 Subject: [PATCH 08/55] refactor: remove redundant palette properties assignment in CreatePalette component --- src/ui/services/CreatePalette.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index 29683c26..bbbd47f6 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -158,14 +158,6 @@ export default class CreatePalette extends PureComponent< // Renders render() { - palette.preset = this.props.preset - palette.min = this.props.preset.min - palette.max = this.props.preset.max - palette.scale = doLightnessScale( - this.props.preset.scale, - this.props.preset.min ?? 0, - this.props.preset.max ?? 100 - ) let fragment switch (this.state.context) { From 4a65b200fd0be9ccae7160c66c9b4d42d6de8a25 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Tue, 10 Dec 2024 22:34:34 +0100 Subject: [PATCH 09/55] fix: set scaling when running without interacting with figma canvas --- src/ui/App.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 6e8ebe8c..b591f994 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -218,6 +218,13 @@ export default class App extends Component, AppStates> { this.props.distributionEasing ), }) + palette.scale = doLightnessScale( + this.state.preset.scale, + this.state.preset.min, + this.state.preset.max, + this.state.preset.isDistributed, + this.props.distributionEasing + ) fetch( `${announcementsWorkerUrl}/?action=get_version&database_id=${process.env.REACT_APP_NOTION_ANNOUNCEMENTS_ID}` ) From 3416cae11cab34bdc56f30eb263368005727510a Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 15:09:12 +0100 Subject: [PATCH 10/55] chore: update @a_ng_d/figmug-ui dependency to version 0.113.3 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e079d44..4c7b81fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "figma-ui-color-palette", "version": "4.1.5", "dependencies": { - "@a_ng_d/figmug-ui": "^0.112.2", + "@a_ng_d/figmug-ui": "^0.113.3", "@a_ng_d/figmug-utils": "^0.1.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", @@ -61,9 +61,9 @@ } }, "node_modules/@a_ng_d/figmug-ui": { - "version": "0.112.2", - "resolved": "https://registry.npmjs.org/@a_ng_d/figmug-ui/-/figmug-ui-0.112.2.tgz", - "integrity": "sha512-6TWwd1VT0O3pDto9YnfKotD/O2VYxCI5VLStsL4Q+vgUrQptqR+PQVmk6AN4G2XXCiJSahy+95hm67ypgWFgUA==", + "version": "0.113.3", + "resolved": "https://registry.npmjs.org/@a_ng_d/figmug-ui/-/figmug-ui-0.113.3.tgz", + "integrity": "sha512-wyz5kmyiAzEsdowsPMyZ+/TrfxTCnRVULKPm3HlMyh4mDJg26OhVsqgjEfkVeZZUVVdaifLObZTk9hZGKAvdnA==", "dependencies": { "@a_ng_d/figmug-utils": "^0.1.2", "@storybook/client-api": "^7.6.17", diff --git a/package.json b/package.json index f318c61e..5a6c3e12 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "webpack-cli": "^4.9.1" }, "dependencies": { - "@a_ng_d/figmug-ui": "^0.112.2", + "@a_ng_d/figmug-ui": "^0.113.3", "@a_ng_d/figmug-utils": "^0.1.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", From ee7e5fda0748c17eda2ab2d22bd41098cb3c21ae Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 15:09:18 +0100 Subject: [PATCH 11/55] fix: adjust padding for settings items in Overview component --- src/ui/contexts/Overview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/contexts/Overview.tsx b/src/ui/contexts/Overview.tsx index eb04e930..9d25c975 100644 --- a/src/ui/contexts/Overview.tsx +++ b/src/ui/contexts/Overview.tsx @@ -362,7 +362,7 @@ export default class Overview extends PureComponent< }) }} > -
+
-
+
Date: Wed, 11 Dec 2024 15:09:25 +0100 Subject: [PATCH 12/55] fix: rename onCleared event handler to onClear in CommunityPalettes and MyPalettes components --- src/ui/contexts/CommunityPalettes.tsx | 2 +- src/ui/contexts/MyPalettes.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/contexts/CommunityPalettes.tsx b/src/ui/contexts/CommunityPalettes.tsx index f83371a6..80d3bf10 100644 --- a/src/ui/contexts/CommunityPalettes.tsx +++ b/src/ui/contexts/CommunityPalettes.tsx @@ -411,7 +411,7 @@ export default class CommunityPalettes extends PureComponent< (e.target as HTMLInputElement).value ) }} - onCleared={(e) => { + onClear={(e) => { this.props.onChangeSearchQuery(e) this.props.onChangeStatus('LOADING') this.props.onChangeCurrentPage(1) diff --git a/src/ui/contexts/MyPalettes.tsx b/src/ui/contexts/MyPalettes.tsx index c35cd019..feb04c3b 100644 --- a/src/ui/contexts/MyPalettes.tsx +++ b/src/ui/contexts/MyPalettes.tsx @@ -641,7 +641,7 @@ export default class MyPalettes extends PureComponent< (e.target as HTMLInputElement).value ) }} - onCleared={(e) => { + onClear={(e) => { this.props.onChangeSearchQuery(e) this.props.onChangeStatus('LOADING') this.props.onChangeCurrentPage(1) From 0c28099224fa694d6cef6adcc47053e17c9250f4 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 16:30:27 +0100 Subject: [PATCH 13/55] fix: spread props in Preview component for Scale, Settings, and Source contexts --- src/ui/contexts/Scale.tsx | 1 + src/ui/contexts/Settings.tsx | 1 + src/ui/contexts/Source.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index f26b7a37..13942c9e 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -906,6 +906,7 @@ export default class Scale extends PureComponent { isActive={Scale.features(this.props.planStatus).PREVIEW.isActive()} > diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index 93d5062e..8e710625 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -532,6 +532,7 @@ export default class Settings extends PureComponent< ).PREVIEW.isActive()} > diff --git a/src/ui/contexts/Source.tsx b/src/ui/contexts/Source.tsx index 3e3a38d9..b431fd65 100644 --- a/src/ui/contexts/Source.tsx +++ b/src/ui/contexts/Source.tsx @@ -142,6 +142,7 @@ export default class Source extends PureComponent { isActive={Source.features(this.props.planStatus).PREVIEW.isActive()} > From cea9f3172b59f06f833b96961068a131d31f5c6f Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 19:03:08 +0100 Subject: [PATCH 14/55] feat: enhance Preview component with WCAG and APCA contrast scoring, and improve styling for tags --- src/ui/modules/Preview.tsx | 122 +++++++++++++++++++++++--- src/ui/stylesheets/app-components.css | 20 +++++ src/ui/stylesheets/app.css | 9 +- 3 files changed, 136 insertions(+), 15 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index cf79c569..9ad81d33 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -3,6 +3,7 @@ import * as blinder from 'color-blind' import { Hsluv } from 'hsluv' import { Component } from 'preact/compat' import React from 'react' +import { APCAcontrast, sRGBtoY } from 'apca-w3' import { ScaleConfiguration, @@ -10,10 +11,13 @@ import { } from '../../types/configurations' import { RgbModel } from '../../types/models' import { palette } from '../../utils/palettePackage' +import { HexModel, texts } from '@a_ng_d/figmug-ui' +import { Language } from '../../types/app' interface PreviewProps { sourceColors: Array | [] scale: ScaleConfiguration + lang: Language } export default class Preview extends Component { @@ -22,7 +26,7 @@ export default class Preview extends Component { } // Direct actions - setColor = (rgb: RgbModel, scale: number) => { + getColor = (rgb: RgbModel, scale: number): HexModel => { scale = palette.colorSpace.includes('OK') || palette.colorSpace === 'HSL' ? scale / 100 @@ -38,7 +42,7 @@ export default class Preview extends Component { ) } - setHsluv = (rgb: RgbModel, scale: number) => { + setHsluv = (rgb: RgbModel, scale: number): HexModel => { const hsluv = new Hsluv() hsluv.rgb_r = rgb.r @@ -57,7 +61,7 @@ export default class Preview extends Component { return hsluv.hex } - setVisionSimulation = (hex: string) => { + setVisionSimulation = (hex: HexModel): HexModel => { if (palette.visionSimulationMode === 'PROTANOMALY') return blinder.protanomaly(hex) if (palette.visionSimulationMode === 'PROTANOPIA') @@ -77,10 +81,81 @@ export default class Preview extends Component { return hex } + getWCAGScore = (background: HexModel, text: HexModel): number => { + return chroma.contrast(background, text) + } + + getAPCAContrast = (background: HexModel, textColor: HexModel) => { + return Math.abs( + APCAcontrast( + sRGBtoY(chroma(background).rgb()), + sRGBtoY(chroma(textColor).rgb()) + ) + ) + } + + // Templates + stopTag = ({ stop }: { stop: string }) => ( +
+ + {stop} + +
+ ) + + wcagScoreTag = ({ color, score }: { color: HexModel; score: number }) => ( +
+
+ + {`${score.toFixed(1)} : 1`} + + + {score < 4.5 ? '✘' : '✔'} + +
+ ) + + apcaScoreTag = ({ color, score }: { color: HexModel; score: number }) => ( +
+
+ {`Lc ${score.toFixed(1)}`} + + {score < 15 ? '✘' : '✔'} + +
+ ) + // Render render() { + if (!this.props.sourceColors.length) return null return (
+
+ {Object.keys(this.props.scale) + .reverse() + .map((scale, index) => { + return ( +
+ +
+ ) + })} +
{this.props.sourceColors.map((sourceColor, index) => (
{ > {Object.values(this.props.scale) .reverse() - .map((scale, index) => ( -
- ))} + .map((scale, index) => { + const background = this.getColor(sourceColor.rgb, scale) + const darkText = palette.textColorsTheme.darkColor + const lightText = palette.textColorsTheme.lightColor + + return ( +
+ + + + +
+ ) + })}
))}
diff --git a/src/ui/stylesheets/app-components.css b/src/ui/stylesheets/app-components.css index f19a3719..8c660b40 100644 --- a/src/ui/stylesheets/app-components.css +++ b/src/ui/stylesheets/app-components.css @@ -246,3 +246,23 @@ div.user__avatar img { width: 100%; height: 100%; } + +/* Tag */ +.preview__tag { + max-width: 100%; + padding: 0 var(--size-xxxsmall); + border-radius: var(--border-radius-small); + background: var(--white4); + display: flex; + gap: var(--size-xxxsmall); + align-items: center; +} + +.preview__tag__color { + width: var(--size-xxsmall); + height: var(--size-xxsmall); + border-radius: var(--size-small); + gap: var(--size-xxxsmall); + flex: 0 0 var(--size-xxsmall); + outline: 1px solid var(--black1) +} diff --git a/src/ui/stylesheets/app.css b/src/ui/stylesheets/app.css index 122c6478..2babf96b 100644 --- a/src/ui/stylesheets/app.css +++ b/src/ui/stylesheets/app.css @@ -211,17 +211,20 @@ div.about__links { .preview { display: flex; flex-direction: column; - overflow: hidden; + border-top: 1px solid var(--figma-color-border); } .preview__row { display: flex; flex: 1; - overflow: hidden; } .preview__cell { flex: 1; overflow: hidden; - height: var(--size-medium); + display: flex; + flex-direction: column; + align-items: flex-end; + padding: var(--size-xxxsmall); + gap: var(--size-xxxsmall); } From f9062be377d0e5e34f49921fa4e753468402c444 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 19:08:31 +0100 Subject: [PATCH 15/55] fix: standardize WCAG method names and update variable references in Properties component --- src/canvas/Properties.ts | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/canvas/Properties.ts b/src/canvas/Properties.ts index c6272cf2..632e07a0 100644 --- a/src/canvas/Properties.ts +++ b/src/canvas/Properties.ts @@ -91,7 +91,7 @@ export default class Properties { return result !== undefined ? result : '#000000' } - getWcagContrast = (textColor: string) => { + getWCAGContrast = (textColor: string) => { return chroma.contrast( chroma(this.rgb).hex(), textColor === 'DARK' @@ -129,11 +129,11 @@ export default class Properties { ) } - getWcagScore = (textColor: string) => { - return this.getWcagContrast(textColor) < 4.5 + getWCAGScore = (textColor: string) => { + return this.getWCAGContrast(textColor) < 4.5 ? 'A' - : this.getWcagContrast(textColor) >= 4.5 && - this.getWcagContrast(textColor) < 7 + : this.getWCAGContrast(textColor) >= 4.5 && + this.getWCAGContrast(textColor) < 7 ? 'AA' : 'AAA' } @@ -322,12 +322,12 @@ export default class Properties { // Insert // WCAG - const wcagLightContrast = this.getWcagContrast('LIGHT').toFixed(2), - wcagDarkContrast = this.getWcagContrast('DARK').toFixed(2), - wcagLightScore = this.getWcagScore('LIGHT'), - wcagDarkScore = this.getWcagScore('DARK') + const wcagLightContrast = this.getWCAGContrast('LIGHT').toFixed(2), + wcagDarkContrast = this.getWCAGContrast('DARK').toFixed(2), + wcagLightScore = this.getWCAGScore('LIGHT'), + wcagDarkScore = this.getWCAGScore('DARK') - const nodeWcagLightProp = new Tag({ + const nodeWCAGLightProp = new Tag({ name: '_wcag21-light', content: wcagLightContrast, isCompact: true, @@ -339,7 +339,7 @@ export default class Properties { ) ).gl() ), - nodeWcagLightScore = new Tag({ + nodeWCAGLightScore = new Tag({ name: '_wcag21-light-score', content: wcagLightScore, backgroundColor: { @@ -347,7 +347,7 @@ export default class Properties { alpha: 1, }, }).makeNodeTag(), - nodeWcagDarkProp = new Tag({ + nodeWCAGDarkProp = new Tag({ name: '_wcag21-dark', content: wcagDarkContrast, isCompact: true, @@ -359,7 +359,7 @@ export default class Properties { ) ).gl() ), - nodeWcagDarkScore = new Tag({ + nodeWCAGDarkScore = new Tag({ name: '_wcag21-dark-score', content: wcagDarkScore, backgroundColor: { @@ -368,8 +368,8 @@ export default class Properties { }, }).makeNodeTag() - nodeWcagLightProp.appendChild(nodeWcagLightScore) - nodeWcagDarkProp.appendChild(nodeWcagDarkScore) + nodeWCAGLightProp.appendChild(nodeWCAGLightScore) + nodeWCAGDarkProp.appendChild(nodeWCAGDarkScore) // APCA const apcaLightContrast = this.getAPCAContrast('LIGHT').toFixed(1), @@ -377,7 +377,7 @@ export default class Properties { apcaDarkContrast = this.getAPCAContrast('DARK').toFixed(1), apcaDarkRecommendation = this.getRecommendedUsage('DARK') - const nodeApcaLightProp = new Tag({ + const nodeAPCALightProp = new Tag({ name: '_apca-light', content: `Lc ${apcaLightContrast}`, isCompact: true, @@ -389,7 +389,7 @@ export default class Properties { ) ).gl() ), - nodeApcaLightScore = new Tag({ + nodeAPCALightScore = new Tag({ name: '_apca-light-score', content: apcaLightRecommendation, backgroundColor: { @@ -397,7 +397,7 @@ export default class Properties { alpha: 1, }, }).makeNodeTag(), - nodeApcaDarkProp = new Tag({ + nodeAPCADarkProp = new Tag({ name: '_apca-dark', content: `Lc ${apcaDarkContrast}`, isCompact: true, @@ -409,7 +409,7 @@ export default class Properties { ) ).gl() ), - nodeApcaDarkScore = new Tag({ + nodeAPCADarkScore = new Tag({ name: '_apca-dark-score', content: apcaDarkRecommendation, backgroundColor: { @@ -418,13 +418,13 @@ export default class Properties { }, }).makeNodeTag() - nodeApcaLightProp.appendChild(nodeApcaLightScore) - nodeApcaDarkProp.appendChild(nodeApcaDarkScore) + nodeAPCALightProp.appendChild(nodeAPCALightScore) + nodeAPCADarkProp.appendChild(nodeAPCADarkScore) - this.nodeContrastScoresProps.appendChild(nodeWcagLightProp) - this.nodeContrastScoresProps.appendChild(nodeApcaLightProp) - this.nodeContrastScoresProps.appendChild(nodeWcagDarkProp) - this.nodeContrastScoresProps.appendChild(nodeApcaDarkProp) + this.nodeContrastScoresProps.appendChild(nodeWCAGLightProp) + this.nodeContrastScoresProps.appendChild(nodeAPCALightProp) + this.nodeContrastScoresProps.appendChild(nodeWCAGDarkProp) + this.nodeContrastScoresProps.appendChild(nodeAPCADarkProp) return this.nodeContrastScoresProps } @@ -518,12 +518,12 @@ export default class Properties { this.nodeDetailedWCAGScoresProps.itemSpacing = 4 // Insert - const wcagLightContrast = this.getWcagContrast('LIGHT').toFixed(2), - wcagDarkContrast = this.getWcagContrast('DARK').toFixed(2), - wcagLightScore = this.getWcagScore('LIGHT'), - wcagDarkScore = this.getWcagScore('DARK') + const wcagLightContrast = this.getWCAGContrast('LIGHT').toFixed(2), + wcagDarkContrast = this.getWCAGContrast('DARK').toFixed(2), + wcagLightScore = this.getWCAGScore('LIGHT'), + wcagDarkScore = this.getWCAGScore('DARK') - const nodeWcagLightProp = new Tag({ + const nodeWCAGLightProp = new Tag({ name: '_wcag21-light', content: wcagLightContrast, isCompact: true, @@ -535,7 +535,7 @@ export default class Properties { ) ).gl() ), - nodeWcagLightScore = new Tag({ + nodeWCAGLightScore = new Tag({ name: '_wcag21-light-score', content: wcagLightScore, backgroundColor: { @@ -543,7 +543,7 @@ export default class Properties { alpha: 1, }, }).makeNodeTag(), - nodeWcagDarkProp = new Tag({ + nodeWCAGDarkProp = new Tag({ name: '_wcag21-dark', content: wcagDarkContrast, isCompact: true, @@ -555,7 +555,7 @@ export default class Properties { ) ).gl() ), - nodeWcagDarkScore = new Tag({ + nodeWCAGDarkScore = new Tag({ name: '_wcag21-dark-score', content: wcagDarkScore, backgroundColor: { @@ -564,8 +564,8 @@ export default class Properties { }, }).makeNodeTag() - nodeWcagLightProp.appendChild(nodeWcagLightScore) - nodeWcagDarkProp.appendChild(nodeWcagDarkScore) + nodeWCAGLightProp.appendChild(nodeWCAGLightScore) + nodeWCAGDarkProp.appendChild(nodeWCAGDarkScore) this.nodeDetailedWCAGScoresProps.appendChild( new Tag({ @@ -574,8 +574,8 @@ export default class Properties { fontSize: 10, }).makeNodeTag() ) - this.nodeDetailedWCAGScoresProps.appendChild(nodeWcagLightProp) - this.nodeDetailedWCAGScoresProps.appendChild(nodeWcagDarkProp) + this.nodeDetailedWCAGScoresProps.appendChild(nodeWCAGLightProp) + this.nodeDetailedWCAGScoresProps.appendChild(nodeWCAGDarkProp) return this.nodeDetailedWCAGScoresProps } @@ -602,7 +602,7 @@ export default class Properties { apcaDarkContrast = this.getAPCAContrast('DARK').toFixed(1), apcaDarkRecommendation = this.getRecommendedUsage('DARK') - const nodeApcaLightProp = new Tag({ + const nodeAPCALightProp = new Tag({ name: '_apca-light', content: `Lc ${apcaLightContrast}`, isCompact: true, @@ -614,7 +614,7 @@ export default class Properties { ) ).gl() ), - nodeApcaLightScore = new Tag({ + nodeAPCALightScore = new Tag({ name: '_apca-light-score', content: apcaLightRecommendation, backgroundColor: { @@ -622,7 +622,7 @@ export default class Properties { alpha: 1, }, }).makeNodeTag(), - nodeApcaDarkProp = new Tag({ + nodeAPCADarkProp = new Tag({ name: '_apca-dark', content: `Lc ${apcaDarkContrast}`, isCompact: true, @@ -634,7 +634,7 @@ export default class Properties { ) ).gl() ), - nodeApcaDarkScore = new Tag({ + nodeAPCADarkScore = new Tag({ name: '_apca-dark-score', content: apcaDarkRecommendation, backgroundColor: { @@ -643,8 +643,8 @@ export default class Properties { }, }).makeNodeTag() - nodeApcaLightProp.appendChild(nodeApcaLightScore) - nodeApcaDarkProp.appendChild(nodeApcaDarkScore) + nodeAPCALightProp.appendChild(nodeAPCALightScore) + nodeAPCADarkProp.appendChild(nodeAPCADarkScore) this.nodeDetailedAPCAScoresProps.appendChild( new Tag({ @@ -656,7 +656,7 @@ export default class Properties { this.nodeDetailedAPCAScoresProps.appendChild( this.makeNodeColumns( [ - nodeApcaLightProp, + nodeAPCALightProp, new Tag({ name: '_minimum-font-sizes', content: locals[lang].paletteProperties.fontSize, @@ -687,7 +687,7 @@ export default class Properties { }).makeNodeTag(), ], [ - nodeApcaDarkProp, + nodeAPCADarkProp, new Tag({ name: '_minimum-font-sizes', content: locals[lang].paletteProperties.fontSize, From d34e58cc21aa2fe09ecc019782ee9524379888bd Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 19:34:00 +0100 Subject: [PATCH 16/55] feat: add WCAG and APCA score display options in Preview component and update locals --- src/content/locals.ts | 10 ++ src/ui/modules/Preview.tsx | 230 +++++++++++++++++++++++++++++++++---- src/ui/stylesheets/app.css | 1 + src/utils/features.ts | 20 +++- 4 files changed, 240 insertions(+), 21 deletions(-) diff --git a/src/content/locals.ts b/src/content/locals.ts index e3b3f960..b68005ba 100644 --- a/src/content/locals.ts +++ b/src/content/locals.ts @@ -339,6 +339,14 @@ export const locals: { [key: string]: any } = { }, }, }, + preview: { + wcag: { + label: 'Display WCAG scores', + }, + apca: { + label: 'Display APCA scores', + }, + }, report: { title: 'Report a bug', fullName: { @@ -455,6 +463,8 @@ export const locals: { [key: string]: any } = { wcag: 'WCAG scores', apca: 'APCA scores', fontSize: 'Minimum font sizes', + pass: 'Pass', + fail: 'Fail', unknown: 'Unknown', avoid: 'Avoid', nonText: 'Non-text', diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index 9ad81d33..bad7bacf 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -9,20 +9,119 @@ import { ScaleConfiguration, SourceColorConfiguration, } from '../../types/configurations' -import { RgbModel } from '../../types/models' +import { ActionsList, RgbModel } from '../../types/models' import { palette } from '../../utils/palettePackage' -import { HexModel, texts } from '@a_ng_d/figmug-ui' -import { Language } from '../../types/app' +import { Bar, HexModel, layouts, Select, texts } from '@a_ng_d/figmug-ui' +import { Language, PlanStatus } from '../../types/app' +import Feature from '../components/Feature' +import { FeatureStatus } from '@a_ng_d/figmug-utils' +import features from '../../config' +import { locals } from '../../content/locals' interface PreviewProps { sourceColors: Array | [] scale: ScaleConfiguration + planStatus: PlanStatus lang: Language } -export default class Preview extends Component { +interface PreviewStates { + isWCAGDisplayed: boolean + isAPCADisplayed: boolean +} + +export default class Preview extends Component { + static features = (planStatus: PlanStatus) => ({ + PREVIEW_WCAG: new FeatureStatus({ + features: features, + featureName: 'PREVIEW_WCAG', + planStatus: planStatus, + }), + PREVIEW_APCA: new FeatureStatus({ + features: features, + featureName: 'PREVIEW_APCA', + planStatus: planStatus, + }), + }) + static defaultProps = { sourceColors: [], + scale: {}, + } + + constructor(props: PreviewProps) { + super(props) + this.state = { + isWCAGDisplayed: true, + isAPCADisplayed: true, + } + } + + // Lifecycle + componentDidMount = (): void => { + parent.postMessage( + { + pluginMessage: { + type: 'GET_ITEMS', + items: ['is_wcag_displayed', 'is_apca_displayed'], + }, + }, + '*' + ) + window.addEventListener('message', this.handleMessage) + } + + componentWillUnmount = (): void => { + window.removeEventListener('message', this.handleMessage) + } + + // Handlers + handleMessage = (e: MessageEvent) => { + const displayWCAGScore = () => { + if (e.data.pluginMessage.value === undefined) + parent.postMessage( + { + pluginMessage: { + type: 'SET_ITEMS', + items: [ + { + key: 'is_wcag_displayed', + value: true, + }, + ], + }, + }, + '*' + ) + else this.setState({ isWCAGDisplayed: e.data.pluginMessage.value }) + } + + const displayAPCAScore = () => { + if (e.data.pluginMessage.value === undefined) + parent.postMessage( + { + pluginMessage: { + type: 'SET_ITEMS', + items: [ + { + key: 'is_apca_displayed', + value: true, + }, + ], + }, + }, + '*' + ) + else this.setState({ isAPCADisplayed: e.data.pluginMessage.value }) + } + + const actions: ActionsList = { + GET_ITEM_IS_WCAG_DISPLAYED: () => displayWCAGScore(), + GET_ITEM_IS_APCA_DISPLAYED: () => displayAPCAScore(), + DEFAULT: () => null, + } + + return actions[e.data.pluginMessage?.type ?? 'DEFAULT']?.() } // Direct actions @@ -142,6 +241,89 @@ export default class Preview extends Component { if (!this.props.sourceColors.length) return null return (
+ + + { + this.setState({ + isAPCADisplayed: !this.state.isAPCADisplayed, + }) + parent.postMessage( + { + pluginMessage: { + type: 'SET_ITEMS', + items: [ + { + key: 'is_apca_displayed', + value: !this.state.isAPCADisplayed, + }, + ], + }, + }, + '*' + ) + }} + /> + +
+ } + border={['BOTTOM']} + />
{Object.keys(this.props.scale) .reverse() @@ -176,22 +358,30 @@ export default class Preview extends Component { backgroundColor: background, }} > - - - - + {this.state.isWCAGDisplayed && ( + + )} + {this.state.isAPCADisplayed && ( + + )} + {this.state.isWCAGDisplayed && ( + + )} + {this.state.isAPCADisplayed && ( + + )}
) })} diff --git a/src/ui/stylesheets/app.css b/src/ui/stylesheets/app.css index 2babf96b..51f6bb7f 100644 --- a/src/ui/stylesheets/app.css +++ b/src/ui/stylesheets/app.css @@ -227,4 +227,5 @@ div.about__links { align-items: flex-end; padding: var(--size-xxxsmall); gap: var(--size-xxxsmall); + min-height: var(--size-medium); } diff --git a/src/utils/features.ts b/src/utils/features.ts index 1c6e46a0..7bd59174 100644 --- a/src/utils/features.ts +++ b/src/utils/features.ts @@ -899,7 +899,25 @@ export const featuresScheme: Array> = [ isPro: false, isNew: false, type: 'DIVISION', - service: ['CREATE'], + service: ['CREATE', 'EDIT'], + }, + { + name: 'PREVIEW_WCAG', + description: '', + isActive: true, + isPro: false, + isNew: false, + type: 'ACTION', + service: ['CREATE', 'EDIT'], + }, + { + name: 'PREVIEW_APCA', + description: '', + isActive: true, + isPro: false, + isNew: false, + type: 'ACTION', + service: ['CREATE', 'EDIT'], }, { name: 'SHORTCUTS', From 1a8bed19c01d10dc4cb7ff1b365f98eaac194df3 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 20:50:18 +0100 Subject: [PATCH 17/55] refactor: remove Preview component from Scale, Settings, and Source contexts; integrate into CreatePalette component --- src/ui/contexts/Scale.tsx | 10 ---------- src/ui/contexts/Settings.tsx | 22 ++++------------------ src/ui/contexts/Source.tsx | 12 ------------ src/ui/modules/Preview.tsx | 23 ++++++++++++++++++----- src/ui/services/CreatePalette.tsx | 25 +++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index 13942c9e..e30f818d 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -38,7 +38,6 @@ import Feature from '../components/Feature' import Slider from '../components/Slider' import Actions from '../modules/Actions' import Dispatcher from '../modules/Dispatcher' -import Preview from '../modules/Preview' interface ScaleProps { sourceColors?: Array @@ -902,15 +901,6 @@ export default class Scale extends PureComponent { {...this.props} service="CREATE" /> - - -
) } diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index 8e710625..2caa1de7 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -33,7 +33,6 @@ import type { AppStates } from '../App' import Feature from '../components/Feature' import Actions from '../modules/Actions' import Dispatcher from '../modules/Dispatcher' -import Preview from '../modules/Preview' import ColorSettings from './ColorSettings' import ContrastSettings from './ContrastSettings' import GlobalSettings from './GlobalSettings' @@ -521,23 +520,10 @@ export default class Settings extends PureComponent< )}
{this.props.service === 'CREATE' ? ( - <> - - - - - + ) : ( @@ -138,15 +135,6 @@ export default class Source extends PureComponent { : () => null } /> - - - ) } diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index bad7bacf..df151bd3 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -1,7 +1,7 @@ import chroma from 'chroma-js' import * as blinder from 'color-blind' import { Hsluv } from 'hsluv' -import { Component } from 'preact/compat' +import { PureComponent } from 'preact/compat' import React from 'react' import { APCAcontrast, sRGBtoY } from 'apca-w3' @@ -26,11 +26,15 @@ interface PreviewProps { } interface PreviewStates { + isLoaded: boolean isWCAGDisplayed: boolean isAPCADisplayed: boolean } -export default class Preview extends Component { +export default class Preview extends PureComponent< + PreviewProps, + PreviewStates +> { static features = (planStatus: PlanStatus) => ({ PREVIEW_WCAG: new FeatureStatus({ features: features, @@ -52,6 +56,7 @@ export default class Preview extends Component { constructor(props: PreviewProps) { super(props) this.state = { + isLoaded: false, isWCAGDisplayed: true, isAPCADisplayed: true, } @@ -93,7 +98,11 @@ export default class Preview extends Component { }, '*' ) - else this.setState({ isWCAGDisplayed: e.data.pluginMessage.value }) + else + this.setState({ + isWCAGDisplayed: e.data.pluginMessage.value, + isLoaded: true, + }) } const displayAPCAScore = () => { @@ -112,7 +121,11 @@ export default class Preview extends Component { }, '*' ) - else this.setState({ isAPCADisplayed: e.data.pluginMessage.value }) + else + this.setState({ + isAPCADisplayed: e.data.pluginMessage.value, + isLoaded: true, + }) } const actions: ActionsList = { @@ -238,7 +251,7 @@ export default class Preview extends Component { // Render render() { - if (!this.props.sourceColors.length) return null + if (!this.props.sourceColors.length || !this.state.isLoaded) return null return (
| [] @@ -68,6 +72,14 @@ export default class CreatePalette extends PureComponent< > { contexts: Array + static features = (planStatus: PlanStatus) => ({ + PREVIEW: new FeatureStatus({ + features: features, + featureName: 'PREVIEW_WCAG', + planStatus: planStatus, + }), + }) + constructor(props: CreatePaletteProps) { super(props) this.contexts = setContexts( @@ -225,6 +237,19 @@ export default class CreatePalette extends PureComponent<
{fragment}
+ + + ) } From 3e9f5d63636bda7e36402048bfa619d556742e2b Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 21:06:36 +0100 Subject: [PATCH 18/55] refactor: rename sourceColors prop to colors in Preview and CreatePalette components for consistency --- src/ui/modules/Preview.tsx | 9 +++++---- src/ui/services/CreatePalette.tsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index df151bd3..dbe44a2f 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -6,6 +6,7 @@ import React from 'react' import { APCAcontrast, sRGBtoY } from 'apca-w3' import { + ColorConfiguration, ScaleConfiguration, SourceColorConfiguration, } from '../../types/configurations' @@ -19,7 +20,7 @@ import features from '../../config' import { locals } from '../../content/locals' interface PreviewProps { - sourceColors: Array | [] + colors: Array | Array | [] scale: ScaleConfiguration planStatus: PlanStatus lang: Language @@ -251,7 +252,7 @@ export default class Preview extends PureComponent< // Render render() { - if (!this.props.sourceColors.length || !this.state.isLoaded) return null + if (!this.props.colors.length || !this.state.isLoaded) return null return (
- {this.props.sourceColors.map((sourceColor, index) => ( + {this.props.colors.map((color, index) => (
{ - const background = this.getColor(sourceColor.rgb, scale) + const background = this.getColor(color.rgb, scale) const darkText = palette.textColorsTheme.darkColor const lightText = palette.textColorsTheme.lightColor diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index 5683dc29..8f992d03 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -246,7 +246,7 @@ export default class CreatePalette extends PureComponent< From a7eaad884cccf72372da4fcc0b007ec20f641634 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 21:07:38 +0100 Subject: [PATCH 19/55] feat: integrate Preview component into EditPalette for enhanced feature display --- src/ui/services/EditPalette.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ui/services/EditPalette.tsx b/src/ui/services/EditPalette.tsx index 59771f26..2e6999e3 100644 --- a/src/ui/services/EditPalette.tsx +++ b/src/ui/services/EditPalette.tsx @@ -40,6 +40,7 @@ import Export from '../contexts/Export' import Scale from '../contexts/Scale' import Settings from '../contexts/Settings' import Themes from '../contexts/Themes' +import Preview from '../modules/Preview' interface EditPaletteProps { name: string @@ -89,6 +90,11 @@ export default class EditPalette extends PureComponent< featureName: 'THEMES', planStatus: planStatus, }), + PREVIEW: new FeatureStatus({ + features: features, + featureName: 'PREVIEW_WCAG', + planStatus: planStatus, + }), }) constructor(props: EditPaletteProps) { @@ -420,6 +426,19 @@ export default class EditPalette extends PureComponent<
{fragment}
+ + + ) } From 513ac8bd25880b203df791d3130cf49f37507e33 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 21:09:54 +0100 Subject: [PATCH 20/55] fix: correct spelling of 'algorithm' in Settings component --- src/ui/contexts/Settings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index 2caa1de7..be0a8acf 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -292,7 +292,7 @@ export default class Settings extends PureComponent< } } - const updateAlgorythmVersion = () => { + const updateAlgorithmVersion = () => { this.settingsMessage.data.name = this.props.name this.settingsMessage.data.description = this.props.description this.settingsMessage.data.colorSpace = this.props.colorSpace @@ -431,7 +431,7 @@ export default class Settings extends PureComponent< UPDATE_VIEW: () => updateView(), UPDATE_COLOR_SPACE: () => updateColorSpace(), UPDATE_COLOR_BLIND_MODE: () => updatevisionSimulationMode(), - UPDATE_ALGORITHM_VERSION: () => updateAlgorythmVersion(), + UPDATE_ALGORITHM_VERSION: () => updateAlgorithmVersion(), UPDATE_TEXT_LIGHT_COLOR: () => updateTextLightColor(), UPDATE_TEXT_DARK_COLOR: () => updateTextDarkColor(), UPDATE_VARIABLES_DEEP_SYNC: () => updateVariablesDeepSync(), From 269bd653e04e7844a4efe16d2529c5685268e29f Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Wed, 11 Dec 2024 21:10:05 +0100 Subject: [PATCH 21/55] fix: correct spelling of 'algorithm' in ColorSettings component --- src/ui/contexts/ColorSettings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/contexts/ColorSettings.tsx b/src/ui/contexts/ColorSettings.tsx index 1fa9bb6b..4c5f68be 100644 --- a/src/ui/contexts/ColorSettings.tsx +++ b/src/ui/contexts/ColorSettings.tsx @@ -482,7 +482,7 @@ export default class ColorSettings extends PureComponent { { ).COLORS_PARAMS.isActive()} > <> -
+
{
{ this.props.planStatus ).COLORS_HUE_SHIFTING.isActive()} > -
+
{ this.props.planStatus ).COLORS_CHROMA_SHIFTING.isActive()} > -
+
{ this.props.planStatus ).COLORS_DESCRIPTION.isActive()} > -
+
{ this.props.planStatus ).THEMES_NAME.isActive()} > -
+
{ this.props.planStatus ).THEMES_PARAMS.isActive()} > -
+
{ this.props.planStatus ).THEMES_DESCRIPTION.isActive()} > -
+
Date: Thu, 12 Dec 2024 11:47:50 +0100 Subject: [PATCH 37/55] feat: stop allowing real time edit --- src/ui/contexts/Scale.tsx | 2 +- src/ui/contexts/Themes.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index e30f818d..ec48fa7d 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -177,7 +177,7 @@ export default class Scale extends PureComponent { const onUpdatingStop = () => { this.scaleMessage.isEditedInRealTime = true this.props.onChangeScale() - if (!this.props.hasPreset) this.dispatch.scale.on.status = true + // if (!this.props.hasPreset) this.dispatch.scale.on.status = true } const actions: ActionsList = { diff --git a/src/ui/contexts/Themes.tsx b/src/ui/contexts/Themes.tsx index ac6f1990..62f6fabf 100644 --- a/src/ui/contexts/Themes.tsx +++ b/src/ui/contexts/Themes.tsx @@ -208,7 +208,7 @@ export default class Themes extends PureComponent { ) } else { this.themesMessage.isEditedInRealTime = true - this.dispatch.themes.on.status = true + // this.dispatch.themes.on.status = true } } From 10a4451c0830d8b60dbbd8c8ff94b6fb1f716fb6 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 11:50:40 +0100 Subject: [PATCH 38/55] refactor: remove unused onboarding actions styles from app-components.css --- src/ui/stylesheets/app-components.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/ui/stylesheets/app-components.css b/src/ui/stylesheets/app-components.css index 66801a1b..43c63445 100644 --- a/src/ui/stylesheets/app-components.css +++ b/src/ui/stylesheets/app-components.css @@ -57,13 +57,6 @@ div.callout--centered { margin: auto; } -div.onboarding__actions { - display: flex; - gap: var(--size-xxsmall); - justify-content: center; - padding: 0 calc(var(--size-xsmall) + var(--size-xxxsmall)); -} - /* Slider */ div.slider { display: flex; From f4a13583cec4afeb73d0d429f0ff2bcafc8aefa0 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 12:12:58 +0100 Subject: [PATCH 39/55] fix: update score threshold logic in Preview component --- src/ui/modules/Preview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index c1226dc1..ab7b76b4 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -212,7 +212,7 @@ export default class Preview extends PureComponent {`${score.toFixed(1)} : 1`} - {score < 4.5 ? '✘' : '✔'} + {score <= 4.5 ? '✘' : '✔'}
) @@ -229,7 +229,7 @@ export default class Preview extends PureComponent className={`preview__tag__score type ${texts['type--truncated']}`} >{`Lc ${score.toFixed(1)}`} - {score < 15 ? '✘' : '✔'} + {score <= 45 ? '✘' : '✔'}
) From 7b429fa5dd898bdceb14e46481e25c1955ff4f13 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 15:22:54 +0100 Subject: [PATCH 40/55] fix: hide the overflowed content --- src/ui/stylesheets/app-components.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/stylesheets/app-components.css b/src/ui/stylesheets/app-components.css index 43c63445..07496e1a 100644 --- a/src/ui/stylesheets/app-components.css +++ b/src/ui/stylesheets/app-components.css @@ -249,6 +249,7 @@ div.user__avatar img { display: flex; gap: var(--size-xxxsmall); align-items: center; + overflow: hidden; } .preview__tag__color { From 80543eeb9e12c3daeba6acb3ef0a681a5e7301e8 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 15:23:03 +0100 Subject: [PATCH 41/55] refactor: optimize color processing in Preview component --- src/ui/modules/Preview.tsx | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index ab7b76b4..7d622a59 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -1,4 +1,3 @@ -import { APCAcontrast, sRGBtoY } from 'apca-w3' import chroma from 'chroma-js' import { PureComponent } from 'preact/compat' import React from 'react' @@ -40,7 +39,10 @@ interface PreviewStates { isAPCADisplayed: boolean } -export default class Preview extends PureComponent { +export default class Preview extends PureComponent< + PreviewProps, + PreviewStates +> { static features = (planStatus: PlanStatus) => ({ PREVIEW_WCAG: new FeatureStatus({ features: features, @@ -151,7 +153,7 @@ export default class Preview extends PureComponent const isString = typeof color === 'string' const colorData = new Color({ sourceColor: isString - ? chroma(color).rgb() + ? chroma(color).rgb(false) : [color.rgb.r * 255, color.rgb.g * 255, color.rgb.b * 255], lightness: scale, hueShifting: isString ? 0 : color.hueShifting, @@ -178,19 +180,6 @@ export default class Preview extends PureComponent } } - getWCAGScore = (background: HexModel, text: HexModel): number => { - return chroma.contrast(background, text) - } - - getAPCAContrast = (background: HexModel, textColor: HexModel) => { - return Math.abs( - APCAcontrast( - sRGBtoY(chroma(background).rgb()), - sRGBtoY(chroma(textColor).rgb()) - ) - ) - } - // Templates stopTag = ({ stop }: { stop: string }) => (
@@ -209,7 +198,7 @@ export default class Preview extends PureComponent }} /> - {`${score.toFixed(1)} : 1`} + {`${score.toFixed(2)} : 1`} {score <= 4.5 ? '✘' : '✔'} @@ -374,12 +363,12 @@ export default class Preview extends PureComponent const darkText = new Color({ visionSimulationMode: palette.visionSimulationMode, }).simulateColorBlindHex( - chroma(palette.textColorsTheme.darkColor).rgb() + chroma(palette.textColorsTheme.darkColor).rgb(false) ) const lightText = new Color({ visionSimulationMode: palette.visionSimulationMode, }).simulateColorBlindHex( - chroma(palette.textColorsTheme.lightColor).rgb() + chroma(palette.textColorsTheme.lightColor).rgb(false) ) return ( @@ -394,7 +383,7 @@ export default class Preview extends PureComponent @@ -403,7 +392,7 @@ export default class Preview extends PureComponent @@ -412,7 +401,7 @@ export default class Preview extends PureComponent @@ -421,7 +410,7 @@ export default class Preview extends PureComponent From a688a79d2b252f27df816893ff5ed485b61e8b19 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 15:29:53 +0100 Subject: [PATCH 42/55] feat: enhance Preview component with additional configuration props --- src/ui/modules/Preview.tsx | 24 +++++++++++++++--------- src/ui/services/CreatePalette.tsx | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index 7d622a59..c404089c 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -15,19 +15,25 @@ import features from '../../config' import { locals } from '../../content/locals' import { Language, PlanStatus } from '../../types/app' import { + AlgorithmVersionConfiguration, ColorConfiguration, + ColorSpaceConfiguration, ScaleConfiguration, SourceColorConfiguration, + VisionSimulationModeConfiguration, } from '../../types/configurations' -import { ActionsList } from '../../types/models' +import { ActionsList, TextColorsThemeHexModel } from '../../types/models' import Color from '../../utils/Color' import Contrast from '../../utils/Contrast' -import { palette } from '../../utils/palettePackage' import Feature from '../components/Feature' interface PreviewProps { colors: Array | Array | [] scale: ScaleConfiguration + colorSpace: ColorSpaceConfiguration + visionSimulationMode: VisionSimulationModeConfiguration + algorithmVersion: AlgorithmVersionConfiguration + textColorsTheme: TextColorsThemeHexModel planStatus: PlanStatus lang: Language onResetSourceColors?: () => void @@ -158,11 +164,11 @@ export default class Preview extends PureComponent< lightness: scale, hueShifting: isString ? 0 : color.hueShifting, chromaShifting: isString ? 100 : color.chromaShifting, - algorithmVersion: palette.algorithmVersion, - visionSimulationMode: palette.visionSimulationMode, + algorithmVersion: this.props.algorithmVersion, + visionSimulationMode: this.props.visionSimulationMode, }) - switch (palette.colorSpace) { + switch (this.props.colorSpace) { case 'LCH': return colorData.lch() as HexModel case 'OKLCH': @@ -361,14 +367,14 @@ export default class Preview extends PureComponent< .map((lightness, index) => { const background: HexModel = this.setColor(color, lightness) const darkText = new Color({ - visionSimulationMode: palette.visionSimulationMode, + visionSimulationMode: this.props.visionSimulationMode, }).simulateColorBlindHex( - chroma(palette.textColorsTheme.darkColor).rgb(false) + chroma(this.props.textColorsTheme.darkColor).rgb(false) ) const lightText = new Color({ - visionSimulationMode: palette.visionSimulationMode, + visionSimulationMode: this.props.visionSimulationMode, }).simulateColorBlindHex( - chroma(palette.textColorsTheme.lightColor).rgb(false) + chroma(this.props.textColorsTheme.lightColor).rgb(false) ) return ( diff --git a/src/ui/services/CreatePalette.tsx b/src/ui/services/CreatePalette.tsx index e14ec9ce..d160de0c 100644 --- a/src/ui/services/CreatePalette.tsx +++ b/src/ui/services/CreatePalette.tsx @@ -257,7 +257,7 @@ export default class CreatePalette extends PureComponent< {...this.props} key="preview" colors={this.props.sourceColors} - scale={this.props.scale ?? {}} + algorithmVersion="v2" onResetSourceColors={this.resetSourceColorsHandler} /> From f60dd0b5f9bc33fa53a891727308fe37058e2091 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 15:29:58 +0100 Subject: [PATCH 43/55] refactor: update SettingsProps to replace view string with ViewConfiguration --- src/ui/contexts/Settings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index df21f82e..39981e99 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -43,10 +43,10 @@ interface SettingsProps { sourceColors?: Array name: string description: string - textColorsTheme: TextColorsThemeHexModel + view: ViewConfiguration colorSpace: ColorSpaceConfiguration visionSimulationMode: VisionSimulationModeConfiguration - view: string + textColorsTheme: TextColorsThemeHexModel algorithmVersion?: AlgorithmVersionConfiguration userIdentity: UserConfiguration userConsent: Array From 234d8372a67ab00819a719dca483d699351963eb Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 16:46:53 +0100 Subject: [PATCH 44/55] chore: update @a_ng_d/figmug-ui dependency to version 0.113.6 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e811cf6..f9944d7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "figma-ui-color-palette", "version": "4.1.5", "dependencies": { - "@a_ng_d/figmug-ui": "^0.113.5", + "@a_ng_d/figmug-ui": "^0.113.6", "@a_ng_d/figmug-utils": "^0.1.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", @@ -61,9 +61,9 @@ } }, "node_modules/@a_ng_d/figmug-ui": { - "version": "0.113.5", - "resolved": "https://registry.npmjs.org/@a_ng_d/figmug-ui/-/figmug-ui-0.113.5.tgz", - "integrity": "sha512-sciG7fNRXFk6mWTgIDjGe0inavP55S1AGnJlvr/Nwk/kDHTxH+jsJHQMOQp7buPEqcqSyNThORq3R+Yliq9PSw==", + "version": "0.113.6", + "resolved": "https://registry.npmjs.org/@a_ng_d/figmug-ui/-/figmug-ui-0.113.6.tgz", + "integrity": "sha512-4owjWT0tL5vlDMvwQsuQ3q4x5TzyXmtBOomXmMTtc251wIDlbkWN7imGy93yP37DJcXHHh5BFXPlf045xmdqdg==", "dependencies": { "@a_ng_d/figmug-utils": "^0.1.2", "@storybook/client-api": "^7.6.17", diff --git a/package.json b/package.json index b830b1cd..eed9c616 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "webpack-cli": "^4.9.1" }, "dependencies": { - "@a_ng_d/figmug-ui": "^0.113.5", + "@a_ng_d/figmug-ui": "^0.113.6", "@a_ng_d/figmug-utils": "^0.1.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", From 4b6be253b48006d6fe3913528952110f6f6644bc Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Thu, 12 Dec 2024 16:48:25 +0100 Subject: [PATCH 45/55] feat: implement dynamic drawer height adjustment in Preview component --- src/ui/modules/Preview.tsx | 69 +++++++++++++++++++++++++++++++++++--- src/ui/stylesheets/app.css | 22 ++++++++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/ui/modules/Preview.tsx b/src/ui/modules/Preview.tsx index c404089c..556f70cf 100644 --- a/src/ui/modules/Preview.tsx +++ b/src/ui/modules/Preview.tsx @@ -43,12 +43,12 @@ interface PreviewStates { isLoaded: boolean isWCAGDisplayed: boolean isAPCADisplayed: boolean + drawerHeight: string } -export default class Preview extends PureComponent< - PreviewProps, - PreviewStates -> { +export default class Preview extends PureComponent { + drawerRef: React.RefObject + static features = (planStatus: PlanStatus) => ({ PREVIEW_WCAG: new FeatureStatus({ features: features, @@ -73,7 +73,9 @@ export default class Preview extends PureComponent< isLoaded: false, isWCAGDisplayed: true, isAPCADisplayed: true, + drawerHeight: 'auto', } + this.drawerRef = React.createRef() } // Lifecycle @@ -94,6 +96,14 @@ export default class Preview extends PureComponent< window.removeEventListener('message', this.handleMessage) } + componentDidUpdate = (): void => { + if (this.props.colors.length === 0) { + this.setState({ + drawerHeight: 'auto', + }) + } + } + // Handlers handleMessage = (e: MessageEvent) => { const displayWCAGScore = () => { @@ -186,6 +196,44 @@ export default class Preview extends PureComponent< } } + onGrab = () => { + document.body.style.cursor = 'ns-resize' + document.addEventListener('mousemove', this.onDrag) + } + + onDrag = (e: MouseEvent) => { + const { drawerRef } = this + const { clientY } = e + const bottom = drawerRef.current + ? drawerRef.current.getBoundingClientRect().bottom + : 0 + const topLimit = 144 + const minheight = 149 + + const delta = bottom - clientY + let drawerHeight + + if (clientY >= topLimit) drawerHeight = delta + if (delta < minheight) drawerHeight = minheight + + this.setState({ + drawerHeight: `${drawerHeight}px`, + }) + + document.body.style.cursor = 'ns-resize' + document.addEventListener('mouseup', () => { + document.body.style.cursor = '' + document.removeEventListener('mousemove', this.onDrag) + }) + } + + clickHandler = (e: React.MouseEvent) => { + if (e.detail === 2) + this.setState({ + drawerHeight: this.state.drawerHeight === 'auto' ? '100%' : 'auto', + }) + } + // Templates stopTag = ({ stop }: { stop: string }) => (
@@ -233,7 +281,18 @@ export default class Preview extends PureComponent< render() { if (!this.props.colors.length || !this.state.isLoaded) return null return ( -
+
+
diff --git a/src/ui/stylesheets/app.css b/src/ui/stylesheets/app.css index 23114748..e96bba31 100644 --- a/src/ui/stylesheets/app.css +++ b/src/ui/stylesheets/app.css @@ -15,7 +15,6 @@ li { div#app { height: 100%; - cursor: default; user-select: none; -webkit-user-select: none; } @@ -212,18 +211,35 @@ div.about__links { display: flex; flex-direction: column; border-top: 1px solid var(--figma-color-border); - overflow: hidden; + position: relative; + max-height: calc(100% - 185px); +} + +.preview__knob-spot { + position: absolute; + width: 100%; + height: var(--size-xxsmall); + z-index: 2; + top: -4px; + cursor: ns-resize; } .preview__rows { overflow-y: auto; + display: flex; + flex-direction: column; + flex: 1; } -.preview__row, .preview__header { +.preview__row { display: flex; flex: 1; } +.preview__header { + display: flex; +} + .preview__cell { flex: 1; overflow: hidden; From 6b15d7ead0e3f4c1877e54f73513780d925170d1 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Fri, 13 Dec 2024 00:48:50 +0100 Subject: [PATCH 46/55] chore: add @nanostores/preact dependency to package.json and package-lock.json --- package-lock.json | 34 ++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 35 insertions(+) diff --git a/package-lock.json b/package-lock.json index f9944d7f..ff69a11b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@a_ng_d/figmug-ui": "^0.113.6", "@a_ng_d/figmug-utils": "^0.1.2", + "@nanostores/preact": "^0.5.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", "@supabase/supabase-js": "^2.44.2", @@ -542,6 +543,24 @@ "node": ">=8" } }, + "node_modules/@nanostores/preact": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@nanostores/preact/-/preact-0.5.2.tgz", + "integrity": "sha512-DZ5G0UuHTJ8NNS8I3Jd6f4RCcWIl4siYD+vaV6jQf0T6xJ3QqTSkJkYNQTZK7O+7NC/mzaLkomyLQqD+w1E0Tg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0", + "preact": ">=10.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5693,6 +5712,21 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanostores": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.3.tgz", + "integrity": "sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/package.json b/package.json index eed9c616..f6bbacf2 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "dependencies": { "@a_ng_d/figmug-ui": "^0.113.6", "@a_ng_d/figmug-utils": "^0.1.2", + "@nanostores/preact": "^0.5.2", "@sentry/react": "^8.8.0", "@sentry/webpack-plugin": "^2.22.6", "@supabase/supabase-js": "^2.44.2", From a34da7c99b5d8e6d2fad5426fec4ca34e95b4b67 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Fri, 13 Dec 2024 00:49:03 +0100 Subject: [PATCH 47/55] feat: add checkUserPreferences function to manage user preference settings --- src/bridges/checks/checkUserPreferences.ts | 33 ++++++++++++++++++++++ src/bridges/loadUI.ts | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 src/bridges/checks/checkUserPreferences.ts diff --git a/src/bridges/checks/checkUserPreferences.ts b/src/bridges/checks/checkUserPreferences.ts new file mode 100644 index 00000000..065a1f46 --- /dev/null +++ b/src/bridges/checks/checkUserPreferences.ts @@ -0,0 +1,33 @@ +const checkUserPreferences = async () => { + const canDeepSyncPalette = await figma.clientStorage.getAsync( + 'can_deep_sync_palette' + ) + const canDeepSyncVariables = await figma.clientStorage.getAsync( + 'can_deep_sync_variables' + ) + const canDeepSyncStyles = await figma.clientStorage.getAsync( + 'can_deep_sync_styles' + ) + + if (canDeepSyncPalette === undefined) + await figma.clientStorage.setAsync('can_deep_sync_palette', false) + + if (canDeepSyncVariables === undefined) + await figma.clientStorage.setAsync('can_deep_sync_variables', false) + + if (canDeepSyncStyles === undefined) + await figma.clientStorage.setAsync('can_deep_sync_styles', false) + + figma.ui.postMessage({ + type: 'CHECK_USER_PREFERENCES', + data: { + canDeepSyncPalette: canDeepSyncPalette ?? false, + canDeepSyncVariables: canDeepSyncVariables ?? false, + canDeepSyncStyles: canDeepSyncStyles ?? false, + }, + }) + + return true +} + +export default checkUserPreferences diff --git a/src/bridges/loadUI.ts b/src/bridges/loadUI.ts index 214f42f5..d5c7d955 100644 --- a/src/bridges/loadUI.ts +++ b/src/bridges/loadUI.ts @@ -5,6 +5,7 @@ import checkEditorType from './checks/checkEditorType' import checkHighlightStatus from './checks/checkHighlightStatus' import checkPlanStatus from './checks/checkPlanStatus' import checkUserConsent from './checks/checkUserConsent' +import checkUserPreferences from './checks/checkUserPreferences' import createLocalStyles from './creations/createLocalStyles' import createLocalVariables from './creations/createLocalVariables' import createPalette from './creations/createPalette' @@ -48,6 +49,7 @@ const loadUI = async () => { checkUserConsent() .then(() => checkEditorType()) .then(() => checkPlanStatus()) + .then(() => checkUserPreferences()) .then(() => processSelection()) // Canvas > UI From 15776e3bcbca530b49611a916ee528f631b67b42 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Fri, 13 Dec 2024 00:49:31 +0100 Subject: [PATCH 48/55] feat: add preferences store and integrate user preference checks in App component --- src/stores/preferences.ts | 5 +++++ src/ui/App.tsx | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/stores/preferences.ts diff --git a/src/stores/preferences.ts b/src/stores/preferences.ts new file mode 100644 index 00000000..3ab0792d --- /dev/null +++ b/src/stores/preferences.ts @@ -0,0 +1,5 @@ +import { atom } from 'nanostores' + +export const $isPaletteDeepSync = atom(false) +export const $areVariablesDeepSync = atom(false) +export const $areStylesDeepSync = atom(false) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index b8806180..70773b16 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -60,6 +60,11 @@ import TransferPalette from './services/TransferPalette' import './stylesheets/app-components.css' import './stylesheets/app.css' import doLightnessScale from '../utils/doLightnessScale' +import { + $isPaletteDeepSync, + $areVariablesDeepSync, + $areStylesDeepSync, +} from '../stores/preferences' export interface AppStates { service: Service @@ -330,6 +335,14 @@ export default class App extends Component, AppStates> { userConsent: e.data.pluginMessage.userConsent, }) + const checkUserPreferences = () => { + $isPaletteDeepSync.set(e.data.pluginMessage.data.canDeepSyncPalette) + $areVariablesDeepSync.set( + e.data.pluginMessage.data.canDeepSyncVariables + ) + $areStylesDeepSync.set(e.data.pluginMessage.data.canDeepSyncStyles) + } + const checkEditorType = () => { this.setState({ editorType: e.data.pluginMessage.data }) setTimeout( @@ -831,6 +844,7 @@ export default class App extends Component, AppStates> { const actions: ActionsList = { CHECK_USER_AUTHENTICATION: () => checkUserAuthentication(), CHECK_USER_CONSENT: () => checkUserConsent(), + CHECK_USER_PREFERENCES: () => checkUserPreferences(), CHECK_EDITOR_TYPE: () => checkEditorType(), PUSH_HIGHLIGHT_STATUS: () => handleHighlight(), CHECK_PLAN_STATUS: () => checkPlanStatus(), From 6f07a7283ebdb99a59ca9bffdedeb5ff13540114 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Fri, 13 Dec 2024 00:50:50 +0100 Subject: [PATCH 49/55] feat: refactor SyncPreferences component to use subscriptions for deep sync state management --- src/ui/contexts/SyncPreferences.tsx | 87 +++++++---------------------- 1 file changed, 21 insertions(+), 66 deletions(-) diff --git a/src/ui/contexts/SyncPreferences.tsx b/src/ui/contexts/SyncPreferences.tsx index 5d91b0a9..3fc88e7d 100644 --- a/src/ui/contexts/SyncPreferences.tsx +++ b/src/ui/contexts/SyncPreferences.tsx @@ -12,7 +12,6 @@ import React from 'react' import features from '../../config' import { locals } from '../../content/locals' import { Language, PlanStatus } from '../../types/app' -import { ActionsList } from '../../types/models' import Feature from '../components/Feature' interface SyncPreferencesProps { @@ -60,70 +59,30 @@ export default class SyncPreferences extends PureComponent< } } - componentDidMount = (): void => { - parent.postMessage( - { - pluginMessage: { - type: 'GET_ITEMS', - items: ['can_deep_sync_variables', 'can_deep_sync_styles'], - }, - }, - '*' - ) - window.addEventListener('message', this.handleMessage) - } - - componentWillUnmount = (): void => { - window.removeEventListener('message', this.handleMessage) + // Lifecycle + componentDidMount() { + this.unsubscribePalette = $isPaletteDeepSync.subscribe((value) => { + this.setState({ isPaletteDeepSync: value }) + console.log('PaletteDeepSync', value) + }) + this.unsubscribeVariables = $areVariablesDeepSync.subscribe((value) => { + this.setState({ areVariablesDeepSync: value }) + }) + this.unsubscribeStyles = $areStylesDeepSync.subscribe((value) => { + this.setState({ areStylesDeepSync: value }) + }) } - // Handlers - handleMessage = (e: MessageEvent) => { - const deepSyncVariables = () => { - if (e.data.pluginMessage.value === undefined) - parent.postMessage( - { - pluginMessage: { - type: 'SET_ITEMS', - items: [ - { - key: 'can_deep_sync_variables', - value: false, - }, - ], - }, - }, - '*' - ) - else this.setState({ areVariablesDeepSync: e.data.pluginMessage.value }) + componentWillUnmount() { + if (this.unsubscribePalette) { + this.unsubscribePalette() } - - const deepSyncStyles = () => { - if (e.data.pluginMessage.value === undefined) - parent.postMessage( - { - pluginMessage: { - type: 'SET_ITEMS', - items: [ - { - key: 'can_deep_sync_styles', - value: false, - }, - ], - }, - }, - '*' - ) - else this.setState({ areStylesDeepSync: e.data.pluginMessage.value }) + if (this.unsubscribeVariables) { + this.unsubscribeVariables() } - - const actions: ActionsList = { - GET_ITEM_CAN_DEEP_SYNC_VARIABLES: () => deepSyncVariables(), - GET_ITEM_CAN_DEEP_SYNC_STYLES: () => deepSyncStyles(), - DEFAULT: () => null, + if (this.unsubscribeStyles) { + this.unsubscribeStyles() } - - return actions[e.data.pluginMessage?.type ?? 'DEFAULT']?.() } // Templates @@ -150,9 +109,7 @@ export default class SyncPreferences extends PureComponent< ).SETTINGS_SYNC_DEEP_VARIABLES.isNew()} feature="UPDATE_VARIABLES_DEEP_SYNC" onChange={(e) => { - this.setState({ - areVariablesDeepSync: !this.state.areVariablesDeepSync, - }) + $areVariablesDeepSync.set(!this.state.areVariablesDeepSync) this.props.onChangeSettings(e) }} /> @@ -181,9 +138,7 @@ export default class SyncPreferences extends PureComponent< ).SETTINGS_SYNC_DEEP_STYLES.isNew()} feature="UPDATE_STYLES_DEEP_SYNC" onChange={(e) => { - this.setState({ - areStylesDeepSync: !this.state.areStylesDeepSync, - }) + $areStylesDeepSync.set(!this.state.areStylesDeepSync) this.props.onChangeSettings(e) }} /> From 4419c7c36d407322619e3c7793ba10e67b70f565 Mon Sep 17 00:00:00 2001 From: "@a-ng-d" Date: Fri, 13 Dec 2024 00:52:34 +0100 Subject: [PATCH 50/55] feat: implement deep synchronization for palette settings in SyncPreferences and related components --- src/content/locals.ts | 3 ++ src/ui/contexts/Colors.tsx | 30 ++++++++++++++--- src/ui/contexts/Scale.tsx | 24 ++++++++++++-- src/ui/contexts/Settings.tsx | 17 ++++++++++ src/ui/contexts/SyncPreferences.tsx | 50 +++++++++++++++++++++++++++++ src/ui/contexts/Themes.tsx | 27 +++++++++++++--- src/utils/features.ts | 9 ++++++ 7 files changed, 149 insertions(+), 11 deletions(-) diff --git a/src/content/locals.ts b/src/content/locals.ts index f9c50f14..2d9cc98b 100644 --- a/src/content/locals.ts +++ b/src/content/locals.ts @@ -328,6 +328,9 @@ export const locals: { [key: string]: any } = { title: 'Synchronization', message: 'A deep synchronization means that the palette and the local variables/styles are synchronized in both directions', + palette: { + label: 'Enable a deep synchronization with the palette', + }, variables: { label: 'Enable a deep synchronization with the local variables in the collection', diff --git a/src/ui/contexts/Colors.tsx b/src/ui/contexts/Colors.tsx index 27eae3c6..3a784655 100644 --- a/src/ui/contexts/Colors.tsx +++ b/src/ui/contexts/Colors.tsx @@ -29,6 +29,7 @@ import type { AppStates } from '../App' import Feature from '../components/Feature' import Actions from '../modules/Actions' import Dispatcher from '../modules/Dispatcher' +import { $isPaletteDeepSync } from '../../stores/preferences' interface ColorsProps { colors: Array @@ -43,9 +44,14 @@ interface ColorsProps { onPublishPalette: () => void } -export default class Colors extends PureComponent { - colorsMessage: ColorsMessage - dispatch: { [key: string]: DispatchProcess } +interface ColorsStates { + isPaletteDeepSync: boolean +} + +export default class Colors extends PureComponent { + private colorsMessage: ColorsMessage + private dispatch: { [key: string]: DispatchProcess } + private unsubscribe: (() => void) | null = null static features = (planStatus: PlanStatus) => ({ COLORS_NAME: new FeatureStatus({ @@ -88,6 +94,22 @@ export default class Colors extends PureComponent { 500 ) as DispatchProcess, } + this.state = { + isPaletteDeepSync: false, + } + } + + // Lifecycle + componentDidMount() { + this.unsubscribe = $isPaletteDeepSync.subscribe((value) => { + this.setState({ isPaletteDeepSync: value }) + }) + } + + componentWillUnmount() { + if (this.unsubscribe) { + this.unsubscribe() + } } // Handlers @@ -211,7 +233,7 @@ export default class Colors extends PureComponent { ) } else { this.colorsMessage.isEditedInRealTime = true - // this.dispatch.colors.on.status = true + if (this.state.isPaletteDeepSync) this.dispatch.colors.on.status = true } } diff --git a/src/ui/contexts/Scale.tsx b/src/ui/contexts/Scale.tsx index ec48fa7d..cb8fd720 100644 --- a/src/ui/contexts/Scale.tsx +++ b/src/ui/contexts/Scale.tsx @@ -38,6 +38,7 @@ import Feature from '../components/Feature' import Slider from '../components/Slider' import Actions from '../modules/Actions' import Dispatcher from '../modules/Dispatcher' +import { $isPaletteDeepSync } from '../../stores/preferences' interface ScaleProps { sourceColors?: Array @@ -67,11 +68,13 @@ interface ScaleProps { interface ScaleStates { isTipsOpen: boolean + isPaletteDeepSync: boolean } export default class Scale extends PureComponent { - scaleMessage: ScaleMessage - dispatch: { [key: string]: DispatchProcess } + private scaleMessage: ScaleMessage + private dispatch: { [key: string]: DispatchProcess } + private unsubscribe: (() => void) | undefined static defaultProps: Partial = { namingConvention: 'ONES', @@ -143,6 +146,20 @@ export default class Scale extends PureComponent { } this.state = { isTipsOpen: false, + isPaletteDeepSync: false, + } + } + + // Lifecycle + componentDidMount() { + this.unsubscribe = $isPaletteDeepSync.subscribe((value) => { + this.setState({ isPaletteDeepSync: value }) + }) + } + + componentWillUnmount() { + if (this.unsubscribe) { + this.unsubscribe() } } @@ -177,7 +194,8 @@ export default class Scale extends PureComponent { const onUpdatingStop = () => { this.scaleMessage.isEditedInRealTime = true this.props.onChangeScale() - // if (!this.props.hasPreset) this.dispatch.scale.on.status = true + if (!this.props.hasPreset && this.state.isPaletteDeepSync) + this.dispatch.scale.on.status = true } const actions: ActionsList = { diff --git a/src/ui/contexts/Settings.tsx b/src/ui/contexts/Settings.tsx index 39981e99..58f1c0e7 100644 --- a/src/ui/contexts/Settings.tsx +++ b/src/ui/contexts/Settings.tsx @@ -399,6 +399,22 @@ export default class Settings extends PureComponent< this.dispatch.textColorsTheme.on.status = true } + const updatePaletteDeepSync = () => + parent.postMessage( + { + pluginMessage: { + type: 'SET_ITEMS', + items: [ + { + key: 'can_deep_sync_palette', + value: target.checked, + }, + ], + }, + }, + '*' + ) + const updateVariablesDeepSync = () => parent.postMessage( { @@ -440,6 +456,7 @@ export default class Settings extends PureComponent< UPDATE_ALGORITHM_VERSION: () => updateAlgorithmVersion(), UPDATE_TEXT_LIGHT_COLOR: () => updateTextLightColor(), UPDATE_TEXT_DARK_COLOR: () => updateTextDarkColor(), + UPDATE_PALETTE_DEEP_SYNC: () => updatePaletteDeepSync(), UPDATE_VARIABLES_DEEP_SYNC: () => updateVariablesDeepSync(), UPDATE_STYLES_DEEP_SYNC: () => updateStylesDeepSync(), DEFAULT: () => null, diff --git a/src/ui/contexts/SyncPreferences.tsx b/src/ui/contexts/SyncPreferences.tsx index 3fc88e7d..f09f88f6 100644 --- a/src/ui/contexts/SyncPreferences.tsx +++ b/src/ui/contexts/SyncPreferences.tsx @@ -8,6 +8,11 @@ import { import { FeatureStatus } from '@a_ng_d/figmug-utils' import { PureComponent } from 'preact/compat' import React from 'react' +import { + $isPaletteDeepSync, + $areVariablesDeepSync, + $areStylesDeepSync, +} from '../../stores/preferences' import features from '../../config' import { locals } from '../../content/locals' @@ -26,6 +31,7 @@ interface SyncPreferencesProps { } interface SyncPreferencesStates { + isPaletteDeepSync: boolean areVariablesDeepSync: boolean areStylesDeepSync: boolean } @@ -34,7 +40,16 @@ export default class SyncPreferences extends PureComponent< SyncPreferencesProps, SyncPreferencesStates > { + private unsubscribePalette: (() => void) | undefined + private unsubscribeVariables: (() => void) | undefined + private unsubscribeStyles: (() => void) | undefined + static features = (planStatus: PlanStatus) => ({ + SETTINGS_SYNC_DEEP_PALETTE: new FeatureStatus({ + features: features, + featureName: 'SETTINGS_SYNC_DEEP_PALETTE', + planStatus: planStatus, + }), SETTINGS_SYNC_DEEP_VARIABLES: new FeatureStatus({ features: features, featureName: 'SETTINGS_SYNC_DEEP_VARIABLES', @@ -54,6 +69,7 @@ export default class SyncPreferences extends PureComponent< constructor(props: SyncPreferencesProps) { super(props) this.state = { + isPaletteDeepSync: false, areVariablesDeepSync: false, areStylesDeepSync: false, } @@ -86,6 +102,37 @@ export default class SyncPreferences extends PureComponent< } // Templates + PaletteDeepSync = () => { + return ( + +