{"release_id":"01a1c502-4ad1-0000-ec62-adc54d3c69aa","chunk_id":"01a1c502-4c48-7080-81aa-82b799ca6571","file":"S3yP0DPh.mjs","mappings":"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","names":["alreadyPosted","variant","open","$.state","caption","nichePick","submitting","error","toastVisible","defaultLabel","$.derived","$$props","t","submit","$.get","$.set","res","j","invalidateAll","onBackdropClick","onKeydown","portal","node","placeholder","button","root_1","text","$.sibling","$.child","$.reset","$.append","$$anchor","button_1","root_2","text_1","button_2","root_3","text_2","$$render","consequent","consequent_1","alternate","div","root_4","div_1","div_2","button_3","text_3","h3","button_4","text_5","div_3","textarea","$.remove_textarea_child","div_4","div_5","NichePicker","node_3","n","$$value","p","root_5","consequent_2","div_6","root_6","consequent_3","$.action","$$node","$.set_attribute","$2","$4","$.delegated","consequent_4","div_7","root_7","$.template_effect","$0","$.set_text","text_9","consequent_5"],"sources":["../../../../../../src/lib/components/post/PostToFeedCta.svelte"],"sourcesContent":["<script lang=\"ts\">\n\timport { t } from '$lib/i18n';\n\timport { invalidateAll } from '$app/navigation';\n\timport NichePicker from '$lib/components/post/NichePicker.svelte';\n\timport type { NicheOption } from '$lib/types/niche';\n\n\t/**\n\t * RAT-271: \"Post to feed\" CTA used on /d/[code], /rate/result/[id],\n\t * /a/submit (post-deploy variant), and /b/[code]. Renders an inline\n\t * button that opens a bottom-sheet modal with:\n\t *   - caption textarea (optional)\n\t *   - NichePicker (optional)\n\t *   - submit gomb\n\t *\n\t * The parent surface stays untouched layout-wise — drops the CTA\n\t * wherever makes sense (next to score/result/etc).\n\t */\n\n\ttype Kind = 'duel_result' | 'rate_result' | 'arena_submission' | 'beat_me';\n\n\tinterface Props {\n\t\tkind: Kind;\n\t\tsourceContentId: string;\n\t\t/** Override the default CTA label (e.g. \"share to feed\" vs \"post to feed\"). */\n\t\tlabel?: string;\n\t\t/** Disable the CTA — typically because already posted. */\n\t\talreadyPosted?: boolean;\n\t\t/** Style variant: 'inline' (compact, bordered), 'text' (borderless link), or 'block' (full-width card). */\n\t\tvariant?: 'inline' | 'block' | 'text';\n\t\t/** Fired once the post lands successfully. Used by callers that\n\t\t *  need to navigate (e.g. arena submit → /a after sharing) or\n\t\t *  dismiss a surrounding prompt. */\n\t\tonposted?: () => void;\n\t}\n\n\tlet {\n\t\tkind,\n\t\tsourceContentId,\n\t\tlabel,\n\t\talreadyPosted = false,\n\t\tvariant = 'inline',\n\t\tonposted\n\t}: Props = $props();\n\n\tlet open = $state(false);\n\tlet caption = $state('');\n\tlet nichePick = $state<NicheOption | null>(null);\n\tlet submitting = $state(false);\n\tlet error = $state('');\n\tlet toastVisible = $state(false);\n\n\tconst defaultLabel = $derived(label ?? (alreadyPosted ? t('posted to feed ✓') : t('post to feed')));\n\n\tasync function submit() {\n\t\tif (submitting) return;\n\t\t// RAT-269: niche is required for cross-content posts so they always\n\t\t// land in *some* niche feed rather than floating in /f home with\n\t\t// no surface. Block submit + show why instead of silently failing.\n\t\tif (!nichePick) {\n\t\t\terror = t('pick a niche first — posts need to land somewhere.');\n\t\t\treturn;\n\t\t}\n\t\tsubmitting = true;\n\t\terror = '';\n\t\ttry {\n\t\t\tconst res = await fetch('/api/post/create', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tkind,\n\t\t\t\t\tsourceContentId,\n\t\t\t\t\tcaption: caption.trim() || null,\n\t\t\t\t\tnicheId: nichePick.id\n\t\t\t\t})\n\t\t\t});\n\t\t\tconst j = await res.json();\n\t\t\tif (!res.ok) {\n\t\t\t\terror = j.error ?? t('failed');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// success — close + toast + refresh + let the parent know\n\t\t\topen = false;\n\t\t\tcaption = '';\n\t\t\tnichePick = null;\n\t\t\ttoastVisible = true;\n\t\t\tsetTimeout(() => (toastVisible = false), 2400);\n\t\t\tawait invalidateAll();\n\t\t\tonposted?.();\n\t\t} catch {\n\t\t\terror = t('network error — try again');\n\t\t} finally {\n\t\t\tsubmitting = false;\n\t\t}\n\t}\n\n\tfunction onBackdropClick(e: MouseEvent) {\n\t\tif (e.target === e.currentTarget) open = false;\n\t}\n\n\tfunction onKeydown(e: KeyboardEvent) {\n\t\tif (e.key === 'Escape') open = false;\n\t}\n\n\t// Portal the overlay to <body> so it escapes any transformed/overflow-clipped\n\t// ancestor that would otherwise trap this fixed modal below the app nav and\n\t// make it impossible to close. Comment placeholder keeps Svelte's {#if}\n\t// teardown pointed at a node that still lives in the original slot.\n\tfunction portal(node: HTMLElement) {\n\t\tconst placeholder = document.createComment('post-feed-portal');\n\t\tnode.parentNode?.replaceChild(placeholder, node);\n\t\tdocument.body.appendChild(node);\n\t\treturn {\n\t\t\tdestroy() {\n\t\t\t\tnode.remove();\n\t\t\t\tplaceholder.remove();\n\t\t\t}\n\t\t};\n\t}\n</script>\n\n<svelte:window onkeydown={onKeydown} />\n\n<!-- TRIGGER -->\n{#if variant === 'inline'}\n\t<button\n\t\ttype=\"button\"\n\t\tonclick={() => (open = true)}\n\t\tdisabled={alreadyPosted}\n\t\tclass=\"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-coral/40 bg-coral/5 text-coral text-xs font-semibold hover:bg-coral/10 transition-colors disabled:opacity-50 disabled:cursor-default\"\n\t>\n\t\t<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n\t\t\t<path d=\"M6 9V3M3 6l3-3 3 3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n\t\t</svg>\n\t\t{defaultLabel}\n\t</button>\n{:else if variant === 'text'}\n\t<button\n\t\ttype=\"button\"\n\t\tonclick={() => (open = true)}\n\t\tdisabled={alreadyPosted}\n\t\tclass=\"inline-flex items-center gap-1.5 text-xs font-semibold text-muted hover:text-text transition-colors disabled:opacity-50 disabled:cursor-default\"\n\t>\n\t\t<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n\t\t\t<path d=\"M6 9V3M3 6l3-3 3 3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n\t\t</svg>\n\t\t{defaultLabel}\n\t</button>\n{:else}\n\t<button\n\t\ttype=\"button\"\n\t\tonclick={() => (open = true)}\n\t\tdisabled={alreadyPosted}\n\t\tclass=\"w-full flex items-center justify-center gap-2 px-4 py-3 rounded-xl border border-coral/40 bg-gradient-to-br from-coral/10 to-bg text-coral font-semibold text-sm hover:bg-coral/10 transition-colors disabled:opacity-50 disabled:cursor-default\"\n\t>\n\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n\t\t\t<path d=\"M7 11V3M3 7l4-4 4 4\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n\t\t</svg>\n\t\t{defaultLabel}\n\t</button>\n{/if}\n\n<!-- CENTERED MODAL -->\n{#if open}\n\t<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->\n\t<!-- z-[210] sits above the duel chat, share-community-modal (z-[200]),\n\t     and the rest of the app. Centered always — bottom-sheet collided\n\t     with sticky chat inputs on the duel/beat pages. -->\n\t<div\n\t\tuse:portal\n\t\tclass=\"fixed inset-0 z-[210] flex items-center justify-center bg-bg/80 backdrop-blur-sm p-4\"\n\t\tonclick={onBackdropClick}\n\t>\n\t\t<div class=\"w-full max-w-md bg-surface border border-border rounded-2xl shadow-soft flex flex-col max-h-[85dvh]\">\n\t\t\t<!-- header -->\n\t\t\t<div class=\"px-4 py-3 border-b border-border flex items-center justify-between\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonclick={() => (open = false)}\n\t\t\t\t\tclass=\"text-sm text-muted hover:text-text\"\n\t\t\t\t>{t('cancel')}</button>\n\t\t\t\t<h3 class=\"font-display font-semibold text-base\">{t('post to feed')}</h3>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tonclick={submit}\n\t\t\t\t\tdisabled={submitting || !nichePick}\n\t\t\t\t\ttitle={nichePick ? '' : t('pick a niche first')}\n\t\t\t\t\tclass=\"text-sm font-semibold text-coral hover:text-coral-dark disabled:cursor-not-allowed disabled:opacity-40\"\n\t\t\t\t>{submitting ? '…' : t('post')}</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"p-4 space-y-3 flex-1 overflow-y-auto\">\n\t\t\t\t<!-- caption -->\n\t\t\t\t<textarea\n\t\t\t\t\tbind:value={caption}\n\t\t\t\t\tplaceholder={t('add a caption (optional)…')}\n\t\t\t\t\trows=\"3\"\n\t\t\t\t\tmaxlength=\"2000\"\n\t\t\t\t\tclass=\"w-full px-3 py-2 rounded-lg bg-bg border border-border focus:border-coral outline-none text-sm resize-none placeholder:text-muted\"\n\t\t\t\t></textarea>\n\n\t\t\t\t<!-- niche picker — required (see submit guard) so every\n\t\t\t\t\t cross-content post lands in a niche feed. -->\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"text-[10px] uppercase tracking-widest text-muted mb-1.5\">\n\t\t\t\t\t\t{t('niche')} <span class=\"text-coral\">*</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<NichePicker bind:selected={nichePick} onSelect={(n) => (nichePick = n)} allowSkip={false} />\n\t\t\t\t\t{#if !nichePick}\n\t\t\t\t\t\t<p class=\"mt-1.5 text-[11px] text-muted/70\">{t('pick a niche so your post lands in a community feed.')}</p>\n\t\t\t\t\t{/if}\n\t\t\t\t</div>\n\n\t\t\t\t{#if error}\n\t\t\t\t\t<div class=\"px-3 py-2 rounded-lg bg-coral/10 border border-coral/40 text-xs text-coral\">{error}</div>\n\t\t\t\t{/if}\n\t\t\t</div>\n\t\t</div>\n\t</div>\n{/if}\n\n<!-- success toast -->\n{#if toastVisible}\n\t<div class=\"fixed bottom-6 left-1/2 -translate-x-1/2 px-4 py-2 rounded-lg bg-surface-2 border border-border text-sm shadow-soft z-[230] flex items-center gap-2\">\n\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" class=\"text-accent\">\n\t\t\t<path d=\"M3 7l3 3 5-5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n\t\t</svg>\n\t\t{t('posted to feed')}\n\t</div>\n{/if}\n"],"version":3}