Formatting and Share Buttons
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<v-btn
|
||||
:color="copied ? 'success' : color"
|
||||
:variant="variant"
|
||||
:icon="iconOnly"
|
||||
:size="iconOnly ? 'x-small' : 'default'"
|
||||
@click="handleCopy"
|
||||
>
|
||||
<v-icon :start="!iconOnly" :icon="copied ? 'mdi-check' : 'mdi-content-copy'" />
|
||||
<template v-if="!iconOnly">{{ copied ? 'Copied Link To Page!' : label }}</template>
|
||||
<v-tooltip v-if="iconOnly" activator="parent" location="top">
|
||||
{{ copied ? 'Copied Link To Page!' : label }}
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useDisplay } from 'vuetify';
|
||||
import { copyToClipboard } from '@/Composables/useClipboard';
|
||||
|
||||
interface Props {
|
||||
label?: string;
|
||||
color?: string;
|
||||
variant?: 'flat' | 'text' | 'elevated' | 'tonal' | 'outlined' | 'plain';
|
||||
resetDelay?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
label: 'Copy link',
|
||||
color: 'primary',
|
||||
variant: 'outlined',
|
||||
resetDelay: 2000,
|
||||
});
|
||||
|
||||
const { mobile } = useDisplay();
|
||||
const iconOnly = mobile;
|
||||
|
||||
const copied = ref(false);
|
||||
let resetTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
async function handleCopy() {
|
||||
try {
|
||||
await copyToClipboard(window.location.href);
|
||||
copied.value = true;
|
||||
|
||||
if (resetTimeout) clearTimeout(resetTimeout);
|
||||
resetTimeout = setTimeout(() => {
|
||||
copied.value = false;
|
||||
}, props.resetDelay);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy URL:', err);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -270,20 +270,6 @@ onMounted(async () => {
|
||||
emitFilters()
|
||||
})
|
||||
|
||||
// ── Copy link ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const linkCopied = ref(false)
|
||||
|
||||
async function copyFilterLink() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(window.location.href)
|
||||
linkCopied.value = true
|
||||
setTimeout(() => { linkCopied.value = false }, 2000)
|
||||
} catch {
|
||||
// Clipboard API unavailable (e.g. non-secure context) - nothing to fall
|
||||
// back to here, the button just silently no-ops.
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -670,18 +656,6 @@ const countryFlagClass = (code: string) =>
|
||||
</v-select>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flight-filters-actions">
|
||||
<v-btn
|
||||
:prepend-icon="linkCopied ? 'mdi-check' : 'mdi-link-variant'"
|
||||
:color="linkCopied ? 'success' : undefined"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
@click="copyFilterLink"
|
||||
>
|
||||
{{ linkCopied ? 'Copied!' : 'Copy Link to This Page With Filters' }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ defineProps<{
|
||||
rowKey: (row: T) => string | number
|
||||
hasItems: (row: T) => boolean
|
||||
labelWidth?: string
|
||||
compactOnMobile?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -15,7 +16,11 @@ defineProps<{
|
||||
class="badge-row"
|
||||
>
|
||||
<!-- Label column: consumer provides content -->
|
||||
<div class="badge-label" :style="labelWidth ? `width: ${labelWidth}` : ''">
|
||||
<div
|
||||
class="badge-label"
|
||||
:class="{ 'badge-label--compact': compactOnMobile }"
|
||||
:style="labelWidth ? `width: ${labelWidth}` : ''"
|
||||
>
|
||||
<slot name="label" :row="row" />
|
||||
</div>
|
||||
|
||||
@@ -38,8 +43,6 @@ defineProps<{
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.badge-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -49,13 +52,13 @@ defineProps<{
|
||||
|
||||
.badge-label {
|
||||
flex: 0 0 auto;
|
||||
width: 15em;
|
||||
width: 21em;
|
||||
padding: 0.5em;
|
||||
border-right: 1px solid var(--table-border);
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size:0.9rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@container (max-width: 480px) {
|
||||
@@ -63,6 +66,12 @@ defineProps<{
|
||||
font-size: 0.75rem;
|
||||
width: 9em;
|
||||
}
|
||||
|
||||
.badge-label--compact {
|
||||
font-size: 0.7rem;
|
||||
width: clamp(6em, 50cqw, 9em);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.badge-scroll-container {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, usePage } from "@inertiajs/vue3"
|
||||
import { SharedProps } from "@/Types/types"
|
||||
import CopyPageButton from "@/Components/FlightsGoneBy/CopyPageButton.vue";
|
||||
|
||||
const page = usePage<SharedProps>().props
|
||||
const year = new Date().getFullYear()
|
||||
@@ -63,9 +64,17 @@ footer {
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
.footer-version {
|
||||
opacity: 0.8;
|
||||
margin-left: 0.4em;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
footer {
|
||||
padding: 0 1rem;
|
||||
flex-wrap: wrap;
|
||||
flex: 0 0 auto;
|
||||
row-gap: 0.5rem;
|
||||
padding: 0.6rem 1rem;
|
||||
}
|
||||
|
||||
.footer-copyright {
|
||||
@@ -75,10 +84,6 @@ footer {
|
||||
.footer-link {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-version {
|
||||
opacity: 0.8;
|
||||
margin-left: 0.4em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,7 +31,7 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
|
||||
<Logo variant="color" />
|
||||
</Link>
|
||||
|
||||
<UserSearchBox density="compact" style="max-width:400px; width: 400px;" />
|
||||
<UserSearchBox class="nav-desktop" density="compact" style="max-width:400px; width: 400px;" />
|
||||
<NotificationMenu v-if="page.props.auth?.user" :unread-count="page.props.unread_notification_count" />
|
||||
|
||||
<!-- Desktop nav -->
|
||||
|
||||
Reference in New Issue
Block a user