web-app/src/pages/DirectoryItem.vue
2025-02-10 21:24:15 +01:00

124 lines
No EOL
3.7 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { Share2, Copy, Check } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import DirectoryItemDetail from '@/components/directory/DirectoryItemDetail.vue'
import { type DirectoryItem } from '@/types/directory'
import { mockDirectoryItems } from '@/data/directory'
const { t } = useI18n()
const props = defineProps<{
id: string
}>()
const item = ref<DirectoryItem | null>(null)
const loading = ref(true)
const error = ref(false)
const justCopied = ref(false)
// Check if Web Share API is available
const canShare = computed(() => typeof navigator !== 'undefined' && !!navigator.share)
// Share functionality
const shareItem = async () => {
if (!item.value) return
const shareData = {
title: item.value.name,
text: item.value.description || `Check out ${item.value.name} on Atitlan Directory`,
url: window.location.href
}
if (canShare.value) {
try {
await navigator.share(shareData)
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
console.error('Error sharing:', err)
}
}
} else {
// Fallback to copying the URL
await copyToClipboard()
}
}
// Copy to clipboard functionality
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(window.location.href)
justCopied.value = true
setTimeout(() => {
justCopied.value = false
}, 2000)
} catch (err) {
console.error('Failed to copy:', err)
}
}
onMounted(async () => {
try {
const found = mockDirectoryItems.find(i => i.id === props.id)
if (!found) {
error.value = true
return
}
item.value = found
} catch (e) {
error.value = true
} finally {
loading.value = false
}
})
</script>
<template>
<div class="container mx-auto px-4 py-8">
<div class="max-w-2xl mx-auto">
<!-- Loading State -->
<div v-if="loading" class="text-center py-12">
<div class="animate-pulse">
<div class="h-8 bg-muted rounded w-3/4 mx-auto mb-4"></div>
<div class="h-4 bg-muted rounded w-1/2 mx-auto"></div>
</div>
</div>
<!-- Error State -->
<div v-else-if="error" class="text-center py-12">
<h2 class="text-xl font-semibold mb-2">{{ t('directory.itemNotFound') }}</h2>
<p class="text-muted-foreground mb-4">{{ t('directory.itemNotFoundDesc') }}</p>
<router-link to="/directory"
class="inline-flex items-center justify-center rounded-md bg-primary px-6 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90">
{{ t('directory.backToDirectory') }}
</router-link>
</div>
<!-- Directory Item -->
<template v-else-if="item">
<div class="mb-6 flex justify-between items-center">
<router-link to="/directory"
class="text-sm text-muted-foreground hover:text-foreground transition-colors">
{{ t('directory.backToDirectory') }}
</router-link>
<!-- Share Button -->
<Button variant="outline" size="sm" @click="shareItem">
<template v-if="canShare">
<Share2 class="h-4 w-4 mr-2" />
{{ t('directory.share') }}
</template>
<template v-else>
<Copy v-if="!justCopied" class="h-4 w-4 mr-2" />
<Check v-else class="h-4 w-4 mr-2" />
{{ justCopied ? t('directory.linkCopied') : t('directory.copyLink') }}
</template>
</Button>
</div>
<DirectoryItemDetail :item="item" />
</template>
</div>
</div>
</template>