Files
remanso/src/components/ShareNote.vue
Julien Calixte 99edff828a feat(notes): use Tabler pin/repeat icons in the share popup
Replace the 📌/🔄 emoji with inline Tabler SVGs colored via --color-accent
to match the note-header icons, and reword the always-latest description so
the two options no longer share the same em-dash phrasing.
2026-07-11 12:12:30 +02:00

204 lines
5.6 KiB
Vue

<script lang="ts" setup>
import { computed } from "vue"
import { LocationQueryRaw, useRoute, useRouter } from "vue-router"
import { stackToLivePaths } from "@/modules/note/liveNotes"
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
import { confirmMessage, errorMessage } from "@/utils/notif"
const route = useRoute()
const router = useRouter()
const store = useUserRepoStore()
const stackedShas = computed<string[]>(() => {
const raw = route.query.stackedNotes
if (!raw) return []
return (Array.isArray(raw) ? raw : [raw]).filter(
(sha): sha is string => typeof sha === "string"
)
})
const hasStack = computed(() => stackedShas.value.length > 0)
const absoluteUrl = (query: LocationQueryRaw): string => {
const { href } = router.resolve({ path: route.path, query })
return `${window.location.origin}${href}`
}
// The exact snapshot: the current URL, with each note pinned to its blob sha.
const snapshotUrl = (): string => absoluteUrl({ ...route.query })
// The living link: the same notes referenced by path, so the recipient always
// lands on the latest version. See useResolveLiveNotes for the read side.
const livingUrl = (): string => {
const query = { ...route.query }
delete query.stackedNotes
return absoluteUrl({
...query,
liveNotes: stackToLivePaths(stackedShas.value, store.files)
})
}
const close = () =>
(document.getElementById("share_modal") as HTMLDialogElement | null)?.close()
const copy = async (url: string, label: string) => {
close()
try {
await navigator.clipboard.writeText(url)
confirmMessage(`🔗 ${label} link copied`)
} catch {
errorMessage("❌ Couldn't copy the link")
}
}
</script>
<template>
<button
class="btn btn-ghost btn-circle text-base-content"
title="Share this view"
aria-label="Share this view"
onclick="share_modal.showModal()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-share"
width="30"
height="30"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<circle cx="6" cy="12" r="3" />
<circle cx="18" cy="6" r="3" />
<circle cx="18" cy="18" r="3" />
<line x1="8.7" y1="10.7" x2="15.3" y2="7.3" />
<line x1="8.7" y1="13.3" x2="15.3" y2="16.7" />
</svg>
</button>
<dialog id="share_modal" class="modal">
<div class="modal-box max-w-md">
<h3 class="text-lg font-bold">Share this view</h3>
<button
type="button"
class="share-option"
@click="copy(snapshotUrl(), 'Snapshot')"
>
<span class="share-option-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-pin"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4" />
<path d="M9 15l-4.5 4.5" />
<path d="M14.5 4l5.5 5.5" />
</svg>
</span>
<span class="share-option-text">
<span class="share-option-title">This exact version</span>
<span class="share-option-desc">
Pinned to what you see now it never changes.
</span>
</span>
</button>
<button
v-if="hasStack"
type="button"
class="share-option"
@click="copy(livingUrl(), 'Always-latest')"
>
<span class="share-option-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-repeat"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4 12v-3a3 3 0 0 1 3 -3h13m-3 -3l3 3l-3 3" />
<path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3" />
</svg>
</span>
<span class="share-option-text">
<span class="share-option-title">Always latest</span>
<span class="share-option-desc">
Follows these notes, so the reader always sees the current version.
</span>
</span>
</button>
<div class="modal-action">
<form method="dialog">
<button class="btn btn-ghost">Close</button>
</form>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
</template>
<style scoped lang="scss">
.share-option {
display: flex;
align-items: flex-start;
gap: 0.75rem;
width: 100%;
margin-top: 1rem;
padding: 0.75rem 1rem;
text-align: left;
border: 1px solid var(--color-base-300);
border-radius: var(--radius-box, 0.5rem);
background-color: var(--color-base-100);
color: var(--color-base-content);
cursor: pointer;
&:hover {
border-color: var(--color-primary);
}
}
.share-option-icon {
flex-shrink: 0;
color: var(--color-accent);
}
.share-option-text {
display: flex;
flex-direction: column;
gap: 0.15rem;
}
.share-option-title {
font-weight: 600;
}
.share-option-desc {
font-size: 0.85em;
opacity: 0.75;
}
</style>