mirror of
https://github.com/Sped0n/bridget.git
synced 2026-04-14 10:09:31 -07:00
refactor: reduce amount of createEffect and improve imports (#284)
* refactor: update import syntax * feat: add GalleryImage component for simplicity * refactor: replace createEffect in GalleryNav with createMemo * refactor: refactor Gallery component logic and improve imports
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { createSignal, onCleanup, onMount, type Accessor, type JSX } from 'solid-js'
|
||||
|
||||
export function CustomCursor(props: {
|
||||
export default function CustomCursor(props: {
|
||||
children?: JSX.Element
|
||||
active: Accessor<boolean>
|
||||
cursorText: Accessor<string>
|
||||
|
||||
@@ -4,10 +4,10 @@ import { Show, createMemo, createSignal, type JSX } from 'solid-js'
|
||||
import type { ImageJSON } from '../resources'
|
||||
import type { Vector } from '../utils'
|
||||
|
||||
import { CustomCursor } from './customCursor'
|
||||
import { Nav } from './nav'
|
||||
import { Stage } from './stage'
|
||||
import { StageNav } from './stageNav'
|
||||
import CustomCursor from './customCursor'
|
||||
import Nav from './nav'
|
||||
import Stage from './stage'
|
||||
import StageNav from './stageNav'
|
||||
|
||||
/**
|
||||
* interfaces and types
|
||||
|
||||
@@ -51,7 +51,7 @@ function updateIndexText(indexValue: string, indexLength: string): void {
|
||||
* Nav component
|
||||
*/
|
||||
|
||||
export function Nav(): null {
|
||||
export default function Nav(): null {
|
||||
const [state, { incThreshold, decThreshold }] = useState()
|
||||
|
||||
createEffect(() => {
|
||||
|
||||
@@ -90,7 +90,7 @@ function onMutation<T extends HTMLElement>(
|
||||
* Stage component
|
||||
*/
|
||||
|
||||
export function Stage(props: {
|
||||
export default function Stage(props: {
|
||||
ijs: ImageJSON[]
|
||||
setIsLoading: Setter<boolean>
|
||||
isOpen: Accessor<boolean>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { decrement, increment, type Vector } from '../utils'
|
||||
|
||||
import type { HistoryItem } from './layout'
|
||||
|
||||
export function StageNav(props: {
|
||||
export default function StageNav(props: {
|
||||
children?: JSX.Element
|
||||
prevText: string
|
||||
closeText: string
|
||||
|
||||
@@ -31,7 +31,7 @@ function onIntersection<T extends HTMLElement>(
|
||||
}).observe(element)
|
||||
}
|
||||
|
||||
export function Collection(props: {
|
||||
export default function Collection(props: {
|
||||
children?: JSX.Element
|
||||
ijs: ImageJSON[]
|
||||
isAnimating: Accessor<boolean>
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { type gsap } from 'gsap'
|
||||
import {
|
||||
createEffect,
|
||||
createSignal,
|
||||
For,
|
||||
on,
|
||||
onMount,
|
||||
Show,
|
||||
type Accessor,
|
||||
type JSX,
|
||||
type Setter
|
||||
} from 'solid-js'
|
||||
import { createStore } from 'solid-js/store'
|
||||
import { type Swiper } from 'swiper'
|
||||
import invariant from 'tiny-invariant'
|
||||
|
||||
@@ -15,8 +18,8 @@ import { type ImageJSON } from '../resources'
|
||||
import { useState } from '../state'
|
||||
import { loadGsap, type Vector } from '../utils'
|
||||
|
||||
import { capitalizeFirstLetter, GalleryNav } from './galleryNav'
|
||||
import type { MobileImage } from './layout'
|
||||
import GalleryImage from './galleryImage'
|
||||
import GalleryNav, { capitalizeFirstLetter } from './galleryNav'
|
||||
|
||||
function removeDuplicates<T>(arr: T[]): T[] {
|
||||
if (arr.length < 2) return arr // optimization
|
||||
@@ -28,7 +31,7 @@ async function loadSwiper(): Promise<typeof Swiper> {
|
||||
return s.Swiper
|
||||
}
|
||||
|
||||
export function Gallery(props: {
|
||||
export default function Gallery(props: {
|
||||
children?: JSX.Element
|
||||
ijs: ImageJSON[]
|
||||
closeText: string
|
||||
@@ -43,10 +46,6 @@ export function Gallery(props: {
|
||||
let _gsap: typeof gsap
|
||||
let _swiper: Swiper
|
||||
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
const imgs: MobileImage[] = Array<MobileImage>(props.ijs.length)
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
const loadingDivs: HTMLDivElement[] = Array<HTMLDivElement>(props.ijs.length)
|
||||
let curtain: HTMLDivElement | undefined
|
||||
let gallery: HTMLDivElement | undefined
|
||||
let galleryInner: HTMLDivElement | undefined
|
||||
@@ -56,16 +55,18 @@ export function Gallery(props: {
|
||||
|
||||
// states
|
||||
let lastIndex = -1
|
||||
let libLoaded = false
|
||||
let mounted = false
|
||||
let navigateVector: Vector = 'none'
|
||||
|
||||
const [state, { setIndex }] = useState()
|
||||
const [libLoaded, setLibLoaded] = createSignal(false)
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
const [loads, setLoads] = createStore(Array<boolean>(props.ijs.length).fill(false))
|
||||
|
||||
// helper functions
|
||||
const slideUp: () => void = () => {
|
||||
// isAnimating is prechecked in isOpen effect
|
||||
if (!libLoaded || !mounted) return
|
||||
if (!libLoaded() || !mounted) return
|
||||
props.setIsAnimating(true)
|
||||
|
||||
invariant(curtain, 'curtain is not defined')
|
||||
@@ -133,11 +134,7 @@ export function Gallery(props: {
|
||||
activeImagesIndex = [currentIndex, nextIndex, prevIndex]
|
||||
break
|
||||
}
|
||||
removeDuplicates(activeImagesIndex).forEach((i) => {
|
||||
const e = imgs[i]
|
||||
if (e.src === e.dataset.src) return // already loaded
|
||||
e.src = e.dataset.src
|
||||
})
|
||||
setLoads(removeDuplicates(activeImagesIndex), true)
|
||||
}
|
||||
|
||||
const changeSlide: (slide: number) => void = (slide) => {
|
||||
@@ -149,22 +146,6 @@ export function Gallery(props: {
|
||||
|
||||
// effects
|
||||
onMount(() => {
|
||||
imgs.forEach((img, i) => {
|
||||
const loadingDiv = loadingDivs[i]
|
||||
img.addEventListener(
|
||||
'load',
|
||||
() => {
|
||||
if (state().index !== parseInt(img.dataset.index)) {
|
||||
_gsap.set(img, { opacity: 1 })
|
||||
_gsap.set(loadingDiv, { opacity: 0 })
|
||||
} else {
|
||||
_gsap.to(img, { opacity: 1, delay: 0.5, duration: 0.5, ease: 'power3.out' })
|
||||
_gsap.to(loadingDiv, { opacity: 0, duration: 0.5, ease: 'power3.in' })
|
||||
}
|
||||
},
|
||||
{ once: true, passive: true }
|
||||
)
|
||||
})
|
||||
window.addEventListener(
|
||||
'touchstart',
|
||||
() => {
|
||||
@@ -186,7 +167,7 @@ export function Gallery(props: {
|
||||
.catch((e) => {
|
||||
console.log(e)
|
||||
})
|
||||
libLoaded = true
|
||||
setLibLoaded(true)
|
||||
},
|
||||
{ once: true, passive: true }
|
||||
)
|
||||
@@ -234,26 +215,19 @@ export function Gallery(props: {
|
||||
<div ref={gallery} class="gallery">
|
||||
<div ref={galleryInner} class="galleryInner">
|
||||
<div class="swiper-wrapper">
|
||||
<For each={props.ijs}>
|
||||
{(ij, i) => (
|
||||
<div class="swiper-slide">
|
||||
<div class="slideContainer">
|
||||
<img
|
||||
ref={imgs[i()]}
|
||||
height={ij.hiImgH}
|
||||
width={ij.hiImgW}
|
||||
data-src={ij.hiUrl}
|
||||
data-index={ij.index}
|
||||
alt={ij.alt}
|
||||
style={{ opacity: 0 }}
|
||||
<Show when={libLoaded()}>
|
||||
<For each={props.ijs}>
|
||||
{(ij, i) => (
|
||||
<div class="swiper-slide">
|
||||
<GalleryImage
|
||||
load={loads[i()]}
|
||||
ij={ij}
|
||||
loadingText={_loadingText}
|
||||
/>
|
||||
<div ref={loadingDivs[i()]} class="loadingText">
|
||||
{_loadingText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
)}
|
||||
</For>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<GalleryNav
|
||||
|
||||
69
assets/ts/mobile/galleryImage.tsx
Normal file
69
assets/ts/mobile/galleryImage.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { onMount, type JSX } from 'solid-js'
|
||||
import invariant from 'tiny-invariant'
|
||||
|
||||
import type { ImageJSON } from '../resources'
|
||||
import { useState } from '../state'
|
||||
import { loadGsap } from '../utils'
|
||||
|
||||
export default function GalleryImage(props: {
|
||||
children?: JSX.Element
|
||||
load: boolean
|
||||
ij: ImageJSON
|
||||
loadingText: string
|
||||
}): JSX.Element {
|
||||
let img: HTMLImageElement | undefined
|
||||
let loadingDiv: HTMLDivElement | undefined
|
||||
|
||||
let _gsap: typeof gsap
|
||||
|
||||
const [state] = useState()
|
||||
|
||||
onMount(() => {
|
||||
loadGsap()
|
||||
.then((g) => {
|
||||
_gsap = g
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e)
|
||||
})
|
||||
img?.addEventListener(
|
||||
'load',
|
||||
() => {
|
||||
invariant(img, 'ref must be defined')
|
||||
invariant(loadingDiv, 'loadingDiv must be defined')
|
||||
if (state().index !== props.ij.index) {
|
||||
_gsap.set(img, { opacity: 1 })
|
||||
_gsap.set(loadingDiv, { opacity: 0 })
|
||||
} else {
|
||||
_gsap.to(img, {
|
||||
opacity: 1,
|
||||
delay: 0.5,
|
||||
duration: 0.5,
|
||||
ease: 'power3.out'
|
||||
})
|
||||
_gsap.to(loadingDiv, { opacity: 0, duration: 0.5, ease: 'power3.in' })
|
||||
}
|
||||
},
|
||||
{ once: true, passive: true }
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="slideContainer">
|
||||
<img
|
||||
ref={img}
|
||||
{...(props.load && { src: props.ij.hiUrl })}
|
||||
height={props.ij.hiImgH}
|
||||
width={props.ij.hiImgW}
|
||||
data-src={props.ij.hiUrl}
|
||||
alt={props.ij.alt}
|
||||
style={{ opacity: 0 }}
|
||||
/>
|
||||
<div ref={loadingDiv} class="loadingText">
|
||||
{props.loadingText}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createEffect, on, type Accessor, type JSX, type Setter } from 'solid-js'
|
||||
import { createMemo, type Accessor, type JSX, type Setter } from 'solid-js'
|
||||
|
||||
import { useState } from '../state'
|
||||
import { expand } from '../utils'
|
||||
@@ -7,63 +7,35 @@ export function capitalizeFirstLetter(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
export function GalleryNav(props: {
|
||||
export default function GalleryNav(props: {
|
||||
children?: JSX.Element
|
||||
closeText: string
|
||||
isAnimating: Accessor<boolean>
|
||||
setIsOpen: Setter<boolean>
|
||||
}): JSX.Element {
|
||||
// variables
|
||||
const indexNums: HTMLSpanElement[] = Array<HTMLSpanElement>(8)
|
||||
|
||||
// states
|
||||
const [state] = useState()
|
||||
const stateLength = state().length
|
||||
|
||||
// helper functions
|
||||
const updateIndexText: () => void = () => {
|
||||
const indexValue: string = expand(state().index + 1)
|
||||
const indexLength: string = expand(stateLength)
|
||||
indexNums.forEach((e: HTMLSpanElement, i: number) => {
|
||||
if (i < 4) {
|
||||
e.innerText = indexValue[i]
|
||||
} else {
|
||||
e.innerText = indexLength[i - 4]
|
||||
}
|
||||
})
|
||||
}
|
||||
const indexValue = createMemo(() => expand(state().index + 1))
|
||||
const indexLength = createMemo(() => expand(state().length))
|
||||
|
||||
const onClick: () => void = () => {
|
||||
if (props.isAnimating()) return
|
||||
props.setIsOpen(false)
|
||||
}
|
||||
|
||||
// effects
|
||||
createEffect(
|
||||
on(
|
||||
() => {
|
||||
state()
|
||||
},
|
||||
() => {
|
||||
updateIndexText()
|
||||
},
|
||||
{ defer: true }
|
||||
)
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="nav">
|
||||
<div>
|
||||
<span ref={indexNums[0]} class="num" />
|
||||
<span ref={indexNums[1]} class="num" />
|
||||
<span ref={indexNums[2]} class="num" />
|
||||
<span ref={indexNums[3]} class="num" />
|
||||
<span class="num">{indexValue()[0]}</span>
|
||||
<span class="num">{indexValue()[1]}</span>
|
||||
<span class="num">{indexValue()[2]}</span>
|
||||
<span class="num">{indexValue()[3]}</span>
|
||||
<span>/</span>
|
||||
<span ref={indexNums[4]} class="num" />
|
||||
<span ref={indexNums[5]} class="num" />
|
||||
<span ref={indexNums[6]} class="num" />
|
||||
<span ref={indexNums[7]} class="num" />
|
||||
<span class="num">{indexLength()[0]}</span>
|
||||
<span class="num">{indexLength()[1]}</span>
|
||||
<span class="num">{indexLength()[2]}</span>
|
||||
<span class="num">{indexLength()[3]}</span>
|
||||
</div>
|
||||
<div onClick={onClick} onKeyDown={onClick}>
|
||||
{capitalizeFirstLetter(props.closeText)}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Show, createSignal, type JSX, type Setter } from 'solid-js'
|
||||
|
||||
import type { ImageJSON } from '../resources'
|
||||
|
||||
import { Collection } from './collection'
|
||||
import { Gallery } from './gallery'
|
||||
import Collection from './collection'
|
||||
import Gallery from './gallery'
|
||||
|
||||
/**
|
||||
* interfaces
|
||||
|
||||
Reference in New Issue
Block a user