Implemented InlineSvg component to fetch and color SVG logos dynamically.

This commit is contained in:
sHa
2025-04-29 12:16:41 +03:00
parent 69f6f30cb3
commit 3d90d9b0da
9 changed files with 380 additions and 34 deletions

View File

@@ -0,0 +1,25 @@
<script>
import { onMount } from 'svelte';
export let path;
export let color;
export let colorConfig = { target: 'path', attribute: 'fill' };
let svgHtml = '';
async function fetchAndColorSvg() {
const res = await fetch(path);
let text = await res.text();
// Parse and update color
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'image/svg+xml');
const targets = doc.querySelectorAll(colorConfig.selector || colorConfig.target);
targets.forEach(el => {
el.setAttribute(colorConfig.attribute, color);
});
svgHtml = doc.documentElement.outerHTML;
}
$: path, color, colorConfig, fetchAndColorSvg();
</script>
{@html svgHtml}

View File

@@ -1,6 +1,8 @@
<script>
import LogoModal from './LogoModal.svelte';
import LogoActions from './LogoActions.svelte';
import InlineSvg from './InlineSvg.svelte';
import { onMount } from 'svelte';
export let logos = [];
export let onCopy;
@@ -17,6 +19,21 @@
function closeModal() {
showModal = false;
}
function isSvgLogo(logo) {
return logo.format && logo.format.toLowerCase() === 'svg';
}
// Inline SVG logic for color switching
let svgCache = {};
async function fetchInlineSvg(path) {
if (svgCache[path]) return svgCache[path];
const res = await fetch(path);
const text = await res.text();
svgCache[path] = text;
return text;
}
</script>
<LogoModal show={showModal} logo={selectedLogo} on:close={closeModal} />
@@ -32,11 +49,38 @@
on:keydown={(e) => (e.key === 'Enter' || e.key === ' ') && openPreview(logo)}
style="cursor:pointer;"
>
<img src={logo.path} alt={logo.name} />
{#if isSvgLogo(logo) && logo.colors}
<InlineSvg path={logo.path} color={logo._activeColor || logo.colors[0].value} colorConfig={logo.colorConfig} alt={logo.name} />
{:else}
<img src={logo.path} alt={logo.name} />
{/if}
</div>
<div class="logo-info">
<h3>{logo.name}</h3>
<p>Format: {logo.format}</p>
<div class="format-row">
<span><strong>Format:</strong> {logo.format}</span>
{#if isSvgLogo(logo) && logo.colors}
<span class="color-switcher-inline">
{#each logo.colors as colorObj}
<span
class="color-circle"
title={colorObj.label}
style="background:{colorObj.value}"
tabindex="0"
role="button"
aria-label={"Switch color to " + colorObj.label}
on:click|stopPropagation={() => logo._activeColor = colorObj.value}
on:keydown|stopPropagation={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
logo._activeColor = colorObj.value;
e.preventDefault();
}
}}
></span>
{/each}
</span>
{/if}
</div>
<div class="logo-actions">
<LogoActions {logo} {onCopy} {onDownload} />
</div>
@@ -77,13 +121,27 @@
cursor: pointer;
transition: background 0.2s, color 0.2s;
}
.logo-image img {
.logo-image img,
.logo-image :global(svg) {
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
object-fit: contain;
object-position: center;
display: block;
margin: 0 auto;
}
/* Make inline SVGs scale and fit like <img> */
.logo-image svg {
max-width: 80%;
max-height: 80%;
width: auto !important;
height: auto !important;
object-fit: contain;
object-position: center;
display: block;
margin: 0 auto;
}
.logo-info {
padding: 1rem;
@@ -96,21 +154,71 @@
margin-bottom: 0.5rem;
color: var(--color-accent, #4f8cff);
}
.logo-info p {
font-size: 0.9rem;
color: var(--color-text);
margin-bottom: 1rem;
}
/* .logo-info p { font-size: 0.9rem; color: var(--color-text); margin-bottom: 1rem; } */
.logo-actions {
display: flex;
align-items: center;
gap: 0.5em;
flex-wrap: nowrap;
}
.format-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1em;
margin-bottom: 0.5em;
}
.color-switcher-inline {
display: flex;
gap: 0.4em;
align-items: center;
margin-left: auto;
}
.color-switcher {
display: flex;
gap: 0.4em;
margin: 0.5em 0 0.5em 0;
align-items: center;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #eee;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
cursor: pointer;
display: inline-block;
transition: border 0.2s, box-shadow 0.2s;
}
.color-circle:hover {
border: 2px solid #888;
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.no-results {
grid-column: 1 / -1;
text-align: center;
padding: 2rem;
color: #666;
}
.color-switcher {
display: flex;
gap: 0.4em;
margin: 0.5em 0 0.5em 0;
align-items: center;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #eee;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
cursor: pointer;
display: inline-block;
transition: border 0.2s, box-shadow 0.2s;
}
.color-circle:hover {
border: 2px solid #888;
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
</style>

View File

@@ -1,6 +1,7 @@
<script>
import LogoModal from './LogoModal.svelte';
import LogoActions from './LogoActions.svelte';
import InlineSvg from './InlineSvg.svelte';
export let logos = [];
export let onCopy;
@@ -18,6 +19,10 @@
showModal = false;
}
function isSvgLogo(logo) {
return logo.format && logo.format.toLowerCase() === 'svg';
}
</script>
<LogoModal show={showModal} logo={selectedLogo} on:close={closeModal} />
@@ -33,11 +38,39 @@
on:keydown={(e) => (e.key === 'Enter' || e.key === ' ') && openPreview(logo)}
style="cursor:pointer;"
>
<img src={logo.path} alt={logo.name} />
>
{#if isSvgLogo(logo) && logo.colors}
<InlineSvg path={logo.path} color={logo._activeColor || logo.colors[0].value} colorConfig={logo.colorConfig} alt={logo.name} />
{:else}
<img src={logo.path} alt={logo.name} />
{/if}
</div>
<div class="logo-info">
<h3>{logo.name}</h3>
<p>Format: {logo.format}</p>
<div class="format-row">
<span><strong>Format:</strong> {logo.format}</span>
</div>
{#if isSvgLogo(logo) && logo.colors}
<div class="color-switcher-under">
{#each logo.colors as colorObj}
<span
class="color-circle"
title={colorObj.label}
style="background:{colorObj.value}"
tabindex="0"
role="button"
aria-label={"Set color " + colorObj.label}
on:click|stopPropagation={() => logo._activeColor = colorObj.value}
on:keydown|stopPropagation={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
logo._activeColor = colorObj.value;
e.preventDefault();
}
}}
></span>
{/each}
</div>
{/if}
</div>
<div class="logo-actions">
<LogoActions {logo} {onCopy} {onDownload} />
@@ -82,6 +115,26 @@
object-fit: contain;
object-position: center;
}
.color-switcher {
display: flex;
gap: 0.4em;
margin: 0.5em 0 0.5em 0;
align-items: center;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #eee;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
cursor: pointer;
display: inline-block;
transition: border 0.2s, box-shadow 0.2s;
}
.color-circle:hover {
border: 2px solid #888;
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.logo-info {
background: var(--color-card);
color: var(--color-text);
@@ -93,11 +146,7 @@
margin-bottom: 0.5rem;
color: var(--color-accent, #4f8cff);
}
.logo-info p {
font-size: 0.9rem;
color: var(--color-text);
margin-bottom: 1rem;
}
/* .logo-info p { font-size: 0.9rem; color: var(--color-text); margin-bottom: 1rem; } */
.logo-actions {
display: flex;
align-items: center;
@@ -114,4 +163,17 @@
padding: 2rem;
color: #666;
}
.format-row {
display: flex;
align-items: center;
gap: 1em;
}
/* .color-switcher-inline { display: flex; gap: 0.4em; align-items: center; margin-left: auto; } */
.color-switcher-under {
display: flex;
gap: 0.4em;
align-items: center;
margin: 0.5em 0 0 0;
}
</style>

View File

@@ -1,5 +1,6 @@
<script>
import { onMount, onDestroy, createEventDispatcher } from 'svelte';
import InlineSvg from './InlineSvg.svelte';
export let show = false;
export let logo = null;
@@ -16,6 +17,10 @@
}
}
function isSvgLogo(logo) {
return logo && logo.format && logo.format.toLowerCase() === 'svg';
}
onMount(() => {
document.addEventListener('keydown', handleKeydown);
});
@@ -44,10 +49,29 @@
on:keydown={(e) => (e.key === 'Enter' || e.key === ' ') && close()}
style="cursor:pointer;"
>
<img src={logo.path} alt={logo.name} />
{#if isSvgLogo(logo) && logo.colors}
<InlineSvg path={logo.path} color={logo._activeColor || logo.colors[0].value} colorConfig={logo.colorConfig} alt={logo.name} />
{:else}
<img src={logo.path} alt={logo.name} />
{/if}
</div>
<div class="logo-details">
<p><strong>Format:</strong> {logo.format}</p>
{#if isSvgLogo(logo) && logo.colors}
<div class="color-switcher-preview">
{#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}
</div>
{/if}
<p><strong>Format:</strong> <span>{logo.format}</span></p>
<p><strong>Path:</strong> {logo.path}</p>
{#if logo.tags && logo.tags.length}
<div class="logo-tags">
@@ -119,8 +143,11 @@
background-color: var(--color-card);
border-radius: 4px;
padding: 2rem;
min-height: 300px;
min-height: 200px;
max-height: 60vh;
max-width: 100%;
transition: background 0.2s, color 0.2s;
overflow: auto;
}
.preview-container img {
@@ -129,6 +156,33 @@
object-fit: contain;
}
/* .color-switcher { display: flex; gap: 0.4em; margin: 0.5em 0 0.5em 0; align-items: center; } */
.color-switcher-inline {
display: flex;
gap: 0.4em;
align-items: center;
margin-left: auto;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #eee;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
cursor: pointer;
display: inline-block;
transition: border 0.2s, box-shadow 0.2s;
}
.color-circle:hover {
border: 2px solid #888;
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
/* .format-row { display: flex; align-items: center; justify-content: space-between; gap: 1em; margin-bottom: 0.5em; } */
.logo-details {
padding: 1rem;
background-color: var(--color-card);
@@ -159,4 +213,42 @@
letter-spacing: 0.02em;
transition: background 0.2s;
}
/* .color-switcher-under { display: flex; gap: 0.4em; align-items: center; margin: 0.5em 0 0 0; } */
.color-switcher-inline {
display: flex;
gap: 0.4em;
align-items: center;
margin-left: auto;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #eee;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
cursor: pointer;
display: inline-block;
transition: border 0.2s, box-shadow 0.2s;
}
.color-circle:hover {
border: 2px solid #888;
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.format-value {
font-weight: 400;
margin-left: 0.3em;
}
.color-switcher-preview {
display: flex;
justify-content: center;
gap: 0.4em;
align-items: center;
margin: 1em 0 0.5em 0;
}
</style>