Skip to content

Commit

Permalink
feat: add image zoom options (#984)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanharwara authored Apr 19, 2022
1 parent b6eeaea commit a78c0ce
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
<IconButton
icon="arrow-left"
title="Go back"
className="flex mr-2 color-neutral"
className="flex mr-2 color-neutral p-0"
onClick={handleGoBack}
focusable={true}
disabled={isRegistering}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const CreateAccount: FunctionComponent<Props> = observer(
<IconButton
icon="arrow-left"
title="Go back"
className="flex mr-2 color-neutral"
className="flex mr-2 color-neutral p-0"
onClick={handleClose}
focusable={true}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/Components/AccountMenu/SignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
<IconButton
icon="arrow-left"
title="Go back"
className="flex mr-2 color-neutral"
className="flex mr-2 color-neutral p-0"
onClick={() => setMenuPane(AccountMenuPane.GeneralMenu)}
focusable={true}
disabled={isSigningIn}
Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/Components/Button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ export const IconButton: FunctionComponent<Props> = ({
<button
type="button"
title={title}
className={`no-border cursor-pointer bg-transparent flex flex-row items-center hover:brightness-130 p-0 ${focusableClass} ${className}`}
className={`no-border cursor-pointer bg-transparent flex flex-row items-center ${focusableClass} ${className}`}
onClick={click}
disabled={disabled}
aria-label={title}
>
<Icon type={icon} className={iconClassName} />
</button>
Expand Down
21 changes: 3 additions & 18 deletions app/assets/javascripts/Components/Files/FilePreviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,14 @@ import { Button } from '@/Components/Button/Button'
import { Icon } from '@/Components/Icon'
import { FilePreviewInfoPanel } from './FilePreviewInfoPanel'
import { isFileTypePreviewable } from './isFilePreviewable'
import { PreviewComponent } from './PreviewComponent'

type Props = {
application: WebApplication
file: SNFile
onDismiss: () => void
}

const getPreviewComponentForFile = (file: SNFile, objectUrl: string) => {
if (file.mimeType.startsWith('image/')) {
return <img src={objectUrl} />
}

if (file.mimeType.startsWith('video/')) {
return <video className="w-full h-full" src={objectUrl} controls />
}

if (file.mimeType.startsWith('audio/')) {
return <audio src={objectUrl} controls />
}

return <object className="w-full h-full" data={objectUrl} />
}

export const FilePreviewModal: FunctionComponent<Props> = ({ application, file, onDismiss }) => {
const [objectUrl, setObjectUrl] = useState<string>()
const [isFilePreviewable, setIsFilePreviewable] = useState(false)
Expand Down Expand Up @@ -132,9 +117,9 @@ export const FilePreviewModal: FunctionComponent<Props> = ({ application, file,
</div>
</div>
<div className="flex flex-grow min-h-0 overflow-auto">
<div className="flex flex-grow items-center justify-center">
<div className="flex flex-grow items-center justify-center relative">
{objectUrl ? (
getPreviewComponentForFile(file, objectUrl)
<PreviewComponent file={file} objectUrl={objectUrl} />
) : isLoadingFile ? (
<div className="sk-spinner w-5 h-5 spinner-info"></div>
) : (
Expand Down
64 changes: 64 additions & 0 deletions app/assets/javascripts/Components/Files/ImagePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { IconType } from '@standardnotes/snjs'
import { FunctionComponent } from 'preact'
import { useEffect, useRef, useState } from 'preact/hooks'
import { IconButton } from '../Button/IconButton'

type Props = {
objectUrl: string
}

export const ImagePreview: FunctionComponent<Props> = ({ objectUrl }) => {
const initialImgHeightRef = useRef<number>()

const [imageZoomPercent, setImageZoomPercent] = useState(100)
const [imageHeight, setImageHeight] = useState(initialImgHeightRef.current)

useEffect(() => {
if (initialImgHeightRef.current) {
setImageHeight(imageZoomPercent * (initialImgHeightRef.current / 100))
}
}, [imageZoomPercent])

return (
<div className="flex items-center justify-center w-full h-full overflow-auto">
<img
src={objectUrl}
height={imageHeight}
ref={(imgElement) => {
if (!initialImgHeightRef.current) {
initialImgHeightRef.current = imgElement?.height
}
}}
/>
<div className="flex items-center absolute bottom-6 py-1 px-3 bg-default border-1 border-solid border-main rounded">
<span className="mr-1.5">Zoom:</span>
<IconButton
className="hover:bg-contrast p-1 rounded"
icon="add"
title="Zoom In"
focusable={true}
onClick={() => {
setImageZoomPercent((percent) => percent + 10)
}}
/>
<span className="mx-2">{imageZoomPercent}%</span>
<IconButton
className="hover:bg-contrast p-1 rounded"
icon={'subtract' as IconType}
title="Zoom Out"
focusable={true}
onClick={() => {
setImageZoomPercent((percent) => {
const newPercent = percent - 10
if (newPercent >= 10) {
return newPercent
} else {
return percent
}
})
}}
/>
</div>
</div>
)
}
24 changes: 24 additions & 0 deletions app/assets/javascripts/Components/Files/PreviewComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { SNFile } from '@standardnotes/snjs'
import { FunctionComponent } from 'preact'
import { ImagePreview } from './ImagePreview'

type Props = {
file: SNFile
objectUrl: string
}

export const PreviewComponent: FunctionComponent<Props> = ({ file, objectUrl }) => {
if (file.mimeType.startsWith('image/')) {
return <ImagePreview objectUrl={objectUrl} />
}

if (file.mimeType.startsWith('video/')) {
return <video className="w-full h-full" src={objectUrl} controls />
}

if (file.mimeType.startsWith('audio/')) {
return <audio src={objectUrl} controls />
}

return <object className="w-full h-full" data={objectUrl} />
}
4 changes: 3 additions & 1 deletion app/assets/javascripts/Components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
UserSwitch,
WarningIcon,
WindowIcon,
SubtractIcon,
} from '@standardnotes/stylekit'

export const ICONS = {
Expand Down Expand Up @@ -177,6 +178,7 @@ export const ICONS = {
user: UserIcon,
warning: WarningIcon,
window: WindowIcon,
subtract: SubtractIcon,
}

type Props = {
Expand All @@ -194,7 +196,7 @@ export const Icon: FunctionalComponent<Props> = ({ type, className = '', ariaLab
<IconComponent
className={`sn-icon ${className}`}
role="img"
{...(ariaLabel ? { 'aria-label': ariaLabel } : {})}
{...(ariaLabel ? { 'aria-label': ariaLabel } : { 'aria-hidden': true })}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const Toggle: FunctionComponent<{
setIsToggled: StateUpdater<boolean>
}> = ({ isToggled, setIsToggled }) => (
<IconButton
className="w-5 h-5 justify-center sk-circle hover:bg-grey-4 color-neutral"
className="w-5 h-5 p-0 justify-center sk-circle hover:bg-grey-4 color-neutral"
icon={isToggled ? 'eye-off' : 'eye'}
iconClassName="sn-icon--small"
title="Show/hide password"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const CopyButton: FunctionComponent<{ copyValue: string }> = ({ copyValue
focusable={false}
title="Copy to clipboard"
icon={isCopied ? 'check' : 'copy'}
className={isCopied ? 'success' : undefined}
className={`${isCopied ? 'success' : undefined} p-0`}
onClick={() => {
navigator?.clipboard?.writeText(secretKey).catch(console.error)
setCopied(() => true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const SaveSecretKey: FunctionComponent<{
focusable={false}
title="Download"
icon="download"
className="p-0"
onClick={() => {
downloadSecretKey(act.secretKey)
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const TagsSectionAddButton: FunctionComponent<Props> = observer(({ tags }
focusable={true}
icon="add"
title="Create a new tag"
className="color-neutral"
className="color-neutral p-0"
onClick={() => tags.createNewTemplate()}
/>
)
Expand Down
5 changes: 5 additions & 0 deletions app/assets/stylesheets/_sn.scss
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@
margin-right: 3rem;
}

.mx-2 {
margin-left: 0.5rem;
margin-right: 0.5rem;
}

.mx-4 {
margin-left: 1rem;
margin-right: 1rem;
Expand Down

0 comments on commit a78c0ce

Please sign in to comment.