add Picture component for displaying images in articles with h/v/s layout support
This commit is contained in:
1 parent
1bd80aa0b2
commit
a55d474336
7 files changed
+75
-75
No files matched your search
+9
-11
@@ -1,5 +1,4 @@
|
|||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import Image from 'next/image'
|
|
||||||
import { App } from 'src/components/App'
|
import { App } from 'src/components/App'
|
||||||
import { tail } from 'lodash'
|
import { tail } from 'lodash'
|
||||||
import { Page } from 'src/components/Page'
|
import { Page } from 'src/components/Page'
|
||||||
@@ -16,6 +15,7 @@ import { paramsToSlug } from '@/remote/lib'
|
|||||||
import { PageGrid } from '@/components/PageGrid'
|
import { PageGrid } from '@/components/PageGrid'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { FileCard } from '@/components/FIleCard'
|
import { FileCard } from '@/components/FIleCard'
|
||||||
|
import { Picture } from '@/components/Picture'
|
||||||
|
|
||||||
async function getUrls() {
|
async function getUrls() {
|
||||||
let urls = []
|
let urls = []
|
||||||
@@ -114,16 +114,14 @@ const Index: NextPage<Props> = props => {
|
|||||||
|
|
||||||
case 'image':
|
case 'image':
|
||||||
return (
|
return (
|
||||||
<figure key={i} className="kazimir__image">
|
<Picture
|
||||||
<Image
|
key={i}
|
||||||
src={x.data.src}
|
src={x.data.src}
|
||||||
alt={x.data.alt}
|
alt={x.data.alt}
|
||||||
width={x.data.width}
|
width={x.data.width}
|
||||||
height={x.data.height}
|
height={x.data.height}
|
||||||
layout={'responsive'}
|
caption={x.data.caption}
|
||||||
/>
|
/>
|
||||||
<figcaption>{x.data.caption}</figcaption>
|
|
||||||
</figure>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
case 'file':
|
case 'file':
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import 'src/style/style.css'
|
|||||||
import 'src/style/content.css'
|
import 'src/style/content.css'
|
||||||
import 'src/style/article.css'
|
import 'src/style/article.css'
|
||||||
import 'src/style/marker/marker-table.css'
|
import 'src/style/marker/marker-table.css'
|
||||||
import 'src/style/kazimir/image.css'
|
|
||||||
import 'src/style/kazimir/video.css'
|
import 'src/style/kazimir/video.css'
|
||||||
|
|
||||||
import App from 'next/app'
|
import App from 'next/app'
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import s from './styles.module.css'
|
|
||||||
|
|
||||||
import { memo, useRef, useEffect, useCallback } from 'react'
|
|
||||||
|
|
||||||
export type ImageProps = {
|
|
||||||
style?: React.CSSProperties
|
|
||||||
src: string
|
|
||||||
alt?: string
|
|
||||||
srcSet?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Image: React.FC<ImageProps> = memo(props => {
|
|
||||||
const ref = useRef<HTMLImageElement>()
|
|
||||||
const onLoad = useCallback((event) => {
|
|
||||||
event.target.classList.add('loaded')
|
|
||||||
event.target.classList.remove('pending')
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (ref.current) {
|
|
||||||
ref.current.classList.add('pending')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<img
|
|
||||||
ref={ref}
|
|
||||||
onLoad={onLoad}
|
|
||||||
className={s.image}
|
|
||||||
style={props.style}
|
|
||||||
alt={props.alt}
|
|
||||||
src={props.src}
|
|
||||||
srcSet={props.srcSet}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
.image {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image.pending {
|
|
||||||
/* opacity: 0; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.image.loaded {
|
|
||||||
/* opacity: 1; */
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import s from './picture.module.css'
|
||||||
|
|
||||||
|
import { memo } from 'react'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { Pic } from '@/types'
|
||||||
|
|
||||||
|
const modifiers = new Map([
|
||||||
|
['square', s.square],
|
||||||
|
['vertical', s.vertical],
|
||||||
|
['horizontal', ''],
|
||||||
|
])
|
||||||
|
|
||||||
|
function size(w: number, h: number, tolerance: number) {
|
||||||
|
const r = w / h
|
||||||
|
if (r < 1 && r > tolerance) {
|
||||||
|
return 'square'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w < h) {
|
||||||
|
return 'vertical'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'horizontal'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PictureProps = Pic & {
|
||||||
|
style?: React.CSSProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Picture: React.FC<PictureProps> = memo(props => {
|
||||||
|
const ss = size(props.width, props.height, 0.95)
|
||||||
|
const layout = modifiers.get(ss)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<figure className={`${s.pic} ${layout}`}>
|
||||||
|
<Image
|
||||||
|
src={props.src}
|
||||||
|
alt={props.alt}
|
||||||
|
width={props.width}
|
||||||
|
height={props.height}
|
||||||
|
layout={'responsive'}
|
||||||
|
/>
|
||||||
|
{!props.caption ? null : (
|
||||||
|
<figcaption>{props.caption} ({props.width}x{props.height})</figcaption>
|
||||||
|
)}
|
||||||
|
</figure>
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
.kazimir__image {
|
.pic {
|
||||||
/* position: relative; */
|
/* position: relative; */
|
||||||
/* width: calc(100% + var(--kazimir-image-increase)); */
|
/* width: calc(100% + var(--kazimir-image-increase)); */
|
||||||
/* margin-left: calc(-0.5 * var(--kazimir-image-increase)); */
|
/* margin-left: calc(-0.5 * var(--kazimir-image-increase)); */
|
||||||
margin-bottom: var(--size-xl);
|
margin-bottom: var(--size-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.kazimir__image p {
|
.pic.vertical {
|
||||||
margin-left: calc(0.5 * var(--kazimir-image-increase));
|
max-width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kazimir__image img {
|
.pic.square {
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pic img {
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 35em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.kazimir__image figcaption {
|
.pic figcaption {
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: var(--font-size-second);
|
font-size: var(--font-size-second);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
+9
-7
@@ -98,6 +98,14 @@ export type ImageDefinition = {
|
|||||||
alt?: string
|
alt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Pic = {
|
||||||
|
src: string
|
||||||
|
alt?: string
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
caption?: string
|
||||||
|
}
|
||||||
|
|
||||||
export type TextToken = {
|
export type TextToken = {
|
||||||
token: 'text'
|
token: 'text'
|
||||||
data: string
|
data: string
|
||||||
@@ -105,13 +113,7 @@ export type TextToken = {
|
|||||||
|
|
||||||
export type ImageToken = {
|
export type ImageToken = {
|
||||||
token: 'image'
|
token: 'image'
|
||||||
data: {
|
data: Pic
|
||||||
src: string
|
|
||||||
alt: string
|
|
||||||
caption: string
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FileTokenData = {
|
export type FileTokenData = {
|
||||||
|
|||||||
Reference in new issue
Block a user