Five polish items landed across two commits.
Commit 1 — editor toolbar, crop, carousel, rules modal
- Description editor. Listing form now uses the shared forum post-toolbar partial (
partials/post-toolbar.php). Same Markdown / HTML toolbar, Visual ↔ source toggle, bold / italic / headings / lists / code / blockquote / link / image / emoji / GIF. One editor pipeline across the whole site. - Per-photo cropping. After picking photos (up to 10), each thumbnail in the tray has a Crop button that opens Cropper.js in a modal. Apply-crop replaces the file in the input via the DataTransfer API, so the native form submit ships the cropped blob — no fetch interception, no extra endpoint. Handles the 5 MB per-photo budget by capping the crop output at 2400 × 2400.
- Photo carousel. Replaces the thumbnail grid on listing detail pages. One large image at a time, thumbnail strip below with click-to-jump, prev/next arrows, arrow-key + touch-swipe navigation, 1/N counter. Keyboard nav only fires while the carousel has focus — doesn't steal arrows from the rest of the page.
- Rules modal on the new-listing form. "Read the rules" no longer navigates away — clicking opens a modal with the rules content inline. Pulled from a new shared partial (
partials/marketplace-rules.php) that the /market/rules page also includes, so the copy stays in sync with no duplication. Escape / backdrop / OK all close it; there's also a fallback "Open rules page" link.
Commit 2 — multi-unit listings
- Quantity field on the form (1–999). Default 1; raise it when you have multiples of the same item. Price is now labelled "per unit" on multi-unit listings.
- Sell one at a time. Clicking Sell 1 unit records a per-sale row (
listing_sales) with the buyer's username and decrementsquantity_remaining. The listing stays active until the last unit sells, at which point it flips to sold and notifies watchers. - Per-buyer feedback.
trade_feedback's unique key changed from(listing, from)to(listing, from, to)so the seller can leave one rating per buyer on a multi-unit listing. Seller's feedback form now shows a buyer dropdown populated from the sales history (only buyers they haven't rated yet). Buyers still leave one rating on the seller per listing. - Feedback unlocks incrementally. Previously gated on listing status = sold; now gated on "at least one unit has been sold with a named buyer", so sellers of multi-unit listings can rate buyers as the sales happen rather than waiting for the whole lot to clear.
- Edit protection. Raising quantity on an existing listing works; lowering it below the number already sold clamps at sold-count so you can't retroactively un-sell real sales.
- Index + detail display. Card shows "X of Y left" when quantity > 1; detail page shows a remaining-count badge and a sales-history list under the feedback card.
Single-unit listings (quantity = 1) behave exactly as before — the multi-unit plumbing is additive.
. __ ____ ___ ____ _ _
/ /_| ___| / _ \___ \(_)___| |__
| '_ \___ \| | | |__) | / __| '_ \
| (_) |__) | |_| / __/| \__ \ | | |
\___/____/ \___/_____|_|___/_| |_|
D2sk - Sysop