mirror of
https://github.com/Sped0n/bridget.git
synced 2026-04-17 03:29:31 -07:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22b81a8e1d | ||
|
|
8432540bde | ||
|
|
bb056d9c4f | ||
|
|
6bf10c103f | ||
|
|
1b1aea5047 | ||
|
|
5132e36e87 | ||
|
|
964c1802d3 | ||
|
|
0af4e20720 | ||
|
|
1f65b08b56 | ||
|
|
9bfaac25f5 | ||
|
|
794b5c0ea6 | ||
|
|
2fd34c2f7f | ||
|
|
44d7da48e3 | ||
|
|
49e9f904e2 | ||
|
|
1a3fade5fc | ||
|
|
4e4c32384a | ||
|
|
88b518b773 | ||
|
|
4eece4684a | ||
|
|
4f9b5ff311 | ||
|
|
c123fd45be | ||
|
|
09506d2d4e | ||
|
|
08350cfb9f | ||
|
|
cf2f36d232 | ||
|
|
480df04e55 | ||
|
|
ae96a07793 | ||
|
|
17ef30c18b | ||
|
|
0717ce1051 | ||
|
|
9fa1b718b8 | ||
|
|
8c6b38bb49 | ||
|
|
80c784262b | ||
|
|
ae1a08eb82 | ||
|
|
ff1a76eef8 | ||
|
|
d9452ca8d2 | ||
|
|
3fef127666 | ||
|
|
ed3b08dce2 | ||
|
|
8ba41fc32c | ||
|
|
0f537630e8 | ||
|
|
3f60289381 | ||
|
|
a3c2310375 | ||
|
|
b9de1b9c70 | ||
|
|
ac5fb33f41 | ||
|
|
ba044a2147 | ||
|
|
b34a85fa92 | ||
|
|
7b0cd6aae7 | ||
|
|
bc04ef37bb | ||
|
|
a5807f7625 | ||
|
|
0c16bab065 | ||
|
|
30a01cfd63 | ||
|
|
1e2f1fadde | ||
|
|
4932953871 | ||
|
|
44f3187540 | ||
|
|
80d5a2071b | ||
|
|
c02099aba9 | ||
|
|
50b0e6a5f4 | ||
|
|
6e066497f6 | ||
|
|
af664924e5 | ||
|
|
cdebc028cb | ||
|
|
6210fdda61 | ||
|
|
58f4ebe137 | ||
|
|
1381190a1a | ||
|
|
99220ec318 | ||
|
|
44b883ea96 | ||
|
|
8fd8ed52fe | ||
|
|
6a75a9bc83 | ||
|
|
96b38e9e60 | ||
|
|
267e79a090 | ||
|
|
b3ca475134 | ||
|
|
0126dfdd7e | ||
|
|
2c8db4abe1 | ||
|
|
4e0f083840 | ||
|
|
b3e3c7b0d4 | ||
|
|
784716658d | ||
|
|
a8975c5324 | ||
|
|
11c6fc4c0c |
@@ -22,6 +22,7 @@
|
|||||||
"arrow-body-style": "off",
|
"arrow-body-style": "off",
|
||||||
"prefer-arrow-callback": "off",
|
"prefer-arrow-callback": "off",
|
||||||
"import/no-cycle": "error",
|
"import/no-cycle": "error",
|
||||||
|
"@typescript-eslint/non-nullable-type-assertion-style": "off",
|
||||||
"sort-imports": [
|
"sort-imports": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
|||||||
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -8,5 +8,5 @@ updates:
|
|||||||
- package-ecosystem: 'npm' # See documentation for possible values
|
- package-ecosystem: 'npm' # See documentation for possible values
|
||||||
directory: '/' # Location of package manifests
|
directory: '/' # Location of package manifests
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'daily'
|
interval: 'weekly'
|
||||||
open-pull-requests-limit: 1000
|
open-pull-requests-limit: 1000
|
||||||
|
|||||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Get changed files in scope
|
- name: Get changed files in scope
|
||||||
id: changed-files-specific
|
id: changed-files-specific
|
||||||
uses: tj-actions/changed-files@v40
|
uses: tj-actions/changed-files@v41
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
package.json
|
package.json
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
title: Update bundled artifacts
|
title: "ci: update bundled artifacts"
|
||||||
commit-message: Update bundled artifacts
|
commit-message: "ci: update bundled artifacts"
|
||||||
branch: update-artifacts-${{ steps.version.outputs.builddate }}
|
branch: update-artifacts-${{ steps.version.outputs.builddate }}
|
||||||
base: main
|
base: main
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -21,4 +21,7 @@ $RECYCLE.BIN/
|
|||||||
|
|
||||||
# Hugo
|
# Hugo
|
||||||
.hugo_build.lock
|
.hugo_build.lock
|
||||||
jsconfig.json
|
jsconfig.json
|
||||||
|
|
||||||
|
# css map
|
||||||
|
*.css.map
|
||||||
|
|||||||
@@ -17,3 +17,7 @@ a,
|
|||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Geist';
|
font-family: 'Geist';
|
||||||
src: url('/lib/fonts/GeistVF.woff2') format('woff2');
|
src:
|
||||||
|
url('/lib/fonts/GeistVF.woff2') format('woff2 supports variations'),
|
||||||
|
url('/lib/fonts/GeistVF.woff2') format('woff2-variations');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
.container {
|
$tablet: map-get($breakpoints, 'tablet') - 1;
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
z-index: 0;
|
|
||||||
|
|
||||||
width: 100vw;
|
@media (max-width: $tablet), (hover: none) {
|
||||||
height: var(--window-height);
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 0;
|
||||||
|
|
||||||
overflow-y: scroll;
|
width: 100vw;
|
||||||
overflow-x: hidden;
|
height: var(--window-height);
|
||||||
background: white;
|
|
||||||
|
|
||||||
overscroll-behavior: none;
|
overflow-y: scroll;
|
||||||
-webkit-overflow-scrolling: none;
|
overflow-x: hidden;
|
||||||
}
|
background: white;
|
||||||
|
|
||||||
.disableScroll {
|
overscroll-behavior: none;
|
||||||
pointer-events: none;
|
-webkit-overflow-scrolling: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disableScroll {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,18 +16,30 @@
|
|||||||
.galleryInner {
|
.galleryInner {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.swiper-slide {
|
.swiper-slide {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.loadingText {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate3d(-50%, -50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slideContainer {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
|
|||||||
@@ -9,3 +9,4 @@
|
|||||||
|
|
||||||
@import '_partial/nav';
|
@import '_partial/nav';
|
||||||
@import '_partial/article';
|
@import '_partial/article';
|
||||||
|
@import '_partial/container';
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
import { scrollable } from './mobile/scroll'
|
import { Watchable } from './globalUtils'
|
||||||
|
|
||||||
export let container: HTMLDivElement
|
export const scrollable = new Watchable<boolean>(true)
|
||||||
|
|
||||||
|
export let container: Container
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Container extends HTMLDivElement {
|
||||||
|
dataset: {
|
||||||
|
next: string
|
||||||
|
close: string
|
||||||
|
prev: string
|
||||||
|
loading: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function initContainer(): void {
|
export function initContainer(): void {
|
||||||
container = document.getElementsByClassName('container').item(0) as HTMLDivElement
|
container = document.getElementsByClassName('container').item(0) as Container
|
||||||
scrollable.addWatcher((o) => {
|
scrollable.addWatcher((o) => {
|
||||||
if (o) {
|
if (o) {
|
||||||
container.classList.remove('disableScroll')
|
container.classList.remove('disableScroll')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { container } from '../container'
|
import { container } from '../container'
|
||||||
|
|
||||||
import { active } from './stage'
|
import { active } from './state'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { initCustomCursor } from './customCursor'
|
|||||||
import { initStage } from './stage'
|
import { initStage } from './stage'
|
||||||
import { initStageNav } from './stageNav'
|
import { initStageNav } from './stageNav'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main functions
|
||||||
|
*/
|
||||||
|
|
||||||
export function initDesktop(ijs: ImageJSON[]): void {
|
export function initDesktop(ijs: ImageJSON[]): void {
|
||||||
initCustomCursor()
|
initCustomCursor()
|
||||||
initStage(ijs)
|
initStage(ijs)
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
import { type Power3, type gsap } from 'gsap'
|
import { type Power3, type gsap } from 'gsap'
|
||||||
|
|
||||||
import { container } from '../container'
|
import { container } from '../container'
|
||||||
|
import { incIndex, isAnimating, navigateVector, state } from '../globalState'
|
||||||
|
import { decrement, increment, loadGsap } from '../globalUtils'
|
||||||
import { type ImageJSON } from '../resources'
|
import { type ImageJSON } from '../resources'
|
||||||
import { incIndex, state } from '../state'
|
|
||||||
import { Watchable, decrement, increment, loadGsap } from '../utils'
|
|
||||||
|
|
||||||
/**
|
import { active, cordHist, isLoading, isOpen } from './state'
|
||||||
* types
|
// eslint-disable-next-line sort-imports
|
||||||
*/
|
import { onMutation, type DesktopImage } from './utils'
|
||||||
|
|
||||||
export interface HistoryItem {
|
|
||||||
i: number
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let imgs: HTMLImageElement[] = []
|
let imgs: DesktopImage[] = []
|
||||||
let last = { x: 0, y: 0 }
|
let last = { x: 0, y: 0 }
|
||||||
export const cordHist = new Watchable<HistoryItem[]>([])
|
|
||||||
export const isOpen = new Watchable<boolean>(false)
|
|
||||||
export const isAnimating = new Watchable<boolean>(false)
|
|
||||||
export const active = new Watchable<boolean>(false)
|
|
||||||
|
|
||||||
let _gsap: typeof gsap
|
let _gsap: typeof gsap
|
||||||
let _Power3: typeof Power3
|
let _Power3: typeof Power3
|
||||||
@@ -35,45 +25,34 @@ let gsapLoaded = false
|
|||||||
* getter
|
* getter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getElTrail(): HTMLImageElement[] {
|
function getTrailElsIndex(): number[] {
|
||||||
return cordHist.get().map((item) => imgs[item.i])
|
return cordHist.get().map((item) => item.i)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElTrailCurrent(): HTMLImageElement[] {
|
function getTrailCurrentElsIndex(): number[] {
|
||||||
return getElTrail().slice(-state.get().trailLength)
|
return getTrailElsIndex().slice(-state.get().trailLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElTrailInactive(): HTMLImageElement[] {
|
function getTrailInactiveElsIndex(): number[] {
|
||||||
const elTrailCurrent = getElTrailCurrent()
|
const trailCurrentElsIndex = getTrailCurrentElsIndex()
|
||||||
return elTrailCurrent.slice(0, elTrailCurrent.length - 1)
|
return trailCurrentElsIndex.slice(0, trailCurrentElsIndex.length - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElCurrent(): HTMLImageElement {
|
function getCurrentElIndex(): number {
|
||||||
const elTrail = getElTrail()
|
const trailElsIndex = getTrailElsIndex()
|
||||||
return elTrail[elTrail.length - 1]
|
return trailElsIndex[trailElsIndex.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElNextSeven(): HTMLImageElement[] {
|
function getPrevElIndex(): number {
|
||||||
const c = cordHist.get()
|
const c = cordHist.get()
|
||||||
const s = state.get()
|
const s = state.get()
|
||||||
const c0 = c.length > 0 ? c[c.length - 1].i : s.index
|
return decrement(c[c.length - 1].i, s.length)
|
||||||
const els = []
|
|
||||||
for (let i = 0; i < 7; i++) {
|
|
||||||
els.push(imgs[increment(c0 + i, s.length)])
|
|
||||||
}
|
|
||||||
return els
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElPrev(): HTMLImageElement {
|
function getNextElIndex(): number {
|
||||||
const c = cordHist.get()
|
const c = cordHist.get()
|
||||||
const s = state.get()
|
const s = state.get()
|
||||||
return imgs[decrement(c[c.length - 1].i, s.length)]
|
return increment(c[c.length - 1].i, s.length)
|
||||||
}
|
|
||||||
|
|
||||||
function getElNext(): HTMLImageElement {
|
|
||||||
const c = cordHist.get()
|
|
||||||
const s = state.get()
|
|
||||||
return imgs[increment(c[c.length - 1].i, s.length)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +61,11 @@ function getElNext(): HTMLImageElement {
|
|||||||
|
|
||||||
// on mouse
|
// on mouse
|
||||||
function onMouse(e: MouseEvent): void {
|
function onMouse(e: MouseEvent): void {
|
||||||
if (isOpen.get() || isAnimating.get() || !gsapLoaded) return
|
if (isOpen.get() || isAnimating.get()) return
|
||||||
|
if (!gsapLoaded) {
|
||||||
|
loadLib()
|
||||||
|
return
|
||||||
|
}
|
||||||
const cord = { x: e.clientX, y: e.clientY }
|
const cord = { x: e.clientX, y: e.clientY }
|
||||||
const travelDist = Math.hypot(cord.x - last.x, cord.y - last.y)
|
const travelDist = Math.hypot(cord.x - last.x, cord.y - last.y)
|
||||||
|
|
||||||
@@ -95,15 +78,14 @@ function onMouse(e: MouseEvent): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set image position with gsap
|
// set image position with gsap (in both stage and navigation)
|
||||||
function setPositions(): void {
|
function setPositions(): void {
|
||||||
const elTrail = getElTrail()
|
const trailElsIndex = getTrailElsIndex()
|
||||||
if (elTrail.length === 0 || !gsapLoaded) return
|
if (trailElsIndex.length === 0 || !gsapLoaded) return
|
||||||
|
|
||||||
// preload
|
const elsTrail = getImagesWithIndexArray(trailElsIndex)
|
||||||
lores(getElNextSeven())
|
|
||||||
|
|
||||||
_gsap.set(elTrail, {
|
_gsap.set(elsTrail, {
|
||||||
x: (i: number) => cordHist.get()[i].x - window.innerWidth / 2,
|
x: (i: number) => cordHist.get()[i].x - window.innerWidth / 2,
|
||||||
y: (i: number) => cordHist.get()[i].y - window.innerHeight / 2,
|
y: (i: number) => cordHist.get()[i].y - window.innerHeight / 2,
|
||||||
opacity: (i: number) =>
|
opacity: (i: number) =>
|
||||||
@@ -113,25 +95,47 @@ function setPositions(): void {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (isOpen.get()) {
|
if (isOpen.get()) {
|
||||||
lores(getElTrail())
|
const elc = getImagesWithIndexArray([getCurrentElIndex()])[0]
|
||||||
hires([getElCurrent(), getElPrev(), getElNext()])
|
elc.classList.add('hide') // hide image to prevent flash
|
||||||
|
const indexArrayToHires: number[] = []
|
||||||
|
switch (navigateVector.get()) {
|
||||||
|
case 'prev':
|
||||||
|
indexArrayToHires.push(getPrevElIndex())
|
||||||
|
break
|
||||||
|
case 'next':
|
||||||
|
indexArrayToHires.push(getNextElIndex())
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hires(getImagesWithIndexArray(indexArrayToHires)) // preload
|
||||||
|
setLoaderForImage(elc)
|
||||||
_gsap.set(imgs, { opacity: 0 })
|
_gsap.set(imgs, { opacity: 0 })
|
||||||
_gsap.set(getElCurrent(), { opacity: 1, x: 0, y: 0, scale: 1 })
|
_gsap.set(elc, { opacity: 1, x: 0, y: 0, scale: 1 })
|
||||||
|
} else {
|
||||||
|
lores(elsTrail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// open image into navigation
|
// open image into navigation
|
||||||
function expandImage(): void {
|
function expandImage(): void {
|
||||||
if (isAnimating.get() || !gsapLoaded) return
|
if (isAnimating.get()) return
|
||||||
|
|
||||||
isOpen.set(true)
|
isOpen.set(true)
|
||||||
isAnimating.set(true)
|
isAnimating.set(true)
|
||||||
|
|
||||||
hires([getElCurrent(), getElPrev(), getElNext()])
|
const elcIndex = getCurrentElIndex()
|
||||||
|
const elc = getImagesWithIndexArray([elcIndex])[0]
|
||||||
|
// don't hide here because we want a better transition
|
||||||
|
// elc.classList.add('hide')
|
||||||
|
|
||||||
|
hires(getImagesWithIndexArray([elcIndex, getPrevElIndex(), getNextElIndex()]))
|
||||||
|
setLoaderForImage(elc)
|
||||||
|
|
||||||
const tl = _gsap.timeline()
|
const tl = _gsap.timeline()
|
||||||
|
const trailInactiveEls = getImagesWithIndexArray(getTrailInactiveElsIndex())
|
||||||
// move down and hide trail inactive
|
// move down and hide trail inactive
|
||||||
tl.to(getElTrailInactive(), {
|
tl.to(trailInactiveEls, {
|
||||||
y: '+=20',
|
y: '+=20',
|
||||||
ease: _Power3.easeIn,
|
ease: _Power3.easeIn,
|
||||||
stagger: 0.075,
|
stagger: 0.075,
|
||||||
@@ -140,7 +144,7 @@ function expandImage(): void {
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
})
|
})
|
||||||
// current move to center
|
// current move to center
|
||||||
tl.to(getElCurrent(), {
|
tl.to(elc, {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
ease: _Power3.easeInOut,
|
ease: _Power3.easeInOut,
|
||||||
@@ -148,7 +152,7 @@ function expandImage(): void {
|
|||||||
delay: 0.3
|
delay: 0.3
|
||||||
})
|
})
|
||||||
// current expand
|
// current expand
|
||||||
tl.to(getElCurrent(), {
|
tl.to(elc, {
|
||||||
delay: 0.1,
|
delay: 0.1,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
ease: _Power3.easeInOut
|
ease: _Power3.easeInOut
|
||||||
@@ -163,23 +167,27 @@ function expandImage(): void {
|
|||||||
|
|
||||||
// close navigation and back to stage
|
// close navigation and back to stage
|
||||||
export function minimizeImage(): void {
|
export function minimizeImage(): void {
|
||||||
if (isAnimating.get() || !gsapLoaded) return
|
if (isAnimating.get()) return
|
||||||
|
|
||||||
isOpen.set(false)
|
isOpen.set(false)
|
||||||
isAnimating.set(true)
|
isAnimating.set(true)
|
||||||
|
navigateVector.set('none') // cleanup
|
||||||
|
|
||||||
lores([getElCurrent()])
|
lores(
|
||||||
lores(getElTrailInactive())
|
getImagesWithIndexArray([...getTrailInactiveElsIndex(), ...[getCurrentElIndex()]])
|
||||||
|
)
|
||||||
|
|
||||||
const tl = _gsap.timeline()
|
const tl = _gsap.timeline()
|
||||||
|
const elc = getImagesWithIndexArray([getCurrentElIndex()])[0]
|
||||||
|
const elsTrailInactive = getImagesWithIndexArray(getTrailInactiveElsIndex())
|
||||||
// shrink current
|
// shrink current
|
||||||
tl.to(getElCurrent(), {
|
tl.to(elc, {
|
||||||
scale: 0.6,
|
scale: 0.6,
|
||||||
duration: 0.6,
|
duration: 0.6,
|
||||||
ease: _Power3.easeInOut
|
ease: _Power3.easeInOut
|
||||||
})
|
})
|
||||||
// move current to original position
|
// move current to original position
|
||||||
tl.to(getElCurrent(), {
|
tl.to(elc, {
|
||||||
delay: 0.3,
|
delay: 0.3,
|
||||||
duration: 0.7,
|
duration: 0.7,
|
||||||
ease: _Power3.easeInOut,
|
ease: _Power3.easeInOut,
|
||||||
@@ -187,7 +195,7 @@ export function minimizeImage(): void {
|
|||||||
y: cordHist.get()[cordHist.get().length - 1].y - window.innerHeight / 2
|
y: cordHist.get()[cordHist.get().length - 1].y - window.innerHeight / 2
|
||||||
})
|
})
|
||||||
// show trail inactive
|
// show trail inactive
|
||||||
tl.to(getElTrailInactive(), {
|
tl.to(elsTrailInactive, {
|
||||||
y: '-=20',
|
y: '-=20',
|
||||||
ease: _Power3.easeOut,
|
ease: _Power3.easeOut,
|
||||||
stagger: -0.1,
|
stagger: -0.1,
|
||||||
@@ -212,14 +220,47 @@ export function initStage(ijs: ImageJSON[]): void {
|
|||||||
// get stage
|
// get stage
|
||||||
const stage = document.getElementsByClassName('stage').item(0) as HTMLDivElement
|
const stage = document.getElementsByClassName('stage').item(0) as HTMLDivElement
|
||||||
// get image elements
|
// get image elements
|
||||||
imgs = Array.from(stage.getElementsByTagName('img'))
|
imgs = Array.from(stage.getElementsByTagName('img')) as DesktopImage[]
|
||||||
|
imgs.forEach((img, i) => {
|
||||||
|
// preload first 5 images on page load
|
||||||
|
if (i < 5) {
|
||||||
|
img.src = img.dataset.loUrl
|
||||||
|
}
|
||||||
|
// lores preloader for rest of the images
|
||||||
|
onMutation(img, (mutations, observer) => {
|
||||||
|
mutations.every((mutation) => {
|
||||||
|
// if open or animating, skip
|
||||||
|
if (isOpen.get() || isAnimating.get()) return true
|
||||||
|
// if mutation is not about style attribute, skip
|
||||||
|
if (mutation.attributeName !== 'style') return true
|
||||||
|
const opacity = parseFloat(img.style.opacity)
|
||||||
|
// if opacity is not 1, skip
|
||||||
|
if (opacity !== 1) return true
|
||||||
|
// preload the i + 5th image
|
||||||
|
if (i + 5 < imgs.length) {
|
||||||
|
imgs[i + 5].src = imgs[i + 5].dataset.loUrl
|
||||||
|
}
|
||||||
|
// disconnect observer and return false to break the loop
|
||||||
|
observer.disconnect()
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
// event listeners
|
// event listeners
|
||||||
stage.addEventListener('click', () => {
|
stage.addEventListener(
|
||||||
expandImage()
|
'click',
|
||||||
})
|
() => {
|
||||||
stage.addEventListener('keydown', () => {
|
expandImage()
|
||||||
expandImage()
|
},
|
||||||
})
|
{ passive: true }
|
||||||
|
)
|
||||||
|
stage.addEventListener(
|
||||||
|
'keydown',
|
||||||
|
() => {
|
||||||
|
expandImage()
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
window.addEventListener('mousemove', onMouse, { passive: true })
|
window.addEventListener('mousemove', onMouse, { passive: true })
|
||||||
// watchers
|
// watchers
|
||||||
isOpen.addWatcher((o) => {
|
isOpen.addWatcher((o) => {
|
||||||
@@ -231,21 +272,11 @@ export function initStage(ijs: ImageJSON[]): void {
|
|||||||
cordHist.addWatcher((_) => {
|
cordHist.addWatcher((_) => {
|
||||||
setPositions()
|
setPositions()
|
||||||
})
|
})
|
||||||
// preload
|
|
||||||
lores(getElNextSeven())
|
|
||||||
// dynamic import
|
// dynamic import
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'mousemove',
|
'mousemove',
|
||||||
() => {
|
() => {
|
||||||
loadGsap()
|
loadLib()
|
||||||
.then((g) => {
|
|
||||||
_gsap = g[0]
|
|
||||||
_Power3 = g[1]
|
|
||||||
gsapLoaded = true
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{ once: true, passive: true }
|
{ once: true, passive: true }
|
||||||
)
|
)
|
||||||
@@ -261,7 +292,7 @@ function createStage(ijs: ImageJSON[]): void {
|
|||||||
stage.className = 'stage'
|
stage.className = 'stage'
|
||||||
// append images to container
|
// append images to container
|
||||||
for (const ij of ijs) {
|
for (const ij of ijs) {
|
||||||
const e = document.createElement('img')
|
const e = document.createElement('img') as DesktopImage
|
||||||
e.height = ij.loImgH
|
e.height = ij.loImgH
|
||||||
e.width = ij.loImgW
|
e.width = ij.loImgW
|
||||||
// set data attributes
|
// set data attributes
|
||||||
@@ -272,23 +303,66 @@ function createStage(ijs: ImageJSON[]): void {
|
|||||||
e.dataset.loImgH = ij.loImgH.toString()
|
e.dataset.loImgH = ij.loImgH.toString()
|
||||||
e.dataset.loImgW = ij.loImgW.toString()
|
e.dataset.loImgW = ij.loImgW.toString()
|
||||||
e.alt = ij.alt
|
e.alt = ij.alt
|
||||||
|
// append
|
||||||
stage.append(e)
|
stage.append(e)
|
||||||
}
|
}
|
||||||
container.append(stage)
|
container.append(stage)
|
||||||
}
|
}
|
||||||
|
|
||||||
function hires(imgs: HTMLImageElement[]): void {
|
function getImagesWithIndexArray(indexArray: number[]): DesktopImage[] {
|
||||||
|
return indexArray.map((i) => imgs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
function hires(imgs: DesktopImage[]): void {
|
||||||
imgs.forEach((img) => {
|
imgs.forEach((img) => {
|
||||||
img.src = img.dataset.hiUrl as string
|
if (img.src === img.dataset.hiUrl) return
|
||||||
img.height = parseInt(img.dataset.hiImgH as string)
|
img.src = img.dataset.hiUrl
|
||||||
img.width = parseInt(img.dataset.hiImgW as string)
|
img.height = parseInt(img.dataset.hiImgH)
|
||||||
|
img.width = parseInt(img.dataset.hiImgW)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function lores(imgs: HTMLImageElement[]): void {
|
function lores(imgs: DesktopImage[]): void {
|
||||||
imgs.forEach((img) => {
|
imgs.forEach((img) => {
|
||||||
img.src = img.dataset.loUrl as string
|
if (img.src === img.dataset.loUrl) return
|
||||||
img.height = parseInt(img.dataset.loImgH as string)
|
img.src = img.dataset.loUrl
|
||||||
img.width = parseInt(img.dataset.loImgW as string)
|
img.height = parseInt(img.dataset.loImgH)
|
||||||
|
img.width = parseInt(img.dataset.loImgW)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setLoaderForImage(e: HTMLImageElement): void {
|
||||||
|
if (!e.complete) {
|
||||||
|
isLoading.set(true)
|
||||||
|
e.addEventListener(
|
||||||
|
'load',
|
||||||
|
() => {
|
||||||
|
isLoading.set(false)
|
||||||
|
e.classList.remove('hide')
|
||||||
|
},
|
||||||
|
{ once: true, passive: true }
|
||||||
|
)
|
||||||
|
e.addEventListener(
|
||||||
|
'error',
|
||||||
|
() => {
|
||||||
|
isLoading.set(false)
|
||||||
|
},
|
||||||
|
{ once: true, passive: true }
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
e.classList.remove('hide')
|
||||||
|
isLoading.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLib(): void {
|
||||||
|
loadGsap()
|
||||||
|
.then((g) => {
|
||||||
|
_gsap = g[0]
|
||||||
|
_Power3 = g[1]
|
||||||
|
gsapLoaded = true
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { container } from '../container'
|
import { container } from '../container'
|
||||||
import { decIndex, incIndex, state } from '../state'
|
import { decIndex, incIndex, isAnimating, navigateVector, state } from '../globalState'
|
||||||
import { decrement, increment } from '../utils'
|
import { decrement, increment } from '../globalUtils'
|
||||||
|
|
||||||
import { setCustomCursor } from './customCursor'
|
import { setCustomCursor } from './customCursor'
|
||||||
import { active, cordHist, isAnimating, isOpen, minimizeImage } from './stage'
|
import { minimizeImage } from './stage'
|
||||||
|
import { active, cordHist, isLoading, isOpen } from './state'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* types
|
* types
|
||||||
@@ -15,12 +16,13 @@ type NavItem = (typeof navItems)[number]
|
|||||||
* variables
|
* variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const mainDiv = document.getElementById('main') as HTMLDivElement
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
mainDiv.getAttribute('prevText') as string,
|
container.dataset.prev,
|
||||||
mainDiv.getAttribute('closeText') as string,
|
container.dataset.close,
|
||||||
mainDiv.getAttribute('nextText') as string
|
container.dataset.next
|
||||||
] as const
|
] as const
|
||||||
|
const loadingText = container.dataset.loading + '...'
|
||||||
|
let loadedText = ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main functions
|
* main functions
|
||||||
@@ -56,39 +58,80 @@ function handleKey(e: KeyboardEvent): void {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function initStageNav(): void {
|
export function initStageNav(): void {
|
||||||
|
// isLoading
|
||||||
|
isLoading.addWatcher((o) => {
|
||||||
|
if (o) setCustomCursor(loadingText)
|
||||||
|
else setCustomCursor(loadedText)
|
||||||
|
})
|
||||||
|
// navOverlay
|
||||||
const navOverlay = document.createElement('div')
|
const navOverlay = document.createElement('div')
|
||||||
navOverlay.className = 'navOverlay'
|
navOverlay.className = 'navOverlay'
|
||||||
for (const navItem of navItems) {
|
for (const [index, navItem] of navItems.entries()) {
|
||||||
const overlay = document.createElement('div')
|
const overlay = document.createElement('div')
|
||||||
overlay.className = 'overlay'
|
overlay.className = 'overlay'
|
||||||
overlay.addEventListener(
|
const isClose = index === 1
|
||||||
'click',
|
// close
|
||||||
() => {
|
if (isClose) {
|
||||||
handleClick(navItem)
|
overlay.addEventListener(
|
||||||
},
|
'click',
|
||||||
{ passive: true }
|
() => {
|
||||||
)
|
handleCloseClick(navItem)
|
||||||
overlay.addEventListener(
|
},
|
||||||
'keydown',
|
{ passive: true }
|
||||||
() => {
|
)
|
||||||
handleClick(navItem)
|
overlay.addEventListener(
|
||||||
},
|
'keydown',
|
||||||
{ passive: true }
|
() => {
|
||||||
)
|
handleCloseClick(navItem)
|
||||||
overlay.addEventListener(
|
},
|
||||||
'mouseover',
|
{ passive: true }
|
||||||
() => {
|
)
|
||||||
setCustomCursor(navItem)
|
overlay.addEventListener(
|
||||||
},
|
'mouseover',
|
||||||
{ passive: true }
|
() => {
|
||||||
)
|
handleCloseHover(navItem)
|
||||||
overlay.addEventListener(
|
},
|
||||||
'focus',
|
{ passive: true }
|
||||||
() => {
|
)
|
||||||
setCustomCursor(navItem)
|
overlay.addEventListener(
|
||||||
},
|
'focus',
|
||||||
{ passive: true }
|
() => {
|
||||||
)
|
handleCloseHover(navItem)
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// prev and next
|
||||||
|
else {
|
||||||
|
overlay.addEventListener(
|
||||||
|
'click',
|
||||||
|
() => {
|
||||||
|
handlePNClick(navItem)
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
|
overlay.addEventListener(
|
||||||
|
'keydown',
|
||||||
|
() => {
|
||||||
|
handlePNClick(navItem)
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
|
overlay.addEventListener(
|
||||||
|
'mouseover',
|
||||||
|
() => {
|
||||||
|
handlePNHover(navItem)
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
|
overlay.addEventListener(
|
||||||
|
'focus',
|
||||||
|
() => {
|
||||||
|
handlePNHover(navItem)
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
navOverlay.append(overlay)
|
navOverlay.append(overlay)
|
||||||
}
|
}
|
||||||
active.addWatcher(() => {
|
active.addWatcher(() => {
|
||||||
@@ -108,6 +151,7 @@ export function initStageNav(): void {
|
|||||||
|
|
||||||
function nextImage(): void {
|
function nextImage(): void {
|
||||||
if (isAnimating.get()) return
|
if (isAnimating.get()) return
|
||||||
|
navigateVector.set('next')
|
||||||
cordHist.set(
|
cordHist.set(
|
||||||
cordHist.get().map((item) => {
|
cordHist.get().map((item) => {
|
||||||
return { ...item, i: increment(item.i, state.get().length) }
|
return { ...item, i: increment(item.i, state.get().length) }
|
||||||
@@ -119,6 +163,7 @@ function nextImage(): void {
|
|||||||
|
|
||||||
function prevImage(): void {
|
function prevImage(): void {
|
||||||
if (isAnimating.get()) return
|
if (isAnimating.get()) return
|
||||||
|
navigateVector.set('prev')
|
||||||
cordHist.set(
|
cordHist.set(
|
||||||
cordHist.get().map((item) => {
|
cordHist.get().map((item) => {
|
||||||
return { ...item, i: decrement(item.i, state.get().length) }
|
return { ...item, i: decrement(item.i, state.get().length) }
|
||||||
@@ -127,3 +172,23 @@ function prevImage(): void {
|
|||||||
|
|
||||||
decIndex()
|
decIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCloseClick(navItem: NavItem): void {
|
||||||
|
handleClick(navItem)
|
||||||
|
isLoading.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseHover(navItem: NavItem): void {
|
||||||
|
loadedText = navItem
|
||||||
|
setCustomCursor(navItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePNClick(navItem: NavItem): void {
|
||||||
|
if (!isLoading.get()) handleClick(navItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePNHover(navItem: NavItem): void {
|
||||||
|
loadedText = navItem
|
||||||
|
if (isLoading.get()) setCustomCursor(loadingText)
|
||||||
|
else setCustomCursor(navItem)
|
||||||
|
}
|
||||||
|
|||||||
20
assets/ts/desktop/state.ts
Normal file
20
assets/ts/desktop/state.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Watchable } from '../globalUtils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface HistoryItem {
|
||||||
|
i: number
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const cordHist = new Watchable<HistoryItem[]>([])
|
||||||
|
export const isOpen = new Watchable<boolean>(false)
|
||||||
|
export const active = new Watchable<boolean>(false)
|
||||||
|
export const isLoading = new Watchable<boolean>(false)
|
||||||
28
assets/ts/desktop/utils.ts
Normal file
28
assets/ts/desktop/utils.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface DesktopImage extends HTMLImageElement {
|
||||||
|
dataset: {
|
||||||
|
hiUrl: string
|
||||||
|
hiImgH: string
|
||||||
|
hiImgW: string
|
||||||
|
loUrl: string
|
||||||
|
loImgH: string
|
||||||
|
loImgW: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function onMutation<T extends HTMLElement>(
|
||||||
|
element: T,
|
||||||
|
callback: (arg0: MutationRecord[], arg1: MutationObserver) => void,
|
||||||
|
observeOptions: MutationObserverInit = { attributes: true }
|
||||||
|
): void {
|
||||||
|
new MutationObserver((mutations, observer) => {
|
||||||
|
callback(mutations, observer)
|
||||||
|
}).observe(element, observeOptions)
|
||||||
|
}
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
import { Watchable, decrement, increment } from './utils'
|
import {
|
||||||
|
Watchable,
|
||||||
|
decrement,
|
||||||
|
getThresholdSessionIndex,
|
||||||
|
increment
|
||||||
|
} from './globalUtils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* types
|
* types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type State = typeof defaultState
|
export type State = typeof defaultState
|
||||||
|
export type NavVec = 'next' | 'none' | 'prev'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
@@ -26,6 +32,8 @@ const defaultState = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const state = new Watchable<State>(defaultState)
|
export const state = new Watchable<State>(defaultState)
|
||||||
|
export const isAnimating = new Watchable<boolean>(false)
|
||||||
|
export const navigateVector = new Watchable<NavVec>('none')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main functions
|
* main functions
|
||||||
@@ -81,9 +89,3 @@ function updateThreshold(state: State, inc: number): State {
|
|||||||
const newItems = thresholds[i]
|
const newItems = thresholds[i]
|
||||||
return { ...state, ...newItems }
|
return { ...state, ...newItems }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getThresholdSessionIndex(): number {
|
|
||||||
const s = sessionStorage.getItem('thresholdsIndex')
|
|
||||||
if (s === null) return 2
|
|
||||||
return parseInt(s)
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { type Power3, type gsap } from 'gsap'
|
import { type Power3, type gsap } from 'gsap'
|
||||||
import { type Swiper } from 'swiper'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* custom helpers
|
* utils
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function increment(num: number, length: number): number {
|
export function increment(num: number, length: number): number {
|
||||||
@@ -17,44 +16,24 @@ export function expand(num: number): string {
|
|||||||
return ('0000' + num.toString()).slice(-4)
|
return ('0000' + num.toString()).slice(-4)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMobile(): boolean {
|
|
||||||
return window.matchMedia('(hover: none)').matches
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRandom(min: number, max: number): number {
|
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
||||||
}
|
|
||||||
|
|
||||||
export function onVisible<T extends Element>(
|
|
||||||
element: T,
|
|
||||||
callback: (arg0: T) => void
|
|
||||||
): void {
|
|
||||||
new IntersectionObserver((entries, observer) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (entry.intersectionRatio > 0) {
|
|
||||||
callback(element)
|
|
||||||
observer.disconnect()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).observe(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function capitalizeFirstLetter(str: string): string {
|
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadGsap(): Promise<[typeof gsap, typeof Power3]> {
|
export async function loadGsap(): Promise<[typeof gsap, typeof Power3]> {
|
||||||
const g = await import('gsap')
|
const g = await import('gsap')
|
||||||
return [g.gsap, g.Power3]
|
return [g.gsap, g.Power3]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadSwiper(): Promise<typeof Swiper> {
|
export function getThresholdSessionIndex(): number {
|
||||||
const s = await import('swiper')
|
const s = sessionStorage.getItem('thresholdsIndex')
|
||||||
return s.Swiper
|
if (s === null) return 2
|
||||||
|
return parseInt(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeDuplicates<T>(arr: T[]): T[] {
|
||||||
|
if (arr.length < 2) return arr // optimization
|
||||||
|
return [...new Set(arr)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* custom types
|
* custom "reactive" object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class Watchable<T> {
|
export class Watchable<T> {
|
||||||
@@ -1,19 +1,33 @@
|
|||||||
import { initContainer } from './container'
|
import { initContainer } from './container'
|
||||||
|
import { initState } from './globalState'
|
||||||
import { initNav } from './nav'
|
import { initNav } from './nav'
|
||||||
import { initResources } from './resources'
|
import { initResources } from './resources'
|
||||||
import { initState } from './state'
|
|
||||||
import { isMobile } from './utils'
|
|
||||||
|
|
||||||
initContainer()
|
// this is the main entry point for the app
|
||||||
const ijs = await initResources()
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
initState(ijs.length)
|
main().catch((e) => {
|
||||||
initNav()
|
console.log(e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// NOTE: it seems firefox and chromnium don't like top layer await
|
/**
|
||||||
// so we are using import then instead
|
* main functions
|
||||||
if (ijs.length > 0) {
|
*/
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
initContainer()
|
||||||
|
const ijs = await initResources()
|
||||||
|
initState(ijs.length)
|
||||||
|
initNav()
|
||||||
|
|
||||||
|
if (ijs.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: it seems firefox and chromnium don't like top layer await
|
||||||
|
// so we are using import then instead
|
||||||
if (!isMobile()) {
|
if (!isMobile()) {
|
||||||
import('./desktop/init')
|
await import('./desktop/init')
|
||||||
.then((d) => {
|
.then((d) => {
|
||||||
d.initDesktop(ijs)
|
d.initDesktop(ijs)
|
||||||
})
|
})
|
||||||
@@ -21,7 +35,7 @@ if (ijs.length > 0) {
|
|||||||
console.log(e)
|
console.log(e)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
import('./mobile/init')
|
await import('./mobile/init')
|
||||||
.then((m) => {
|
.then((m) => {
|
||||||
m.initMobile(ijs)
|
m.initMobile(ijs)
|
||||||
})
|
})
|
||||||
@@ -30,3 +44,11 @@ if (ijs.length > 0) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hepler
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isMobile(): boolean {
|
||||||
|
return window.matchMedia('(hover: none)').matches
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { container } from '../container'
|
import { container } from '../container'
|
||||||
|
import { setIndex } from '../globalState'
|
||||||
import { type ImageJSON } from '../resources'
|
import { type ImageJSON } from '../resources'
|
||||||
import { setIndex } from '../state'
|
|
||||||
import { getRandom, onVisible } from '../utils'
|
|
||||||
|
|
||||||
import { slideUp } from './gallery'
|
import { slideUp } from './gallery'
|
||||||
import { mounted } from './mounted'
|
import { mounted } from './state'
|
||||||
|
// eslint-disable-next-line sort-imports
|
||||||
|
import { getRandom, onIntersection, type MobileImage } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export let imgs: HTMLImageElement[] = []
|
export let imgs: MobileImage[] = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main functions
|
* main functions
|
||||||
@@ -40,9 +41,14 @@ export function initCollection(ijs: ImageJSON[]): void {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// get image elements
|
// get image elements
|
||||||
imgs = Array.from(collection.getElementsByTagName('img'))
|
imgs = Array.from(collection.getElementsByTagName('img')) as MobileImage[]
|
||||||
// add event listeners
|
// add event listeners
|
||||||
imgs.forEach((img, i) => {
|
imgs.forEach((img, i) => {
|
||||||
|
// preload first 5 images on page load
|
||||||
|
if (i < 5) {
|
||||||
|
img.src = img.dataset.src
|
||||||
|
}
|
||||||
|
// event listeners
|
||||||
img.addEventListener(
|
img.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
() => {
|
() => {
|
||||||
@@ -58,12 +64,18 @@ export function initCollection(ijs: ImageJSON[]): void {
|
|||||||
{ passive: true }
|
{ passive: true }
|
||||||
)
|
)
|
||||||
// preload
|
// preload
|
||||||
onVisible(img, () => {
|
onIntersection(img, (entries, observer) => {
|
||||||
for (let _i = 0; _i < 5; _i++) {
|
entries.every((entry) => {
|
||||||
const n = i + _i
|
// no intersection, skip
|
||||||
if (n < 0 || n > imgs.length - 1) continue
|
if (entry.intersectionRatio <= 0) return true
|
||||||
imgs[n].src = imgs[n].dataset.src as string
|
// preload the i + 5th image
|
||||||
}
|
if (i + 5 < imgs.length) {
|
||||||
|
imgs[i + 5].src = imgs[i + 5].dataset.src
|
||||||
|
}
|
||||||
|
// disconnect observer and return false to break the loop
|
||||||
|
observer.disconnect()
|
||||||
|
return false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -82,7 +94,7 @@ function createCollection(ijs: ImageJSON[]): void {
|
|||||||
const x = i !== 0 ? getRandom(-25, 25) : 0
|
const x = i !== 0 ? getRandom(-25, 25) : 0
|
||||||
const y = i !== 0 ? getRandom(-30, 30) : 0
|
const y = i !== 0 ? getRandom(-30, 30) : 0
|
||||||
// element
|
// element
|
||||||
const e = document.createElement('img')
|
const e = document.createElement('img') as MobileImage
|
||||||
e.dataset.src = ij.loUrl
|
e.dataset.src = ij.loUrl
|
||||||
e.height = ij.loImgH
|
e.height = ij.loImgH
|
||||||
e.width = ij.loImgW
|
e.width = ij.loImgW
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { type Power3, type gsap } from 'gsap'
|
import { type Power3, type gsap } from 'gsap'
|
||||||
import { type Swiper } from 'swiper'
|
import { type Swiper } from 'swiper'
|
||||||
|
|
||||||
import { container } from '../container'
|
import { container, scrollable } from '../container'
|
||||||
|
import { isAnimating, navigateVector, setIndex, state } from '../globalState'
|
||||||
|
import { expand, loadGsap, removeDuplicates } from '../globalUtils'
|
||||||
import { type ImageJSON } from '../resources'
|
import { type ImageJSON } from '../resources'
|
||||||
import { setIndex, state } from '../state'
|
|
||||||
import {
|
|
||||||
Watchable,
|
|
||||||
capitalizeFirstLetter,
|
|
||||||
expand,
|
|
||||||
loadGsap,
|
|
||||||
loadSwiper
|
|
||||||
} from '../utils'
|
|
||||||
|
|
||||||
import { mounted } from './mounted'
|
import { mounted } from './state'
|
||||||
import { scrollable } from './scroll'
|
// eslint-disable-next-line sort-imports
|
||||||
|
import { capitalizeFirstLetter, loadSwiper, type MobileImage } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
@@ -23,11 +18,10 @@ let swiperNode: HTMLDivElement
|
|||||||
let gallery: HTMLDivElement
|
let gallery: HTMLDivElement
|
||||||
let curtain: HTMLDivElement
|
let curtain: HTMLDivElement
|
||||||
let swiper: Swiper
|
let swiper: Swiper
|
||||||
const isAnimating = new Watchable<boolean>(false)
|
|
||||||
let lastIndex = -1
|
let lastIndex = -1
|
||||||
let indexDispNums: HTMLSpanElement[] = []
|
let indexDispNums: HTMLSpanElement[] = []
|
||||||
let galleryImages: HTMLImageElement[] = []
|
let galleryImages: MobileImage[] = []
|
||||||
let collectionImages: HTMLImageElement[] = []
|
let collectionImages: MobileImage[] = []
|
||||||
|
|
||||||
let _Swiper: typeof Swiper
|
let _Swiper: typeof Swiper
|
||||||
let _gsap: typeof gsap
|
let _gsap: typeof gsap
|
||||||
@@ -44,7 +38,7 @@ export function slideUp(): void {
|
|||||||
isAnimating.set(true)
|
isAnimating.set(true)
|
||||||
|
|
||||||
// load active image
|
// load active image
|
||||||
loadImages()
|
galleryLoadImages()
|
||||||
|
|
||||||
_gsap.to(curtain, {
|
_gsap.to(curtain, {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
@@ -61,11 +55,12 @@ export function slideUp(): void {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
scrollable.set(false)
|
scrollable.set(false)
|
||||||
isAnimating.set(false)
|
isAnimating.set(false)
|
||||||
}, 1200)
|
}, 1400)
|
||||||
}
|
}
|
||||||
|
|
||||||
function slideDown(): void {
|
function slideDown(): void {
|
||||||
scrollable.set(true)
|
if (isAnimating.get()) return
|
||||||
|
isAnimating.set(true)
|
||||||
scrollToActive()
|
scrollToActive()
|
||||||
|
|
||||||
_gsap.to(gallery, {
|
_gsap.to(gallery, {
|
||||||
@@ -79,6 +74,11 @@ function slideDown(): void {
|
|||||||
duration: 1.2,
|
duration: 1.2,
|
||||||
delay: 0.4
|
delay: 0.4
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollable.set(true)
|
||||||
|
isAnimating.set(false)
|
||||||
|
}, 1600)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,18 +95,22 @@ export function initGallery(ijs: ImageJSON[]): void {
|
|||||||
swiperNode = document.getElementsByClassName('galleryInner').item(0) as HTMLDivElement
|
swiperNode = document.getElementsByClassName('galleryInner').item(0) as HTMLDivElement
|
||||||
gallery = document.getElementsByClassName('gallery').item(0) as HTMLDivElement
|
gallery = document.getElementsByClassName('gallery').item(0) as HTMLDivElement
|
||||||
curtain = document.getElementsByClassName('curtain').item(0) as HTMLDivElement
|
curtain = document.getElementsByClassName('curtain').item(0) as HTMLDivElement
|
||||||
galleryImages = Array.from(gallery.getElementsByTagName('img'))
|
galleryImages = Array.from(gallery.getElementsByTagName('img')) as MobileImage[]
|
||||||
collectionImages = Array.from(
|
collectionImages = Array.from(
|
||||||
document
|
document
|
||||||
.getElementsByClassName('collection')
|
.getElementsByClassName('collection')
|
||||||
.item(0)
|
.item(0)
|
||||||
?.getElementsByTagName('img') ?? []
|
?.getElementsByTagName('img') ?? []
|
||||||
)
|
) as MobileImage[]
|
||||||
// state watcher
|
// state watcher
|
||||||
state.addWatcher(() => {
|
state.addWatcher(() => {
|
||||||
const s = state.get()
|
const s = state.get()
|
||||||
// change slide only when index is changed
|
// change slide only when index is changed
|
||||||
if (s.index === lastIndex) return
|
if (s.index === lastIndex) return
|
||||||
|
else if (lastIndex === -1)
|
||||||
|
navigateVector.set('none') // lastIndex before first set
|
||||||
|
else if (s.index < lastIndex) navigateVector.set('prev')
|
||||||
|
else navigateVector.set('next')
|
||||||
changeSlide(s.index)
|
changeSlide(s.index)
|
||||||
updateIndexText()
|
updateIndexText()
|
||||||
lastIndex = s.index
|
lastIndex = s.index
|
||||||
@@ -152,7 +156,7 @@ export function initGallery(ijs: ImageJSON[]): void {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function changeSlide(slide: number): void {
|
function changeSlide(slide: number): void {
|
||||||
loadImages()
|
galleryLoadImages()
|
||||||
swiper.slideTo(slide, 0)
|
swiper.slideTo(slide, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +179,29 @@ function updateIndexText(): void {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function galleryLoadImages(): void {
|
||||||
|
let activeImagesIndex: number[] = []
|
||||||
|
const currentIndex = state.get().index
|
||||||
|
const nextIndex = Math.min(currentIndex + 1, state.get().length - 1)
|
||||||
|
const prevIndex = Math.max(currentIndex - 1, 0)
|
||||||
|
switch (navigateVector.get()) {
|
||||||
|
case 'next':
|
||||||
|
activeImagesIndex = [nextIndex]
|
||||||
|
break
|
||||||
|
case 'prev':
|
||||||
|
activeImagesIndex = [prevIndex]
|
||||||
|
break
|
||||||
|
case 'none':
|
||||||
|
activeImagesIndex = [currentIndex, nextIndex, prevIndex]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
removeDuplicates(activeImagesIndex).forEach((i) => {
|
||||||
|
const e = galleryImages[i]
|
||||||
|
if (e.src === e.dataset.src) return // already loaded
|
||||||
|
e.src = e.dataset.src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function createGallery(ijs: ImageJSON[]): void {
|
function createGallery(ijs: ImageJSON[]): void {
|
||||||
/**
|
/**
|
||||||
* gallery
|
* gallery
|
||||||
@@ -192,18 +219,39 @@ function createGallery(ijs: ImageJSON[]): void {
|
|||||||
// swiper wrapper
|
// swiper wrapper
|
||||||
const _swiperWrapper = document.createElement('div')
|
const _swiperWrapper = document.createElement('div')
|
||||||
_swiperWrapper.className = 'swiper-wrapper'
|
_swiperWrapper.className = 'swiper-wrapper'
|
||||||
// swiper slide
|
// loading text
|
||||||
|
const loadingText = container.dataset.loading
|
||||||
for (const ij of ijs) {
|
for (const ij of ijs) {
|
||||||
|
// swiper slide
|
||||||
const _swiperSlide = document.createElement('div')
|
const _swiperSlide = document.createElement('div')
|
||||||
_swiperSlide.className = 'swiper-slide'
|
_swiperSlide.className = 'swiper-slide'
|
||||||
|
// loading indicator
|
||||||
|
const l = document.createElement('div')
|
||||||
|
l.className = 'loadingText'
|
||||||
|
l.innerText = loadingText
|
||||||
// img
|
// img
|
||||||
const e = document.createElement('img')
|
const e = document.createElement('img') as MobileImage
|
||||||
e.dataset.src = ij.hiUrl
|
e.dataset.src = ij.hiUrl
|
||||||
e.height = ij.hiImgH
|
e.height = ij.hiImgH
|
||||||
e.width = ij.hiImgW
|
e.width = ij.hiImgW
|
||||||
e.alt = ij.alt
|
e.alt = ij.alt
|
||||||
|
e.classList.add('hide')
|
||||||
|
// load event
|
||||||
|
e.addEventListener(
|
||||||
|
'load',
|
||||||
|
() => {
|
||||||
|
e.classList.remove('hide')
|
||||||
|
l.classList.add('hide')
|
||||||
|
},
|
||||||
|
{ once: true, passive: true }
|
||||||
|
)
|
||||||
|
// parent container
|
||||||
|
const p = document.createElement('div')
|
||||||
|
p.className = 'slideContainer'
|
||||||
// append
|
// append
|
||||||
_swiperSlide.append(e)
|
p.append(e)
|
||||||
|
p.append(l)
|
||||||
|
_swiperSlide.append(p)
|
||||||
_swiperWrapper.append(_swiperSlide)
|
_swiperWrapper.append(_swiperSlide)
|
||||||
}
|
}
|
||||||
// swiper node
|
// swiper node
|
||||||
@@ -220,10 +268,7 @@ function createGallery(ijs: ImageJSON[]): void {
|
|||||||
)
|
)
|
||||||
// close
|
// close
|
||||||
const _close = document.createElement('div')
|
const _close = document.createElement('div')
|
||||||
const str: string = document
|
_close.innerText = capitalizeFirstLetter(container.dataset.close)
|
||||||
.getElementById('main')
|
|
||||||
?.getAttribute('closeText') as string
|
|
||||||
_close.innerText = capitalizeFirstLetter(str)
|
|
||||||
_close.addEventListener(
|
_close.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
() => {
|
() => {
|
||||||
@@ -261,16 +306,3 @@ function createGallery(ijs: ImageJSON[]): void {
|
|||||||
*/
|
*/
|
||||||
container.append(_gallery, _curtain)
|
container.append(_gallery, _curtain)
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadImages(): void {
|
|
||||||
const activeImages: HTMLImageElement[] = []
|
|
||||||
// load current, next, prev image
|
|
||||||
activeImages.push(galleryImages[swiper.activeIndex])
|
|
||||||
activeImages.push(
|
|
||||||
galleryImages[Math.min(swiper.activeIndex + 1, swiper.slides.length)]
|
|
||||||
)
|
|
||||||
activeImages.push(galleryImages[Math.max(swiper.activeIndex - 1, 0)])
|
|
||||||
for (const e of activeImages) {
|
|
||||||
e.src = e.dataset.src as string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import { Watchable } from '../utils'
|
|
||||||
|
|
||||||
export const scrollable = new Watchable<boolean>(true)
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
import { Watchable } from '../utils'
|
import { Watchable } from '../globalUtils'
|
||||||
|
|
||||||
export const mounted = new Watchable<boolean>(false)
|
export const mounted = new Watchable<boolean>(false)
|
||||||
37
assets/ts/mobile/utils.ts
Normal file
37
assets/ts/mobile/utils.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { type Swiper } from 'swiper'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface MobileImage extends HTMLImageElement {
|
||||||
|
dataset: {
|
||||||
|
src: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function getRandom(min: number, max: number): number {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onIntersection<T extends HTMLElement>(
|
||||||
|
element: T,
|
||||||
|
callback: (arg0: IntersectionObserverEntry[], arg1: IntersectionObserver) => void
|
||||||
|
): void {
|
||||||
|
new IntersectionObserver((entries, observer) => {
|
||||||
|
callback(entries, observer)
|
||||||
|
}).observe(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function capitalizeFirstLetter(str: string): string {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadSwiper(): Promise<typeof Swiper> {
|
||||||
|
const s = await import('swiper')
|
||||||
|
return s.Swiper
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { decThreshold, incThreshold, state } from './state'
|
import { decThreshold, incThreshold, state } from './globalState'
|
||||||
import { expand } from './utils'
|
import { expand } from './globalUtils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* variables
|
* variables
|
||||||
@@ -31,37 +31,11 @@ const indexDispNums = Array.from(
|
|||||||
indexDiv.getElementsByClassName('num')
|
indexDiv.getElementsByClassName('num')
|
||||||
) as HTMLSpanElement[]
|
) as HTMLSpanElement[]
|
||||||
|
|
||||||
// links div
|
|
||||||
const linksDiv = document.getElementsByClassName('links').item(0) as HTMLDivElement
|
|
||||||
|
|
||||||
// links
|
|
||||||
const links = Array.from(linksDiv.getElementsByClassName('link')) as HTMLAnchorElement[]
|
|
||||||
|
|
||||||
// current link index
|
|
||||||
const currentLinkIndex = document
|
|
||||||
.getElementById('main')
|
|
||||||
?.getAttribute('currentMenuItemIndex') as string
|
|
||||||
|
|
||||||
// set current link
|
|
||||||
for (const [index, link] of links.entries()) {
|
|
||||||
if (index === parseInt(currentLinkIndex)) {
|
|
||||||
// set current link style
|
|
||||||
link.classList.add('current')
|
|
||||||
// set current link title (only if not home)
|
|
||||||
if (index !== 0) document.title = link.innerText + ' | ' + document.title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init
|
* init
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function initNav(): void {
|
export function initNav(): void {
|
||||||
const s = state.get()
|
|
||||||
// init threshold text
|
|
||||||
updateThresholdText(expand(s.threshold))
|
|
||||||
// init index text
|
|
||||||
updateIndexText(expand(s.index + 1), expand(s.length))
|
|
||||||
// add watcher for updating nav text
|
// add watcher for updating nav text
|
||||||
state.addWatcher((o) => {
|
state.addWatcher((o) => {
|
||||||
updateIndexText(expand(o.index + 1), expand(o.length))
|
updateIndexText(expand(o.index + 1), expand(o.length))
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ The minimum required Hugo version can be seen in the [`theme.toml`](https://gith
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Git
|
### Git (for adavanced user)
|
||||||
|
|
||||||
On the main branch, you can find the theme's latest source code. To use the latest version, you can clone the repository to `themes/bridget` by running the following command in the root directory of your Hugo site:
|
On the main branch, you can find the theme's latest source code. To use the latest version, you can clone the repository to `themes/bridget` by running the following command in the root directory of your Hugo site:
|
||||||
|
|
||||||
@@ -36,9 +36,13 @@ If you are already using Git for your site, you can add the theme as a submodule
|
|||||||
git submodule add https://github.com/Sped0n/bridget themes/bridget
|
git submodule add https://github.com/Sped0n/bridget themes/bridget
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> ⚠️⚠️⚠️
|
||||||
|
>
|
||||||
|
> Please refer to the config section for the following content.
|
||||||
|
|
||||||
### Module (recommended)
|
### Module (recommended)
|
||||||
|
|
||||||
> If you want to modify the theme, use Git installation instead.
|
> If you want to have some customizations, use Git installation instead.
|
||||||
|
|
||||||
This theme is also available as a [Hugo module](https://gohugo.io/hugo-modules/). Run the following command in the root directory of your Hugo site:
|
This theme is also available as a [Hugo module](https://gohugo.io/hugo-modules/). Run the following command in the root directory of your Hugo site:
|
||||||
|
|
||||||
@@ -46,7 +50,7 @@ First turn your site into a Hugo module (in case you haven't done it yet):
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
hugo mod init github.com/me/my-new-site
|
hugo mod init github.com/me/my-new-site
|
||||||
# or whatever you like, it doesn’t necessarily have to be a GitHub link.
|
# or whatever you like, it doesn’t necessarily have to be a GitHub repo link.
|
||||||
hugo mod init blablabla
|
hugo mod init blablabla
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,6 +69,10 @@ If you want to upgrade the theme, just run:
|
|||||||
hugo mod get -u
|
hugo mod get -u
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> ⚠️⚠️⚠️
|
||||||
|
>
|
||||||
|
> Please refer to the config section for the following content.
|
||||||
|
|
||||||
## Content Management
|
## Content Management
|
||||||
|
|
||||||
The content is where the pictures/text is stored, while the static refers to the website icons.
|
The content is where the pictures/text is stored, while the static refers to the website icons.
|
||||||
@@ -155,8 +163,12 @@ replacements = "github.com/Sped0n/bridget -> ../.."
|
|||||||
path = "github.com/Sped0n/bridget"
|
path = "github.com/Sped0n/bridget"
|
||||||
```
|
```
|
||||||
|
|
||||||
- If you want to <u>modify the theme</u> or you have <u>installation with Git</u>, please keep the `replacements` configuration and change the path after the arrow to the location of your local theme file.
|
- If you have <u>installation with Git</u>
|
||||||
- If you have <u>installation with Module</u>, remove the `replacements` configuration.
|
|
||||||
|
- `replacement`: replace the <u>path after the arrow</u>(`../..`) with the location of your local theme file (⚠️⚠️⚠️**relative path only**, example: `themes/bridget`)
|
||||||
|
- `path`: no change
|
||||||
|
|
||||||
|
- If you have <u>installation with Module</u>, **remove the `replacements` configuration**.
|
||||||
|
|
||||||
### `markup.toml`
|
### `markup.toml`
|
||||||
|
|
||||||
@@ -164,8 +176,40 @@ path = "github.com/Sped0n/bridget"
|
|||||||
|
|
||||||
### `params.toml`
|
### `params.toml`
|
||||||
|
|
||||||
There is a detailed description in the comments.
|
Detailed description in the comments.
|
||||||
|
|
||||||
|
> ⚠️⚠️⚠️
|
||||||
|
>
|
||||||
|
> Only thing that you need to pay **extra attention** is the [`bundled`](https://github.com/Sped0n/bridget/blob/1e2f1fadde9c16989eef1ab771f2ac8463dec5a4/exampleSite/config/_default/params.toml#L6) option, please read the corresponding doc and set it as your need.
|
||||||
|
>
|
||||||
|
> For users who have installation with module, please always set this option to `true`, unless you know what you are doing.
|
||||||
|
>
|
||||||
|
> Or you might get the error related to `node_modules/swiper/swiper.scss`.
|
||||||
|
|
||||||
### `sitemap.toml`
|
### `sitemap.toml`
|
||||||
|
|
||||||
https://gohugo.io/templates/sitemap-template/#configuration
|
https://gohugo.io/templates/sitemap-template/#configuration
|
||||||
|
|
||||||
|
## Customization (AKA for developer)
|
||||||
|
|
||||||
|
> Before heading to this section, please make sure you have **installation with Git**.
|
||||||
|
|
||||||
|
### Option 1: _it just works_ way
|
||||||
|
|
||||||
|
> If you want to modify js/ts file, please use option 2.
|
||||||
|
|
||||||
|
1. Use hugo create a site and move the bridget theme into the theme directory.
|
||||||
|
2. Run `npm install` in the <u>bridget theme root dir</u>, not <u>your hugo site root dir</u>.
|
||||||
|
3. After the command is done, copy the `node_modules` dir from <u>bridget theme root dir</u> to <u>your hugo site root dir</u>.
|
||||||
|
4. In <u>your hugo site root dir</u>, write/modify configuration files according to your needs, remember to set `bundled` option to `false`, so hugo will not use prebuilt css file.
|
||||||
|
5. Run `hugo server` in <u>your hugo site root dir</u>, and you are good to go.
|
||||||
|
|
||||||
|
### Option 2: recommended way
|
||||||
|
|
||||||
|
1. Use hugo create a site and move the bridget theme into the theme directory.
|
||||||
|
2. Run `npm install` in the <u>bridget theme root dir</u>, not <u>your hugo site root dir</u>.
|
||||||
|
3. Run `npm run dev` in the <u>bridget theme root dir</u>, we will use content in exampleSite to debug.
|
||||||
|
4. Make your customization.
|
||||||
|
5. After modification, run `npm run build` in the <u>bridget theme root dir</u> to build artifacts.
|
||||||
|
6. In <u>your hugo site root dir</u>, write/modify configuration files according to your needs, remember to set `bundled` option to `true`, so hugo will use the artifacts you built in step 5.
|
||||||
|
7. Run `hugo server` in <u>your hugo site root dir</u>, and you are good to go.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# description of the site (will be placed in meta)
|
# description of the site (will be placed in meta)
|
||||||
description = "Bridget is a minimal Hugo theme designed for photographers / visual artists."
|
description = "Bridget is a minimal Hugo theme designed for photographers/visual artists."
|
||||||
# use bundled js and css
|
# use bundled js and css
|
||||||
# * if you want to build the js and css from scratch, set this to false and run `npm install` and `npm run build`
|
# * if you want to build the js and css from scratch, set this to false and run `npm install` and `npm run build`
|
||||||
# * tldr: set this to false if you want to develop and edit the js and css
|
# * tldr: set this to false if you want to develop and edit the js and css
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ menu:
|
|||||||
unifiedAlt: ''
|
unifiedAlt: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
Bridget is a _minimal_ Hugo theme designed for photographers / visual artists.
|
Bridget is a _minimal_ Hugo theme designed for photographers/visual artists.
|
||||||
|
|
||||||
The inspiration for this theme came from a video by <u>[Hyperlexed](https://www.youtube.com/@Hyperplexed)</u>, which can be found <u>[here](https://www.youtube.com/watch?v=Jt3A2lNN2aE)</u>. Initially, it was designed using pure TypeScript and CSS. However, after website designer <u>[Tyler McRobert](https://tylermcrobert.com)</u> made the source code publicly available, the whole project was modified to mimic the original design. The animations in Bridget are achieved using gsap and swiper. In essence, it is more like a porting of the original design into Hugo.
|
The inspiration for this theme came from a video by <u>[Hyperlexed](https://www.youtube.com/@Hyperplexed)</u>, which can be found <u>[here](https://www.youtube.com/watch?v=Jt3A2lNN2aE)</u>. Initially, it was developed using raw TypeScript and CSS. However, after website designer <u>[Tyler McRobert](https://tylermcrobert.com)</u> made the source code publicly available, I realized that I have invented many unnecessary components, and this project was modified to porting the original design to hugo while focusing on _performance_.
|
||||||
|
|
||||||
Once again, great shout out to <u>[Tyler McRobert](https://tylermcrobert.com)</u> for his inspiration to this project.
|
Once again, great shout out to <u>[Tyler McRobert](https://tylermcrobert.com)</u> for his inspiration to this project.
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "schließen"
|
|||||||
other = "schwelle"
|
other = "schwelle"
|
||||||
[404]
|
[404]
|
||||||
other = "seite nicht gefunden"
|
other = "seite nicht gefunden"
|
||||||
|
[loading]
|
||||||
|
other = "lade"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "close"
|
|||||||
other = "threshold"
|
other = "threshold"
|
||||||
[404]
|
[404]
|
||||||
other = "page not found"
|
other = "page not found"
|
||||||
|
[loading]
|
||||||
|
other = "loading"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "cerrar"
|
|||||||
other = "umbral"
|
other = "umbral"
|
||||||
[404]
|
[404]
|
||||||
other = "página no encontrada"
|
other = "página no encontrada"
|
||||||
|
[loading]
|
||||||
|
other = "cargando"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "fermer"
|
|||||||
other = "seuil"
|
other = "seuil"
|
||||||
[404]
|
[404]
|
||||||
other = "page non trouvée"
|
other = "page non trouvée"
|
||||||
|
[loading]
|
||||||
|
other = "chargement"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "chiudi"
|
|||||||
other = "soglia"
|
other = "soglia"
|
||||||
[404]
|
[404]
|
||||||
other = "pagina non trovata"
|
other = "pagina non trovata"
|
||||||
|
[loading]
|
||||||
|
other = "caricamento"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "閉じる"
|
|||||||
other = "しきい値"
|
other = "しきい値"
|
||||||
[404]
|
[404]
|
||||||
other = "ページが見つかりません"
|
other = "ページが見つかりません"
|
||||||
|
[loading]
|
||||||
|
other = "読み込み中"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "닫기"
|
|||||||
other = "임계값"
|
other = "임계값"
|
||||||
[404]
|
[404]
|
||||||
other = "페이지를 찾을 수 없습니다"
|
other = "페이지를 찾을 수 없습니다"
|
||||||
|
[loading]
|
||||||
|
other = "로딩중"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "关闭"
|
|||||||
other = "阈值"
|
other = "阈值"
|
||||||
[404]
|
[404]
|
||||||
other = "页面不存在"
|
other = "页面不存在"
|
||||||
|
[loading]
|
||||||
|
other = "加载中"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "關閉"
|
|||||||
other = "閾值"
|
other = "閾值"
|
||||||
[404]
|
[404]
|
||||||
other = "找不到頁面"
|
other = "找不到頁面"
|
||||||
|
[loading]
|
||||||
|
other = "載入中"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "關閉"
|
|||||||
other = "閾值"
|
other = "閾值"
|
||||||
[404]
|
[404]
|
||||||
other = "找不到頁面"
|
other = "找不到頁面"
|
||||||
|
[loading]
|
||||||
|
other = "載入中"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "关闭"
|
|||||||
other = "阈值"
|
other = "阈值"
|
||||||
[404]
|
[404]
|
||||||
other = "页面不存在"
|
other = "页面不存在"
|
||||||
|
[loading]
|
||||||
|
other = "加载中"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ other = "關閉"
|
|||||||
other = "閾值"
|
other = "閾值"
|
||||||
[404]
|
[404]
|
||||||
other = "找不到頁面"
|
other = "找不到頁面"
|
||||||
|
[loading]
|
||||||
|
other = "載入中"
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
{{- define "main" -}}
|
{{- define "main" -}}
|
||||||
{{- $params := .Scratch.Get "params" -}}
|
|
||||||
{{- $currentPage := . -}}
|
|
||||||
{{- with partial "function/currentMenuItem.html" . -}}
|
|
||||||
<script>document.getElementById("main").setAttribute("currentMenuItemIndex", "{{- (sub .ID 1) -}}")</script>
|
|
||||||
{{- end -}}
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{{- partial "nav.html" . -}}
|
{{- partial "nav.html" . -}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{{ site.Title }}</title>
|
{{- partial "head/link.html" . -}}
|
||||||
{{- partial "head/link.html" -}}
|
{{- partial "head/meta.html" . -}}
|
||||||
{{- partial "head/meta.html" -}}
|
{{- partial "head/seo.html" . -}}
|
||||||
{{- partial "head/seo.html" -}}
|
{{- partial "head/favicon.html" . -}}
|
||||||
{{- partial "head/favicon.html" -}}
|
|
||||||
</head>
|
</head>
|
||||||
<body lang="{{- site.LanguageCode -}}">
|
<body lang="{{- site.LanguageCode -}}">
|
||||||
<div id="main">
|
<div id="main">
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
{{- define "main" -}}
|
{{- define "main" -}}
|
||||||
{{- $params := .Scratch.Get "params" -}}
|
<div
|
||||||
{{- $currentPage := . -}}
|
class="container"
|
||||||
{{- with partial "function/currentMenuItem.html" . -}}
|
data-next="{{- i18n "next" -}}"
|
||||||
<script>
|
data-prev="{{- i18n "prev" -}}"
|
||||||
document.getElementById("main").setAttribute("currentMenuItemIndex", "{{- (sub .ID 1) -}}")
|
data-close="{{- i18n "close" -}}"
|
||||||
document.getElementById("main").setAttribute("nextText", "{{- i18n "next" -}}")
|
data-loading="{{- i18n "loading" -}}"
|
||||||
document.getElementById("main").setAttribute("prevText", "{{- i18n "prev" -}}")
|
>
|
||||||
document.getElementById("main").setAttribute("closeText", "{{- i18n "close" -}}")
|
|
||||||
</script>
|
|
||||||
{{- end -}}
|
|
||||||
<div class="container">
|
|
||||||
{{- partial "nav.html" . -}}
|
{{- partial "nav.html" . -}}
|
||||||
|
{{- with .Content -}}
|
||||||
|
<article class="info">
|
||||||
|
{{- . -}}
|
||||||
|
</article>
|
||||||
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
<article class="info">
|
|
||||||
{{ .Content }}
|
|
||||||
</article>
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
{{- $Page := . -}}
|
{{- $context := . -}}
|
||||||
{{- $Path := "" -}}
|
|
||||||
{{- $params := .Page.Params | merge .Site.Params.Page -}}
|
{{- $params := .Page.Params | merge .Site.Params.Page -}}
|
||||||
|
|
||||||
{{- with partial "function/currentMenuItem.html" . -}}
|
{{- with partial "function/getImageSlice.html" . -}}
|
||||||
{{- $Path = .DirName -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- $gallery := site.GetPage $Path -}}
|
|
||||||
{{- with $gallery.Resources.ByType "image" -}}
|
|
||||||
{{- $index := len . -}}
|
{{- $index := len . -}}
|
||||||
{{- $Page.Scratch.Add "img" slice -}}
|
{{- $context.Scratch.Add "img" slice -}}
|
||||||
{{- range sort . "Name" "desc" -}}
|
{{- range sort . "Name" "desc" -}}
|
||||||
{{- $image := . -}}
|
{{- $image := . -}}
|
||||||
{{- $index = sub $index 1 -}}
|
{{- $index = sub $index 1 -}}
|
||||||
@@ -19,7 +13,7 @@
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $lores := .Resize (site.Params.loResOpt | default "700x webp Lanczos q60") -}}
|
{{- $lores := .Resize (site.Params.loResOpt | default "700x webp Lanczos q60") -}}
|
||||||
{{- $hires := .Resize (site.Params.hiResOpt | default "2000x webp Lanczos q75") -}}
|
{{- $hires := .Resize (site.Params.hiResOpt | default "2000x webp Lanczos q75") -}}
|
||||||
{{- $Page.Scratch.Add "img" (dict
|
{{- $context.Scratch.Add "img" (dict
|
||||||
"index" (int $index)
|
"index" (int $index)
|
||||||
"alt" (string $alt)
|
"alt" (string $alt)
|
||||||
"loUrl" (string $lores.RelPermalink)
|
"loUrl" (string $lores.RelPermalink)
|
||||||
@@ -31,7 +25,7 @@
|
|||||||
)
|
)
|
||||||
-}}
|
-}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{ $Page.Scratch.Get "img" | jsonify }}
|
{{ $context.Scratch.Get "img" | jsonify }}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
[]
|
[]
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
{{- $currentPage := . -}}
|
{{- $currentPage := . -}}
|
||||||
|
|
||||||
{{- $dirName := "" -}}
|
{{- $identifier := "" -}}
|
||||||
{{- $id := -1 -}}
|
{{- $title := "" -}}
|
||||||
|
{{- $weight := -1 -}}
|
||||||
|
|
||||||
{{- range site.Menus.main -}}
|
{{- range site.Menus.main -}}
|
||||||
{{ $menu_item_url := .URL | relLangURL }}
|
{{ $menu_item_url := .URL | relLangURL }}
|
||||||
{{ $page_url:= $currentPage.RelPermalink | relLangURL }}
|
{{ $page_url:= $currentPage.RelPermalink | relLangURL }}
|
||||||
{{ if eq $menu_item_url $page_url }}
|
{{ if eq $menu_item_url $page_url }}
|
||||||
{{- $dirName = .Identifier -}}
|
{{- $identifier = .Identifier -}}
|
||||||
{{- $id = .Weight -}}
|
{{- $title = .Title -}}
|
||||||
|
{{- $weight = .Weight -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- return (dict "DirName" $dirName "ID" $id) -}}
|
{{- return (dict "Identifier" $identifier "Title" $title "Weight" $weight) -}}
|
||||||
|
|||||||
10
layouts/partials/function/getImageSlice.html
Normal file
10
layouts/partials/function/getImageSlice.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{{- $context := . -}}
|
||||||
|
{{- $Path := "" -}}
|
||||||
|
{{- $params := .Page.Params | merge .Site.Params.Page -}}
|
||||||
|
|
||||||
|
{{- with partial "function/currentMenuItem.html" . -}}
|
||||||
|
{{- $Path = .Identifier -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- $gallery := site.GetPage $Path -}}
|
||||||
|
{{- return $gallery.Resources.ByType "image" -}}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
{{- partial "plugin/style.html" $style -}}
|
{{- partial "plugin/style.html" $style -}}
|
||||||
|
|
||||||
{{/* main style */}}
|
{{/* main style */}}
|
||||||
{{- if site.Params.bundled -}}
|
{{- if (site.Params.bundled | default true) -}}
|
||||||
{{- $style := dict "Link" "/bundled/css/style.min.css" "Defer" true -}}
|
{{- $style := dict "Link" "/bundled/css/style.min.css" "Defer" true -}}
|
||||||
{{- partial "plugin/style.html" $style -}}
|
{{- partial "plugin/style.html" $style -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
@@ -18,6 +18,16 @@
|
|||||||
{{- partial "plugin/style.html" $style -}}
|
{{- partial "plugin/style.html" $style -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/* fuck safari */}}
|
||||||
|
<script>
|
||||||
|
function z() {
|
||||||
|
const r = document.querySelector(':root')
|
||||||
|
r.style.setProperty('--window-height', `${window.innerHeight}px`)
|
||||||
|
}
|
||||||
|
z()
|
||||||
|
window.addEventListener('resize', z, { passive: true })
|
||||||
|
</script>
|
||||||
|
|
||||||
{{/* main js */}}
|
{{/* main js */}}
|
||||||
{{- $script := dict "Link" "/bundled/js/main.js" "Defer" true "Esm" true -}}
|
{{- $script := dict "Link" "/bundled/js/main.js" "Defer" true "Esm" true -}}
|
||||||
{{- partial "plugin/script.html" $script -}}
|
{{- partial "plugin/script.html" $script -}}
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
<meta name="Description" content="{{- site.Params.description -}}" />
|
{{/* Title */}}
|
||||||
<meta
|
{{- $page_title := "" -}}
|
||||||
name="application-name"
|
{{- with partial "function/currentMenuItem.html" . -}}
|
||||||
content="{{- .Site.Params.app.title | default site.Title -}}"
|
{{ $page_title = printf "%s" site.Title | printf "%s%s" " | " | printf "%s%s" .Title | printf "%s" }}
|
||||||
/>
|
{{- end -}}
|
||||||
<meta
|
<title>{{ $page_title }}</title>
|
||||||
name="apple-mobile-web-app-title"
|
|
||||||
content="{{- .Site.Params.app.title | default site.Title -}}"
|
{{/* Basic */}}
|
||||||
/>
|
<meta name="Description" content="{{ site.Params.description }}" />
|
||||||
|
<meta name="application-name" content="{{ $page_title }}" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="{{ $page_title }}" />
|
||||||
|
|
||||||
|
{{/* Opengraph */}}
|
||||||
|
<meta property="og:title" content="{{ $page_title }}" />
|
||||||
|
<meta name="twitter:title" content="{{ $page_title }}" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="{{ .Permalink }}" />
|
||||||
|
<meta property="og:description" content="{{ site.Params.description }}" />
|
||||||
|
<meta name="twitter:description" content="{{ site.Params.description }}" />
|
||||||
|
|
||||||
|
{{/* Generator */}}
|
||||||
|
{{ hugo.Generator }}
|
||||||
|
|||||||
@@ -4,19 +4,39 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="links">
|
<div class="links">
|
||||||
{{- $index := 0 -}}
|
{{- $index := 0 -}}
|
||||||
|
{{- $currentIndex := -1 -}}
|
||||||
|
{{- with partial "function/currentMenuItem.html" . -}}
|
||||||
|
{{- $currentIndex = sub .Weight 1 -}}
|
||||||
|
{{- end -}}
|
||||||
{{- $menus := .Site.Menus.main -}}
|
{{- $menus := .Site.Menus.main -}}
|
||||||
{{- $len := len $menus }}
|
{{- $len := len $menus }}
|
||||||
{{- range $menus -}}
|
{{- range $menus -}}
|
||||||
{{- $url := .URL | relURL -}}
|
{{- $url := .URL | relURL -}}
|
||||||
{{- if eq (add $index 1) $len -}}
|
{{- if eq (add $index 1) $len -}}
|
||||||
<a href="{{- .URL | relURL -}}" class="link">{{- .Title -}}</a>
|
<a
|
||||||
|
href="{{- .URL | relURL -}}"
|
||||||
|
class="link{{- if eq $index $currentIndex -}}
|
||||||
|
{{- printf " current" -}}
|
||||||
|
{{- end -}}"
|
||||||
|
>{{- .Title -}}</a
|
||||||
|
>
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
<a href="{{- .URL | relURL -}}" class="link">{{- .Title -}}</a>, 
|
<a
|
||||||
|
href="{{- .URL | relURL -}}"
|
||||||
|
class="link{{- if eq $index $currentIndex -}}
|
||||||
|
{{- printf " current" -}}
|
||||||
|
{{- end -}}"
|
||||||
|
>{{- .Title -}}</a
|
||||||
|
>, 
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $index = add $index 1 -}}
|
{{- $index = add $index 1 -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
<div class="threshold">
|
<div class="threshold">
|
||||||
|
{{- $length := 0 -}}
|
||||||
|
{{- with partial "function/getImageSlice.html" . -}}
|
||||||
|
{{- $length = len . -}}
|
||||||
|
{{- end -}}
|
||||||
<span>{{- i18n "threshold" | strings.FirstUpper -}}:</span>
|
<span>{{- i18n "threshold" | strings.FirstUpper -}}:</span>
|
||||||
<span>
|
<span>
|
||||||
<button class="dec">-</button>
|
<button class="dec">-</button>
|
||||||
@@ -26,10 +46,43 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="index">
|
<div class="index">
|
||||||
<span class="num"></span><span class="num"></span><span class="num"></span
|
<span class="num">0</span><span class="num">0</span><span class="num">0</span
|
||||||
><span class="num"></span>
|
><span class="num">0</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span class="num"></span><span class="num"></span><span class="num"></span
|
<span class="num">{{- math.Floor (div $length 1000) -}}</span
|
||||||
><span class="num"></span>
|
><span class="num">{{- mod (math.Floor (div $length 100)) 10 -}}</span
|
||||||
|
><span class="num">{{- mod (math.Floor (div $length 10)) 10 -}}</span
|
||||||
|
><span class="num">{{- mod $length 10 -}}</span>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
{{- /* for threshold */ -}}
|
||||||
|
<script>
|
||||||
|
i = 2
|
||||||
|
const s = sessionStorage.getItem('thresholdsIndex')
|
||||||
|
if (s !== null) {
|
||||||
|
i = parseInt(s)
|
||||||
|
}
|
||||||
|
var t = ''
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
t = '0020'
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
t = '0040'
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
t = '0080'
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
t = '0140'
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
t = '0200'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Array.from(
|
||||||
|
document.getElementsByClassName('threshold').item(0).getElementsByClassName('num')
|
||||||
|
).forEach((e, i) => {
|
||||||
|
e.innerText = t[i]
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|||||||
36
package.json
36
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bridget",
|
"name": "bridget",
|
||||||
"version": "v0.0.3",
|
"version": "v1.0.0",
|
||||||
"description": "bridget theme source file",
|
"description": "bridget theme source file",
|
||||||
"packageManager": "pnpm@8.10.2",
|
"packageManager": "pnpm@8.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"lint": "eslint . --fix && prettier --write .",
|
"lint": "eslint . --fix && prettier --write .",
|
||||||
"lint:check": "eslint . && prettier . --check",
|
"lint:check": "eslint . && prettier . --check",
|
||||||
"dev": "run-p rollup:dev hugo:dev",
|
"dev": "run-p rollup:dev hugo:dev",
|
||||||
"build": "rm -f ./static/bundled/js/* && run-s rollup:build hugo:build && yes | cp -rf ./exampleSite/public/css/* ./static/bundled/css",
|
"build": "rm -f ./static/bundled/js/* && run-s rollup:build hugo:build && yes | cp -rf ./exampleSite/public/css/*.css ./static/bundled/css",
|
||||||
"server": "run-p rollup:server hugo:server",
|
"server": "run-p rollup:server hugo:server",
|
||||||
"rollup:build": "rollup -c --environment BUILD:production",
|
"rollup:build": "rollup -c --environment BUILD:production",
|
||||||
"rollup:server": "rollup -c --watch --environment BUILD:production",
|
"rollup:server": "rollup -c --watch --environment BUILD:production",
|
||||||
@@ -37,29 +37,29 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/Sped0n/bridget#readme",
|
"homepage": "https://github.com/Sped0n/bridget#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@typescript-eslint/parser": "^6.20.0",
|
||||||
"@rollup/plugin-typescript": "^11.1.5",
|
"eslint": "^8.56.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"@typescript-eslint/parser": "^6.10.0",
|
|
||||||
"eslint": "^8.53.0",
|
|
||||||
"eslint-config-prettier": "^9.0.0",
|
|
||||||
"eslint-config-standard": "^17.1.0",
|
"eslint-config-standard": "^17.1.0",
|
||||||
"eslint-config-standard-with-typescript": "^39.1.1",
|
"eslint-config-standard-with-typescript": "^43.0.1",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-n": "^16.3.1",
|
"eslint-plugin-n": "^16.6.2",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.2.4",
|
||||||
"prettier-plugin-go-template": "^0.0.15",
|
"prettier-plugin-go-template": "^0.0.15",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
"rollup": "^4.3.0",
|
"typescript": "^5.3.3"
|
||||||
"typescript": "^5.2.2"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gsap": "^3.12.2",
|
"gsap": "^3.12.5",
|
||||||
"swiper": "^11.0.4"
|
"swiper": "^11.0.5",
|
||||||
|
"rollup": "^4.9.6",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
|
"@rollup/plugin-typescript": "^11.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
829
pnpm-lock.yaml
generated
829
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
2
static/bundled/css/style.min.css
vendored
2
static/bundled/css/style.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/bundled/js/EY5BO_.js
Normal file
1
static/bundled/js/EY5BO_.js
Normal file
File diff suppressed because one or more lines are too long
1
static/bundled/js/Ej2jsy.js
Normal file
1
static/bundled/js/Ej2jsy.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{W as e,s as t,n,f as a,l as s,g as c,h as o,r as i,c as r,i as d}from"./main.js";const l=new e(!1);function m(e,t){return Math.floor(Math.random()*(t-e+1))+e}let p,u,g,h,v,E,y,f=-1,N=[],w=[],x=[],L=!1;function B(){d.get()||(d.set(!0),x[t.get().index].scrollIntoView({block:"center",behavior:"auto"}),E.to(u,{y:"100%",ease:y.easeInOut,duration:1}),E.to(g,{opacity:0,duration:1.2,delay:.4}),setTimeout((()=>{a.set(!0),d.set(!1)}),1600))}function I(){let e=[];const a=t.get().index,s=Math.min(a+1,t.get().length-1),c=Math.max(a-1,0);switch(n.get()){case"next":e=[s];break;case"prev":e=[c];break;case"none":e=[a,s,c]}i(e).forEach((e=>{const t=w[e];t.src!==t.dataset.src&&(t.src=t.dataset.src)}))}let T=[];function C(e){c(e),!d.get()&&L&&(d.set(!0),I(),E.to(g,{opacity:1,duration:1}),E.to(u,{y:0,ease:y.easeInOut,duration:1,delay:.4}),setTimeout((()=>{a.set(!1),d.set(!1)}),1400))}function b(e){(function(e){!function(e){const t=document.createElement("div");t.className="collection";for(const[n,a]of e.entries()){const e=0!==n?m(-25,25):0,s=0!==n?m(-30,30):0,c=document.createElement("img");c.dataset.src=a.loUrl,c.height=a.loImgH,c.width=a.loImgW,c.alt=a.alt,c.style.transform=`translate3d(${e}%, ${s-50}%, 0)`,t.append(c)}r.append(t)}(e);const t=document.getElementsByClassName("collection").item(0);l.addWatcher((e=>{e?t.classList.remove("hidden"):t.classList.add("hidden")})),T=Array.from(t.getElementsByTagName("img")),T.forEach(((e,t)=>{var n,a;t<5&&(e.src=e.dataset.src),e.addEventListener("click",(()=>{C(t)}),{passive:!0}),e.addEventListener("keydown",(()=>{C(t)}),{passive:!0}),n=e,a=(e,n)=>{e.every((e=>e.intersectionRatio<=0||(t+5<T.length&&(T[t+5].src=T[t+5].dataset.src),n.disconnect(),!1)))},new IntersectionObserver(((e,t)=>{a(e,t)})).observe(n)}))})(e),function(e){!function(e){const t=document.createElement("div");t.className="swiper-wrapper";const n=r.dataset.loading;for(const a of e){const e=document.createElement("div");e.className="swiper-slide";const s=document.createElement("div");s.className="loadingText",s.innerText=n;const c=document.createElement("img");c.dataset.src=a.hiUrl,c.height=a.hiImgH,c.width=a.hiImgW,c.alt=a.alt,c.classList.add("hide"),c.addEventListener("load",(()=>{c.classList.remove("hide"),s.classList.add("hide")}),{once:!0,passive:!0});const o=document.createElement("div");o.className="slideContainer",o.append(c),o.append(s),e.append(o),t.append(e)}const a=document.createElement("div");a.className="galleryInner",a.append(t);const s=document.createElement("div");s.insertAdjacentHTML("afterbegin",'<span class="num"></span><span class="num"></span><span class="num"></span><span class="num"></span>\n <span>/</span>\n <span class="num"></span><span class="num"></span><span class="num"></span><span class="num"></span>');const c=document.createElement("div");var o;c.innerText=(o=r.dataset.close).charAt(0).toUpperCase()+o.slice(1),c.addEventListener("click",(()=>{B()}),{passive:!0}),c.addEventListener("keydown",(()=>{B()}),{passive:!0});const i=document.createElement("div");i.className="nav",i.append(s,c);const d=document.createElement("div");d.className="gallery",d.append(a),d.append(i);const l=document.createElement("div");l.className="curtain",r.append(d,l)}(e),N=Array.from(document.getElementsByClassName("nav").item(0)?.getElementsByClassName("num")??[]),p=document.getElementsByClassName("galleryInner").item(0),u=document.getElementsByClassName("gallery").item(0),g=document.getElementsByClassName("curtain").item(0),w=Array.from(u.getElementsByTagName("img")),x=Array.from(document.getElementsByClassName("collection").item(0)?.getElementsByTagName("img")??[]),t.addWatcher((()=>{const e=t.get();var a;e.index!==f&&(-1===f?n.set("none"):e.index<f?n.set("prev"):n.set("next"),a=e.index,I(),h.slideTo(a,0),function(){const e=o(t.get().index+1),n=o(t.get().length);N.forEach(((t,a)=>{t.innerText=a<4?e[a]:n[a-4]}))}(),f=e.index)})),l.addWatcher((e=>{e&&a.set(!0)})),window.addEventListener("touchstart",(()=>{s().then((e=>{E=e[0],y=e[1]})).catch((e=>{console.log(e)})),async function(){return(await import("./f6JTi3.js")).Swiper}().then((e=>{v=e,h=new v(p,{spaceBetween:20}),h.on("slideChange",(({realIndex:e})=>{c(e)}))})).catch((e=>{console.log(e)})),L=!0}),{once:!0,passive:!0}),l.set(!0)}(e)}export{b as initMobile};
|
||||||
1
static/bundled/js/LbzzjK.js
Normal file
1
static/bundled/js/LbzzjK.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{l as e,c as t,W as n,s as a,i as s,a as i,d as o,b as c}from"./main.js";let r=[],d={x:0,y:0};const g=new n([]),l=new n(!1),m=new n(!1),h=new n(!1);let u,p,f=!1;function v(){return g.get().map((e=>r[e.i]))}function y(){const e=v().slice(-a.get().trailLength);return e.slice(0,e.length-1)}function w(){const e=v();return e[e.length-1]}function I(){const e=g.get(),t=a.get(),n=e.length>0?e[e.length-1].i:t.index,i=[];for(let e=0;e<7;e++)i.push(r[s(n+e,t.length)]);return i}function E(){const e=g.get(),t=a.get();return r[o(e[e.length-1].i,t.length)]}function x(){const e=g.get(),t=a.get();return r[s(e[e.length-1].i,t.length)]}function L(e){if(l.get()||m.get()||!f)return;const t={x:e.clientX,y:e.clientY};if(Math.hypot(t.x-d.x,t.y-d.y)>a.get().threshold){d=t,i();const e={i:a.get().index,...t};g.set([...g.get(),e].slice(-a.get().length))}}function W(){if(m.get()||!f)return;l.set(!0),m.set(!0),k([w(),E(),x()]);const e=u.timeline();e.to(y(),{y:"+=20",ease:p.easeIn,stagger:.075,duration:.3,delay:.1,opacity:0}),e.to(w(),{x:0,y:0,ease:p.easeInOut,duration:.7,delay:.3}),e.to(w(),{delay:.1,scale:1,ease:p.easeInOut}),e.then((()=>{m.set(!1)})).catch((e=>{console.log(e)}))}function H(){if(m.get()||!f)return;l.set(!1),m.set(!0),N([w()]),N(y());const e=u.timeline();e.to(w(),{scale:.6,duration:.6,ease:p.easeInOut}),e.to(w(),{delay:.3,duration:.7,ease:p.easeInOut,x:g.get()[g.get().length-1].x-window.innerWidth/2,y:g.get()[g.get().length-1].y-window.innerHeight/2}),e.to(y(),{y:"-=20",ease:p.easeOut,stagger:-.1,duration:.3,opacity:1}),e.then((()=>{m.set(!1)})).catch((e=>{console.log(e)}))}function k(e){e.forEach((e=>{e.src=e.dataset.hiUrl,e.height=parseInt(e.dataset.hiImgH),e.width=parseInt(e.dataset.hiImgW)}))}function N(e){e.forEach((e=>{e.src=e.dataset.loUrl,e.height=parseInt(e.dataset.loImgH),e.width=parseInt(e.dataset.loImgW)}))}const b=document.createElement("div"),A=document.createElement("div");function O(e){const t=e.clientX,n=e.clientY;b.style.transform=`translate3d(${t}px, ${n}px, 0)`}function U(e){A.innerText=e}const T=document.getElementById("main"),S=[T.getAttribute("prevText"),T.getAttribute("closeText"),T.getAttribute("nextText")];function B(e){e===S[0]?$():e===S[1]?H():Y()}function X(e){if(!l.get()&&!m.get())switch(e.key){case"ArrowLeft":$();break;case"Escape":H();break;case"ArrowRight":Y()}}function Y(){m.get()||(g.set(g.get().map((e=>({...e,i:s(e.i,a.get().length)})))),i())}function $(){m.get()||(g.set(g.get().map((e=>({...e,i:o(e.i,a.get().length)})))),c())}function j(n){b.className="cursor",A.className="cursorInner",b.append(A),t.append(b),window.addEventListener("mousemove",O,{passive:!0}),h.addWatcher((e=>{e?b.classList.add("active"):b.classList.remove("active")})),function(n){!function(e){const n=document.createElement("div");n.className="stage";for(const t of e){const e=document.createElement("img");e.height=t.loImgH,e.width=t.loImgW,e.dataset.hiUrl=t.hiUrl,e.dataset.hiImgH=t.hiImgH.toString(),e.dataset.hiImgW=t.hiImgW.toString(),e.dataset.loUrl=t.loUrl,e.dataset.loImgH=t.loImgH.toString(),e.dataset.loImgW=t.loImgW.toString(),e.alt=t.alt,n.append(e)}t.append(n)}(n);const s=document.getElementsByClassName("stage").item(0);r=Array.from(s.getElementsByTagName("img")),s.addEventListener("click",(()=>{W()})),s.addEventListener("keydown",(()=>{W()})),window.addEventListener("mousemove",L,{passive:!0}),l.addWatcher((e=>{h.set(e&&!m.get())})),m.addWatcher((e=>{h.set(l.get()&&!e)})),g.addWatcher((e=>{!function(){const e=v();0!==e.length&&f&&(N(I()),u.set(e,{x:e=>g.get()[e].x-window.innerWidth/2,y:e=>g.get()[e].y-window.innerHeight/2,opacity:e=>e+1+a.get().trailLength<=g.get().length?0:1,zIndex:e=>e,scale:.6}),l.get()&&(N(v()),k([w(),E(),x()]),u.set(r,{opacity:0}),u.set(w(),{opacity:1,x:0,y:0,scale:1})))}()})),N(I()),window.addEventListener("mousemove",(()=>{e().then((e=>{u=e[0],p=e[1],f=!0})).catch((e=>{console.log(e)}))}),{once:!0,passive:!0})}(n),function(){const e=document.createElement("div");e.className="navOverlay";for(const t of S){const n=document.createElement("div");n.className="overlay",n.addEventListener("click",(()=>{B(t)}),{passive:!0}),n.addEventListener("keydown",(()=>{B(t)}),{passive:!0}),n.addEventListener("mouseover",(()=>{U(t)}),{passive:!0}),n.addEventListener("focus",(()=>{U(t)}),{passive:!0}),e.append(n)}h.addWatcher((()=>{h.get()?e.classList.add("active"):e.classList.remove("active")})),t.append(e),window.addEventListener("keydown",X,{passive:!0})}()}export{j as initDesktop};
|
|
||||||
File diff suppressed because one or more lines are too long
1
static/bundled/js/f6JTi3.js
Normal file
1
static/bundled/js/f6JTi3.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{W as e,s as t,e as n,l as a,f as s,g as c,h as o,j as l,c as m,o as i,k as d}from"./main.js";const r=new e(!1);let p,u,g,h;const E=new e(!1);let y,v,f,N=-1,w=[],x=[],I=[],B=!1;function T(){n.set(!0),I[t.get().index].scrollIntoView({block:"center",behavior:"auto"}),v.to(u,{y:"100%",ease:f.easeInOut,duration:1}),v.to(g,{opacity:0,duration:1.2,delay:.4})}function C(){const e=[];e.push(x[h.activeIndex]),e.push(x[Math.min(h.activeIndex+1,h.slides.length)]),e.push(x[Math.max(h.activeIndex-1,0)]);for(const t of e)t.src=t.dataset.src}let L=[];function k(e){c(e),!E.get()&&B&&(E.set(!0),C(),v.to(g,{opacity:1,duration:1}),v.to(u,{y:0,ease:f.easeInOut,duration:1,delay:.4}),setTimeout((()=>{n.set(!1),E.set(!1)}),1200))}function A(e){(function(e){!function(e){const t=document.createElement("div");t.className="collection";for(const[n,a]of e.entries()){const e=0!==n?d(-25,25):0,s=0!==n?d(-30,30):0,c=document.createElement("img");c.dataset.src=a.loUrl,c.height=a.loImgH,c.width=a.loImgW,c.alt=a.alt,c.style.transform=`translate3d(${e}%, ${s-50}%, 0)`,t.append(c)}m.append(t)}(e);const t=document.getElementsByClassName("collection").item(0);r.addWatcher((e=>{e?t.classList.remove("hidden"):t.classList.add("hidden")})),L=Array.from(t.getElementsByTagName("img")),L.forEach(((e,t)=>{e.addEventListener("click",(()=>{k(t)}),{passive:!0}),e.addEventListener("keydown",(()=>{k(t)}),{passive:!0}),i(e,(()=>{for(let e=0;e<5;e++){const n=t+e;n<0||n>L.length-1||(L[n].src=L[n].dataset.src)}}))}))})(e),function(e){!function(e){const t=document.createElement("div");t.className="swiper-wrapper";for(const n of e){const e=document.createElement("div");e.className="swiper-slide";const a=document.createElement("img");a.dataset.src=n.hiUrl,a.height=n.hiImgH,a.width=n.hiImgW,a.alt=n.alt,e.append(a),t.append(e)}const n=document.createElement("div");n.className="galleryInner",n.append(t);const a=document.createElement("div");a.insertAdjacentHTML("afterbegin",'<span class="num"></span><span class="num"></span><span class="num"></span><span class="num"></span>\n <span>/</span>\n <span class="num"></span><span class="num"></span><span class="num"></span><span class="num"></span>');const s=document.createElement("div"),c=document.getElementById("main")?.getAttribute("closeText");s.innerText=l(c),s.addEventListener("click",(()=>{T()}),{passive:!0}),s.addEventListener("keydown",(()=>{T()}),{passive:!0});const o=document.createElement("div");o.className="nav",o.append(a,s);const i=document.createElement("div");i.className="gallery",i.append(n),i.append(o);const d=document.createElement("div");d.className="curtain",m.append(i,d)}(e),w=Array.from(document.getElementsByClassName("nav").item(0)?.getElementsByClassName("num")??[]),p=document.getElementsByClassName("galleryInner").item(0),u=document.getElementsByClassName("gallery").item(0),g=document.getElementsByClassName("curtain").item(0),x=Array.from(u.getElementsByTagName("img")),I=Array.from(document.getElementsByClassName("collection").item(0)?.getElementsByTagName("img")??[]),t.addWatcher((()=>{const e=t.get();var n;e.index!==N&&(n=e.index,C(),h.slideTo(n,0),function(){const e=o(t.get().index+1),n=o(t.get().length);w.forEach(((t,a)=>{t.innerText=a<4?e[a]:n[a-4]}))}(),N=e.index)})),r.addWatcher((e=>{e&&n.set(!0)})),window.addEventListener("touchstart",(()=>{a().then((e=>{v=e[0],f=e[1]})).catch((e=>{console.log(e)})),s().then((e=>{y=e,h=new y(p,{spaceBetween:20}),h.on("slideChange",(({realIndex:e})=>{c(e)}))})).catch((e=>{console.log(e)})),B=!0}),{once:!0,passive:!0}),r.set(!0)}(e)}export{A as initMobile};
|
|
||||||
@@ -1 +1 @@
|
|||||||
function t(t,e){return(t+1)%e}function e(t,e){return(t+e-1)%e}function n(t){return("0000"+t.toString()).slice(-4)}function s(t,e){return Math.floor(Math.random()*(e-t+1))+t}function o(t,e){new IntersectionObserver(((n,s)=>{n.forEach((n=>{n.intersectionRatio>0&&(e(t),s.disconnect())}))})).observe(t)}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}async function i(){const t=await import("./-BhIIs.js");return[t.gsap,t.Power3]}async function a(){return(await import("./ep7_9p.js")).Swiper}class c{constructor(t){this.obj=t,this.watchers=[]}get(){return this.obj}set(t){this.obj=t,this.watchers.forEach((t=>{t(this.obj)}))}addWatcher(t){this.watchers.push(t)}}const l=new c(!0);let h;const d=[{threshold:20,trailLength:20},{threshold:40,trailLength:10},{threshold:80,trailLength:5},{threshold:140,trailLength:5},{threshold:200,trailLength:5}],m=new c({index:-1,length:0,threshold:d[p()].threshold,trailLength:d[p()].trailLength});function u(t){const e=m.get();e.index=t,m.set(e)}function g(){const e=m.get();e.index=t(e.index,e.length),m.set(e)}function f(){const t=m.get();t.index=e(t.index,t.length),m.set(t)}function x(t,e){const n=d.findIndex((e=>t.threshold===e.threshold))+e;if(n<0||n>=d.length)return t;sessionStorage.setItem("thresholdsIndex",n.toString());const s=d[n];return{...t,...s}}function p(){const t=sessionStorage.getItem("thresholdsIndex");return null===t?2:parseInt(t)}const w=document.getElementsByClassName("threshold").item(0),y=Array.from(w.getElementsByClassName("num")),E=w.getElementsByClassName("dec").item(0),j=w.getElementsByClassName("inc").item(0),L=document.getElementsByClassName("index").item(0),b=Array.from(L.getElementsByClassName("num")),I=document.getElementsByClassName("links").item(0),B=Array.from(I.getElementsByClassName("link")),C=document.getElementById("main")?.getAttribute("currentMenuItemIndex");for(const[t,e]of B.entries())t===parseInt(C)&&(e.classList.add("current"),0!==t&&(document.title=e.innerText+" | "+document.title));function N(t){y.forEach(((e,n)=>{e.innerText=t[n]}))}function v(t,e){b.forEach(((n,s)=>{n.innerText=s<4?t[s]:e[s-4]}))}h=document.getElementsByClassName("container").item(0),l.addWatcher((t=>{t?h.classList.remove("disableScroll"):h.classList.add("disableScroll")}));const S=await async function(){try{const t=await fetch(`${window.location.href}index.json`,{headers:{Accept:"application/json"}});return(await t.json()).sort(((t,e)=>t.index<e.index?-1:1))}catch(t){return[]}}();!function(t){const e=m.get();e.length=t,x(e,0),m.set(e)}(S.length),function(){const t=m.get();N(n(t.threshold)),v(n(t.index+1),n(t.length)),m.addWatcher((t=>{v(n(t.index+1),n(t.length)),N(n(t.threshold))})),E.addEventListener("click",(()=>{!function(){let t=m.get();t=x(t,-1),m.set(t)}()}),{passive:!0}),j.addEventListener("click",(()=>{!function(){let t=m.get();t=x(t,1),m.set(t)}()}),{passive:!0})}(),S.length>0&&(window.matchMedia("(hover: none)").matches?import("./fRwBqI.js").then((t=>{t.initMobile(S)})).catch((t=>{console.log(t)})):import("./PR3rto.js").then((t=>{t.initDesktop(S)})).catch((t=>{console.log(t)})));export{c as W,g as a,f as b,h as c,e as d,l as e,a as f,u as g,n as h,t as i,r as j,s as k,i as l,o,m as s};
|
function t(t,e){return(t+1)%e}function e(t,e){return(t+e-1)%e}function n(t){return("0000"+t.toString()).slice(-4)}async function s(){const t=await import("./EY5BO_.js");return[t.gsap,t.Power3]}function o(){const t=sessionStorage.getItem("thresholdsIndex");return null===t?2:parseInt(t)}function a(t){return t.length<2?t:[...new Set(t)]}class i{constructor(t){this.obj=t,this.watchers=[]}get(){return this.obj}set(t){this.obj=t,this.watchers.forEach((t=>{t(this.obj)}))}addWatcher(t){this.watchers.push(t)}}const r=new i(!0);let c;const h=[{threshold:20,trailLength:20},{threshold:40,trailLength:10},{threshold:80,trailLength:5},{threshold:140,trailLength:5},{threshold:200,trailLength:5}],l=new i({index:-1,length:0,threshold:h[o()].threshold,trailLength:h[o()].trailLength}),d=new i(!1),g=new i("none");function m(t){const e=l.get();e.index=t,l.set(e)}function u(){const e=l.get();e.index=t(e.index,e.length),l.set(e)}function f(){const t=l.get();t.index=e(t.index,t.length),l.set(t)}function w(t,e){const n=h.findIndex((e=>t.threshold===e.threshold))+e;if(n<0||n>=h.length)return t;sessionStorage.setItem("thresholdsIndex",n.toString());const s=h[n];return{...t,...s}}const x=document.getElementsByClassName("threshold").item(0),p=Array.from(x.getElementsByClassName("num")),y=x.getElementsByClassName("dec").item(0),E=x.getElementsByClassName("inc").item(0),L=document.getElementsByClassName("index").item(0),j=Array.from(L.getElementsByClassName("num"));document.addEventListener("DOMContentLoaded",(()=>{(async function(){c=document.getElementsByClassName("container").item(0),r.addWatcher((t=>{t?c.classList.remove("disableScroll"):c.classList.add("disableScroll")}));const t=await async function(){try{const t=await fetch(`${window.location.href}index.json`,{headers:{Accept:"application/json"}});return(await t.json()).sort(((t,e)=>t.index<e.index?-1:1))}catch(t){return[]}}();(function(t){const e=l.get();e.length=t,w(e,0),l.set(e)})(t.length),l.addWatcher((t=>{var e,s,o;e=n(t.index+1),s=n(t.length),j.forEach(((t,n)=>{t.innerText=n<4?e[n]:s[n-4]})),o=n(t.threshold),p.forEach(((t,e)=>{t.innerText=o[e]}))})),y.addEventListener("click",(()=>{!function(){let t=l.get();t=w(t,-1),l.set(t)}()}),{passive:!0}),E.addEventListener("click",(()=>{!function(){let t=l.get();t=w(t,1),l.set(t)}()}),{passive:!0}),0!==t.length&&(window.matchMedia("(hover: none)").matches?await import("./Ej2jsy.js").then((e=>{e.initMobile(t)})).catch((t=>{console.log(t)})):await import("./LbzzjK.js").then((e=>{e.initDesktop(t)})).catch((t=>{console.log(t)})))})().catch((t=>{console.log(t)}))}));export{i as W,u as a,t as b,c,e as d,f as e,r as f,m as g,n as h,d as i,s as l,g as n,a as r,l as s};
|
||||||
Binary file not shown.
Reference in New Issue
Block a user