mirror of
https://github.com/shadoll/sLogos.git
synced 2026-02-04 02:53:22 +00:00
Add CountryMap component to display highlighted countries on the world map
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import CountryMap from "./CountryMap.svelte";
|
||||||
import { onMount, getContext } from "svelte";
|
import { onMount, getContext } from "svelte";
|
||||||
import InlineSvg from "./InlineSvg.svelte";
|
import InlineSvg from "./InlineSvg.svelte";
|
||||||
import Actions from "./Actions.svelte";
|
import Actions from "./Actions.svelte";
|
||||||
import ColorSwitcher from "./ColorSwitcher.svelte";
|
import ColorSwitcher from "./ColorSwitcher.svelte";
|
||||||
import { getDefaultLogoColor, getThemeColor } from "../utils/colorTheme.js";
|
import { getDefaultLogoColor, getThemeColor } from "../utils/colorTheme.js";
|
||||||
import { fetchSvgSource } from "../utils/svgSource.js";
|
import { fetchSvgSource } from "../utils/svgSource.js";
|
||||||
import { collections } from '../collections.js';
|
import { collections } from "../collections.js";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
export let show = false;
|
export let show = false;
|
||||||
export let logo = null;
|
export let logo = null;
|
||||||
@@ -109,11 +110,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the current collection context for baseDir
|
// Use the current collection context for baseDir
|
||||||
let collection = getContext('collection');
|
let collection = getContext("collection");
|
||||||
if (!collection) {
|
if (!collection) {
|
||||||
// fallback: try to infer from window.appData
|
// fallback: try to infer from window.appData
|
||||||
if (typeof window !== 'undefined' && window.appData && window.appData.collection) {
|
if (
|
||||||
collection = collections.find(c => c.name === window.appData.collection) || collections[0];
|
typeof window !== "undefined" &&
|
||||||
|
window.appData &&
|
||||||
|
window.appData.collection
|
||||||
|
) {
|
||||||
|
collection =
|
||||||
|
collections.find((c) => c.name === window.appData.collection) ||
|
||||||
|
collections[0];
|
||||||
} else {
|
} else {
|
||||||
collection = collections[0];
|
collection = collections[0];
|
||||||
}
|
}
|
||||||
@@ -137,7 +144,7 @@
|
|||||||
<div class="header-spacer"></div>
|
<div class="header-spacer"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="preview-body">
|
<div class="preview-body">
|
||||||
<div class="preview-container" >
|
<div class="preview-container">
|
||||||
{#if isSvgLogo(logo)}
|
{#if isSvgLogo(logo)}
|
||||||
<InlineSvg
|
<InlineSvg
|
||||||
bind:this={inlineSvgRef}
|
bind:this={inlineSvgRef}
|
||||||
@@ -157,48 +164,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="right-column">
|
<div class="right-column">
|
||||||
<!-- Country flag section for logos with 'Country' tag and ISO code -->
|
{#if logo.tags && logo.tags.some((tagObj) => (tagObj.text || tagObj) === "Country") && logo.meta && logo.meta["ISO code"]}
|
||||||
{#if logo.tags && logo.tags.some(tagObj => (tagObj.text || tagObj) === 'Country') && logo.meta && logo.meta["ISO code"]}
|
<CountryMap countryCodes={[logo.meta["ISO code"]]} countryNames={[logo.meta["country"]]} />
|
||||||
<div class="country-map-section">
|
|
||||||
<h3 style="margin-bottom:0.5em;">Country</h3>
|
|
||||||
<div class="country-meta">
|
|
||||||
<strong>ISO code:</strong> <span>{logo.meta["ISO code"]}</span>
|
|
||||||
</div>
|
|
||||||
<InlineSvg
|
|
||||||
path="/data/world.svg"
|
|
||||||
alt="World map with highlighted country"
|
|
||||||
bind:this={inlineSvgRef}
|
|
||||||
color={undefined}
|
|
||||||
/>
|
|
||||||
<style>
|
|
||||||
.country-map-section {
|
|
||||||
background: var(--color-card);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 1rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
box-shadow: 0 2px 8px 2px rgba(0,0,0,0.08);
|
|
||||||
}
|
|
||||||
.country-meta {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
.country-map-section .svg-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 180px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: var(--color-bg);
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.04);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{@html `<style>
|
|
||||||
.country-map-section .svg-wrapper svg #${logo.meta["ISO code"]} {
|
|
||||||
fill: #4f8cff !important;
|
|
||||||
stroke: #222 !important;
|
|
||||||
filter: drop-shadow(0 0 4px #4f8cff44);
|
|
||||||
}
|
|
||||||
</style>`}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="logo-details fullscreen-details">
|
<div class="logo-details fullscreen-details">
|
||||||
@@ -223,10 +190,24 @@
|
|||||||
<div class="logo-meta">
|
<div class="logo-meta">
|
||||||
{#each Object.entries(logo.meta) as [key, value]}
|
{#each Object.entries(logo.meta) as [key, value]}
|
||||||
<p>
|
<p>
|
||||||
{#if typeof value === 'string' && value.startsWith('https://')}
|
{#if typeof value === "string" && value.startsWith("https://")}
|
||||||
<a class="meta-link" href={value} target="_blank" rel="noopener noreferrer">
|
<a
|
||||||
|
class="meta-link"
|
||||||
|
href={value}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
{capitalizeFirst(key)}
|
{capitalizeFirst(key)}
|
||||||
<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m6 1h5v5l-2.14-2.15-4.16 4.15-.7-.7 4.15-4.16zm-4 2h2v1h-2v6h6v-2h1v2a1 1 0 0 1 -1 1h-6a1 1 0 0 1 -1-1v-6a1 1 0 0 1 1-1" fill="currentColor"/></svg>
|
<svg
|
||||||
|
height="12"
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
width="12"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
><path
|
||||||
|
d="m6 1h5v5l-2.14-2.15-4.16 4.15-.7-.7 4.15-4.16zm-4 2h2v1h-2v6h6v-2h1v2a1 1 0 0 1 -1 1h-6a1 1 0 0 1 -1-1v-6a1 1 0 0 1 1-1"
|
||||||
|
fill="currentColor"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<strong>{capitalizeFirst(key)}:</strong>
|
<strong>{capitalizeFirst(key)}:</strong>
|
||||||
@@ -359,7 +340,6 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
box-shadow: 0 2px 16px 4px rgba(0, 0, 0, 0.18);
|
box-shadow: 0 2px 16px 4px rgba(0, 0, 0, 0.18);
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
}
|
||||||
.logo-tags {
|
.logo-tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -530,4 +510,5 @@
|
|||||||
.logo-details span {
|
.logo-details span {
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
85
src/components/CountryMap.svelte
Normal file
85
src/components/CountryMap.svelte
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<script>
|
||||||
|
import { afterUpdate, onMount } from "svelte";
|
||||||
|
import InlineSvg from "./InlineSvg.svelte";
|
||||||
|
export let countryCodes = [];
|
||||||
|
export let countryNames = [];
|
||||||
|
export let mapPath = "/data/world.svg";
|
||||||
|
let wrapperRef;
|
||||||
|
|
||||||
|
// Highlight countries after SVG loads, using MutationObserver for reliability
|
||||||
|
let observer;
|
||||||
|
function highlightCountries() {
|
||||||
|
if (!wrapperRef) return;
|
||||||
|
const svgEl = wrapperRef.querySelector("svg");
|
||||||
|
if (!svgEl) return;
|
||||||
|
// Highlight by country code (id)
|
||||||
|
countryCodes.forEach((code) => {
|
||||||
|
const countryPath = svgEl.querySelector(`#${code}`);
|
||||||
|
if (countryPath) {
|
||||||
|
countryPath.setAttribute("fill", "#4f8cff");
|
||||||
|
countryPath.setAttribute("stroke", "#222");
|
||||||
|
countryPath.style.filter = "drop-shadow(0 0 4px #4f8cff44)";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Highlight by country name (name attribute)
|
||||||
|
const names = Array.isArray(countryNames) ? countryNames : countryNames ? [countryNames] : [];
|
||||||
|
names.forEach((name) => {
|
||||||
|
// Find all elements with matching name attribute or class name
|
||||||
|
console.log(`Highlighting country: ${name}`);
|
||||||
|
const pathsByName = svgEl.querySelectorAll(`[name='${name}']`);
|
||||||
|
const pathsByClass = svgEl.querySelectorAll(`.${name.replace(/ /g, '.')}`);
|
||||||
|
const allPaths = [...pathsByName, ...pathsByClass];
|
||||||
|
console.log(`Found paths for ${name}:`, allPaths, `(${allPaths.length})`);
|
||||||
|
allPaths.forEach((countryPath) => {
|
||||||
|
countryPath.setAttribute("fill", "#4f8cff");
|
||||||
|
countryPath.setAttribute("stroke", "#222");
|
||||||
|
countryPath.style.filter = "drop-shadow(0 0 4px #4f8cff44)";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function observeSvg() {
|
||||||
|
if (!wrapperRef) return;
|
||||||
|
if (observer) observer.disconnect();
|
||||||
|
observer = new MutationObserver(() => {
|
||||||
|
highlightCountries();
|
||||||
|
});
|
||||||
|
observer.observe(wrapperRef, { childList: true, subtree: true });
|
||||||
|
// Initial run in case SVG is already present
|
||||||
|
highlightCountries();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
observeSvg();
|
||||||
|
return () => {
|
||||||
|
if (observer) observer.disconnect();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
observeSvg();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="country-map-section">
|
||||||
|
<div class="svg-wrapper" bind:this={wrapperRef}>
|
||||||
|
<InlineSvg path={mapPath} alt="World map" color={undefined} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.country-map-section {
|
||||||
|
background: var(--color-card);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1rem;
|
||||||
|
box-shadow: 0 2px 8px 2px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
.svg-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 180px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: var(--color-bg);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user