wip bsky client for the web & android bbell.vt3e.cat
at main 66 lines 1.5 kB view raw
1<script setup lang="ts" generic="N extends PageNames"> 2import { computed } from 'vue' 3import type { PageNames, RouteParams } from '@/router' 4import { useNavigationStore } from '@/stores/navigation' 5import { getPageByName, compileUrl } from '@/router' 6 7type LinkProps<N extends PageNames> = { 8 name: N 9 ariaLabel?: string 10 params?: RouteParams<N> 11} 12 13const props = defineProps<LinkProps<N>>() 14 15const nav = useNavigationStore() 16 17const href = computed(() => { 18 const page = getPageByName(props.name) 19 if (!page) return '#' 20 21 const { url, remainingProps } = compileUrl(page.path, props.params || {}) 22 23 let path = url 24 if (Object.keys(remainingProps).length > 0) { 25 const searchParams = new URLSearchParams() 26 Object.entries(remainingProps).forEach(([key, value]) => { 27 if (typeof value === 'object') { 28 searchParams.set(key, JSON.stringify(value)) 29 } else { 30 searchParams.set(key, String(value)) 31 } 32 }) 33 path += `?${searchParams.toString()}` 34 } 35 36 return path 37}) 38 39const handleClick = (e: MouseEvent) => { 40 if (e.metaKey || e.ctrlKey) return 41 e.preventDefault() 42 console.log('Navigating to', props.name, props.params) 43 nav.push(props.name, { 44 props: props.params, 45 }) 46} 47</script> 48 49<template> 50 <a class="app-link" :href="href" @click.stop="handleClick" :aria-label="ariaLabel"> 51 <slot /> 52 </a> 53</template> 54 55<style scoped> 56.app-link { 57 text-decoration: none; 58 color: inherit; 59 cursor: pointer; 60 background: none; 61 border: none; 62 padding: 0; 63 font: inherit; 64 display: inline-block; 65} 66</style>