{ return ( @@ -680,7 +685,7 @@ export let Block = ({ if (block.level === 2) return (
@@ -690,7 +695,7 @@ export let Block = ({ if (block.level === 3) return (
@@ -699,7 +704,7 @@ export let Block = ({ ); return (
diff --git a/components/Blocks/ImageAltButton.tsx b/components/Blocks/ImageAltButton.tsx index 1c7631a7..be2462f7 100644 --- a/components/Blocks/ImageAltButton.tsx +++ b/components/Blocks/ImageAltButton.tsx @@ -4,7 +4,7 @@ import { EditTiny } from "components/Icons/EditTiny"; import { useState } from "react"; import { useSpring, animated } from "@react-spring/web"; import useMeasure from "react-use-measure"; -import { ReadOnlyAltText } from "./ReadOnlyAltText"; +import { AltTextBody, ReadOnlyAltText } from "./ReadOnlyAltText"; // Overlaid on an image; visible on hover (within a `group/image`), while the // containing block is selected, or whenever alt text already exists. Opens the @@ -16,6 +16,7 @@ export function ImageAltButton(props: { selected: boolean; canEdit?: boolean; className?: string; + onSeeMore?: () => void; }) { let canEdit = props.canEdit ?? true; let alt = useEntity(props.entityID, "image/alt")?.data.value; @@ -26,14 +27,20 @@ export function ImageAltButton(props: { let altStyle = useSpring({ height: showAlt ? altHeight : 0, opacity: showAlt ? 1 : 0, - config: { tension: 450, friction: 30 }, + config: { tension: 450, friction: 30, clamp: true }, }); // Readers have nothing to interact with when there's no alt text. if (!canEdit && !hasAlt) return null; // Readers get the plain ALT pill + preview, shared with published posts. if (!canEdit) - return
; + return ( + + ); return ( diff --git a/components/Blocks/ImageBlock.tsx b/components/Blocks/ImageBlock.tsx index df512a33..fff0f1bd 100644 --- a/components/Blocks/ImageBlock.tsx +++ b/components/Blocks/ImageBlock.tsx @@ -61,6 +61,7 @@ export function ImageBlock(props: BlockProps & { preview?: boolean }) { let [lightbox, setLightbox] = useState<{ ids: string[]; index: number; + altExpanded?: boolean; } | null>(null); // Writers select the block first; a second click on the image opens the @@ -68,7 +69,7 @@ export function ImageBlock(props: BlockProps & { preview?: boolean }) { let canOpenLightbox = !props.preview && (!entity_set.permissions.write || !!isSelected); - let openLightbox = () => { + let openLightbox = (opts?: { altExpanded?: boolean }) => { let ids = rep ? getPostImageEntities(rep, props.parent) : []; let index = ids.indexOf(props.entityID); // Fall back to just this image if it isn't in the gathered list (e.g. on the @@ -77,7 +78,7 @@ export function ImageBlock(props: BlockProps & { preview?: boolean }) { ids = [props.entityID]; index = 0; } - setLightbox({ ids, index }); + setLightbox({ ids, index, altExpanded: opts?.altExpanded }); }; let nextIsFullBleed = useEntity( @@ -258,6 +259,7 @@ export function ImageBlock(props: BlockProps & { preview?: boolean }) { -- {alt} -+{ if (i === null) setLightbox(null); }} @@ -271,6 +273,7 @@ export function ImageBlock(props: BlockProps & { preview?: boolean }) { entityID={props.entityID} selected={!!isSelected} canEdit={entity_set.permissions.write} + onSeeMore={() => openLightbox({ altExpanded: true })} /> ) : null} diff --git a/components/Blocks/ImageGalleryBlock/GalleryImageItem.tsx b/components/Blocks/ImageGalleryBlock/GalleryImageItem.tsx index c79e41e9..f03f3d1b 100644 --- a/components/Blocks/ImageGalleryBlock/GalleryImageItem.tsx +++ b/components/Blocks/ImageGalleryBlock/GalleryImageItem.tsx @@ -50,6 +50,7 @@ export function EditorGalleryImageItem( editable: boolean; selected: boolean; onClick: () => void; + onSeeMoreAlt?: () => void; } & GalleryItemClasses, ) { let image = useGalleryImage(props.entityID); @@ -69,6 +70,7 @@ export function EditorGalleryImageItem( entityID={props.entityID} selected={props.selected} canEdit={props.editable} + onSeeMore={props.onSeeMoreAlt} /> > } diff --git a/components/Blocks/ImageGalleryBlock/ImageGalleryLightbox.tsx b/components/Blocks/ImageGalleryBlock/ImageGalleryLightbox.tsx index 1f133dcf..c94ebe00 100644 --- a/components/Blocks/ImageGalleryBlock/ImageGalleryLightbox.tsx +++ b/components/Blocks/ImageGalleryBlock/ImageGalleryLightbox.tsx @@ -1,14 +1,24 @@ -import { ReactNode, useEffect, useRef, useState } from "react"; +import { + createContext, + ReactNode, + useContext, + useEffect, + useRef, + useState, +} from "react"; import * as Dialog from "@radix-ui/react-dialog"; import { CloseTiny } from "components/Icons/CloseTiny"; import { GalleryImage, useGalleryImage } from "./shared"; import { GoToArrowLined } from "components/Icons/GoToArrowLined"; +const AltExpandedContext = createContext(false); + export function ImageGalleryLightbox(props: { count: number; index: number | null; onIndexChange: (index: number | null) => void; renderSlide: (index: number) => ReactNode; + altExpanded?: boolean; }) { let open = props.index !== null; @@ -37,6 +47,7 @@ export function ImageGalleryLightbox(props: { props.onIndexChange(null)} /> @@ -50,6 +61,7 @@ export function ImageGalleryLightbox(props: { function LightboxContent(props: { count: number; initialIndex: number; + altExpanded: boolean; renderSlide: (index: number) => ReactNode; onClose: () => void; }) { @@ -103,7 +115,11 @@ function LightboxContent(props: { key={i} className="h-full snap-center snap-always flex flex-col items-center justify-center gap-3" > - {props.renderSlide(i)} + + {props.renderSlide(i)} +