--- /** * The write-a-review form: a login gate, stars, body, identity row, actions. * * One markup, two dialogs. The reviews panel on a mint page opens it directly; the * review-by-URL dialog on an index page opens it as its second step, once the reader's * pasted address has been indexed. Its behaviour lives in `lib/write-review.ts`, and * every hook below (`data-write-*`) is what that module binds to. * * Three states, only one of which is ever on screen: * * 1. **Gate.** No session and no NIP-07 extension: there is nothing to sign with, so * the dialog asks for a login before it asks for anything else. Writing a review * into a form that cannot publish it is the one outcome worth designing away. * 2. **Stars.** The rating is the whole first step. It is the one thing every review * must carry, it takes one tap, and it is what the rest of the form is *for*. * 3. **The rest.** Body, identity and publish, revealed once a rating is chosen. * * Nothing here knows which ecosystem is being reviewed. The heading is a slot because * the two dialogs have genuinely different heads — one names the mint, the other has a * step back to the address field — and the lede and placeholder are props for the same * reason: "how did minting and melting work out" means nothing about a federation. */ import { useI18n, type Locale } from '../i18n'; interface Props { locale: Locale; /** The one line under the heading, chosen per ecosystem by the caller. */ lede: string; /** The body placeholder, chosen per ecosystem by the caller. */ placeholder: string; /** * Prefix for the two element ids in here. * * A mint page carries both dialogs at once — the panel's, and the one the header * button opens — so the ids cannot be constants. `for`/`aria-describedby` are the * whole reason they exist; nothing styles by id. */ idPrefix?: string; } const { locale, lede, placeholder, idPrefix = 'review' } = Astro.props; const t = useI18n(locale); const bodyId = `${idPrefix}-body`; const countId = `${idPrefix}-count`; ---