Add shareable URLs for works with scores
- Score icon updates URL to /?work=[slug] without navigation - Modal closes to reset URL back to / - Direct /work/[slug] access redirects to /?work=[slug] - Index page opens modal when ?work= query param is present - Works with SSG/prerendering for /?work= routes
This commit is contained in:
parent
2fe7dad9fa
commit
9af20c1e5d
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="inline-flex p-1 min-w-[25px]">
|
<div class="inline-flex p-1 min-w-[25px]">
|
||||||
<div v-show="visible" class="bg-black rounded-full text-xs inline-flex" >
|
<div v-show="visible" class="bg-black rounded-full text-xs inline-flex" >
|
||||||
|
|
||||||
<button v-if="type === 'score'" @click="modalStore.setModalProps('pdf', 'aspect-[1/1.414]', true, '', '', '', link, work.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + work.soundcloud_trackid + '&auto_play=true&show_user=false' : '')" class="inline-flex p-1">
|
<button v-if="type === 'score'" @click="openScoreModal()" class="inline-flex p-1">
|
||||||
<Icon name="ion:book-sharp" style="color: white" />
|
<Icon name="ion:book-sharp" style="color: white" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
@ -41,13 +41,20 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
|
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
|
||||||
import { useModalStore } from "@/stores/ModalStore"
|
import { useModalStore } from "@/stores/ModalStore"
|
||||||
import { computed } from "vue"
|
import { computed, watch } from "vue"
|
||||||
|
|
||||||
const props = defineProps(['type', 'work', 'visible', 'link', 'newTab'])
|
const props = defineProps(['type', 'work', 'visible', 'link', 'newTab'])
|
||||||
|
|
||||||
const audioPlayerStore = useAudioPlayerStore()
|
const audioPlayerStore = useAudioPlayerStore()
|
||||||
const modalStore = useModalStore()
|
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 isExternalLink = computed(() => {
|
const isExternalLink = computed(() => {
|
||||||
return props.link && !props.link.endsWith('.pdf') && !props.link.startsWith('/')
|
return props.link && !props.link.endsWith('.pdf') && !props.link.startsWith('/')
|
||||||
})
|
})
|
||||||
|
|
@ -63,4 +70,17 @@
|
||||||
modalStore.setModalProps('document', 'aspect-[1/1.414]', true, '', '', '', '', '', props.link)
|
modalStore.setModalProps('document', 'aspect-[1/1.414]', true, '', '', '', '', '', props.link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openScoreModal = () => {
|
||||||
|
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' : '')
|
||||||
|
if (workSlug.value && typeof window !== 'undefined') {
|
||||||
|
window.history.replaceState({}, '', '/?work=' + workSlug.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => modalStore.isOpen, (isOpen) => {
|
||||||
|
if (!isOpen && workSlug.value && typeof window !== 'undefined' && window.location.search.includes('work=')) {
|
||||||
|
window.history.replaceState({}, '', '/')
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,16 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import { useModalStore } from "@/stores/ModalStore"
|
import { useModalStore } from "@/stores/ModalStore"
|
||||||
|
import { watch, watchEffect } from "vue"
|
||||||
|
|
||||||
const modalStore = useModalStore()
|
const modalStore = useModalStore()
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
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 groupBy = (x,f)=>x.reduce((a,b,i)=>((a[f(b,i,x)]||=[]).push(b),a),{});
|
||||||
|
|
||||||
|
|
@ -164,4 +172,37 @@
|
||||||
titleTemplate: 'Michael Winter - Home / Works - Pieces, Publications, and Albums'
|
titleTemplate: 'Michael Winter - Home / Works - Pieces, Publications, and Albums'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const workFromSlug = computed(() => {
|
||||||
|
const workSlug = route.query.work
|
||||||
|
if (!workSlug || !works.value) return null
|
||||||
|
for (const group of works.value) {
|
||||||
|
const found = group.works.find(w => slugify(w.title) === workSlug)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const workSlug = route.query.work
|
||||||
|
const work = workFromSlug.value
|
||||||
|
if (workSlug && work?.score) {
|
||||||
|
modalStore.setModalProps(
|
||||||
|
'pdf',
|
||||||
|
'aspect-[1/1.414]',
|
||||||
|
true,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
work.score,
|
||||||
|
work.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + work.soundcloud_trackid + '&auto_play=true&show_user=false' : ''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => modalStore.isOpen, (isOpen) => {
|
||||||
|
if (!isOpen && route.query.work && typeof window !== 'undefined') {
|
||||||
|
window.history.replaceState({}, '', '/')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
14
pages/work/[slug].vue
Normal file
14
pages/work/[slug].vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup>
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const slug = route.params.slug
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
router.replace('/?work=' + slug)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
Loading…
Reference in a new issue