Files
personal-website/src/lib/world-opinions/CountryPanel.svelte
Stan Runge afb1f191df
All checks were successful
Test and deploy staging / staging (push) Successful in 1m49s
add world opinions project
World map with switchable layers (what "liberal" means, what left vs right
is about, traditional/secular and survival/self-expression values), country
cards, a shared-scale party compass, a values scatter and national
narratives of major events.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 16:24:40 +00:00

96 lines
3.2 KiB
Svelte

<script lang="ts">
import EyeOff from 'lucide-svelte/icons/eye-off';
import Swords from 'lucide-svelte/icons/swords';
import { countryById, divides, liberalMeanings, profileById, regions } from './data';
let { id }: { id: string } = $props();
let country = $derived(countryById.get(id));
let profile = $derived(profileById.get(id));
const colors: Record<string, string> = {
left: 'var(--wo-s1)',
market: 'var(--wo-s2)',
western: 'var(--wo-s3)',
economy: 'var(--wo-s1)',
culture: 'var(--wo-s2)',
history: 'var(--wo-s3)',
none: 'var(--wo-none)'
};
// Map a -2.5…2.5 score onto the gauge.
const position = (value: number) => `${Math.min(Math.max((value + 2.5) / 5, 0), 1) * 100}%`;
</script>
{#if country}
<div class="wo-card">
<div class="mb-4 flex flex-wrap items-baseline justify-between gap-2">
<h3 class="text-2xl font-semibold">{country.name}</h3>
<span class="text-sm text-[var(--site-muted)]">{regions[country.region]}</span>
</div>
{#if profile}<p class="mb-5 text-lg">{profile.center}</p>{/if}
<div class="grid gap-6 md:grid-cols-2">
<div class="space-y-4">
{#if country.values}
{#each [{ label: ['traditional', 'secular'], value: country.values.y }, { label: ['survival', 'self-expression'], value: country.values.x }] as gauge (gauge.label[0])}
<div>
<div class="wo-gauge" aria-hidden="true">
<span class="wo-gauge-marker" style:left={position(gauge.value)}></span>
</div>
<div class="mt-1 flex justify-between text-xs text-[var(--site-muted)]">
<span>{gauge.label[0]}</span><span>{gauge.label[1]}</span>
</div>
<span class="sr-only">{gauge.label[0]} to {gauge.label[1]}: {gauge.value}</span>
</div>
{/each}
{/if}
<div class="flex flex-wrap gap-2 text-sm">
{#if country.liberal}
<span class="wo-tag"
><span class="wo-swatch" style:background={colors[country.liberal]}></span>"liberal" = {liberalMeanings[
country.liberal
]}</span
>
{/if}
{#if country.divide}
<span class="wo-tag"
><span class="wo-swatch" style:background={colors[country.divide]}></span>left vs
right: {divides[country.divide]}</span
>
{/if}
</div>
</div>
{#if profile}
<div class="space-y-4">
<div class="flex flex-wrap items-center gap-2">
<span class="wo-tag-label"><Swords size={16} aria-hidden="true" />fights over</span>
{#each profile.fights as fight (fight)}
<span class="wo-tag">{fight}</span>
{/each}
</div>
<div class="flex flex-wrap items-center gap-2">
<span class="wo-tag-label"><EyeOff size={16} aria-hidden="true" />blind spots</span>
{#each profile.blindSpots as spot (spot)}
<span class="wo-tag wo-tag-dashed">{spot}</span>
{/each}
</div>
</div>
{/if}
</div>
{#if profile}
<ol class="wo-timeline mt-8" aria-label="History that shaped it">
{#each profile.timeline as moment (moment.year)}
<li>
<span class="wo-timeline-year">{moment.year}</span>
<span class="wo-timeline-dot" aria-hidden="true"></span>
<span class="wo-timeline-label">{moment.label}</span>
</li>
{/each}
</ol>
{/if}
</div>
{/if}