mirror of
https://github.com/shadoll/sLogos.git
synced 2025-12-20 13:32:01 +00:00
feat: add color conversion and target/sets configuration for logos
- Updated Makefile to include a new target for converting logo colors format. - Added a new script `convertColorsFormat.js` to convert colors from array to object format in `logos.json`. - Modified `logos.json` structure to use an object for colors and added targets and sets for SVG logos. - Updated `scanLogos.js` to set default colorConfig, targets, and sets for SVG logos. - Enhanced Svelte components (`Grid.svelte`, `List.svelte`, `Preview.svelte`, `InlineSvg.svelte`) to support new targets, sets, and colors structure. - Updated color theme utility functions to handle the new colors object format. - Removed deprecated `mono_white.svg` logo file.
This commit is contained in:
@@ -62,6 +62,10 @@ $: getLogoThemeColor = logo => getDefaultLogoColor(logo.colors, theme);
|
||||
path={logo.path}
|
||||
color={logo.colors ? (logo._activeColor || getLogoThemeColor(logo)) : undefined}
|
||||
colorConfig={logo.colors ? logo.colorConfig : undefined}
|
||||
targets={logo.targets}
|
||||
sets={logo.sets}
|
||||
colors={logo.colors}
|
||||
activeSet={logo._activeSet}
|
||||
alt={logo.name}
|
||||
/>
|
||||
{/key}
|
||||
@@ -105,17 +109,40 @@ $: getLogoThemeColor = logo => getDefaultLogoColor(logo.colors, theme);
|
||||
<path d="M682.843,117.843l-565.686,565.685c-156.209,-156.21 -156.209,-409.476 0,-565.685c156.21,-156.21 409.476,-156.21 565.686,-0Z" style="fill:#33363f;"/>
|
||||
</svg>
|
||||
</span>
|
||||
{#each logo.colors as colorObj}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorObj.label}
|
||||
style="background:{colorObj.value}"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => logo._activeColor = colorObj.value}
|
||||
on:keydown|stopPropagation={(e) => (e.key === 'Enter' || e.key === ' ') && (logo._activeColor = colorObj.value)}
|
||||
></span>
|
||||
{/each}
|
||||
{#if logo.sets}
|
||||
{#each Object.entries(logo.sets) as [setName, setConfig], i}
|
||||
<span
|
||||
class="color-circle set-circle"
|
||||
title={`Color Set ${i + 1}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}}
|
||||
on:keydown|stopPropagation={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</span>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each Object.entries(logo.colors) as [colorName, colorValue], i}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorName.replace('_', ' ')}
|
||||
style="background:{colorValue}"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => logo._activeColor = colorValue}
|
||||
on:keydown|stopPropagation={(e) => (e.key === 'Enter' || e.key === ' ') && (logo._activeColor = colorValue)}
|
||||
></span>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -189,4 +216,20 @@ $: getLogoThemeColor = logo => getDefaultLogoColor(logo.colors, theme);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.set-circle {
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Dark theme variation */
|
||||
:global(.dark-theme) .set-circle {
|
||||
background: #444;
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
export let path;
|
||||
export let color;
|
||||
export let colorConfig = { target: "path", attribute: "fill" };
|
||||
export let targets = null;
|
||||
export let sets = null;
|
||||
export let activeSet = null;
|
||||
export let colors = null; // Add colors object for access to all color values
|
||||
export const alt = "";
|
||||
|
||||
let svgHtml = "";
|
||||
@@ -54,36 +58,70 @@
|
||||
});
|
||||
// Remove all <style> elements
|
||||
styleEls.forEach((styleEl) => styleEl.remove());
|
||||
let targets;
|
||||
if (colorConfig.selector) {
|
||||
targets = doc.querySelectorAll(colorConfig.selector);
|
||||
} else if (colorConfig.target) {
|
||||
targets = doc.querySelectorAll(colorConfig.target);
|
||||
} else {
|
||||
targets = [];
|
||||
}
|
||||
targets.forEach((el) => {
|
||||
if (colorConfig.attribute) {
|
||||
// Legacy: force a single attribute
|
||||
el.setAttribute(colorConfig.attribute, color);
|
||||
} else {
|
||||
// Always override fill and stroke unless they are 'none'
|
||||
if (el.hasAttribute("fill") && el.getAttribute("fill") !== "none") {
|
||||
el.setAttribute("fill", color);
|
||||
}
|
||||
if (el.hasAttribute("stroke") && el.getAttribute("stroke") !== "none") {
|
||||
el.setAttribute("stroke", color);
|
||||
}
|
||||
if (!el.hasAttribute("fill") && !el.hasAttribute("stroke")) {
|
||||
// If neither, prefer fill
|
||||
el.setAttribute("fill", color);
|
||||
// Handle the new format with targets and sets if available
|
||||
if (targets && sets && activeSet && sets[activeSet]) {
|
||||
// Get the color assignments from the active set
|
||||
const colorAssignments = sets[activeSet];
|
||||
|
||||
// Apply each target-color pair
|
||||
for (const [targetName, colorName] of Object.entries(colorAssignments)) {
|
||||
if (targets[targetName] && colors && colors[colorName]) {
|
||||
// Get the selector for this target
|
||||
const selector = targets[targetName];
|
||||
const targetElements = doc.querySelectorAll(selector);
|
||||
// Get the actual color value for this target
|
||||
const targetColor = colors[colorName];
|
||||
|
||||
// Apply the color to all elements matching this selector
|
||||
targetElements.forEach(el => {
|
||||
// Always override fill and stroke unless they are 'none'
|
||||
if (el.hasAttribute("fill") && el.getAttribute("fill") !== "none") {
|
||||
el.setAttribute("fill", targetColor);
|
||||
}
|
||||
if (el.hasAttribute("stroke") && el.getAttribute("stroke") !== "none") {
|
||||
el.setAttribute("stroke", targetColor);
|
||||
}
|
||||
if (!el.hasAttribute("fill") && !el.hasAttribute("stroke")) {
|
||||
// If neither, prefer fill
|
||||
el.setAttribute("fill", targetColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Otherwise, use the legacy format for backward compatibility
|
||||
else {
|
||||
let targetElements;
|
||||
if (colorConfig.selector) {
|
||||
targetElements = doc.querySelectorAll(colorConfig.selector);
|
||||
} else if (colorConfig.target) {
|
||||
targetElements = doc.querySelectorAll(colorConfig.target);
|
||||
} else {
|
||||
targetElements = [];
|
||||
}
|
||||
targetElements.forEach((el) => {
|
||||
if (colorConfig.attribute) {
|
||||
// Legacy: force a single attribute
|
||||
el.setAttribute(colorConfig.attribute, color);
|
||||
} else {
|
||||
// Always override fill and stroke unless they are 'none'
|
||||
if (el.hasAttribute("fill") && el.getAttribute("fill") !== "none") {
|
||||
el.setAttribute("fill", color);
|
||||
}
|
||||
if (el.hasAttribute("stroke") && el.getAttribute("stroke") !== "none") {
|
||||
el.setAttribute("stroke", color);
|
||||
}
|
||||
if (!el.hasAttribute("fill") && !el.hasAttribute("stroke")) {
|
||||
// If neither, prefer fill
|
||||
el.setAttribute("fill", color);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
svgHtml = doc.documentElement.outerHTML;
|
||||
}
|
||||
|
||||
$: path, color, colorConfig, fetchAndColorSvg();
|
||||
$: path, color, colorConfig, targets, sets, activeSet, colors, fetchAndColorSvg();
|
||||
</script>
|
||||
|
||||
{@html svgHtml}
|
||||
|
||||
@@ -98,6 +98,10 @@
|
||||
? logo._activeColor || getLogoThemeColor(logo)
|
||||
: undefined}
|
||||
colorConfig={logo.colors ? logo.colorConfig : undefined}
|
||||
targets={logo.targets}
|
||||
sets={logo.sets}
|
||||
colors={logo.colors}
|
||||
activeSet={logo._activeSet}
|
||||
alt={logo.name}
|
||||
/>
|
||||
{:else}
|
||||
@@ -142,20 +146,43 @@
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
{#each logo.colors as colorObj}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorObj.label}
|
||||
style={`background:${colorObj.value}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() =>
|
||||
(logo._activeColor = colorObj.value)}
|
||||
on:keydown|stopPropagation={(e) =>
|
||||
(e.key === "Enter" || e.key === " ") &&
|
||||
(logo._activeColor = colorObj.value)}
|
||||
></span>
|
||||
{/each}
|
||||
{#if logo.sets}
|
||||
{#each Object.entries(logo.sets) as [setName, setConfig], i}
|
||||
<span
|
||||
class="color-circle set-circle"
|
||||
title={`Color Set ${i + 1}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}}
|
||||
on:keydown|stopPropagation={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</span>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each Object.entries(logo.colors) as [colorName, colorValue]}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorName.replace('_', ' ')}
|
||||
style={`background:${colorValue}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() =>
|
||||
(logo._activeColor = colorValue)}
|
||||
on:keydown|stopPropagation={(e) =>
|
||||
(e.key === "Enter" || e.key === " ") &&
|
||||
(logo._activeColor = colorValue)}
|
||||
></span>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -271,4 +298,19 @@
|
||||
justify-content: space-between;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.set-circle {
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Dark theme variation */
|
||||
:global(.dark-theme) .set-circle {
|
||||
background: #444;
|
||||
color: #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -141,6 +141,10 @@
|
||||
path={logo.path}
|
||||
color={logo.colors ? (logo._activeColor || getLogoThemeColor(logo)) : undefined}
|
||||
colorConfig={validColorConfig}
|
||||
targets={logo.targets}
|
||||
sets={logo.sets}
|
||||
colors={logo.colors}
|
||||
activeSet={logo._activeSet}
|
||||
alt={logo.name}
|
||||
/>
|
||||
{:else}
|
||||
@@ -166,17 +170,40 @@
|
||||
<path d="M682.843,117.843l-565.686,565.685c-156.209,-156.21 -156.209,-409.476 0,-565.685c156.21,-156.21 409.476,-156.21 565.686,-0Z" style="fill:#33363f;"/>
|
||||
</svg>
|
||||
</span>
|
||||
{#each logo.colors as colorObj}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorObj.label}
|
||||
style={`background:${colorObj.value}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => logo._activeColor = colorObj.value}
|
||||
on:keydown|stopPropagation={(e) => (e.key === 'Enter' || e.key === ' ') && (logo._activeColor = colorObj.value)}
|
||||
></span>
|
||||
{/each}
|
||||
{#if logo.sets}
|
||||
{#each Object.entries(logo.sets) as [setName, setConfig], i}
|
||||
<span
|
||||
class="color-circle set-circle"
|
||||
title={`Color Set ${i + 1}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}}
|
||||
on:keydown|stopPropagation={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
logo._activeColor = Object.values(logo.colors)[i % Object.keys(logo.colors).length];
|
||||
logo._activeSet = setName;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</span>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each Object.entries(logo.colors) as [colorName, colorValue]}
|
||||
<span
|
||||
class="color-circle"
|
||||
title={colorName.replace('_', ' ')}
|
||||
style={`background:${colorValue}`}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
on:click|stopPropagation={() => logo._activeColor = colorValue}
|
||||
on:keydown|stopPropagation={(e) => (e.key === 'Enter' || e.key === ' ') && (logo._activeColor = colorValue)}
|
||||
></span>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if logo.brand}
|
||||
@@ -198,6 +225,21 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.set-circle {
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:global(.dark-theme) .set-circle {
|
||||
background: #444;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.modal-backdrop.fullscreen {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
@@ -316,6 +358,22 @@
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.set-circle {
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Dark theme variation */
|
||||
:global(.dark-theme) .set-circle {
|
||||
background: #444;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.modal-body.fullscreen-body {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
// Utility to pick the logo color for the current theme using the "theme" key only
|
||||
export function getDefaultLogoColor(colors, theme = 'light') {
|
||||
if (!colors || colors.length === 0) return undefined;
|
||||
// Use the color with the matching theme key if present
|
||||
const match = colors.find(c => c.theme === theme);
|
||||
if (match) return match.value;
|
||||
if (!colors || Object.keys(colors).length === 0) return undefined;
|
||||
|
||||
// Look through all colors to find one with a theme property
|
||||
for (const [colorName, colorValue] of Object.entries(colors)) {
|
||||
// If color value is an object with theme property matching current theme
|
||||
if (typeof colorValue === 'object' && colorValue.theme === theme) {
|
||||
return colorValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: do not colorize (undefined)
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Utility to select the color with the matching theme key from the colors array
|
||||
// Utility to select the color with the matching theme key from the colors object
|
||||
export function getThemeColor(colors, theme = 'light') {
|
||||
if (!colors || colors.length === 0) return undefined;
|
||||
// Try to find a color with the matching theme key
|
||||
const match = colors.find(c => c.theme === theme);
|
||||
if (match) return match.value;
|
||||
if (!colors || Object.keys(colors).length === 0) return undefined;
|
||||
|
||||
// Look through all colors to find one with a theme property
|
||||
for (const [colorName, colorValue] of Object.entries(colors)) {
|
||||
// If color value is an object with theme property matching current theme
|
||||
if (typeof colorValue === 'object' && colorValue.theme === theme) {
|
||||
return colorValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: pick the first color
|
||||
return colors[0].value;
|
||||
return Object.values(colors)[0];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user