import { ref, computed, watch, onMounted } from "vue"; import type { CartItem } from "../types/cart"; import type { TemplateType } from "../types/template"; const STORAGE_KEY = "vibery-cart"; const URL_PARAM = "cart"; const items = ref([]); let initialized = false; let watcherSetup = false; // Load from URL params (priority) or localStorage function loadFromStorage() { if (typeof window === "undefined") return; try { // Check URL params first const urlParams = new URLSearchParams(window.location.search); const cartParam = urlParams.get(URL_PARAM); if (cartParam) { // Parse URL cart: format is "type:name,type:name" const parsed = cartParam.split(",").map((item) => { const [type, name] = item.split(":"); return { name, type: type as TemplateType }; }); items.value = parsed.filter((i) => i.name && i.type); // Save to localStorage to persist saveToStorage(); // Clean URL without reload const newUrl = new URL(window.location.href); newUrl.searchParams.delete(URL_PARAM); window.history.replaceState({}, "", newUrl.toString()); return; } // Fallback to localStorage const saved = localStorage.getItem(STORAGE_KEY); if (saved) { items.value = JSON.parse(saved); } } catch (e) { console.error("Failed to load cart from storage:", e); items.value = []; } } // Save to localStorage function saveToStorage() { if (typeof window === "undefined") return; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(items.value)); } catch (e) { console.error("Failed to save cart to storage:", e); } } export function useCart() { // Setup watcher only once if (!watcherSetup && typeof window !== "undefined") { watch(items, saveToStorage, { deep: true }); watcherSetup = true; } // Load from storage on mount (deferred to avoid hydration mismatch) onMounted(() => { if (!initialized) { loadFromStorage(); initialized = true; } }); const count = computed(() => items.value.length); function addItem(item: CartItem): boolean { if (hasItem(item.name)) return false; items.value.push(item); return true; } function removeItem(name: string): void { items.value = items.value.filter((i) => i.name !== name); } function clearCart(): void { items.value = []; } function hasItem(name: string): boolean { return items.value.some((i) => i.name === name); } function toggleItem(item: CartItem): boolean { if (hasItem(item.name)) { removeItem(item.name); return false; } else { addItem(item); return true; } } function generateCommand(): string { if (items.value.length === 0) return "vibery install"; return `vibery install ${items.value.map((i) => i.name).join(" ")}`; } function generateShareUrl(): string { if (typeof window === "undefined" || items.value.length === 0) return ""; const cartParam = items.value.map((i) => `${i.type}:${i.name}`).join(","); const url = new URL(window.location.origin); url.searchParams.set(URL_PARAM, cartParam); return url.toString(); } function getIcon(type: TemplateType): string { const icons: Record = { agent: "ph-robot", command: "ph-terminal", mcp: "ph-plug", setting: "ph-gear", hook: "ph-webhooks-logo", skill: "ph-magic-wand", }; return icons[type] || "ph-package"; } return { items: computed(() => items.value), count, addItem, removeItem, clearCart, hasItem, toggleItem, generateCommand, generateShareUrl, getIcon, }; }