Refactor the List-specific screen into a data-driven, reusable viewer: - generic Blueprint type + shared LoadState machine + registry - vue-router: / (gallery) and /b/:slug (illustration) - BlueprintViewer renders any blueprint; specimens stay bespoke - add Grid blueprint (6 functions incl. Position) + GridSpecimen
41 lines
929 B
Vue
41 lines
929 B
Vue
<script setup lang="ts">
|
|
import { computed } from "vue"
|
|
import { entryFor } from "@/data/blueprints"
|
|
import BlueprintViewer from "@/components/BlueprintViewer.vue"
|
|
|
|
const props = defineProps<{ slug: string }>()
|
|
const entry = computed(() => entryFor(props.slug))
|
|
</script>
|
|
|
|
<template>
|
|
<BlueprintViewer v-if="entry" :blueprint="entry.blueprint" :specimen="entry.specimen" />
|
|
<div v-else class="notfound">
|
|
<p>
|
|
No blueprint <code>{{ slug }}</code> is illustrated yet.
|
|
</p>
|
|
<RouterLink to="/" class="back">▸ back to the gallery</RouterLink>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.notfound {
|
|
max-width: 1180px;
|
|
margin: 0 auto;
|
|
padding: 60px 20px;
|
|
color: #9db8d2;
|
|
text-align: center;
|
|
}
|
|
.notfound code {
|
|
color: var(--color-accent);
|
|
}
|
|
.back {
|
|
display: inline-block;
|
|
margin-top: 14px;
|
|
color: var(--color-secondary);
|
|
text-decoration: none;
|
|
}
|
|
.back:hover {
|
|
text-decoration: underline;
|
|
}
|
|
</style>
|