diff options
| author | Fuwn <[email protected]> | 2026-02-08 07:07:59 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-08 07:07:59 -0800 |
| commit | a33dbfa6a1cb1d34ce9a5286efdb25818ff7b6c1 (patch) | |
| tree | 7d44bdcb94cc1b69fbc201a4757f27f3751c5adb /apps/web/app/api/share | |
| parent | chore: gate Vercel analytics and speed insights to production only (diff) | |
| download | asa.news-a33dbfa6a1cb1d34ce9a5286efdb25818ff7b6c1.tar.xz asa.news-a33dbfa6a1cb1d34ce9a5286efdb25818ff7b6c1.zip | |
feat: share with highlighted excerpt and fix auth redirect URLs
Add "share" button to text selection toolbar so users can share an entry
with a highlighted passage visible to visitors. The public share page
renders the highlight and scrolls to it on load.
Also fix magic link and password reset redirects to use NEXT_PUBLIC_APP_URL
instead of window.location.origin so emails link to the production domain.
Diffstat (limited to 'apps/web/app/api/share')
| -rw-r--r-- | apps/web/app/api/share/route.ts | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/apps/web/app/api/share/route.ts b/apps/web/app/api/share/route.ts index b6a9c88..58d0c2a 100644 --- a/apps/web/app/api/share/route.ts +++ b/apps/web/app/api/share/route.ts @@ -64,6 +64,26 @@ export async function POST(request: Request) { note = rawNote.trim() || null } + let highlightedText: string | null = null + let highlightTextOffset: number | null = null + let highlightTextLength: number | null = null + let highlightTextPrefix: string = "" + let highlightTextSuffix: string = "" + + if (body.highlightedText && typeof body.highlightedText === "string") { + if (typeof body.highlightTextOffset !== "number" || typeof body.highlightTextLength !== "number") { + return NextResponse.json( + { error: "highlightTextOffset and highlightTextLength are required with highlightedText" }, + { status: 400 } + ) + } + highlightedText = body.highlightedText + highlightTextOffset = body.highlightTextOffset + highlightTextLength = body.highlightTextLength + highlightTextPrefix = typeof body.highlightTextPrefix === "string" ? body.highlightTextPrefix : "" + highlightTextSuffix = typeof body.highlightTextSuffix === "string" ? body.highlightTextSuffix : "" + } + const { data: entryAccess } = await supabaseClient .from("entries") .select("id, feed_id") @@ -95,12 +115,24 @@ export async function POST(request: Request) { const { data: existingShare } = await supabaseClient .from("shared_entries") - .select("share_token") + .select("share_token, id") .eq("entry_id", entryIdentifier) .eq("user_id", user.id) .maybeSingle() if (existingShare) { + if (highlightedText !== null) { + await supabaseClient + .from("shared_entries") + .update({ + highlighted_text: highlightedText, + highlight_text_offset: highlightTextOffset, + highlight_text_length: highlightTextLength, + highlight_text_prefix: highlightTextPrefix, + highlight_text_suffix: highlightTextSuffix, + }) + .eq("id", existingShare.id) + } const shareUrl = `${origin}/shared/${existingShare.share_token}` return NextResponse.json({ shareToken: existingShare.share_token, @@ -116,6 +148,11 @@ export async function POST(request: Request) { share_token: shareToken, expires_at: expiresAt, note, + highlighted_text: highlightedText, + highlight_text_offset: highlightTextOffset, + highlight_text_length: highlightTextLength, + highlight_text_prefix: highlightTextPrefix, + highlight_text_suffix: highlightTextSuffix, }) if (error) { |