portfolio/components/IconButton.vue
Michael Winter 1bbb7e0250 Fix mobile handling for score and document icons
- Score icon: mobile downloads PDF, desktop opens modal
- Document icon: reverts to same behavior on mobile and desktop (opens modal)
- Remove console.log from isMobile
- Remove documentLink computed property
2026-03-06 18:36:40 +01:00

115 lines
4.9 KiB
Vue

<template>
<div class="inline-flex p-1 min-w-[25px]">
<div v-show="visible" class="bg-black rounded-full text-xs inline-flex" >
<!-- Score: Mobile = PDF (downloads), Desktop = work page with hash (opens modal) -->
<span v-if="type === 'score' && isMobile()">
<a :href="scoreLink" class="inline-flex p-1">
<Icon name="ion:book-sharp" style="color: white" />
</a>
</span>
<span v-else-if="type === 'score'">
<button @click="openWithHash('score')" class="inline-flex p-1">
<Icon name="ion:book-sharp" style="color: white" />
</button>
</span>
<!-- Document: Mobile = External opens new tab, PDF downloads, internal pages open modal -->
<span v-if="type === 'document'">
<a :href="isExternalLink ? link : undefined" :target="isExternalLink ? '_blank' : undefined" :rel="isExternalLink ? 'noopener noreferrer' : undefined" @click="openDocument()" class="inline-flex p-1 cursor-pointer">
<Icon name="ion:book-sharp" style="color: white" />
</a>
</span>
<a v-else-if="type === 'buy'" :href="link" :target="newTab ? '_blank' : undefined" :rel="newTab ? 'noopener noreferrer' : undefined" class="inline-flex p-1 cursor-pointer">
<Icon name="bxs:purchase-tag" style="color: white" />
</a>
<NuxtLink v-else-if="type === 'email'" class="inline-flex p-1" :to="link">
<Icon name="ic:baseline-email" style="color: white" />
</NuxtLink>
<a v-else-if="type === 'discogs'" :href="link" :target="newTab ? '_blank' : undefined" :rel="newTab ? 'noopener noreferrer' : undefined" class="inline-flex p-1 cursor-pointer">
<Icon name="simple-icons:discogs" style="color: white" />
</a>
<button @click="audioPlayerStore.setSoundCloudTrackID(work.soundcloud_trackid)" v-else-if="type === 'audio'" class="inline-flex p-1">
<Icon name="wpf:speaker" style="color: white" />
</button>
<button @click="openWithHash('video')" v-else-if="type === 'video'" class="inline-flex p-1">
<Icon name="fluent:video-48-filled" style="color: white" />
</button>
<button @click="openWithHash('image')" v-else-if="type === 'image'" class="inline-flex p-1">
<Icon name="mdi:camera" style="color: white" />
</button>
</div>
</div>
</template>
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
import { useModalStore } from "@/stores/ModalStore"
import { computed } from "vue"
const props = defineProps(['type', 'work', 'visible', 'link', 'newTab'])
const audioPlayerStore = useAudioPlayerStore()
const modalStore = useModalStore()
const slugify = (title) => {
if (!title) return ''
return title.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '')
}
const workSlug = computed(() => slugify(props.work?.title))
const scoreLink = computed(() => {
if (!props.work?.score) return null
if (props.work.score.startsWith('/scores/')) {
return props.work.score
}
return '/scores/' + props.work.score
})
const isExternalLink = computed(() => {
return props.link && !props.link.endsWith('.pdf') && !props.link.startsWith('/')
})
const isInternalPage = computed(() => {
return props.link && props.link.startsWith('/') && !props.link.endsWith('.pdf')
})
const isMobile = () => {
if (typeof window === 'undefined') return false
return window.innerWidth < 768
}
const openDocument = () => {
if (props.link?.endsWith('.pdf')) {
modalStore.setModalProps('pdf', 'aspect-[1/1.414]', true, '', '', '', props.link)
} else if (props.link?.startsWith('/')) {
modalStore.setModalProps('document', 'aspect-[1/1.414]', true, '', '', '', '', '', props.link)
}
}
const openWithHash = (type) => {
const slug = workSlug.value
const hash = type + '|' + slug
if (type === 'score') {
modalStore.setModalProps('pdf', 'aspect-[1/1.414]', true, '', '', '', props.link, props.work?.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + props.work.soundcloud_trackid + '&auto_play=true&show_user=false' : '')
} else if (type === 'video') {
modalStore.setModalProps('video', 'aspect-video', true, '', '', props.work.vimeo_trackid)
} else if (type === 'image') {
modalStore.setModalProps('image', 'aspect-auto', true, 'images', props.work.gallery, '', '', props.work.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + props.work.soundcloud_trackid + '&auto_play=true&show_user=false' : '')
}
if (slug && typeof window !== 'undefined') {
window.history.replaceState({}, '', '/#' + hash)
}
}
</script>