diff --git a/components/Image.module.styl b/components/Image.module.styl new file mode 100644 index 0000000..4e1a8f5 --- /dev/null +++ b/components/Image.module.styl @@ -0,0 +1,41 @@ +.image + transition .3s + object-fit contain + z-index 2 + transition .3s + + + &.ph1 + position fixed + transition 0s + + + &.ph2 + width 100% !important + position fixed + max-width 100% !important + max-height 100% !important + box-sizing border-box + padding 5% + top 0 !important + left 0 !important + height 100% + background #000000A0 + + + &.after + background #00000000 + /* height 100% */ + box-sizing border-box + position fixed + /* width 100% */ + z-index 0 + padding initial + + +.hideOverflow + overflow hidden + + +.none + display none diff --git a/components/Image.tsx b/components/Image.tsx new file mode 100644 index 0000000..d061b3c --- /dev/null +++ b/components/Image.tsx @@ -0,0 +1,209 @@ +import React, { SyntheticEvent } from 'react' +import css from './Image.module.styl' + +interface Props { + defaultHeight?: number + src?: string + sources?: Array + deleteOnError?: boolean + downgradeOnError?: string + canFullscreen?: boolean + max?: { + height?: number|string + width?: number|string + } + width?: number|string + default?: { + height?: number|string + width?: number|string + } + alt?: string +} + +const mimeTypes = { + apng: 'image/apng', + bmp: 'image/bmp', + gif: 'image/gif', + + ico: 'image/x-icon', + cur: 'image/x-icon', + + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + jfif: 'image/jpeg', + pjpeg: 'image/jpeg', + pjp: 'image/jpeg', + + png: 'image/png', + svg: 'image/svg+xml', + + tif: 'image/tiff', + tiff: 'image/tiff', + + webp: 'image/webp', +} + +const getMimeType = (img: string) => { + const arr = img.split('.') + return mimeTypes[arr[arr.length-1] as 'apng'] || mimeTypes.png +} + +type evType = SyntheticEvent + +export default class Image extends React.Component { + + private ref: React.RefObject = React.createRef() + private plchldr: React.RefObject = React.createRef() + private parent: React.RefObject = React.createRef() + private pic: React.RefObject = React.createRef() + + private wasDowngraded = false + private cardPos: Array = [] + private cardSize: Array = [] + + private isFullscreen = false + + public async componentDidMount() { + if (this.props.canFullscreen) { + window.addEventListener('scroll', this.onScroll) + window.addEventListener('resize', this.onResize) + this.onScroll() + this.onResize() + } + } + + public async componentDidUpdate() { + this.pic.current?.classList.remove(css.none) + if (this.props.canFullscreen) { + this.onScroll() + this.onResize() + } + if (this.isFullscreen) {this.onClick()} + } + + public async componentWillUnmount() { + if (this.props.canFullscreen) { + window.removeEventListener('scroll', this.onScroll) + window.removeEventListener('resize', this.onResize) + } + } + + public render() { + const pic = ( + + {this.props.sources && this.props.sources.map((el,index) => ( + + ))} + {this.props.alt} + + ) + if (this.props.canFullscreen) {return ( +
+
+ {pic} +
+ )} + return pic + } + + private onScroll = async () => { + if (!this.ref.current || this.isFullscreen || !this.props.canFullscreen) { + return + } + + this.cardPos = [this.ref.current.offsetTop - window.scrollY, this.ref.current.offsetLeft - window.scrollX] + this.ref.current.style.top = this.cardPos[0] + 'px' + this.ref.current.style.left = this.cardPos[1] + 'px' + } + + private onResize = async () => { + if (!this.ref.current || !this.plchldr.current || !this.props.canFullscreen || this.isFullscreen) { + return + } + let tmp = [this.ref.current.offsetHeight, this.ref.current.offsetWidth] + if (this.parent.current) { + tmp = [this.parent.current.offsetHeight, this.ref.current.offsetWidth] + } + this.plchldr.current.style.width = `${tmp[1]}px` + this.plchldr.current.style.height = `${tmp[0]}px` + } + + private onClick = async () => { + if (!this.ref.current || !this.props.canFullscreen || !this.plchldr.current) { + return + } + + const i = this.ref.current + const c = this.plchldr.current + const body = document.body + i.style.top = this.cardPos[0] + 'px' + i.style.left = this.cardPos[1] + 'px' + + if (this.isFullscreen) { + i.style.width = this.cardSize[1] + 'px' + i.style.height = this.cardSize[0] + 'px' + body.classList.remove(css.hideOverflow) + i.classList.remove(css.ph2) + i.classList.add(css.after) + + setTimeout(() => { + if (i.classList.contains(css.ph2) || i.classList.contains(css.ph1) || this.isFullscreen) {return} + const w = this.valToPixel(this.props.width) + const mh = this.valToPixel(this.props.max?.height) + const mw = this.valToPixel(this.props.max?.width) + c.classList.add(css.none) + i.style.height = '' + i.style.width = w + i.style.maxHeight = mh + i.style.maxWidth = mw + i.classList.remove(css.after) + }, 350) + this.isFullscreen = false + } else { + i.classList.add(css.ph1) + c.classList.remove(css.none) + i.classList.add(css.ph2) + i.classList.remove(css.ph1) + body.classList.add(css.hideOverflow) + this.isFullscreen = true + } + } + + private valToPixel(value: number|string|undefined): string { + if (typeof value === 'number') { + return `${value}px` + } + if (typeof value === 'undefined') { + return '' + } + return value + } + + private onLoad = async (ev: evType) => { + ev.currentTarget.style.height = '' + ev.currentTarget.style.width = '' + } + + private onError = async (ev: evType) => { + this.w('Picture not loaded', ev.currentTarget.src) + ev.currentTarget.parentElement?.classList.add(css.none) + } + + private w(...messages: any) { + console.warn('[ Picture ]', ...messages) + } +} diff --git a/pages/_app.tsx b/pages/_app.tsx index 62dbafa..3111d4f 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -4,7 +4,7 @@ import React from 'react' import '../styl/index.styl' -export default class Index extends App { +export default class CApp extends App { public render() { const { Component, pageProps } = this.props diff --git a/pages/index.tsx b/pages/index.tsx index 53fbbdd..c8abadd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,16 +1,21 @@ import React from 'react' import '../styl/index.styl' +import HelloWorld from '../components/HelloWorld' +import Image from '../components/Image' export default class Index extends React.Component { public render() { return( <> -

Hello World !

- + Hello World + + Hello World ) }