fix: ui fixes

This commit is contained in:
gosangam
2026-06-14 15:56:58 +05:30
parent 0280a81777
commit 752ad20fed
2 changed files with 68 additions and 6 deletions
+61
View File
@@ -25,6 +25,7 @@
import { useEffect, useRef, useState } from "react";
import { useRouter, usePathname } from "next/navigation";
import { Check, Link2 } from "lucide-react";
import { cn } from "@/lib/utils";
const SEARCH_RETURN_KEY = "spsays_from_search";
@@ -91,6 +92,43 @@ export function PageHeader({
return () => window.removeEventListener("scroll", onScroll);
}, [sticky]);
// "Copy link to this page" — copies the full, unshortened absolute URL of
// the active page. Deliberately bypasses useCopyFeedback (which rewrites
// `?hl=` highlight URLs into short /share links); here we want the literal
// page URL. The write is synchronous within the click so a single tap works.
const [copied, setCopied] = useState(false);
const copyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
return () => {
if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
};
}, []);
async function copyPageLink() {
const url = window.location.href;
try {
await navigator.clipboard.writeText(url);
} catch {
// Fallback for browsers without the async clipboard API.
const ta = document.createElement("textarea");
ta.value = url;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.focus();
ta.select();
try {
document.execCommand("copy");
} catch {
// silent fail
}
document.body.removeChild(ta);
}
setCopied(true);
if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
copyTimerRef.current = setTimeout(() => setCopied(false), 1500);
}
return (
<header
className={cn(
@@ -123,6 +161,29 @@ export function PageHeader({
) : (
children
)}
{/* Copy-link-to-this-page control, anchored at the header's bottom. */}
<div className="mt-3">
<button
type="button"
onClick={copyPageLink}
aria-label="Copy link to this page"
title="Copy link to this page"
className={cn(
"inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1 text-xs transition-colors",
copied
? "text-foreground border-primary/40"
: "text-muted-foreground hover:text-foreground hover:bg-muted",
)}
>
{copied ? (
<Check className="size-3.5 text-primary" />
) : (
<Link2 className="size-3.5" />
)}
{copied ? "Link copied" : "Copy link to this page"}
</button>
</div>
</div>
</header>
);
+7 -6
View File
@@ -12,10 +12,7 @@ import {
} from "lucide-react";
import { toast } from "sonner";
import { formatCopyText, getSourceReference } from "@/lib/source-reference";
import {
buildHighlightUrl,
buildShortHighlightUrl,
} from "@/lib/text-highlight";
import { buildHighlightUrl } from "@/lib/text-highlight";
import { bookmarks, SocialError } from "@/lib/social";
import {
KautilyaIcon,
@@ -393,8 +390,12 @@ export function TextSelectionToolbar() {
}
async function onCopyLink() {
const url = await buildShortHighlightUrl(selectedText);
await copy(url);
// Hand copy() the long ?hl= URL synchronously — it shortens it to the
// /share/<code> form inside the ClipboardItem promise, which keeps the
// click's transient activation alive so the short link copies in one go.
// (Pre-awaiting buildShortHighlightUrl here would burn the gesture and
// require a second click, the way "copy caption" via onCopyText doesn't.)
await copy(buildHighlightUrl(selectedText));
toast.success("Link copied", { duration: 1500 });
finishAction();
}