feat: scaffold blueprints SPA with List functional-blueprint illustration

This commit is contained in:
Julien Calixte
2026-07-02 18:12:20 +02:00
commit 4405497658
27 changed files with 5108 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
<script setup lang="ts">
import { computed } from "vue"
import { COMP_CAPS, COMP_FUNCS, COMP_LINKS } from "@/data/listBlueprint"
const PAL = {
boxFill: "#103763",
boxStroke: "#3d5f85",
ink: "#dbe9f7",
inkFaint: "#4f7099",
cyan: "#8fd0ff",
amber: "#ffb84d",
}
const W = 640
const lx = 24
const lw = 170
const rx = 446
const rw = 170
const bh = 34
const top = 16
const lstep = 40
const rstep = 52
const H = top + COMP_CAPS.length * lstep + 16
const capY = (i: number) => top + i * lstep + bh / 2
const funcY = (i: number) => top + i * rstep + bh / 2
const capIndex = computed(
() => Object.fromEntries(COMP_CAPS.map((c, i) => [c.id, i])) as Record<string, number>,
)
const funcIndex = computed(
() => Object.fromEntries(COMP_FUNCS.map((f, i) => [f, i])) as Record<string, number>,
)
const leftBoxes = computed(() =>
COMP_CAPS.map((c, i) => ({ ...c, x: lx, y: capY(i) - bh / 2, w: lw, h: bh })),
)
const rightBoxes = computed(() =>
COMP_FUNCS.map((f, i) => ({ label: f, x: rx, y: funcY(i) - bh / 2, w: rw, h: bh })),
)
const edges = computed(() =>
COMP_LINKS.map(([a, b]) => {
const y1 = capY(capIndex.value[a])
const y2 = funcY(funcIndex.value[b])
const x1 = lx + lw
const x2 = rx
const mx = (x1 + x2) / 2
const color = a === "core" ? PAL.inkFaint : PAL.cyan
return {
key: `${a}-${b}`,
d: `M${x1} ${y1} C ${mx} ${y1}, ${mx} ${y2}, ${x2} ${y2}`,
color,
x2,
y2,
}
}),
)
</script>
<template>
<svg :viewBox="`0 0 ${W} ${H}`" role="img" aria-label="Composition map" class="schematic">
<path
v-for="e in edges"
:key="e.key"
:d="e.d"
fill="none"
stroke-width="1.4"
:stroke="e.color"
opacity="0.55"
/>
<circle v-for="e in edges" :key="`c-${e.key}`" :cx="e.x2" :cy="e.y2" r="2.4" :fill="e.color" />
<g v-for="b in leftBoxes" :key="b.id">
<rect
:x="b.x"
:y="b.y"
:width="b.w"
:height="b.h"
rx="2"
:fill="PAL.boxFill"
:stroke="b.core ? PAL.amber : PAL.boxStroke"
stroke-width="1.5"
/>
<text :x="b.x + 12" :y="b.y + 15" :fill="PAL.ink" font-size="12">{{ b.label }}</text>
<text :x="b.x + 12" :y="b.y + 27" :fill="PAL.inkFaint" font-size="9.5">{{ b.sub }}</text>
</g>
<g v-for="b in rightBoxes" :key="b.label">
<rect
:x="b.x"
:y="b.y"
:width="b.w"
:height="b.h"
rx="2"
:fill="PAL.boxFill"
:stroke="PAL.amber"
stroke-width="1.5"
/>
<text :x="b.x + 12" :y="b.y + 21" :fill="PAL.amber" font-size="12">{{ b.label }}</text>
</g>
<text :x="lx" :y="H - 4" :fill="PAL.inkFaint" font-size="10" letter-spacing="1.5">
CAPABILITIES (compose onto host)
</text>
<text :x="rx" :y="H - 4" :fill="PAL.inkFaint" font-size="10" letter-spacing="1.5">
FUNCTIONS
</text>
</svg>
</template>
<style scoped>
.schematic {
display: block;
max-width: 100%;
height: auto;
margin: 0 auto;
font-family: var(--font-mono);
}
</style>