From b76eeafeaa9371f0d94d79733e2a0c059cdb1c45 Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Sat, 14 Mar 2026 21:36:36 -0400 Subject: [PATCH] use styling from previous branch --- .../actions/ShareOptions/DomainOptions.tsx | 334 ++++++++++-------- components/ActionBar/ProfileButton.tsx | 7 +- components/Domains/DomainList.tsx | 167 +++++++-- components/Domains/ManageDomains.tsx | 16 +- components/Icons/UnlinkTiny.tsx | 18 + components/Icons/WebSmall.tsx | 19 + components/utils/CoordDebugger.tsx | 30 ++ 7 files changed, 408 insertions(+), 183 deletions(-) create mode 100644 components/Icons/UnlinkTiny.tsx create mode 100644 components/Icons/WebSmall.tsx create mode 100644 components/utils/CoordDebugger.tsx diff --git a/app/[leaflet_id]/actions/ShareOptions/DomainOptions.tsx b/app/[leaflet_id]/actions/ShareOptions/DomainOptions.tsx index aa94b680..4a856f03 100644 --- a/app/[leaflet_id]/actions/ShareOptions/DomainOptions.tsx +++ b/app/[leaflet_id]/actions/ShareOptions/DomainOptions.tsx @@ -15,8 +15,11 @@ import { removeDomainRoute } from "actions/domains/removeDomainRoute"; import { useReplicache } from "src/replicache"; import { AddDomainForm } from "components/Domains/AddDomainForm"; import { DomainSettingsView } from "components/Domains/DomainSettingsView"; -import { AddTiny } from "components/Icons/AddTiny"; import { DotLoader } from "components/utils/DotLoader"; +import { GoToArrow } from "components/Icons/GoToArrow"; +import { LoadingTiny } from "components/Icons/LoadingTiny"; +import { UnlinkTiny } from "components/Icons/UnlinkTiny"; +import Link from "next/link"; type DomainMenuState = | { state: "default" } @@ -73,11 +76,9 @@ const DomainOptions = (props: { }) => { let { data: domains, mutate: mutateDomains } = useLeafletDomains(); let [selectedDomain, setSelectedDomain] = useState( - domains?.[0]?.domain, - ); - let [selectedRoute, setSelectedRoute] = useState( - domains?.[0]?.route.slice(1) || "", + undefined, ); + let [selectedRoute, setSelectedRoute] = useState(""); let { identity, mutate: mutateIdentity } = useIdentityData(); let { permission_token } = useReplicache(); @@ -85,15 +86,32 @@ const DomainOptions = (props: { let toaster = useToaster(); let publishLink = useReadOnlyShareLink(); - // Filter out domains assigned to publications — they can't be used for leaflets - let availableDomains = (identity?.custom_domains || []).filter( + // Filter out domains assigned to publications + let allDomains = (identity?.custom_domains || []).filter( (d: CustomDomain) => d.publication_domains.length === 0, ); + // Categorize domains + let linkedDomains = allDomains.filter((d: CustomDomain) => + d.custom_domain_routes.some( + (r) => r.edit_permission_token === permission_token.id, + ), + ); + let pendingDomainsList: CustomDomain[] = []; + let availableDomainsList: CustomDomain[] = []; + + // We'll categorize in the render since pending requires a hook per domain + let nonLinkedDomains = allDomains.filter( + (d: CustomDomain) => + !d.custom_domain_routes.some( + (r) => r.edit_permission_token === permission_token.id, + ), + ); + // Check if the selected route is already assigned to a different leaflet let routeConflict = (() => { if (!selectedDomain) return false; - let domain = availableDomains.find( + let domain = allDomains.find( (d: CustomDomain) => d.domain === selectedDomain, ); if (!domain) return false; @@ -110,13 +128,11 @@ const DomainOptions = (props: { setLoading(true); let route = "/" + selectedRoute; - // Optimistic update mutateIdentityData(mutateIdentity, (draft) => { let domain = draft.custom_domains.find( (d) => d.domain === selectedDomain, ); if (domain) { - // Remove existing route for this leaflet, add new one domain.custom_domain_routes = [ ...domain.custom_domain_routes.filter( (r) => r.edit_permission_token !== permission_token.id, @@ -160,164 +176,184 @@ const DomainOptions = (props: { } return ( -
-

Choose a Domain

-
- {availableDomains.map((domain: CustomDomain) => { - return ( - setSelectedDomain(d)} - setDomainMenuState={props.setDomainMenuState} - /> - ); - })} +
+
+

Choose a Domain

+
+
+ {linkedDomains.length > 0 && ( +
+ Currently Linked + {linkedDomains.map((domain: CustomDomain) => ( + { + mutateIdentityData(mutateIdentity, (draft) => { + let d = draft.custom_domains.find( + (dd) => dd.domain === domain.domain, + ); + if (d) { + d.custom_domain_routes = + d.custom_domain_routes.filter( + (r) => r.id !== routeId, + ); + } + }); + mutateDomains(); + toaster({ + content: ( +
+ Unpublished from custom domain! +
+ ), + type: "success", + }); + await removeDomainRoute({ routeId }); + }} + /> + ))} +
+ )} + {nonLinkedDomains.length > 0 && ( + + )} +
+ Add or delete domains from your profile on{" "} + + home + +
+
{routeConflict && (

Route already assigned

)} -
- {domains?.[0] && ( - - )} + + {loading ? : "Publish!"} + +
+ ); +}; - - {loading ? : "Publish!"} - +const LinkedDomainOption = (props: { + domain: CustomDomain; + permission_token_id: string; + onUnlink: (routeId: string) => void; +}) => { + let route = props.domain.custom_domain_routes.find( + (r) => r.edit_permission_token === props.permission_token_id, + ); + if (!route) return null; + + return ( +
+
+ {props.domain.domain} + {route.route}
+
); }; -const DomainOption = (props: { +function NonLinkedDomains(props: { + domains: CustomDomain[]; + selectedDomain: string | undefined; + setSelectedDomain: (d: string) => void; selectedRoute: string; - setSelectedRoute: (s: string) => void; - checked: boolean; - setChecked: (checked: string) => void; + setSelectedRoute: (r: string) => void; + setDomainMenuState: (state: DomainMenuState) => void; +}) { + // Separate pending vs available using hooks rendered per-domain + return ( + <> + {props.domains.map((domain) => ( + + ))} + + ); +} + +function NonLinkedDomainRow(props: { domain: CustomDomain; + selectedDomain: string | undefined; + setSelectedDomain: (d: string) => void; + selectedRoute: string; + setSelectedRoute: (r: string) => void; setDomainMenuState: (state: DomainMenuState) => void; -}) => { - let [value, setValue] = useState(""); +}) { let { pending } = useDomainStatus(props.domain.domain); + if (pending) { + return ( +
+
{props.domain.domain}/
+ + +
+ ); + } + + let isSelected = props.selectedDomain === props.domain.domain; + return ( -