206 lines
4.2 KiB
Vue
206 lines
4.2 KiB
Vue
<script setup>
|
|
import { ref, watch } from 'vue'
|
|
import { fetchElements } from '../api.js'
|
|
import { renderMarkdown } from '../markdown.js'
|
|
|
|
const props = defineProps({
|
|
topic: { type: String, required: true },
|
|
version: { type: Number, default: 0 }, // Erhöhung = Elemente neu laden
|
|
})
|
|
|
|
const emit = defineEmits(['open'])
|
|
|
|
const elements = ref([])
|
|
|
|
watch([() => props.topic, () => props.version], load, { immediate: true })
|
|
|
|
async function load() {
|
|
try {
|
|
elements.value = await fetchElements(props.topic)
|
|
} catch (e) {
|
|
console.error('Fehler beim Laden der Elemente:', e)
|
|
}
|
|
}
|
|
|
|
function plain(text) {
|
|
return (text || '').replace(/```[a-z]*\n?/g, '').replace(/[`*_#]/g, '')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="elements-overview">
|
|
<div class="overview-scroll">
|
|
<div class="overview-content">
|
|
<header class="overview-head">
|
|
<h1>{{ topic }}</h1>
|
|
<span class="overview-format">Elemente</span>
|
|
</header>
|
|
<p v-if="!elements.length" class="overview-empty">
|
|
Noch keine Elemente. Rechts in der Sidebar Stichwort eingeben und + klicken.
|
|
</p>
|
|
<div class="element-grid">
|
|
<article
|
|
v-for="el in elements"
|
|
:key="el.id"
|
|
class="element-card"
|
|
@click="emit('open', el)"
|
|
>
|
|
<h3>{{ plain(el.title) }}</h3>
|
|
<div class="markdown" v-html="renderMarkdown(el.description)"></div>
|
|
<div v-for="(ex, i) in el.examples" :key="i" class="markdown el-example" v-html="renderMarkdown(ex)"></div>
|
|
<div v-if="el.hints.length" class="el-hints-block">
|
|
<h4>Hinweise</h4>
|
|
<ul>
|
|
<li v-for="(h, i) in el.hints" :key="i" class="markdown" v-html="renderMarkdown(h)"></li>
|
|
</ul>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.elements-overview {
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--bg-preview);
|
|
}
|
|
|
|
.overview-scroll {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.overview-content {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 2.5rem 2rem 4rem;
|
|
}
|
|
|
|
.overview-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.8rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.overview-head h1 {
|
|
margin: 0;
|
|
font-size: 2.2rem;
|
|
color: var(--text);
|
|
}
|
|
|
|
.overview-format {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
.overview-empty {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.element-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
|
gap: 1rem;
|
|
align-items: start;
|
|
}
|
|
|
|
.element-card {
|
|
background: var(--panel);
|
|
border: 1px solid var(--border);
|
|
border-top: 3px solid var(--accent);
|
|
border-radius: 10px;
|
|
padding: 1rem 1.1rem;
|
|
cursor: pointer;
|
|
transition: box-shadow 0.15s, transform 0.15s;
|
|
}
|
|
|
|
.element-card:hover {
|
|
box-shadow: 0 4px 16px var(--shadow);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.element-card h3 {
|
|
margin: 0 0 0.5rem;
|
|
font-size: 1.05rem;
|
|
color: var(--text);
|
|
}
|
|
|
|
.el-example {
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.el-hints-block {
|
|
margin-top: 0.7rem;
|
|
}
|
|
|
|
.el-hints-block h4 {
|
|
margin: 0 0 0.3rem;
|
|
font-size: 0.72rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
.el-hints-block ul {
|
|
margin: 0;
|
|
padding-left: 1.1rem;
|
|
}
|
|
|
|
.el-hints-block li {
|
|
font-size: 0.85rem;
|
|
line-height: 1.5;
|
|
color: var(--text);
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
|
|
/* Markdown im Guide-Stil */
|
|
.markdown {
|
|
font-size: 0.9rem;
|
|
line-height: 1.55;
|
|
color: var(--text);
|
|
}
|
|
|
|
.markdown :deep(p) {
|
|
margin: 0 0 0.5em;
|
|
}
|
|
|
|
.markdown :deep(p:last-child) {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.markdown :deep(code) {
|
|
background: var(--border);
|
|
padding: 1px 4px;
|
|
border-radius: 4px;
|
|
font-family: "SF Mono", Consolas, monospace;
|
|
font-size: 0.85em;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.markdown :deep(pre) {
|
|
background: var(--code-bg, #1e2330);
|
|
color: var(--code-fg, #e6e8ee);
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
/* Umbrechen statt horizontal scrollen — Scrollbar verdeckt sonst die Code-Zeile */
|
|
white-space: pre-wrap;
|
|
overflow-wrap: anywhere;
|
|
margin: 0.4em 0;
|
|
}
|
|
|
|
.markdown :deep(pre code) {
|
|
background: none;
|
|
padding: 0;
|
|
color: inherit;
|
|
font-size: 0.85em;
|
|
}
|
|
</style>
|