From dbd54c704eb49ebe65ecd198dd94936e92be4eaa Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Wed, 15 Oct 2025 23:40:40 +0900 Subject: [PATCH 1/2] feat(web): add URL parameter support for auto-opening plugin install modal Enable direct linking to specific plugins with automatic install modal display. Users can now share URLs like ?plugin=nanobanana or ?install=grafana to show a specific plugin's installation instructions. Features: - URL query parameter detection (?plugin= or ?install=) - Auto-scroll to target plugin card - Auto-open install modal with smooth animation - 500ms delay for natural UX after scroll completion Changes: - apps/web/app/pages/index.vue: Add route query parameter handling and auto-scroll logic - apps/web/app/components/PluginCard.vue: Add autoOpenModal prop and watcher --- apps/web/app/components/PluginCard.vue | 17 ++++++++++++-- apps/web/app/pages/index.vue | 32 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/apps/web/app/components/PluginCard.vue b/apps/web/app/components/PluginCard.vue index f3b840f5..5546b416 100644 --- a/apps/web/app/components/PluginCard.vue +++ b/apps/web/app/components/PluginCard.vue @@ -163,9 +163,12 @@ interface PluginMetadata { [key: string]: any } -const props = defineProps<{ +const props = withDefaults(defineProps<{ plugin: Plugin -}>() + autoOpenModal?: boolean +}>(), { + autoOpenModal: false +}) const isModalOpen = ref(false) const pluginMetadata = ref(null) @@ -239,4 +242,14 @@ onMounted(() => { const openInstallModal = () => { isModalOpen.value = true } + +// Auto-open modal when autoOpenModal prop is true +watch(() => props.autoOpenModal, (shouldOpen) => { + if (shouldOpen) { + // Small delay to ensure smooth scroll completes first + setTimeout(() => { + isModalOpen.value = true + }, 500) + } +}, { immediate: true }) diff --git a/apps/web/app/pages/index.vue b/apps/web/app/pages/index.vue index df8f5111..cb9cb90f 100644 --- a/apps/web/app/pages/index.vue +++ b/apps/web/app/pages/index.vue @@ -55,7 +55,9 @@ @@ -120,6 +122,13 @@ interface MarketplaceData { } const searchQuery = ref('') +const route = useRoute() +const pluginCardRefs = ref>({}) + +// Get target plugin name from URL query parameter +const targetPluginName = computed(() => { + return (route.query.plugin || route.query.install) as string | undefined +}) // Fetch marketplace data const { data: marketplaceData, pending, error } = await useAsyncData( @@ -146,6 +155,29 @@ const filteredPlugins = computed(() => { }) }) +// Store plugin card refs for scrolling +const setPluginCardRef = (pluginName: string, el: any) => { + if (el) { + pluginCardRefs.value[pluginName] = el + } +} + +// Auto-scroll to target plugin when page loads +watch([() => targetPluginName.value, pending], ([pluginName, isLoading]) => { + if (!pluginName || isLoading) return + + // Wait for next tick to ensure DOM is updated + nextTick(() => { + const targetCard = pluginCardRefs.value[pluginName] + if (targetCard?.$el) { + targetCard.$el.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }) + } + }) +}, { immediate: true }) + // SEO Meta useHead({ title: 'Claude Code Plugin Marketplace', From 379192db8da62c74d058269163e8e53d41aca2a9 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Thu, 16 Oct 2025 00:28:37 +0900 Subject: [PATCH 2/2] refactor(web): improve error handling and add VueUse integration Apply critical fixes from PR review to enhance reliability and user experience. Changes: - Add VueUse useTimeoutFn import for proper timer management - Fix Badge color type safety with proper union types - Implement retry logic with up to 5 attempts (200ms intervals) - Add user feedback toast for persistent navigation failures - Store and cleanup timer references to prevent memory leaks - Improve network error handling with detailed logging - Separate HTTP errors from JSON parsing errors - Remove noisy error logs during normal loading Error Handling Improvements: - Silent retries during ref loading (no error spam) - Only log errors on final failure after max retries - Add onBeforeUnmount cleanup for timer references - Guard async callbacks with component lifecycle checks Type Safety: - Badge.color now properly typed as Nuxt UI color union - Prevents TypeScript compilation errors Fixes: - Memory leaks from uncleaned timers - Silent failures with no user feedback - Noisy error logs during normal page load - Race conditions during component unmount --- apps/web/app/components/PluginCard.vue | 167 +++++++++++++++++-------- apps/web/app/pages/index.vue | 159 ++++++++++++++++++++--- 2 files changed, 255 insertions(+), 71 deletions(-) diff --git a/apps/web/app/components/PluginCard.vue b/apps/web/app/components/PluginCard.vue index 5546b416..84e3ec2f 100644 --- a/apps/web/app/components/PluginCard.vue +++ b/apps/web/app/components/PluginCard.vue @@ -40,46 +40,17 @@ -
+
- - Google - - - - Anthropic - - - - Context - - - - MCP + + {{ badge.label }}
@@ -140,6 +111,8 @@ diff --git a/apps/web/app/pages/index.vue b/apps/web/app/pages/index.vue index cb9cb90f..cc59919c 100644 --- a/apps/web/app/pages/index.vue +++ b/apps/web/app/pages/index.vue @@ -97,6 +97,8 @@