331 lines
9.1 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>
<CallToActionBox
:headline="$t('pages.references.ctaBox.headline')"
:text="$t('pages.references.ctaBox.text')"
:button-text="$t('pages.references.ctaBox.button')"
/>
</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>