portfolio/pages/pieces.vue

117 lines
3.9 KiB
Vue

<template>
<div class="grid grid-cols-1 lg:grid-cols-5 gap-8">
<div class="lg:col-span-3">
<section>
<h1 class="text-2xl mb-6 border-b border-gray-200 pb-2">pieces</h1>
<div v-for="item in works" :key="item.year" class="mb-8">
<p class="text-sm text-gray-500 mb-3">{{ item.year }}</p>
<div v-for="work in item.works" :key="work.title" class="mb-4">
<div class="flex items-start gap-2">
<NuxtLink
v-if="hasItems(work)"
:to="'/works/' + slugify(work.title)"
class="italic hover:underline"
>
<span v-html="work.title"></span>
</NuxtLink>
<span v-else class="italic">
<span v-html="work.title"></span>
</span>
<div class="flex gap-1">
<IconButton v-if="work.score" type="score" :work="work" :link="work.score" :visible="true"></IconButton>
<IconButton v-if="work.soundcloud_trackid" type="audio" :work="work" :visible="true"></IconButton>
<IconButton v-if="work.vimeo_trackid" type="video" :work="work" :visible="true"></IconButton>
<IconButton v-if="work.gallery" type="image" :work="work" :visible="true"></IconButton>
</div>
</div>
</div>
</div>
</section>
</div>
<div class="lg:col-span-2">
<section v-if="worksWithImages.length">
<div class="grid grid-cols-1 gap-4">
<NuxtLink
v-for="work in worksWithImages"
:key="work.title"
:to="'/works/' + slugify(work.title)"
class="block group relative overflow-hidden"
>
<nuxt-img
:src="'/images/' + work.images[0].filename"
:alt="work.title"
class="w-full aspect-[4/3] object-cover transition-opacity duration-200 group-hover:opacity-50"
/>
<p class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 text-center italic px-2" v-html="work.title"></p>
</NuxtLink>
</div>
</section>
</div>
</div>
</template>
<script setup>
import { useModalStore } from "@/stores/ModalStore"
const modalStore = useModalStore()
const route = useRoute()
const slugify = (title) => {
if (!title) return ''
return title.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '')
}
const groupBy = (x,f)=>x.reduce((a,b,i)=>((a[f(b,i,x)]||=[]).push(b),a),{});
const hasItems = (work) => {
return work.vimeo_trackid || (work.images && work.images.length) || work.score
}
const worksWithImages = computed(() => {
if (!works.value) return []
const allWorks = works.value.flatMap(group => group.works)
return allWorks.filter(work => work.images && work.images.length)
})
const { data: works } = await useFetch('/api/works', {
key: 'works-pieces',
transform: (works) => {
const cloned = JSON.parse(JSON.stringify(works))
for (const work of cloned) {
if(work.score){
work.score = "/scores/" + work.score
}
if(work.images){
let gallery = [];
for (const image of work.images){
gallery.push({
image: image.filename,
})
}
work.gallery = gallery
}
}
let priorityGroups = groupBy(cloned, work => work.priority)
let groups = groupBy(priorityGroups["1"], work => new Date(work.date).getFullYear())
groups = Object.keys(groups).map((year) => {
return {
year,
works: groups[year].sort((a,b) => new Date(b.date) - new Date(a.date))
};
});
groups.sort((a,b) => b.year - a.year)
if (priorityGroups["2"]) {
groups.push({year: "miscellany", works: priorityGroups["2"].sort((a,b) => new Date(b.date) - new Date(a.date))})
}
return groups
}
})
useHead({
titleTemplate: 'Michael Winter - Pieces'
})
</script>