Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zoom photos #1121

Merged
merged 33 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7b33703
Refactor ImageSwitcher to take a generic "view" instead of in img source
jboolean Dec 16, 2024
fe8b508
Create a stack component and switch that instead of the image directly
jboolean Dec 20, 2024
13c36de
Add color layer to ImageStack
jboolean Dec 20, 2024
4f767db
Preload images on Carousel
jboolean Dec 20, 2024
7b4632f
Use key to not reuse the color layer from another image
jboolean Dec 20, 2024
5cc3618
Add ability to togger high res layer
jboolean Dec 20, 2024
89e1656
Add react-zoom-pan-pinch
jboolean Dec 21, 2024
d4d4d0f
Do not fail to compile due to style errors
jboolean Dec 21, 2024
23dd874
Add !important to width and height in ViewerPane styles
jboolean Dec 21, 2024
d4d675c
Load high res when zoomed
jboolean Dec 21, 2024
d45c1d7
Zoom on single click
jboolean Dec 21, 2024
58a17b7
polish up click to zoom
jboolean Dec 21, 2024
4e6cb86
Add return type annotation to recordDown function
jboolean Dec 21, 2024
8e6f073
CLICK in the hit area, but allow panning everywhere
jboolean Dec 21, 2024
b3aea42
touch action none on overlay?
jboolean Dec 21, 2024
fbc4d47
passive?
jboolean Dec 21, 2024
9c25777
Add .gitignore for Yalc files
jboolean Dec 22, 2024
bf2e723
Use forked version of react-zoom-pan-pinch
jboolean Dec 22, 2024
55f21db
change overlay from pointerdown to pointerup
jboolean Dec 22, 2024
95a5a40
remove extract event registration?
jboolean Dec 22, 2024
a394a43
lint
jboolean Dec 22, 2024
f54f60b
Ignore bad touches on overlay
jboolean Dec 22, 2024
15ebee1
Update @jboolean/react-zoom-pan-pinch to version 3.7.1
jboolean Dec 23, 2024
98702e7
fix issue with Android reporting faux mouse hovering?
jboolean Dec 23, 2024
d07b27e
ignore tap overlay if you can hover
jboolean Dec 23, 2024
c7f670d
ignore events not originating from overlay or overlay content
jboolean Dec 23, 2024
3853078
Update @jboolean/react-zoom-pan-pinch to version 3.7.2
jboolean Dec 23, 2024
9873df3
remove unnecessary media query for zoomable
jboolean Dec 23, 2024
0b5dd88
Remove debug statements
jboolean Dec 23, 2024
1450e60
lint
jboolean Dec 23, 2024
d9386a5
delete useEventForwarding
jboolean Dec 23, 2024
bd2d919
Add announcement
jboolean Dec 23, 2024
7d2d1f6
Add drop shadow effect to button in ViewerPane
jboolean Dec 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.yalc/
.yalcignore
yalc.lock
33 changes: 33 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"author": "Julian Boilen",
"license": "UNLICENSED",
"dependencies": {
"@jboolean/react-zoom-pan-pinch": "^3.7.2",
"@sentry/react": "^7.119.2",
"@sentry/tracing": "^7.114.0",
"@stripe/stripe-js": "^1.42.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import React from 'react';
import Announcment from './Announcement';

const ANNOUNCEMENTS_REGISTRY: Announcment[] = [
{
id: 'zoom',
expiresAt: new Date('2025-01-31'),
render: () => (
<React.Fragment>
🔍 What&rsquo;s that sign say? Is that mom? <b>New</b>: zoom in and find
out.
</React.Fragment>
),
},
{
id: 'high-quality-imagery',
expiresAt: new Date('2024-09-05'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function AnnouncementBanner(): JSX.Element | null {
<div className={stylesheet.container}>
{announcementToDisplay.render()}{' '}
<button className={stylesheet.hideButton} onClick={hide}>
Hide
Hide this
</button>
</div>
);
Expand Down
57 changes: 39 additions & 18 deletions frontend/src/screens/App/screens/ViewerPane/ViewerPane.less
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,14 @@
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

.colorLayer {
z-index: 1;
position: absolute;

user-select: none;
pointer-events: none;

// We get low res color images and "upscole" them here by only using the color information
// and blending in the lightness of the full image
mix-blend-mode: color;
}

.image,
.colorLayer {
object-fit: contain;
object-position: center center;
.imageStack {
width: 100%;
height: 100%;
transform: scale(1.05); // cuts off the borders
}

.overlay {
z-index: 2;
touch-action: none;
}

@content-padding: 5.5px;
Expand All @@ -48,7 +33,7 @@
grid-template-columns: 100%;
grid-template-areas:
'alternates'
'.'
'zoomHitArea'
'stories'
'buttons'
'credit';
Expand Down Expand Up @@ -84,6 +69,9 @@
border: none;

cursor: pointer;

// drop shadow
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
}

.alternates {
Expand Down Expand Up @@ -111,6 +99,8 @@
box-sizing: border-box;

color: white;

user-select: all;
}

.buttons {
Expand Down Expand Up @@ -146,4 +136,35 @@
// https://bugs.chromium.org/p/chromium/issues/detail?id=1194050
// Maybe revisit this later
}

.zoomHitArea {
grid-area: zoomHitArea;
}

// Class name to exclude from pinch zoom
.panPinchExcluded {
user-select: text;
}

.panning {
cursor: grabbing !important;
}

.transformWrapper,
.transformContent {
width: 100% !important;
height: 100% !important;
}

.zoomable {
cursor: zoom-in;

& > * {
cursor: auto;
}

&.zoomed {
cursor: zoom-out;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
.colorLayer {
// default state
.faded();

z-index: 1;
position: absolute;

user-select: none;
pointer-events: none;

// We get low res color images and "upscale" them here by only using the color information
// and blending in the lightness of the full image
mix-blend-mode: color;
}

.enter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function ColorLayer({
className,
}: {
photoIdentifier: string;
className: string;
className?: string;
}): JSX.Element | null {
const {
colorEnabledForIdentifier,
Expand Down Expand Up @@ -49,7 +49,6 @@ export default function ColorLayer({
className={classNames(stylesheet.colorLayer, className)}
src={colorizedImageSrc}
onLoad={() => {
console.log('loaded', enabled);
if (enabled) {
handleImageLoaded();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:local {
.image {
display: block;
object-fit: contain;
object-position: center center;
width: 100%;
height: 100%;
}

.overlayLayer {
z-index: 1;
position: absolute;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { ImgHTMLAttributes } from 'react';

import classNames from 'classnames';
import { PHOTO_BASE } from 'shared/utils/apiConstants';
import preloadImage from 'shared/utils/preloadImage';
import ColorLayer from './ColorLayer';
import stylesheet from './ImageStack.less';
import { View } from './ImageSwitcher';

type Props = {
photoIdentifier: string;
imgProps?: Omit<ImgHTMLAttributes<unknown>, 'src'>;
className: string;
isFullResVisible?: boolean;
};

type ImageFormat = '720-jpg' | '420-jpg' | 'jpg';

const forgeImgSrc = (
photoIdentifier: string,
format: ImageFormat = '720-jpg'
): string => `${PHOTO_BASE}/${format}/${photoIdentifier}.jpg`;

function HighResLayer({
photoIdentifier,
}: {
photoIdentifier: string;
}): JSX.Element {
const [loaded, setLoaded] = React.useState(false);

return (
<img
data-image-type="high-res"
src={forgeImgSrc(photoIdentifier, 'jpg')}
className={classNames(stylesheet.image, stylesheet.overlayLayer)}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
}

/**
* An ImageStack keeps all the layers for one photo aligned and combined so they can be treated as one.
* Layers: Base layer, high res layer, color layer.
*/
export default function ImageStack({
photoIdentifier,
imgProps,
className,
isFullResVisible,
}: Props): JSX.Element | null {
const baseImageSrc = forgeImgSrc(photoIdentifier);

return (
<div className={className}>
{isFullResVisible && (
<HighResLayer
key={'high-res_' + photoIdentifier}
photoIdentifier={photoIdentifier}
/>
)}
<ColorLayer
key={'color_' + photoIdentifier}
photoIdentifier={photoIdentifier}
className={stylesheet.image}
/>
<img
data-image-type="base"
{...imgProps}
src={baseImageSrc}
className={classNames(stylesheet.image, imgProps.className)}
/>
</div>
);
}
export function makeImageSwitcherView(props: Props): View {
const imgSrc = forgeImgSrc(props.photoIdentifier);
return {
key: props.photoIdentifier,
element: <ImageStack key={props.photoIdentifier} {...props} />,
preload: () => preloadImage(imgSrc),
};
}
Loading
Loading