New Responsive design

This commit is contained in:
2026-05-23 18:08:27 +02:00
parent 3fdbaf0285
commit 0d436d8190
19 changed files with 2152 additions and 607 deletions
+92 -56
View File
@@ -2,21 +2,20 @@
import { ref, shallowRef, onMounted } from "vue"
const props = defineProps({
tabs: {
type: Array,
required: true,
// [{ title: "Titel", component: Component, endpoint: "/wp-json/..." }]
},
subTabIndex: {
type: Number,
required: false,
default: 0
}
tabs: {
type: Array,
required: true,
},
subTabIndex: {
type: Number,
required: false,
default: 0
}
})
const activeTab = ref(null) // aktuell ausgewählter Tab
const tabData = ref({}) // Daten für jeden Tab
const tabComponent = shallowRef(null) // Komponente für aktuellen Tab
const activeTab = ref(null)
const tabData = ref({})
const tabComponent = shallowRef(null)
const loading = ref(false)
const error = ref(null)
@@ -34,13 +33,13 @@ async function selectTab(index) {
?.getAttribute('content')
const response = await fetch(tab.endpoint, {
method: 'GET', // oder POST, PUT, DELETE …
method: 'GET',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken,
'X-Requested-With': 'XMLHttpRequest',
},
credentials: 'same-origin', // wichtig für Session/Auth
credentials: 'same-origin',
})
if (!response.ok) throw new Error("Fehler: " + response.status)
@@ -56,65 +55,102 @@ async function selectTab(index) {
}
}
// ersten Tab automatisch laden
onMounted(() => {
if (props.tabs.length > 0) {
selectTab(props.subTabIndex)
}
if (props.tabs.length > 0) {
selectTab(props.subTabIndex)
}
})
</script>
<template>
<div class="tabs">
<!-- Tab Header -->
<div class="tab-header">
<button
v-for="(tab, index) in tabs"
:key="index"
:class="['tab-button', { active: activeTab === index }]"
@click="selectTab(index)"
>
{{ tab.title }}
</button>
</div>
<div class="tabs">
<div class="tab-header">
<button
v-for="(tab, index) in tabs"
:key="index"
:class="['tab-button', { active: activeTab === index }]"
@click="selectTab(index)"
>
{{ tab.title }}
</button>
</div>
<!-- Tab Content -->
<div class="tab-content" id="tab-content">
<div v-if="loading"> Lädt...</div>
<div v-else-if="error"> {{ error }}</div>
<component
v-else-if="tabComponent"
:is="tabComponent"
:data="tabData[activeTab]"
:deep_jump_id="tabs[activeTab].deep_jump_id"
:deep_jump_id_sub="tabs[activeTab].deep_jump_id_sub"
/>
<div class="tab-content" id="tab-content">
<div v-if="loading"> Lädt...</div>
<div v-else-if="error"> {{ error }}</div>
<component
v-else-if="tabComponent"
:is="tabComponent"
:data="tabData[activeTab]"
:deep_jump_id="tabs[activeTab].deep_jump_id"
:deep_jump_id_sub="tabs[activeTab].deep_jump_id_sub"
/>
</div>
</div>
</div>
</template>
<style scoped>
.tabs {
border: 1px solid #ddd;
border-radius: 8px;
border: 1px solid #ddd;
border-radius: 8px;
}
.tab-header {
display: flex;
border-bottom: 1px solid #ddd;
display: flex;
border-bottom: 1px solid #ddd;
flex-wrap: wrap;
gap: 2px;
background: #f8f8f8;
}
.tab-button {
padding: 0.5rem 1rem;
cursor: pointer;
border: none;
background: #f8f8f8;
padding: 0.5rem 1rem;
cursor: pointer;
border: none;
background: #f8f8f8;
white-space: nowrap;
font-size: 0.95rem;
}
.tab-button.active {
font-weight: bold;
background: white;
border-bottom: 2px solid #0073aa;
font-weight: bold;
background: white;
border-bottom: 2px solid #0073aa;
}
.tab-content {
padding: 1rem;
width: 100%;
padding: 1rem;
width: 100%;
overflow-x: auto;
}
/* ─── Tablet ─── */
@media (max-width: 1023px) {
.tab-button {
font-size: 0.85rem;
padding: 0.5rem 0.75rem;
}
}
/* ─── Smartphone ─── */
@media (max-width: 639px) {
.tab-header {
flex-direction: column;
flex-wrap: nowrap;
}
.tab-button {
width: 100%;
text-align: left;
padding: 0.65rem 1rem;
border-bottom: 1px solid #e5e7eb;
font-size: 0.9rem;
}
.tab-button.active {
border-bottom: none;
border-left: 4px solid #0073aa;
background: #ffffff;
}
.tab-content {
padding: 0.75rem;
}
}
</style>