From 3babb277d0429cebf54fdaa14cbd5ab3eafc6770 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 2 Jan 2026 01:12:56 -0500 Subject: [PATCH] a --- package-lock.json | 122 ++-- src/api/client.js | 14 + src/components/Map/MapView.jsx | 733 +++++++++++------------ src/components/Posts/PostCard.jsx | 102 +++- src/components/Search/SmartSearchBar.jsx | 37 +- src/services/recoSearch.js | 98 ++- src/styles/map.css | 382 +++++++++++- src/styles/posts.css | 47 ++ src/styles/smartSearchBar.css | 45 ++ 9 files changed, 1089 insertions(+), 491 deletions(-) diff --git a/package-lock.json b/package-lock.json index c9e6ef6..6374637 100644 --- a/package-lock.json +++ b/package-lock.json @@ -346,9 +346,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -466,9 +466,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -673,9 +673,9 @@ } }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.3.1.tgz", - "integrity": "sha512-TUM5JD40H2mgtVXl5IwWz03BuQabw8oZQLJTmPpJA0YTYF+B+oZppy5lNMO6bMvHzB+/5mxqW9VLG3wFdeqtOw==", + "version": "24.4.1", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.4.1.tgz", + "integrity": "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==", "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", @@ -702,9 +702,9 @@ } }, "node_modules/@maplibre/vt-pbf": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.1.0.tgz", - "integrity": "sha512-9LjFAoWtxdGRns8RK9vG3Fcw/fb3eHMxvAn2jffwn3jnVO1k49VOv6+FEza70rK7WzF8GnBiKa0K39RyfevKUw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.2.0.tgz", + "integrity": "sha512-bxrk/kQUwWXZgmqYgwOCnZCMONCRi3MJMqJdza4T3E4AeR5i+VyMnaJ8iDWtWxdfEAJRtrzIOeJtxZSy5mFrFA==", "license": "MIT", "dependencies": { "@mapbox/point-geometry": "^1.1.0", @@ -717,9 +717,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz", - "integrity": "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", "dev": true, "license": "MIT", "optional": true, @@ -727,6 +727,10 @@ "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, "node_modules/@oxc-project/runtime": { @@ -1219,9 +1223,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.5.tgz", - "integrity": "sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==", + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1298,9 +1302,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001759", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", - "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", + "version": "1.0.30001762", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", "dev": true, "funding": [ { @@ -1556,9 +1560,9 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "peer": true, @@ -1569,7 +1573,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -1637,9 +1641,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", - "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1695,9 +1699,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2212,9 +2216,9 @@ "license": "ISC" }, "node_modules/keycloak-js": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.1.tgz", - "integrity": "sha512-bZt6fQj/TLBAmivXSxSlqAJxBx/knNZDQGJIW4ensGYGN4N6tUKV8Zj3Y7/LOV8eIpvWsvqV70fbACihK8Ze0Q==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.2.tgz", + "integrity": "sha512-ug7pNZ1xNkd7PPkerOJCEU2VnUhS7CYStDOCFJgqCNQ64h53ppxaKrh4iXH0xM8hFu5b1W6e6lsyYWqBMvaQFg==", "license": "Apache-2.0", "workspaces": [ "test" @@ -2539,9 +2543,9 @@ } }, "node_modules/maplibre-gl": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.14.0.tgz", - "integrity": "sha512-O2ok6N/bQ9NA9nJ22r/PRQQYkUe9JwfDMjBPkQ+8OwsVH4TpA5skIAM2wc0k+rni5lVbAVONVyBvgi1rF2vEPA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.15.0.tgz", + "integrity": "sha512-pPeu/t4yPDX/+Uf9ibLUdmaKbNMlGxMAX+tBednYukol2qNk2TZXAlhdohWxjVvTO3is8crrUYv3Ok02oAaKzA==", "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", @@ -2551,9 +2555,9 @@ "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", - "@maplibre/maplibre-gl-style-spec": "^24.3.1", + "@maplibre/maplibre-gl-style-spec": "^24.4.1", "@maplibre/mlt": "^1.1.2", - "@maplibre/vt-pbf": "^4.1.0", + "@maplibre/vt-pbf": "^4.2.0", "@types/geojson": "^7946.0.16", "@types/geojson-vt": "3.2.5", "@types/supercluster": "^7.1.3", @@ -2864,9 +2868,9 @@ "license": "ISC" }, "node_modules/react": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", - "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "peer": true, "engines": { @@ -2874,16 +2878,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", - "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.1" + "react": "^19.2.3" } }, "node_modules/react-refresh": { @@ -2897,9 +2901,9 @@ } }, "node_modules/react-router": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.10.1.tgz", - "integrity": "sha512-gHL89dRa3kwlUYtRQ+m8NmxGI6CgqN+k4XyGjwcFoQwwCWF6xXpOCUlDovkXClS0d0XJN/5q7kc5W3kiFEd0Yw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.11.0.tgz", + "integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -2919,12 +2923,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.10.1.tgz", - "integrity": "sha512-JNBANI6ChGVjA5bwsUIwJk7LHKmqB4JYnYfzFwyp2t12Izva11elds2jx7Yfoup2zssedntwU0oZ5DEmk5Sdaw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.11.0.tgz", + "integrity": "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==", "license": "MIT", "dependencies": { - "react-router": "7.10.1" + "react-router": "7.11.0" }, "engines": { "node": ">=20.0.0" @@ -3134,9 +3138,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -3299,9 +3303,9 @@ } }, "node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz", + "integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==", "dev": true, "license": "MIT", "peer": true, diff --git a/src/api/client.js b/src/api/client.js index e6a4840..995e73b 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -108,6 +108,11 @@ async function resolveAssetRefsInPosts(posts) { [p?.image_small, p?.image_medium, p?.image_large, p?.image, p?.media_url].forEach((v) => { if (isAssetRef(v)) ids.push(v.replace("asset://", "")); }); + if (Array.isArray(p?.media_urls)) { + p.media_urls.forEach((v) => { + if (isAssetRef(v)) ids.push(v.replace("asset://", "")); + }); + } } const uniq = Array.from(new Set(ids)); if (!uniq.length) return posts; @@ -127,6 +132,15 @@ async function resolveAssetRefsInPosts(posts) { if (resolved[id]) clone[k] = resolved[id]; } }); + if (Array.isArray(clone.media_urls)) { + clone.media_urls = clone.media_urls.map((value) => { + if (isAssetRef(value)) { + const id = value.replace("asset://", ""); + return resolved[id] || value; + } + return value; + }); + } return clone; }); } diff --git a/src/components/Map/MapView.jsx b/src/components/Map/MapView.jsx index 04c9cb6..eb3dab2 100644 --- a/src/components/Map/MapView.jsx +++ b/src/components/Map/MapView.jsx @@ -23,6 +23,92 @@ import UserProfile from "../Profile/UserProfile"; import { fetchPostById, fetchPostByUrl } from "../../api/client"; import { trackEvent } from "../../utils/analytics"; +const CONTENT_CREATOR_MODES = [ + { + id: "live", + label: "Live video", + icon: "fa-solid fa-broadcast-tower", + hint: "Broadcast a live scene with a headline or link.", + detail: [ + "Drop the stream URL or quick headline to pin the feed instantly.", + "We’ll open the location where you place the crosshair so viewers know where to tune.", + ], + }, + { + id: "link", + label: "Link story", + icon: "fa-solid fa-link", + hint: "Share a URL and we’ll prefill the preview.", + detail: [ + "Paste a news link, playlist, or update so we can fetch an image and snippet.", + "Choose the most relevant pin so the story belongs to the right neighborhood.", + ], + }, + { + id: "photo", + label: "Photo story", + icon: "fa-solid fa-camera-retro", + hint: "Upload or link an image with context.", + detail: [ + "Upload a photo set or paste an image URL from your gallery.", + "Caption quickly so the community knows what they’re looking at.", + ], + }, + { + id: "text", + label: "Written update", + icon: "fa-solid fa-pen-to-square", + hint: "Type a short report or microblog.", + detail: [ + "Write the key message in the title field (or add more context in the body).", + "Use subcategory filters to mark the tone: News, Event, Market, etc.", + ], + }, + { + id: "other", + label: "Other", + icon: "fa-solid fa-ellipsis", + hint: "Custom content that spans media types.", + detail: [ + "Mix media, public drafts, or reference notes in one place.", + "Tag a region or Island to give the update a home.", + ], + }, +]; + +const MODE_FLOW_CONFIG = { + live: { + hero: "Pin where the live scene is happening and paste your stream link or headline.", + placeholder: "Streaming link or headline", + hint: "We’ll treat this as a live broadcast and show it as soon as the pin lands.", + bodyPlaceholder: "Context for viewers, optional.", + }, + link: { + hero: "Drop the link, describe what it is, and pin the relevant spot.", + placeholder: "Article or playlist URL", + hint: "We’ll auto-fetch a preview once the link is detected.", + bodyPlaceholder: "What matters about this link?", + }, + photo: { + hero: "Snap or upload a photo and pin the place you captured it.", + placeholder: "Photo caption or image URL", + hint: "Add a quick caption so the community knows what they’re seeing.", + bodyPlaceholder: "Describe the scene in a few words.", + }, + text: { + hero: "Type a short update and pin the area you’re reporting from.", + placeholder: "Headline or short note", + hint: "Readers should understand the gist before opening the full card.", + bodyPlaceholder: "Provide more context, opinions, or call to actions.", + }, + other: { + hero: "Combine media, notes, or references and pin wherever it matters.", + placeholder: "Describe your update", + hint: "This mode is flexible—add whatever helps the reader.", + bodyPlaceholder: "Add links, attachments, or extra context if needed.", + }, +}; + export default function MapView({ theme = "dark", onPostsState, @@ -198,7 +284,14 @@ export default function MapView({ const [draftSubCategory, setDraftSubCategory] = useState( CREATE_CATEGORY_MAP.News[0] ); + const [contentMode, setContentMode] = useState(CONTENT_CREATOR_MODES[0].id); + const currentContentMode = + CONTENT_CREATOR_MODES.find((mode) => mode.id === contentMode) || + CONTENT_CREATOR_MODES[0]; + const currentFlow = MODE_FLOW_CONFIG[contentMode] || MODE_FLOW_CONFIG.text; const [draftCoords, setDraftCoords] = useState(null); + const [modeSelectorVisible, setModeSelectorVisible] = useState(false); + const [modeChosen, setModeChosen] = useState(false); const [draftImage, setDraftImage] = useState(""); const [draftImageSmall, setDraftImageSmall] = useState(""); const [draftImageMedium, setDraftImageMedium] = useState(""); @@ -888,6 +981,22 @@ export default function MapView({ return () => document.removeEventListener('click', handleAuthorClick); }, []); + const closeCreateModal = () => { + setIsCreating(false); + setModeSelectorVisible(false); + setModeChosen(false); + }; + + const handleModeSelect = (modeId) => { + setContentMode(modeId); + setModeSelectorVisible(false); + setModeChosen(true); + }; + + const handlePrevStep = () => { + setCreateStep((prev) => Math.max(0, prev - 1)); + }; + const handleOpenCreate = () => { if (!authenticated) { try { @@ -946,6 +1055,8 @@ export default function MapView({ const list = CREATE_CATEGORY_MAP[main] || CREATE_CATEGORY_MAP.News; setDraftSubCategory(list[0]); setDraftCoords(null); + setModeSelectorVisible(true); + setModeChosen(false); }; const handleSearchSubmit = (e) => { @@ -1357,408 +1468,278 @@ export default function MapView({ - {isCreating && ( + {isCreating && modeChosen && (
)} - {isCreating && ( -
-
- Create wire - + ))} +
+
+ )} + + {isCreating && modeChosen && ( +
+
+ {`Share as ${currentContentMode.label}`} +
- -
- {["Pin", "Details", "Share"].map((label, idx) => ( -
-
{idx + 1}
-
{label}
-
- ))} -
-
- -
- - {createStep === 0 && ( -
- - Move the map, aim with the crosshair — your wire will be pinned - there. - - -
- - - -
- - { - const next = e.target.value; - if (isLikelyUrl(next)) { - setDraftTitle(next); - setTitleTouched(false); - setDraftUrl(next.trim()); - setUrlPreviewError(""); - setDraftSource(""); - setDraftPublishedAt(""); - handleUrlPreview(next); - return; - } - setDraftTitle(next); - setTitleTouched(true); - }} - /> -
- Type a title or paste a link — we’ll auto-fill from the URL. -
- {draftUrl && !draftSource && !draftPublishedAt && ( -
- Link detected · fetching preview... -
+
+
Step {createStep + 1} / 3
+

{currentFlow.hero}

+
+ {createStep === 0 && ( +

{currentFlow.hint}

)} - {(draftSource || draftPublishedAt) && ( -
- {draftSource ? {draftSource} : null} - {draftPublishedAt ? ( - {formatPreviewDate(draftPublishedAt)} - ) : null} -
- )} - {urlPreviewError && ( -
{urlPreviewError}
- )} -
- )} - - {createStep === 1 && ( -
- {(draftImagePreview || - draftImageLarge || - draftImageMedium || - draftImageSmall || - draftImage) && ( -
- Link preview -
- {draftSource ? {draftSource} : null} - {draftPublishedAt ? ( - {formatPreviewDate(draftPublishedAt)} - ) : null} -
-
- )} - -