wip bsky client for the web & android
bbell.vt3e.cat
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>