326 lines
8.9 KiB
Vue
326 lines
8.9 KiB
Vue
<template>
|
|
<section class="project topSpace">
|
|
<!-- SideBarNaviSlider mit dynamischem Link und i18n-Label -->
|
|
<SideBarNaviSlider :link="localePath('references')">
|
|
{{ t('referenceoverview') }}
|
|
</SideBarNaviSlider>
|
|
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-md-9">
|
|
<h1>{{ t('project.detail.title', 'Kundenprojektvorstellung') }}</h1>
|
|
<h2>{{ project.projectTitle }}</h2>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="customerBox">
|
|
<NuxtImg
|
|
:src="customer.logo.url"
|
|
:alt="customer.logo.alternativeText"
|
|
provider="strapi"
|
|
/>
|
|
{{ }}
|
|
<h4>
|
|
{{ project.customer.company }} |
|
|
{{ project.customer.city }}
|
|
</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row detailBox">
|
|
<div class="col-lg-4">
|
|
<transition name="fade" mode="out-in">
|
|
<NuxtImg
|
|
v-if="currentImage"
|
|
id="currentImage"
|
|
:src="currentImage.url"
|
|
:alt="currentImage.alternativeText || project.projectTitle"
|
|
provider="strapi"
|
|
/>
|
|
</transition>
|
|
<div class="preview">
|
|
<h3>{{ t('project.detail.moreViews', 'Weitere Ansichten') }}</h3>
|
|
<div class="imageNavigation">
|
|
<NuxtImg
|
|
v-for="(img, index) in project.projectImages"
|
|
:key="index"
|
|
:src="img.url"
|
|
:alt="img.alternativeText"
|
|
provider="strapi"
|
|
:class="{ active: currentImage?.url === img.url }"
|
|
@click="setCurrentImage(img)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="col-lg-8 pt-4">
|
|
<span v-html="htmlContent(project.projectDescription)"/>
|
|
|
|
|
|
<h4>{{ t('project.detail.technologies', 'Verwendete Technologien') }}</h4>
|
|
<div class="techChipsBox">
|
|
<span
|
|
v-for="(tech, index) in project.technologies"
|
|
:key="index"
|
|
class="techChip"
|
|
>
|
|
{{ tech.titel }}
|
|
</span>
|
|
</div>
|
|
<div v-if="project.webpage" class="row">
|
|
<div class="col-12 text-end">
|
|
<a
|
|
class="webPageBtn"
|
|
:href="project.webpage"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<svg>
|
|
<use xlink:href="/assets/icons/collection.svg#desktop" />
|
|
</svg>
|
|
{{ t('project.detail.visitProject', 'Projekt live erleben') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
definePageMeta({
|
|
name: 'project-link'
|
|
})
|
|
import { ref, computed, watch } from "vue"
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
import { useMainStore } from '@/stores/main'
|
|
|
|
import { useHtmlConverter } from '@/composables/useHTMLConverter'
|
|
const { t } = useI18n()
|
|
const localePath = useLocalePath()
|
|
const route = useRoute()
|
|
const mainStore = useMainStore()
|
|
const project = computed(() => mainStore.getProjectByLink(route.params.link))
|
|
const customer = computed(() => {
|
|
if (!project.value || !project.value.customer) return null
|
|
return mainStore.getCustomerById(project.value.customer.id)
|
|
})
|
|
const currentImage = ref(null)
|
|
|
|
if (project.value && project.value.projectImages?.length > 0) {
|
|
currentImage.value = project.value.projectImages[0]
|
|
}
|
|
|
|
watch(project, (newProject) => {
|
|
if (newProject && newProject.projectImages?.length > 0) {
|
|
currentImage.value = newProject.projectImages[0]
|
|
} else {
|
|
currentImage.value = null
|
|
}
|
|
})
|
|
const { convertToHTML } = useHtmlConverter()
|
|
const htmlContent = (data: string) => {
|
|
return convertToHTML(data)
|
|
}
|
|
|
|
// Setze das aktuelle Bild
|
|
const setCurrentImage = (image: any) => {
|
|
currentImage.value = image
|
|
}
|
|
|
|
// META INFO UND JSON_LD für Projekte
|
|
|
|
const runtimeConfig = useRuntimeConfig()
|
|
|
|
watchEffect(() => {
|
|
if (!project.value) return
|
|
|
|
const metaTitle = project.value.projectTitle.length > 60
|
|
? project.value.projectTitle.slice(0, 57).trim() + '…'
|
|
: project.value.projectTitle
|
|
|
|
const firstParagraph = project.value.projectDescription?.[0]?.children?.[0]?.text || ''
|
|
const metaDescription = firstParagraph.length > 160
|
|
? firstParagraph.slice(0, 157).trim() + '…'
|
|
: firstParagraph
|
|
|
|
const customerCompany = project.value.customer?.company || ''
|
|
const customerCity = project.value.customer?.city || ''
|
|
|
|
const technologyKeywords = project.value.technologies?.map(t => t.titel).join(', ') || ''
|
|
const metaKeywords = [customerCompany, customerCity, technologyKeywords]
|
|
.filter(Boolean)
|
|
.join(', ')
|
|
|
|
const metaImage = project.value.projectImages?.[0]?.url
|
|
? `${runtimeConfig.public.cmsBaseUrl}${project.value.projectImages[0].url}`
|
|
: 'https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png'
|
|
|
|
const canonical = `${runtimeConfig.public.appUrl}${route.fullPath}`
|
|
|
|
const jsonLd = {
|
|
"@context": "https://schema.org",
|
|
"@type": "CreativeWork",
|
|
name: project.value.projectTitle,
|
|
description: metaDescription,
|
|
url: canonical,
|
|
image: metaImage,
|
|
datePublished: project.value.launchDate,
|
|
author: {
|
|
"@type": "Organization",
|
|
name: "digimedialoop"
|
|
},
|
|
publisher: {
|
|
"@type": "Organization",
|
|
name: "digimedialoop",
|
|
logo: {
|
|
"@type": "ImageObject",
|
|
url: "https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png"
|
|
}
|
|
}
|
|
}
|
|
|
|
useHead({
|
|
title: metaTitle,
|
|
meta: [
|
|
{ name: 'description', content: metaDescription },
|
|
{ name: 'keywords', content: metaKeywords },
|
|
{ name: 'robots', content: 'index, follow' },
|
|
{ property: 'og:title', content: metaTitle },
|
|
{ property: 'og:description', content: metaDescription },
|
|
{ property: 'og:image', content: metaImage },
|
|
{ property: 'og:type', content: 'website' },
|
|
{ name: 'twitter:title', content: metaTitle },
|
|
{ name: 'twitter:description', content: metaDescription },
|
|
{ name: 'twitter:image', content: metaImage }
|
|
],
|
|
link: [
|
|
{ rel: 'canonical', href: canonical }
|
|
],
|
|
script: [
|
|
{
|
|
type: 'application/ld+json',
|
|
children: JSON.stringify(jsonLd)
|
|
}
|
|
]
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style lang="sass">
|
|
.project
|
|
h1
|
|
color: $pink //adjust-color($darkgrey, $lightness: 40%)
|
|
font-size: 1.1rem
|
|
text-transform: uppercase
|
|
margin-bottom: 0
|
|
letter-spacing: .08rem
|
|
h2
|
|
margin-top: 0
|
|
img
|
|
width: 100%
|
|
.preview
|
|
h3
|
|
font-size: 1rem
|
|
color: adjust-color($darkgrey, $lightness: 40%)
|
|
img
|
|
width: 100px
|
|
margin: 0
|
|
cursor: pointer
|
|
transition: .6s
|
|
padding: 1.2rem
|
|
border: 2px solid transparent
|
|
&.active
|
|
border: 2px solid $lightgrey
|
|
padding: .5rem
|
|
border-radius: .5rem
|
|
.customerBox
|
|
width: 100%
|
|
max-width: 50vw
|
|
text-align: center
|
|
background-image: linear-gradient(to left bottom, rgba($lightgrey, .6), transparent, transparent)
|
|
border-top-right-radius: 20px
|
|
padding: 1rem
|
|
border-top: 1px solid rgba($lightgrey, .3)
|
|
border-right: 1px solid rgba($lightgrey, .3)
|
|
margin: 1rem 0
|
|
img
|
|
min-height: 2rem
|
|
width: 50%
|
|
max-width: 200px
|
|
margin: 1rem
|
|
h4
|
|
font-size: .8rem
|
|
@media(max-width: $breakPointLG)
|
|
background-image: linear-gradient(to left, rgba($lightgrey, .6), transparent, transparent)
|
|
margin-top: 0
|
|
.detailBox
|
|
h4
|
|
font-size: 1rem
|
|
margin-top: 2.5rem
|
|
color: adjust-color($darkgrey, $lightness: 20%)
|
|
font-family: 'Mainfont-Bold'
|
|
.webPageBtn
|
|
font-size: .8rem
|
|
margin-top: 2rem
|
|
margin-right: 6%
|
|
text-decoration: none
|
|
border: 1px solid adjust-color($darkgrey, $lightness: 20%)
|
|
padding: .5rem 1rem
|
|
border-radius: 5px
|
|
display: inline-block
|
|
color: adjust-color($darkgrey, $lightness: 30%)
|
|
transition: .6s
|
|
&:hover
|
|
transform: scale(1.1)
|
|
svg
|
|
height: .8rem
|
|
width: .9rem
|
|
margin-right: .3rem
|
|
fill: adjust-color($darkgrey, $lightness: 20%)
|
|
.ctaBox
|
|
padding: 3rem 0
|
|
h2
|
|
margin-bottom: .5rem
|
|
h3
|
|
margin-bottom: .5rem
|
|
.navigationBox
|
|
margin-top: 2rem
|
|
width: 100%
|
|
color: adjust-color($darkgrey, $lightness: 35%)
|
|
font-size: .85rem
|
|
|
|
&:hover
|
|
cursor: pointer
|
|
.navBtn
|
|
transition: .6s
|
|
&:hover
|
|
transform: scale(1.05)
|
|
span
|
|
display: inline-block
|
|
svg
|
|
fill: adjust-color($lightgrey, $lightness: -10%)
|
|
width: 80%
|
|
max-width: 50px
|
|
.techChipsBox
|
|
display: block
|
|
width: 100%
|
|
.techChip
|
|
background-color: $lightgrey
|
|
padding: .2rem 1rem
|
|
margin: .3rem
|
|
border-radius: .6rem
|
|
font-size: .9rem
|
|
display: inline-block
|
|
color: adjust-color($darkgrey, $lightness: 25%)
|
|
</style>
|
|
|