Skip to content

Commit

Permalink
✨ feat: add multi-format color export
Browse files Browse the repository at this point in the history
- Add format selector (HSL, RGB, HEX) for each palette
- Implement color format conversion functions
- Add copy functionality for different formats
- Style format selector to match existing design
  • Loading branch information
SylvieCanongia committed Nov 20, 2024
1 parent 6bbb114 commit d4d1f93
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 57 deletions.
138 changes: 90 additions & 48 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -194,26 +194,40 @@ <h2>Primary Color Palettes</h2>
<section class="palette-container">
<h3>Normal</h3>
<div id="primaryNormalPalette" class="palette"></div>
<button id="copyPrimaryNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copyPrimaryNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
<section class="palette-container">
<h3>Vivid</h3>
<div id="primaryVividPalette" class="palette"></div>
<button id="copyPrimaryVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copyPrimaryVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
</div>
</div>
Expand All @@ -225,26 +239,40 @@ <h2>Secondary Color Palettes</h2>
<section class="palette-container">
<h3>Normal</h3>
<div id="secondaryNormalPalette" class="palette"></div>
<button id="copySecondaryNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copySecondaryNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
<section class="palette-container">
<h3>Vivid</h3>
<div id="secondaryVividPalette" class="palette"></div>
<button id="copySecondaryVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copySecondaryVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
</div>
</div>
Expand All @@ -256,26 +284,40 @@ <h2>Accent Color Palettes</h2>
<section class="palette-container">
<h3>Normal</h3>
<div id="accentNormalPalette" class="palette"></div>
<button id="copyAccentNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copyAccentNormal" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
<section class="palette-container">
<h3>Vivid</h3>
<div id="accentVividPalette" class="palette"></div>
<button id="copyAccentVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
<div class="copy-actions">
<select class="format-select" aria-label="Format d'export">
<option value="hsl">HSL</option>
<option value="rgb">RGB</option>
<option value="hex">HEX</option>
</select>
<button id="copyAccentVivid" class="copy-button" aria-label="Copier la palette">
<svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
</svg>
<svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
</button>
</div>
</section>
</div>
</div>
Expand Down
60 changes: 53 additions & 7 deletions src/css/components/palette.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
.palette-container {
position: relative;
padding-block-end: 32px;
padding-inline-end: 15px;
padding-inline-end: 37px;
}

/* Palette Grid */
Expand Down Expand Up @@ -135,16 +135,62 @@
/* ==========================================================================
Action Buttons
========================================================================== */
.copy-actions {
position: absolute;
right: -10px;
top: 55%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
/* width: 45px; */
overflow: hidden;
}

.format-select {
/* base styles */
line-height: calc(var(--line-height-base) + 0.1);
padding-left: var(--spacing-xxs);
background: var(--color-surface);
border: 1px solid --color-border;
border-radius: var(--border-radius-md);
color: var(--color-text);
font-size: var(--font-size-xxs);
cursor: pointer;
padding-right: var(--spacing-sm);
/* styles of the arrow */
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 16 16'%3E%3Cpath fill='currentColor' d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E");
background-size: 10px;
background-repeat: no-repeat;
background-position: right 3px center;
}

.format-select:hover {
border: 2px solid var(--color-primary);
}

.format-select:focus {
outline: none;
border-color: var(--color-border-focus);
}


/* Adjust arrow color in dark mode */
@media (prefers-color-scheme: dark) {
.format-select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 16 16'%3E%3Cpath fill='%23E5E7EB' d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E");
}
}

.copy-button {
position: absolute;
/* position: absolute; */
background: none;
border: none;
padding: var(--spacing-xs);
padding: var(--spacing-xs) 0;
cursor: pointer;
right: -19px;
top: 48%;
transform: translateY(-50%);
/* right: -19px; */
/* top: 48%; */
/* transform: translateY(-20%); */
z-index: 2;
color: var(--color-text);
opacity: 0.7;
Expand All @@ -154,7 +200,7 @@

.copy-button:hover {
opacity: 1;
transform: translateY(-50%) scale(1.1);
transform: /*translateY(-50%)*/ scale(1.1);
}

.copy-button svg {
Expand Down
1 change: 1 addition & 0 deletions src/css/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
--font-family-base: system-ui, -apple-system, sans-serif;
--font-family-mono: monospace;

--font-size-xxs: 0.625rem; /* 10px */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
Expand Down
9 changes: 7 additions & 2 deletions src/js/components/palette.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// src/js/components/palette.js

import { createHSLString, generatePaletteVariations } from "../utils/colorUtils.js";
import { createHSLString, createColorString, generatePaletteVariations } from "../utils/colorUtils.js";

// Constants for palette generation
const TYPES = {
Expand Down Expand Up @@ -84,7 +84,12 @@ const updatePalette = (type, variations, paletteType) => {
if (copyButton) {
copyButton.disabled = false;
copyButton.onclick = () => {
const cssVariables = variations.map((hsl, index) => `--color-${type.toLowerCase()}-${index * 100}: ${createHSLString(hsl)};`).join("\n");
const formatSelect = copyButton.parentElement.querySelector(".format-select");
console.log("format-select", formatSelect);
const format = formatSelect ? formatSelect.value : "hsl";
console.log("format", format);
const cssVariables = variations.map((hsl, index) => `--color-${type.toLowerCase()}-${index * 100}: ${createColorString(hsl, format)};`).join("\n");
console.log("variables", cssVariables);

navigator.clipboard.writeText(cssVariables);
copyButton.classList.add("copied");
Expand Down
39 changes: 39 additions & 0 deletions src/js/utils/colorUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,42 @@ export const generatePaletteVariations = (baseHsl, paletteType) => {

return variations;
};

export const hslToRgb = ({ hue, saturation, lightness }) => {
const s = saturation / 100;
const l = lightness / 100;
const k = (n) => (n + hue / 30) % 12;
const a = s * Math.min(l, 1 - l);
const f = (n) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));

return {
r: Math.round(255 * f(0)),
g: Math.round(255 * f(8)),
b: Math.round(255 * f(4)),
};
};

export const rgbToHex = ({ r, g, b }) => {
const toHex = (x) => {
const hex = x.toString(16);
return hex.length === 1 ? "0" + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
};

export const createColorString = (hsl, format) => {
switch (format) {
case "hsl":
return createHSLString(hsl);
case "rgb": {
const rgb = hslToRgb(hsl);
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
}
case "hex": {
const rgb = hslToRgb(hsl);
return rgbToHex(rgb);
}
default:
return createHSLString(hsl);
}
};

0 comments on commit d4d1f93

Please sign in to comment.