From 9af20c1e5d2cd60a5a19ac8b8a2510fd06b62042 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 09:19:25 +0100 Subject: [PATCH 01/32] 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 --- components/IconButton.vue | 24 +++++++++++++++++++++-- pages/index.vue | 41 +++++++++++++++++++++++++++++++++++++++ pages/work/[slug].vue | 14 +++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 pages/work/[slug].vue diff --git a/components/IconButton.vue b/components/IconButton.vue index c75c36f..69680f7 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,7 +2,7 @@
- @@ -41,13 +41,20 @@ diff --git a/pages/index.vue b/pages/index.vue index 239c9d6..1f66d0f 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -78,8 +78,16 @@ diff --git a/pages/work/[slug].vue b/pages/work/[slug].vue new file mode 100644 index 0000000..4272bbe --- /dev/null +++ b/pages/work/[slug].vue @@ -0,0 +1,14 @@ + + + From 635cbe0482d6fea5fd6fdb81b9d36da36060b726 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 10:23:45 +0100 Subject: [PATCH 02/32] Add shareable work pages with modal support - Create IndexContent component to avoid code duplication - Score icon links to /work/[slug] with clean URLs - Modal opens automatically via slug prop (works with SSR) - Crawler finds and prerenders all /work/ pages (145 routes) - Work page redirects to / when modal closes - Single source of truth for data fetching in IndexContent --- components/IconButton.vue | 19 +--- components/IndexContent.vue | 193 ++++++++++++++++++++++++++++++++++ pages/index.vue | 201 +----------------------------------- pages/work/[slug].vue | 18 ++-- 4 files changed, 209 insertions(+), 222 deletions(-) create mode 100644 components/IndexContent.vue diff --git a/components/IconButton.vue b/components/IconButton.vue index 69680f7..c06fe41 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,9 +2,9 @@
- + @@ -41,7 +41,7 @@ diff --git a/components/IndexContent.vue b/components/IndexContent.vue new file mode 100644 index 0000000..2d81c69 --- /dev/null +++ b/components/IndexContent.vue @@ -0,0 +1,193 @@ + + + diff --git a/pages/index.vue b/pages/index.vue index 1f66d0f..afcd7f6 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,208 +1,9 @@ diff --git a/pages/work/[slug].vue b/pages/work/[slug].vue index 4272bbe..ebe890f 100644 --- a/pages/work/[slug].vue +++ b/pages/work/[slug].vue @@ -1,14 +1,20 @@ + + - - From 6ffe5aa1fc9b31f526b9850eca331840cbe42c44 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 15:08:30 +0100 Subject: [PATCH 03/32] Add work pages with hash-based modal URLs and proper 404 handling - Create dedicated /work/[slug] pages with sticky nav - Use hash URLs (#type|slug) for modals instead of work page URLs - Make works without items non-clickable on index - Add server route to return 404 for non-existent score files --- components/IconButton.vue | 25 ++++++-- components/IndexContent.vue | 71 ++++++++++++++++++++++- pages/work/[slug].vue | 95 +++++++++++++++++++++++++++---- server/routes/scores/[...path].ts | 25 ++++++++ 4 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 server/routes/scores/[...path].ts diff --git a/components/IconButton.vue b/components/IconButton.vue index c06fe41..45de733 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,9 +2,9 @@
- + @@ -26,11 +26,11 @@ - - @@ -70,4 +70,21 @@ 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) + } + } diff --git a/components/IndexContent.vue b/components/IndexContent.vue index 2d81c69..8622f37 100644 --- a/components/IndexContent.vue +++ b/components/IndexContent.vue @@ -8,7 +8,12 @@

{{ item.year }}

- + + + + + +
@@ -61,7 +66,7 @@

albums

{{ item.title }}

- @@ -77,11 +82,12 @@ diff --git a/pages/work/[slug].vue b/pages/work/[slug].vue index ebe890f..81c093c 100644 --- a/pages/work/[slug].vue +++ b/pages/work/[slug].vue @@ -1,20 +1,91 @@ + + diff --git a/server/routes/scores/[...path].ts b/server/routes/scores/[...path].ts new file mode 100644 index 0000000..ef20578 --- /dev/null +++ b/server/routes/scores/[...path].ts @@ -0,0 +1,25 @@ +import { existsSync, createReadStream } from 'fs' +import { join } from 'path' +import { sendStream } from 'h3' +import { createError } from 'h3' + +export default defineEventHandler(async (event) => { + const url = event.path + + // Get the filename from the URL + const filename = url.replace('/scores/', '') + + // Check if file exists in public/scores/ + const filePath = join(process.cwd(), 'public/scores', filename) + + if (!existsSync(filePath)) { + throw createError({ + statusCode: 404, + statusMessage: 'Not Found' + }) + } + + // Serve the file + event.node.res.statusCode = 200 + return sendStream(event, createReadStream(filePath)) +}) From 8f73a3388e341ef84360032f9f111c080d35e815 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 15:49:29 +0100 Subject: [PATCH 04/32] Clean up navigation links with hover underline - Add hover:underline to header nav links - Add hover:underline to works links - Rename /work/ route to /works/ - Include works.json manual tweak --- components/IndexContent.vue | 2 +- layouts/default.vue | 8 ++++---- pages/{work => works}/[slug].vue | 8 ++++---- server/data/works.json | 1 - 4 files changed, 9 insertions(+), 10 deletions(-) rename pages/{work => works}/[slug].vue (84%) diff --git a/components/IndexContent.vue b/components/IndexContent.vue index 8622f37..c127645 100644 --- a/components/IndexContent.vue +++ b/components/IndexContent.vue @@ -8,7 +8,7 @@

{{ item.year }}

- + diff --git a/layouts/default.vue b/layouts/default.vue index 7386837..e563b6b 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -3,10 +3,10 @@ diff --git a/server/data/works.json b/server/data/works.json index fabf506..ddec93e 100644 --- a/server/data/works.json +++ b/server/data/works.json @@ -1052,7 +1052,6 @@ "variable ensemble" ], "date": "2004-04-02", - "score": "Tri_Dimensional_Canon_score.pdf", "priority": 2, "type": "sound" }, From d5fc1eed21091b80badd31a6b808bdb7b6e0c38e Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 16:31:36 +0100 Subject: [PATCH 05/32] Add mobile-friendly PDF handling- Score icon on mobile: direct link to PDF triggers download - Works page: hide score iframe on mobile, Score link downloads PDF - Desktop behavior unchanged --- components/IconButton.vue | 18 +++++++++++++++++- pages/works/[slug].vue | 9 +++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/components/IconButton.vue b/components/IconButton.vue index 45de733..2cb1fa5 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,7 +2,10 @@
- @@ -55,6 +58,19 @@ const workSlug = computed(() => slugify(props.work?.title)) + const isMobile = computed(() => { + if (typeof window === 'undefined') return false + return window.innerWidth < 768 + }) + + 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('/') }) diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index 9aa18e2..6c363a9 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -8,7 +8,7 @@
@@ -22,7 +22,7 @@
-
+
@@ -77,6 +77,11 @@ const itemCount = computed(() => { return count }) +const isMobile = computed(() => { + if (typeof window === 'undefined') return false + return window.innerWidth < 768 +}) + onMounted(() => { if (work.value?.soundcloud_trackid) { audioPlayerStore.setSoundCloudTrackID(work.value.soundcloud_trackid) From 54ab2d8b24d1eab183715a65ceb5094e47804214 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 17:12:33 +0100 Subject: [PATCH 06/32] Add CSS-only mobile handling for PDFs - Score icon: mobile downloads PDF, desktop opens modal - Document icon: mobile downloads PDF, desktop opens modal - Works page: mobile hides score iframe, Score link downloads PDF - Uses pure CSS (md:hidden/hidden md:block) - no JS needed --- components/IconButton.vue | 36 ++++++++++++++++++++++-------------- pages/works/[slug].vue | 14 +++++++------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/components/IconButton.vue b/components/IconButton.vue index 2cb1fa5..f2085b1 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,16 +2,29 @@ @@ -22,7 +27,7 @@
-
+
@@ -77,11 +82,6 @@ const itemCount = computed(() => { return count }) -const isMobile = computed(() => { - if (typeof window === 'undefined') return false - return window.innerWidth < 768 -}) - onMounted(() => { if (work.value?.soundcloud_trackid) { audioPlayerStore.setSoundCloudTrackID(work.value.soundcloud_trackid) From 49f427256f732c0a6e8b295e00e5636a33de5e5f Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 17:26:58 +0100 Subject: [PATCH 07/32] Always show nav on works page regardless of item count --- pages/works/[slug].vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index fab50a3..54fd8a8 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -5,7 +5,7 @@

-
- @@ -82,6 +82,11 @@ const itemCount = computed(() => { return count }) +const isMobile = () => { + if (typeof window === 'undefined') return false + return window.innerWidth < 768 +} + onMounted(() => { if (work.value?.soundcloud_trackid) { audioPlayerStore.setSoundCloudTrackID(work.value.soundcloud_trackid) From 6e9f859d59dcae1353f13235f315b55df0a5e3a3 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Fri, 6 Mar 2026 18:53:35 +0100 Subject: [PATCH 09/32] Make mobile and desktop behave identically - Remove isMobile() function from IconButton and works page - Remove mobile-specific conditionals for score and document icons - Always show nav and score iframe on works page - No more hydration mismatch - same HTML on server and client --- components/IconButton.vue | 28 ++++------------------------ pages/works/[slug].vue | 14 ++------------ 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/components/IconButton.vue b/components/IconButton.vue index 2572744..1e8cf2f 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -2,17 +2,10 @@
- - - - - - - - - + + @@ -66,14 +59,6 @@ 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('/') }) @@ -82,11 +67,6 @@ 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) diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index a4874c8..0369081 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -8,12 +8,7 @@
@@ -27,7 +22,7 @@
-
+
@@ -82,11 +77,6 @@ const itemCount = computed(() => { return count }) -const isMobile = () => { - if (typeof window === 'undefined') return false - return window.innerWidth < 768 -} - onMounted(() => { if (work.value?.soundcloud_trackid) { audioPlayerStore.setSoundCloudTrackID(work.value.soundcloud_trackid) From 97debc4d10a9cdcf043c17383f24d966fe8117aa Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 11:28:55 +0100 Subject: [PATCH 10/32] Redesign with hamburger menu and separate pages for pieces/writings/albums/performances/lectures --- components/IndexContent.vue | 146 +++++++++++++++++++----------------- components/Menu.vue | 108 ++++++++++++++++++++++++++ layouts/default.vue | 74 +++++++----------- pages/albums.vue | 64 ++++++++++++++++ pages/index.vue | 6 +- pages/lectures.vue | 62 +++++++++++++++ pages/performances.vue | 76 +++++++++++++++++++ pages/pieces.vue | 116 ++++++++++++++++++++++++++++ pages/writings.vue | 66 ++++++++++++++++ 9 files changed, 601 insertions(+), 117 deletions(-) create mode 100644 components/Menu.vue create mode 100644 pages/albums.vue create mode 100644 pages/lectures.vue create mode 100644 pages/performances.vue create mode 100644 pages/pieces.vue create mode 100644 pages/writings.vue diff --git a/components/IndexContent.vue b/components/IndexContent.vue index c127645..ecbff0c 100644 --- a/components/IndexContent.vue +++ b/components/IndexContent.vue @@ -1,82 +1,94 @@ diff --git a/components/Menu.vue b/components/Menu.vue new file mode 100644 index 0000000..648f3ab --- /dev/null +++ b/components/Menu.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/layouts/default.vue b/layouts/default.vue index e563b6b..214cdb0 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -1,40 +1,34 @@ diff --git a/pages/albums.vue b/pages/albums.vue new file mode 100644 index 0000000..3e9d5d4 --- /dev/null +++ b/pages/albums.vue @@ -0,0 +1,64 @@ + + + diff --git a/pages/index.vue b/pages/index.vue index afcd7f6..6e2c95c 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,9 +1,7 @@ diff --git a/pages/lectures.vue b/pages/lectures.vue new file mode 100644 index 0000000..233c278 --- /dev/null +++ b/pages/lectures.vue @@ -0,0 +1,62 @@ + + + diff --git a/pages/performances.vue b/pages/performances.vue new file mode 100644 index 0000000..d87551a --- /dev/null +++ b/pages/performances.vue @@ -0,0 +1,76 @@ + + + diff --git a/pages/pieces.vue b/pages/pieces.vue new file mode 100644 index 0000000..7cfcd00 --- /dev/null +++ b/pages/pieces.vue @@ -0,0 +1,116 @@ + + + diff --git a/pages/writings.vue b/pages/writings.vue new file mode 100644 index 0000000..c8ecd20 --- /dev/null +++ b/pages/writings.vue @@ -0,0 +1,66 @@ + + + From be041de733ac01c56ca48da8983b44e3895a9998 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 11:46:54 +0100 Subject: [PATCH 11/32] Redesign about page with new layout matching pieces page --- pages/about.vue | 163 +++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 77 deletions(-) diff --git a/pages/about.vue b/pages/about.vue index 779020b..6f4966d 100644 --- a/pages/about.vue +++ b/pages/about.vue @@ -1,91 +1,100 @@ - \ No newline at end of file + From 69fab67601dcb54187113ac7822bfb910e0aaef1 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 13:16:46 +0100 Subject: [PATCH 12/32] Update works page with new layout; fix audio player to only autoplay on click --- layouts/default.vue | 1 - pages/pieces.vue | 8 +-- pages/works/[slug].vue | 119 ++++++++++++++++++++++++++++--------- stores/AudioPlayerStore.js | 11 +++- 4 files changed, 102 insertions(+), 37 deletions(-) diff --git a/layouts/default.vue b/layouts/default.vue index 214cdb0..9377105 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -22,7 +22,6 @@ height="20px" scrolling="no" frameborder="no" - allow="autoplay" :src="'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + audioPlayerStore.soundcloud_trackid + '&inverse=false&auto_play=true&show_user=false'" > diff --git a/pages/pieces.vue b/pages/pieces.vue index 7cfcd00..d469626 100644 --- a/pages/pieces.vue +++ b/pages/pieces.vue @@ -20,10 +20,10 @@
- - - - + + + +
diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index 0369081..594121b 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -1,29 +1,81 @@ diff --git a/stores/AudioPlayerStore.js b/stores/AudioPlayerStore.js index 90dbc33..689f0a5 100644 --- a/stores/AudioPlayerStore.js +++ b/stores/AudioPlayerStore.js @@ -1,15 +1,20 @@ import {defineStore} from "pinia"; export const useAudioPlayerStore = defineStore("AudioPlayerStore", { - state: () => ({"soundcloud_trackid": "1032587794"}), + state: () => ({ + "soundcloud_trackid": "undefined", + "currentTrackTitle": "" + }), actions: { - setSoundCloudTrackID(trackid) { + setSoundCloudTrackID(trackid, title = "") { if (typeof trackid !== 'undefined') { this.soundcloud_trackid = trackid + this.currentTrackTitle = title } }, clearSoundCloudTrackID() { this.soundcloud_trackid = 'undefined' + this.currentTrackTitle = "" } } -}) \ No newline at end of file +}) From f0133650f673f598fe7c0d4ba4a63fc394b3e1fb Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 13:34:02 +0100 Subject: [PATCH 13/32] Replace icons with text links; add video and images modal on pieces page --- pages/pieces.vue | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/pages/pieces.vue b/pages/pieces.vue index d469626..7482e31 100644 --- a/pages/pieces.vue +++ b/pages/pieces.vue @@ -6,25 +6,33 @@

{{ item.year }}

-
-
+
+
- + +
-
- - - - -
+
+ + + + + score +
@@ -55,8 +63,10 @@ From f9ff74ee925bef7ce52a5c84d262f7bbf21457e1 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 15:39:28 +0100 Subject: [PATCH 20/32] Style contact, cv, and works list links with gray text --- pages/about.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/about.vue b/pages/about.vue index 769ad86..eb4065b 100644 --- a/pages/about.vue +++ b/pages/about.vue @@ -12,9 +12,9 @@
From 95d8707ec1792c36af2f3c137ccdf7cbedde31ba Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 17:16:07 +0100 Subject: [PATCH 21/32] Disable payload extraction to fix prerender warnings --- nuxt.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuxt.config.ts b/nuxt.config.ts index a28775e..3a2692a 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -33,6 +33,6 @@ export default defineNuxtConfig({ prerender: { crawlLinks: true} }, experimental: { - payloadExtraction: true + payloadExtraction: false } }) From 5f9ce311274b9df9e86ce052e4b0a7ef6e689ead Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 17:39:14 +0100 Subject: [PATCH 22/32] Fix title and date wrapping on mobile --- pages/works/[slug].vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index 9e75000..c000e9b 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -4,9 +4,9 @@
-
-

- ({{ year }}) +
+

+ ({{ year }})
@@ -43,12 +44,11 @@
From 9e4435e5128ade03e1c8eb924fd027781a545fbf Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sat, 7 Mar 2026 17:41:49 +0100 Subject: [PATCH 23/32] Fix modal to open at clicked image instead of first image --- components/IconButton.vue | 2 +- components/ImageSlider.vue | 3 ++- components/IndexContent.vue | 6 ++++-- layouts/default.vue | 2 +- pages/about.vue | 2 +- pages/albums.vue | 2 +- pages/pieces.vue | 2 +- pages/works/[slug].vue | 2 +- stores/ModalStore.js | 5 +++-- 9 files changed, 15 insertions(+), 11 deletions(-) diff --git a/components/IconButton.vue b/components/IconButton.vue index 1e8cf2f..d898bb6 100644 --- a/components/IconButton.vue +++ b/components/IconButton.vue @@ -84,7 +84,7 @@ } 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' : '') + 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' : '', '', 0) } if (slug && typeof window !== 'undefined') { diff --git a/components/ImageSlider.vue b/components/ImageSlider.vue index 1ecf818..bab618c 100644 --- a/components/ImageSlider.vue +++ b/components/ImageSlider.vue @@ -4,6 +4,7 @@ :loop="true" :spaceBetween="30" :centeredSlides="true" + :initialSlide="initialIndex" :autoplay="{ delay: 4000, disableOnInteraction: false, @@ -33,6 +34,6 @@ diff --git a/components/IndexContent.vue b/components/IndexContent.vue index ecbff0c..3bafdb2 100644 --- a/components/IndexContent.vue +++ b/components/IndexContent.vue @@ -196,7 +196,7 @@ } const openAlbumModal = (album) => { - modalStore.setModalProps('image', 'aspect-auto', true, 'album_art', [{image: album.album_art}], '') + modalStore.setModalProps('image', 'aspect-auto', true, 'album_art', [{image: album.album_art}], '', '', '', '', 0) } const openModalFromHash = () => { @@ -233,7 +233,9 @@ work.gallery, '', '', - work.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + work.soundcloud_trackid + '&auto_play=true&show_user=false' : '' + work.soundcloud_trackid ? 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + work.soundcloud_trackid + '&auto_play=true&show_user=false' : '', + '', + 0 ) } } diff --git a/layouts/default.vue b/layouts/default.vue index 595c633..b8f3832 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -69,7 +69,7 @@ - +
diff --git a/pages/about.vue b/pages/about.vue index eb4065b..dd833ac 100644 --- a/pages/about.vue +++ b/pages/about.vue @@ -66,7 +66,7 @@ const modalStore = useModalStore() const { data: gallery } = await useFetch('/api/my_image_gallery') const openImageModal = (index) => { - modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery.value, '') + modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery.value, '', '', '', '', index) } useHead({ diff --git a/pages/albums.vue b/pages/albums.vue index 517b166..14a3d85 100644 --- a/pages/albums.vue +++ b/pages/albums.vue @@ -53,7 +53,7 @@ const { data: releases } = await useFetch('/api/releases', { }) const openAlbumModal = (album) => { - modalStore.setModalProps('image', 'aspect-auto', true, 'album_art', [{image: album.album_art}], '') + modalStore.setModalProps('image', 'aspect-auto', true, 'album_art', [{image: album.album_art}], '', '', '', '', 0) } useHead({ diff --git a/pages/pieces.vue b/pages/pieces.vue index e6e393a..e2580e3 100644 --- a/pages/pieces.vue +++ b/pages/pieces.vue @@ -88,7 +88,7 @@ const openVideoModal = (vimeoId) => { const openImageModal = (work) => { const gallery = work.images.map(img => ({ image: img.filename })) - modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery, '') + modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery, '', '', '', '', 0) } const worksWithImages = computed(() => { diff --git a/pages/works/[slug].vue b/pages/works/[slug].vue index c000e9b..26ec6ad 100644 --- a/pages/works/[slug].vue +++ b/pages/works/[slug].vue @@ -136,7 +136,7 @@ const navItems = computed(() => { }) const openImageModal = (index) => { - modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery.value, '') + modalStore.setModalProps('image', 'aspect-auto', true, 'images', gallery.value, '', '', '', '', index) } useHead({ diff --git a/stores/ModalStore.js b/stores/ModalStore.js index 1323320..d7fe5ba 100644 --- a/stores/ModalStore.js +++ b/stores/ModalStore.js @@ -1,9 +1,9 @@ import {defineStore} from "pinia"; export const useModalStore = defineStore("ModalStore", { - state: () => ({"type": "", "aspect":"", "isOpen":false, "bucket":"", "gallery":"", "vimeo_trackid": "", "pdfUrl": "", "soundcloudUrl": "", "iframeUrl": ""}), + state: () => ({"type": "", "aspect":"", "isOpen":false, "bucket":"", "gallery":"", "vimeo_trackid": "", "pdfUrl": "", "soundcloudUrl": "", "iframeUrl": "", "initialIndex": 0}), actions: { - setModalProps(type, aspect, isOpen, bucket, gallery, vimeo_trackid, pdfUrl, soundcloudUrl, iframeUrl) { + setModalProps(type, aspect, isOpen, bucket, gallery, vimeo_trackid, pdfUrl, soundcloudUrl, iframeUrl, initialIndex = 0) { this.type = type this.aspect = aspect this.isOpen = isOpen @@ -13,6 +13,7 @@ export const useModalStore = defineStore("ModalStore", { this.pdfUrl = pdfUrl this.soundcloudUrl = soundcloudUrl this.iframeUrl = iframeUrl + this.initialIndex = initialIndex } } }) \ No newline at end of file From f47470c85119f66ea4beff1c318166835bd6c4b3 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sun, 8 Mar 2026 11:05:50 +0100 Subject: [PATCH 24/32] Simplify modal layout and reduce pieces page font size --- layouts/default.vue | 29 ++++++++++++++++++++--------- pages/pieces.vue | 4 ++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/layouts/default.vue b/layouts/default.vue index b8f3832..b055379 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -68,26 +68,37 @@ - +
-
- - - +
+
+ + + +
-
+
-
diff --git a/pages/pieces.vue b/pages/pieces.vue index e2580e3..04febe9 100644 --- a/pages/pieces.vue +++ b/pages/pieces.vue @@ -9,11 +9,11 @@ - +
From ffe6bd44094c007eb42f68a6a83be066698d6655 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sun, 8 Mar 2026 11:10:44 +0100 Subject: [PATCH 25/32] Replace Swiper with simple image viewer with prev/next buttons --- components/ImageViewer.vue | 62 ++++++++++++++++++++++++++++++++++++++ layouts/default.vue | 4 ++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 components/ImageViewer.vue diff --git a/components/ImageViewer.vue b/components/ImageViewer.vue new file mode 100644 index 0000000..2c5a2ef --- /dev/null +++ b/components/ImageViewer.vue @@ -0,0 +1,62 @@ + + + diff --git a/layouts/default.vue b/layouts/default.vue index b055379..823250d 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -69,7 +69,9 @@
- +
+ +
From 5347bf0023d8ef4051301ae9b5a95a75b5af4ce6 Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Sun, 8 Mar 2026 11:40:37 +0100 Subject: [PATCH 26/32] Update modal and image viewer with simpler carousel --- components/ImageViewer.vue | 36 +++++++----------------------------- components/Modal/Modal.vue | 2 +- layouts/default.vue | 38 +++++++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/components/ImageViewer.vue b/components/ImageViewer.vue index 2c5a2ef..21980d2 100644 --- a/components/ImageViewer.vue +++ b/components/ImageViewer.vue @@ -1,34 +1,16 @@