mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 21:19:18 +00:00
Rewrite sidebar to Typescript
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
"add": "Tilføj",
|
||||
"cancel": "Annuller",
|
||||
"delete": "Slet",
|
||||
"more": "Mere",
|
||||
"remove": "Fjern",
|
||||
"save": "Gem"
|
||||
},
|
||||
@@ -76,7 +77,7 @@
|
||||
"title": "Billeder"
|
||||
},
|
||||
"places_page": {
|
||||
"title": null
|
||||
"title": "Kort"
|
||||
},
|
||||
"routes": {
|
||||
"page_not_found": "Side ikke fundet"
|
||||
@@ -169,7 +170,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"album": {
|
||||
"title": "Album indstillinger"
|
||||
"title": "Indstillinger for album"
|
||||
},
|
||||
"download": {
|
||||
"filesize": {
|
||||
@@ -223,7 +224,7 @@
|
||||
"flash": "Blitz",
|
||||
"focal_length": "Brændvidde",
|
||||
"iso": "ISO",
|
||||
"lens": "Lense",
|
||||
"lens": "Objektiv",
|
||||
"maker": "Mærke"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"more": "More",
|
||||
"remove": "Remove",
|
||||
"save": "Save"
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"delete": "Effacer",
|
||||
"more": null,
|
||||
"remove": "Supprimer",
|
||||
"save": "Sauvegarder"
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"add": "Lägg till",
|
||||
"cancel": "Avbryt",
|
||||
"delete": "Radera",
|
||||
"more": null,
|
||||
"remove": "Ta bort",
|
||||
"save": "Spara"
|
||||
},
|
||||
|
||||
@@ -24,6 +24,8 @@ import {
|
||||
sidebarPhoto_media_videoMetadata,
|
||||
} from './__generated__/sidebarPhoto'
|
||||
|
||||
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
|
||||
|
||||
const SIDEBAR_MEDIA_QUERY = gql`
|
||||
query sidebarPhoto($id: ID!) {
|
||||
media(id: $id) {
|
||||
@@ -161,13 +163,15 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||
x => mediaExif[x] !== null && x != '__typename'
|
||||
)
|
||||
|
||||
const exif = exifKeys.reduce(
|
||||
(prev, curr) => ({
|
||||
const exif = exifKeys.reduce((prev, curr) => {
|
||||
const value = mediaExif[curr]
|
||||
if (isNil(value)) return prev
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[curr]: mediaExif[curr],
|
||||
}),
|
||||
{} as { [key: string]: string | number | null }
|
||||
)
|
||||
[curr]: value,
|
||||
}
|
||||
}, {} as { [key: string]: string | number })
|
||||
|
||||
if (!isNil(exif.dateShot)) {
|
||||
exif.dateShot = new Date(exif.dateShot).toLocaleString()
|
||||
@@ -202,7 +206,7 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||
}
|
||||
|
||||
exifItems = exifKeys.map(key => (
|
||||
<SidebarItem key={key} name={exifName[key]} value={exif[key]} />
|
||||
<SidebarItem key={key} name={exifName[key]} value={exif[key] as string} />
|
||||
))
|
||||
}
|
||||
|
||||
@@ -214,13 +218,15 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||
|
||||
let metadata = Object.keys(videoMetadata)
|
||||
.filter(x => !['id', '__typename', 'width', 'height'].includes(x))
|
||||
.reduce(
|
||||
(prev, curr) => ({
|
||||
.reduce((prev, curr) => {
|
||||
const value = videoMetadata[curr as string]
|
||||
if (isNil(value)) return prev
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[curr]: videoMetadata[curr as string],
|
||||
}),
|
||||
{} as { [key: string]: string | number | null }
|
||||
)
|
||||
[curr]: value,
|
||||
}
|
||||
}, {} as { [key: string]: string | number })
|
||||
|
||||
metadata = {
|
||||
dimensions: `${media.videoMetadata.width}x${media.videoMetadata.height}`,
|
||||
@@ -228,7 +234,7 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||
}
|
||||
|
||||
videoMetadataItems = Object.keys(metadata).map(key => (
|
||||
<SidebarItem key={key} name={key} value={metadata[key]} />
|
||||
<SidebarItem key={key} name={key} value={metadata[key] as string} />
|
||||
))
|
||||
}
|
||||
|
||||
@@ -376,7 +382,7 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
|
||||
)}
|
||||
<Name>{media.title}</Name>
|
||||
<MetadataInfo media={media} />
|
||||
<SidebarDownload photo={media} />
|
||||
<SidebarDownload media={media} />
|
||||
<SidebarPhotoShare id={media.id} />
|
||||
</div>
|
||||
)
|
||||
@@ -403,6 +409,7 @@ export interface MediaSidebarMedia {
|
||||
videoMetadata?: sidebarPhoto_media_videoMetadata | null
|
||||
exif?: sidebarPhoto_media_exif | null
|
||||
faces?: sidebarPhoto_media_faces[]
|
||||
downloads?: sidebarDownloadQuery_media_downloads[]
|
||||
}
|
||||
|
||||
type MediaSidebarType = {
|
||||
|
||||
@@ -211,7 +211,7 @@ const ShareItemMoreDropdown = ({
|
||||
// onClose={() => setDropdownOpen(false)}
|
||||
// open={dropdownOpen}
|
||||
button
|
||||
text="More"
|
||||
text={t('general.action.more', 'More')}
|
||||
closeOnChange={false}
|
||||
closeOnBlur={false}
|
||||
>
|
||||
|
||||
@@ -6,6 +6,13 @@ import { MessageState } from '../messages/Messages'
|
||||
import { useLazyQuery, gql } from '@apollo/client'
|
||||
import { authToken } from '../../helpers/authentication'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { TranslationFn } from '../../localization'
|
||||
import { MediaSidebarMedia } from './MediaSidebar'
|
||||
import {
|
||||
sidebarDownloadQuery,
|
||||
sidebarDownloadQueryVariables,
|
||||
sidebarDownloadQuery_media_downloads,
|
||||
} from './__generated__/sidebarDownloadQuery'
|
||||
|
||||
export const SIDEBAR_DOWNLOAD_QUERY = gql`
|
||||
query sidebarDownloadQuery($mediaId: ID!) {
|
||||
@@ -24,10 +31,12 @@ export const SIDEBAR_DOWNLOAD_QUERY = gql`
|
||||
}
|
||||
`
|
||||
|
||||
const formatBytes = t => bytes => {
|
||||
if (bytes == 0) return '0 Byte'
|
||||
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
|
||||
const count = Math.round(bytes / Math.pow(1024, i), 2)
|
||||
const formatBytes = (t: TranslationFn) => (bytes: number) => {
|
||||
if (bytes == 0)
|
||||
return t('sidebar.download.filesize.byte', '{{count}} Byte', { count: 0 })
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024))
|
||||
const count = Math.round(bytes / Math.pow(1024, i))
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
@@ -46,7 +55,7 @@ const formatBytes = t => bytes => {
|
||||
}
|
||||
}
|
||||
|
||||
const downloadMedia = t => async url => {
|
||||
const downloadMedia = (t: TranslationFn) => async (url: string) => {
|
||||
const imgUrl = new URL(url, location.origin)
|
||||
|
||||
if (authToken() == null) {
|
||||
@@ -68,15 +77,32 @@ const downloadMedia = t => async url => {
|
||||
blob = await response.blob()
|
||||
}
|
||||
|
||||
const filename = url.match(/[^/]*$/)[0]
|
||||
if (blob == null) {
|
||||
console.log('Blob is null canceling')
|
||||
return
|
||||
}
|
||||
|
||||
const filenameMatch = url.match(/[^/]*$/)
|
||||
|
||||
if (filenameMatch == null) {
|
||||
console.error('Could not extract filename', url)
|
||||
return
|
||||
}
|
||||
|
||||
const filename = filenameMatch[0]
|
||||
downloadBlob(blob, filename)
|
||||
}
|
||||
|
||||
const downloadMediaShowProgress = t => async response => {
|
||||
const downloadMediaShowProgress = (t: TranslationFn) => async (
|
||||
response: Response
|
||||
) => {
|
||||
const totalBytes = Number(response.headers.get('content-length'))
|
||||
const reader = response.body.getReader()
|
||||
let data = new Uint8Array(totalBytes)
|
||||
const reader = response.body?.getReader()
|
||||
const data = new Uint8Array(totalBytes)
|
||||
|
||||
if (reader == null) {
|
||||
throw new Error('Download reader is null')
|
||||
}
|
||||
|
||||
let canceled = false
|
||||
const onDismiss = () => {
|
||||
@@ -84,9 +110,9 @@ const downloadMediaShowProgress = t => async response => {
|
||||
reader.cancel('Download canceled by user')
|
||||
}
|
||||
|
||||
const notifKey = Math.random().toString(26)
|
||||
const notifyKey = Math.random().toString(26)
|
||||
MessageState.add({
|
||||
key: notifKey,
|
||||
key: notifyKey,
|
||||
type: 'progress',
|
||||
onDismiss,
|
||||
props: {
|
||||
@@ -108,7 +134,7 @@ const downloadMediaShowProgress = t => async response => {
|
||||
receivedBytes += result.value ? result.value.length : 0
|
||||
|
||||
MessageState.add({
|
||||
key: notifKey,
|
||||
key: notifyKey,
|
||||
type: 'progress',
|
||||
onDismiss,
|
||||
props: {
|
||||
@@ -126,7 +152,7 @@ const downloadMediaShowProgress = t => async response => {
|
||||
}
|
||||
|
||||
MessageState.add({
|
||||
key: notifKey,
|
||||
key: notifyKey,
|
||||
type: 'progress',
|
||||
props: {
|
||||
header: 'Downloading photo completed',
|
||||
@@ -137,20 +163,20 @@ const downloadMediaShowProgress = t => async response => {
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
MessageState.removeKey(notifKey)
|
||||
MessageState.removeKey(notifyKey)
|
||||
}, 2000)
|
||||
|
||||
const content = new Blob([data.buffer], {
|
||||
type: response.headers.get('content-type'),
|
||||
type: response.headers.get('content-type') || undefined,
|
||||
})
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
const downloadBlob = async (blob, filename) => {
|
||||
let objectUrl = window.URL.createObjectURL(blob)
|
||||
const downloadBlob = async (blob: Blob, filename: string) => {
|
||||
const objectUrl = window.URL.createObjectURL(blob)
|
||||
|
||||
let anchor = document.createElement('a')
|
||||
const anchor = document.createElement('a')
|
||||
document.body.appendChild(anchor)
|
||||
|
||||
anchor.href = objectUrl
|
||||
@@ -166,36 +192,43 @@ const DownloadTableRow = styled(Table.Row)`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const SidebarDownload = ({ photo }) => {
|
||||
type SidebarDownladProps = {
|
||||
media: MediaSidebarMedia
|
||||
}
|
||||
|
||||
const SidebarDownload = ({ media }: SidebarDownladProps) => {
|
||||
const { t } = useTranslation()
|
||||
if (!photo || !photo.id) return null
|
||||
if (!media || !media.id) return null
|
||||
|
||||
const [
|
||||
loadPhotoDownloads,
|
||||
{ called, loading, data },
|
||||
] = useLazyQuery(SIDEBAR_DOWNLOAD_QUERY, { variables: { mediaId: photo.id } })
|
||||
const [loadPhotoDownloads, { called, loading, data }] = useLazyQuery<
|
||||
sidebarDownloadQuery,
|
||||
sidebarDownloadQueryVariables
|
||||
>(SIDEBAR_DOWNLOAD_QUERY, { variables: { mediaId: media.id } })
|
||||
|
||||
let downloads = []
|
||||
let downloads: sidebarDownloadQuery_media_downloads[] = []
|
||||
|
||||
if (called) {
|
||||
if (!loading) {
|
||||
downloads = data && data.media.downloads
|
||||
downloads = (data && data.media.downloads) || []
|
||||
}
|
||||
} else {
|
||||
if (!photo.downloads) {
|
||||
if (!media.downloads) {
|
||||
loadPhotoDownloads()
|
||||
} else {
|
||||
downloads = photo.downloads
|
||||
downloads = media.downloads
|
||||
}
|
||||
}
|
||||
|
||||
const extractExtension = url => {
|
||||
return url.split(/[#?]/)[0].split('.').pop().trim().toLowerCase()
|
||||
const extractExtension = (url: string) => {
|
||||
const urlMatch = url.split(/[#?]/)
|
||||
if (urlMatch == null) return
|
||||
|
||||
return urlMatch[0].split('.').pop()?.trim().toLowerCase()
|
||||
}
|
||||
|
||||
const download = downloadMedia(t)
|
||||
const bytes = formatBytes(t)
|
||||
let downloadRows = downloads.map(x => (
|
||||
const downloadRows = downloads.map(x => (
|
||||
<DownloadTableRow
|
||||
key={x.mediaUrl.url}
|
||||
onClick={() => download(x.mediaUrl.url)}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const ItemName = styled.div`
|
||||
@@ -17,16 +16,16 @@ const ItemValue = styled.div`
|
||||
font-size: 1rem;
|
||||
`
|
||||
|
||||
const SidebarItem = ({ name, value }) => (
|
||||
type SidebarItemProps = {
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
||||
const SidebarItem = ({ name, value }: SidebarItemProps) => (
|
||||
<div>
|
||||
<ItemName>{name}</ItemName>
|
||||
<ItemValue>{value}</ItemValue>
|
||||
</div>
|
||||
)
|
||||
|
||||
SidebarItem.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.any.isRequired,
|
||||
}
|
||||
|
||||
export default SidebarItem
|
||||
@@ -3,7 +3,7 @@
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
"incremental": true /* Enable incremental compilation */,
|
||||
// "incremental": true /* Enable incremental compilation */,
|
||||
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||
"lib": [
|
||||
|
||||
Reference in New Issue
Block a user