Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions src/common/utils/colorUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { clampChroma, converter, formatHex, wcagContrast } from "culori";
import { SHADE_STEPS } from "../constants/colorConstants";

/**
* Génère une palette de teintes (shades) à partir d'une couleur de base en hex.
*
* L'algorithme place la couleur de base à l'étape la plus proche de sa luminosité
* naturelle, puis dérive les autres étapes autour d'elle dans l'espace OKLCH.
*
* @param colorHex - Couleur de départ au format hex (#RRGGBB)
* @returns Tableau trié de { step, color } pour chaque étape définie dans SHADE_STEPS
*/
export function generateShades(
colorHex: string,
): { step: number; color: string }[] {
Expand All @@ -9,9 +18,10 @@ export function generateShades(
const { l: baseL, c: CO, h: H0 } = base;
const lMax = 0.95;
const lMin = 0.15;
// Fix: utiliser le spread ES2020 plutôt que Math.min/max.apply (antipattern ES5)
const stepNumbers = SHADE_STEPS.map(Number);
const minStep = Math.min.apply(Math, stepNumbers);
const maxStep = Math.max.apply(Math, stepNumbers);
const minStep = Math.min(...stepNumbers);
const maxStep = Math.max(...stepNumbers);

// Trouve la shade la plus proche de la luminosité de base
let closestStep = SHADE_STEPS[0];
Expand All @@ -38,8 +48,7 @@ export function generateShades(
return { step, color: colorHex };
}

const stepValue = step;
const t = (stepValue - minStep) / (maxStep - minStep);
const t = (step - minStep) / (maxStep - minStep);
// Appliquer le décalage de luminosité pour adapter le dégradé autour de la couleur de base
const l = lMax - Math.pow(t, 1.15) * (lMax - lMin) + luminosityOffset;
const c = CO * Math.pow(Math.sin(Math.PI * t), 0.9);
Expand All @@ -48,14 +57,23 @@ export function generateShades(
});
}

/**
* Génère une palette de niveaux de gris pour un ensemble d'étapes données.
*
* @param steps - Valeurs d'étape entre 0 et 1000 (0 = blanc, 1000 = noir)
* @param hue - Teinte optionnelle pour un gris légèrement teinté (défaut : 0 = neutre)
* @returns Dictionnaire { step → couleur hex }
*/
export function generateGreyShades(
steps: number[],
hue: number = 0,
): Record<number, string> {
const greyShades: Record<number, string> = {};
for (const step of steps) {
const t = step / 1000;
const lightness = 1 - t * 1;
// Fix: clamp lightness dans [0, 1] — si step > 1000, la valeur non clampée
// serait négative, ce que culori accepte silencieusement avec un rendu indéfini.
const lightness = Math.max(0, Math.min(1, 1 - t));
greyShades[step] = formatHex({
mode: "hsl",
h: hue,
Expand All @@ -67,6 +85,15 @@ export function generateGreyShades(
return greyShades;
}

/**
* Détermine la couleur de texte (clair ou foncé) offrant le meilleur contraste WCAG
* sur un fond donné.
*
* @param background - Couleur de fond en RGBA Figma (valeurs 0–1)
* @param light - Couleur "claire" candidate en RGBA Figma
* @param dark - Couleur "foncée" candidate en RGBA Figma
* @returns "Light" si la couleur claire offre le meilleur contraste, "Dark" sinon
*/
export function getContrastColor(
background: { r: number; g: number; b: number; a: number },
light: { r: number; g: number; b: number; a: number },
Expand Down
20 changes: 14 additions & 6 deletions src/main/builders/variables/variableBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,24 @@ export class VariableBuilder {
return vars.filter((v) => v.name === variableName)[0];
}

/**
* Trouve plusieurs variables par collection et noms.
*
* Effectue un seul appel à l'API Figma (getLocalVariablesAsync) puis
* filtre le résultat en mémoire — bien plus efficace que N appels séquentiels.
*
* @param collectionName - Nom de la collection cible
* @param variableNames - Liste des noms de variables recherchées
* @returns Variables trouvées (dans l'ordre de variableNames)
*/
async findVariables(
collectionName: string,
variableNames: string[],
): Promise<Variable[]> {
const variables: Variable[] = [];
for (const name of variableNames) {
const variable = await this.findVariable(collectionName, name);
if (variable) variables.push(variable);
}
return variables;
// Un seul appel API au lieu de N appels séquentiels via findVariable()
const allVars = await this.getCollectionVariables(collectionName);
const nameSet = new Set(variableNames);
return allVars.filter((v) => nameSet.has(v.name));
}

/**
Expand Down
9 changes: 6 additions & 3 deletions src/ui/components/colorSelector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { COLOR_DATA } from "../constants";

/** Mettre à true pour activer les logs de débogage. Toujours false en production. */
const DEBUG = false;

function formatColorName(name: string): string {
return name
.replace(/([A-Z])/g, " $1")
Expand Down Expand Up @@ -140,7 +143,7 @@ export function initColorSelector(wrapper: HTMLElement): void {
const text = wrapper.querySelector<HTMLElement>(".color-text");

if (!button || !popup || !preview || !text) {
console.warn("❌ Color selector elements not found", {
if (DEBUG) console.warn("❌ Color selector elements not found", {
button: !!button,
popup: !!popup,
preview: !!preview,
Expand Down Expand Up @@ -267,7 +270,7 @@ export function initAllColorSelectors(): void {

if (wrappers.length === 0) {
console.error("❌ CRITICAL: No color selector wrappers found!");
console.log("Available divs:", document.querySelectorAll("div").length);
if (DEBUG) console.log("Available divs:", document.querySelectorAll("div").length);
return;
}

Expand All @@ -294,4 +297,4 @@ export function initAllColorSelectors(): void {
});
}
});
}
}
7 changes: 5 additions & 2 deletions src/ui/initializers/buttonListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { debugPanel } from "../components/debugPanel";
import { layoutGuideType } from "../../common/types";
import { stringify } from "querystring";

/** Mettre à true pour activer les logs de débogage. Toujours false en production. */
const DEBUG = false;

// List of button IDs corresponding to different actions
const btns = [
"brand-colors",
Expand Down Expand Up @@ -104,7 +107,7 @@ export function attachButtonListeners() {
// debugPanel.show();

const formData = getFormData();
console.log("📋 FormData complète:", formData);
if (DEBUG) console.log("📋 FormData complète:", formData);

// Handle Color Families
const colorsData: Record<string, Record<string, string>> = {};
Expand Down Expand Up @@ -309,4 +312,4 @@ export function attachButtonListeners() {
});
}
});
}
}
7 changes: 5 additions & 2 deletions src/ui/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
} from "./initializers";
import { initImageCategoryList } from "./initializers/imageCategoryInitializer";

/** Mettre à true pour activer les logs de débogage. Toujours false en production. */
const DEBUG = false;

document.addEventListener("DOMContentLoaded", () => {
initTabs();

Expand Down Expand Up @@ -42,8 +45,8 @@ document.addEventListener("DOMContentLoaded", () => {

switch (message.type) {
case "notification":
console.log("Plugin notification:", message.message);
if (DEBUG) console.log("Plugin notification:", message.message);
break;
}
};
});
});
8 changes: 6 additions & 2 deletions src/ui/utils/formData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@


/** Mettre à true pour activer les logs de débogage. Toujours false en production. */
const DEBUG = false;
export interface FormData {
[key: string]: string | number | File[];
}
Expand Down Expand Up @@ -87,12 +91,12 @@ export function getFormData(): FormData {
const files = fileListInstance.getFiles();
data[inputId] = files;
} else {
console.warn(
if (DEBUG) console.warn(
"❌ Pas d'instance ou pas de méthode getFiles pour:",
inputId,
);
}
});

return data;
}
}