From 1c3b2d7d2997b3f7e5ccc71159aacec7b49c176b Mon Sep 17 00:00:00 2001 From: niranjan-uma-shankar Date: Sun, 10 Aug 2025 15:22:20 +0530 Subject: [PATCH 1/4] Fixes mobile responsiveness The Unsplash modal is not optimised for mobile and tablet viewports and is practically unusable. These fixes ensure that the UX on mobile and tablet views works as one would expect it to. --- .../src/UnsplashSearchModal.tsx | 48 ++++++++++++++++++- .../src/api/UnsplashService.ts | 4 ++ .../src/ui/UnsplashGallery.tsx | 14 +++++- .../src/ui/UnsplashImage.tsx | 10 ++-- .../src/ui/UnsplashSelector.tsx | 7 +-- 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx b/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx index 3edd012bc3..c9d90bc506 100644 --- a/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx +++ b/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx @@ -16,6 +16,9 @@ interface UnsplashModalProps { } export const UnsplashSearchModal : React.FC = ({onClose, onImageInsert, unsplashProviderConfig}) => { + const ONE_COLUMN_WIDTH = 540; + const TWO_COLUMN_WIDTH = 1024; + const unsplashProvider = useMemo(() => { if (!unsplashProviderConfig) { return new InMemoryUnsplashProvider(); @@ -73,6 +76,39 @@ export const UnsplashSearchModal : React.FC = ({onClose, onI } }, [galleryRef, zoomedImg]); + const calculateColumnCountForViewport = () => { + const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); + + if (width < ONE_COLUMN_WIDTH) { + return 1; + } + + if (width < TWO_COLUMN_WIDTH) { + return 2; + } + + return 3; + }; + + React.useEffect(() => { + const handleResize = () => { + const newColumnCount = calculateColumnCountForViewport(); + masonryService.changeColumnCount(newColumnCount); + UnsplashLib.layoutPhotos(); + const columns = UnsplashLib.getColumns(); + setDataset(columns || []); + }; + + window.addEventListener('resize', handleResize); + + // Call once to make sure state is in sync on mount + handleResize(); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [UnsplashLib, masonryService]); + const loadInitPhotos = React.useCallback(async () => { if (initLoadRef.current === false || searchTerm.length === 0) { setDataset([]); @@ -155,6 +191,14 @@ export const UnsplashSearchModal : React.FC = ({onClose, onI }, [galleryRef, loadMorePhotos, zoomedImg]); const selectImg = (payload:Photo) => { + // if (UnsplashLib.getColumnCount() < 3) { + // setZoomedImg(null); + // if (galleryRef.current) { + // galleryRef.current.scrollTop = lastScrollPos; + // } + // return; + // } + if (payload) { setZoomedImg(payload); setLastScrollPos(scrollPos); @@ -176,10 +220,12 @@ export const UnsplashSearchModal : React.FC = ({onClose, onI } return ( ; isLoading?: boolean; zoomed?: Photo | null; } interface UnsplashGalleryProps extends GalleryLayoutProps { + columnCount?: number; error?: string | null; dataset?: Photo[][] | []; selectImg?: any; @@ -78,9 +80,17 @@ const UnsplashGalleryColumns: React.FC = (props) => }; const GalleryLayout: React.FC = (props) => { + const classNames = [ + 'flex', + 'size-full', + 'justify-center', + 'overflow-auto', + props?.zoomed ? 'pb-10' : '', + !props?.zoomed && (props?.columnCount ?? 0) < 3 ? 'px-5' : 'px-20' + ].filter(Boolean).join(' '); return (
-
+
{props.children} {props?.isLoading && }
@@ -89,6 +99,7 @@ const GalleryLayout: React.FC = (props) => { }; const UnsplashGallery: React.FC = ({zoomed, + columnCount, error, galleryRef, isLoading, @@ -133,6 +144,7 @@ const UnsplashGallery: React.FC = ({zoomed, return ( diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx index f4b151d49d..e498ed9ec4 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx @@ -27,7 +27,7 @@ export interface UnsplashImageProps { const UnsplashImage: FC = ({payload, srcUrl, links, likes, user, alt, urls, height, width, zoomed, insertImage, selectImg}) => { const handleClick = (e: MouseEvent) => { e.stopPropagation(); - selectImg(zoomed ? null : payload); + // selectImg(zoomed ? null : payload); }; return ( @@ -61,10 +61,10 @@ const UnsplashImage: FC = ({payload, srcUrl, links, likes, u icon="download" />
-
-
- author -
{user.name}
+
+
+ author +
{user.name}
{ e.stopPropagation(); diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx index 8f49534a08..b66fbd5f4b 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx @@ -5,11 +5,12 @@ import {ChangeEvent, FunctionComponent, ReactNode} from 'react'; interface UnsplashSelectorProps { closeModal: () => void; + columnCount: number; handleSearch: (e: ChangeEvent) => void; children: ReactNode; } -const UnsplashSelector: FunctionComponent = ({closeModal, handleSearch, children}) => { +const UnsplashSelector: FunctionComponent = ({closeModal, columnCount, handleSearch, children}) => { return ( <>
@@ -22,9 +23,9 @@ const UnsplashSelector: FunctionComponent = ({closeModal, />
-
+

- + Unsplash

From 52e94cc0838c5eb27a464e536f88c0209820971b Mon Sep 17 00:00:00 2001 From: niranjan-uma-shankar Date: Sun, 10 Aug 2025 21:13:47 +0530 Subject: [PATCH 2/4] Handles zoom levels on touch and non-touch devices Zoom behaviour is handled on touch and non-touch devices. This also improves the CSS for better UX on small screens. --- .../src/UnsplashSearchModal.tsx | 21 +++++++++---------- .../src/ui/UnsplashGallery.tsx | 5 +++-- .../src/ui/UnsplashImage.tsx | 4 ++-- .../src/ui/UnsplashZoomed.tsx | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx b/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx index c9d90bc506..1d9aedb16f 100644 --- a/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx +++ b/packages/kg-unsplash-selector/src/UnsplashSearchModal.tsx @@ -77,13 +77,11 @@ export const UnsplashSearchModal : React.FC = ({onClose, onI }, [galleryRef, zoomedImg]); const calculateColumnCountForViewport = () => { - const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); - - if (width < ONE_COLUMN_WIDTH) { + if (window.matchMedia(`(max-width: ${ONE_COLUMN_WIDTH}px)`).matches) { return 1; } - if (width < TWO_COLUMN_WIDTH) { + if (window.matchMedia(`(max-width: ${TWO_COLUMN_WIDTH}px)`).matches) { return 2; } @@ -191,13 +189,14 @@ export const UnsplashSearchModal : React.FC = ({onClose, onI }, [galleryRef, loadMorePhotos, zoomedImg]); const selectImg = (payload:Photo) => { - // if (UnsplashLib.getColumnCount() < 3) { - // setZoomedImg(null); - // if (galleryRef.current) { - // galleryRef.current.scrollTop = lastScrollPos; - // } - // return; - // } + const isMobileViewport = window.matchMedia('(max-width: 540px)').matches; + const isTouchDevice = window.matchMedia('(pointer: coarse)').matches; + const shouldNotZoom = isMobileViewport || isTouchDevice; + + if (shouldNotZoom) { + setZoomedImg(null); + return; + } if (payload) { setZoomedImg(payload); diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashGallery.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashGallery.tsx index 0095cabcb9..5dba7b268e 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashGallery.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashGallery.tsx @@ -80,16 +80,17 @@ const UnsplashGalleryColumns: React.FC = (props) => }; const GalleryLayout: React.FC = (props) => { + const columnCount = props?.columnCount ?? 0; const classNames = [ 'flex', 'size-full', 'justify-center', 'overflow-auto', props?.zoomed ? 'pb-10' : '', - !props?.zoomed && (props?.columnCount ?? 0) < 3 ? 'px-5' : 'px-20' + columnCount < 3 ? 'px-5' : 'px-20' ].filter(Boolean).join(' '); return ( -
+
{props.children} {props?.isLoading && } diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx index e498ed9ec4..00e0719d49 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashImage.tsx @@ -27,12 +27,12 @@ export interface UnsplashImageProps { const UnsplashImage: FC = ({payload, srcUrl, links, likes, user, alt, urls, height, width, zoomed, insertImage, selectImg}) => { const handleClick = (e: MouseEvent) => { e.stopPropagation(); - // selectImg(zoomed ? null : payload); + selectImg(zoomed ? null : payload); }; return (
diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashZoomed.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashZoomed.tsx index 88860d3b18..9de6be8ac0 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashZoomed.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashZoomed.tsx @@ -9,7 +9,7 @@ interface UnsplashZoomedProps extends Omit { const UnsplashZoomed: FC = ({payload, insertImage, selectImg, zoomed}) => { return ( -
selectImg(null)}> +
selectImg(null)}> Date: Sun, 10 Aug 2025 21:50:35 +0530 Subject: [PATCH 3/4] Extends the search box to full width in small viewports --- packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx index b66fbd5f4b..e1fdc6f8f9 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx @@ -28,7 +28,7 @@ const UnsplashSelector: FunctionComponent = ({closeModal, Unsplash -
+
From 9154f3142f63da6a2ba001d2d7fa5b22aa03afe3 Mon Sep 17 00:00:00 2001 From: niranjan-uma-shankar Date: Mon, 11 Aug 2025 08:39:07 +0530 Subject: [PATCH 4/4] Aligns search bar width with column count rather than tailwind's screen width breakpoints. This ensures that the UI is overall aligned with column count behaviour --- packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx index e1fdc6f8f9..5f7f286901 100644 --- a/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx +++ b/packages/kg-unsplash-selector/src/ui/UnsplashSelector.tsx @@ -28,7 +28,7 @@ const UnsplashSelector: FunctionComponent = ({closeModal, Unsplash -
+