forked from root/public
14 changed files with 17 additions and 561 deletions
@ -1,8 +1,10 @@ |
|||||||
FROM buildkite/puppeteer:latest |
FROM buildkite/puppeteer:latest |
||||||
|
|
||||||
ENV GIT_TERMINAL_PROMPT=0 |
ENV GIT_TERMINAL_PROMPT=0 |
||||||
# RUN apk add --no-cache git |
RUN apt-get update |
||||||
|
RUN apt-get install -y git |
||||||
WORKDIR /app |
WORKDIR /app |
||||||
COPY ./puppeteer . |
COPY ./dom . |
||||||
COPY ./subjects ./subjects |
COPY ./subjects ./subjects |
||||||
|
RUN ls -la |
||||||
ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"] |
ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"] |
||||||
|
@ -1,47 +0,0 @@ |
|||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const create = (tag) => { |
|
||||||
const element = document.createElement(tag) |
|
||||||
return element |
|
||||||
} |
|
||||||
|
|
||||||
export const build = (amount = 54) => { |
|
||||||
let count = 1 |
|
||||||
const intervalID = setInterval(() => { |
|
||||||
const brick = create('div') |
|
||||||
brick.title = 'brick' |
|
||||||
brick.id = `brick-${count}` |
|
||||||
if (count % 3 === 2) { |
|
||||||
brick.dataset.foundation = true |
|
||||||
} |
|
||||||
brick.append(count) |
|
||||||
body.append(brick) |
|
||||||
|
|
||||||
if (count === amount) { |
|
||||||
window.clearInterval(intervalID) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
count++ |
|
||||||
}, 100) |
|
||||||
} |
|
||||||
|
|
||||||
export const repair = (...ids) => { |
|
||||||
ids.forEach((id) => { |
|
||||||
const toRepair = document.getElementById(id) |
|
||||||
if (toRepair) { |
|
||||||
toRepair.dataset.repaired = toRepair.hasAttribute('data-foundation') |
|
||||||
? 'in progress' |
|
||||||
: true |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
export const destroy = () => { |
|
||||||
const bricks = [...document.querySelectorAll('[title="brick"]')] |
|
||||||
const toRemove = bricks[bricks.length - 1] |
|
||||||
|
|
||||||
if (toRemove) { |
|
||||||
toRemove.remove() |
|
||||||
} |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
import { colors } from './data.js' |
|
||||||
|
|
||||||
export const generateClasses = () => { |
|
||||||
document.head.append( |
|
||||||
Object.assign(document.createElement('style'), { |
|
||||||
type: 'text/css', |
|
||||||
id: 'colors', |
|
||||||
innerHTML: colors |
|
||||||
.map((color) => `.${color} { background: ${color}; }`) |
|
||||||
.join('\n'), |
|
||||||
}), |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const cold = ['aqua', 'blue', 'turquoise', 'green', 'purple', 'cyan', 'navy'] |
|
||||||
|
|
||||||
export const generateColdShades = () => { |
|
||||||
const shades = colors.filter((color) => { |
|
||||||
for (const c of cold) { |
|
||||||
if (color.includes(c)) { |
|
||||||
return true |
|
||||||
} |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
shades.forEach((c) => { |
|
||||||
const shade = document.createElement('div') |
|
||||||
shade.className = c |
|
||||||
shade.textContent = c |
|
||||||
body.append(shade) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
export const choseShade = (shade) => { |
|
||||||
const all = [...document.querySelectorAll('div')] |
|
||||||
all.forEach((a) => { |
|
||||||
if (!a.classList.contains(shade)) { |
|
||||||
a.classList.replace(a.className, shade) |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
@ -1,25 +0,0 @@ |
|||||||
export const getArchitects = () => { |
|
||||||
const architects = [...document.getElementsByTagName('a')] |
|
||||||
const others = [...document.getElementsByTagName('span')] |
|
||||||
return [architects, others] |
|
||||||
} |
|
||||||
|
|
||||||
export const getClassical = () => { |
|
||||||
const classicals = [...document.getElementsByClassName('classical')] |
|
||||||
const others = [...document.querySelectorAll('a:not(.classical)')] |
|
||||||
return [classicals, others] |
|
||||||
} |
|
||||||
|
|
||||||
export const getActive = () => { |
|
||||||
const active = [...document.querySelectorAll('.classical.active')] |
|
||||||
const others = [...document.querySelectorAll('.classical:not(.active)')] |
|
||||||
return [active, others] |
|
||||||
} |
|
||||||
|
|
||||||
export const getBonannoPisano = () => { |
|
||||||
const bonanno = document.getElementById('BonannoPisano') |
|
||||||
const others = [ |
|
||||||
...document.querySelectorAll('a.classical.active:not(#BonannoPisano)'), |
|
||||||
] |
|
||||||
return [bonanno, others] |
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
import { gossips } from './data.js' |
|
||||||
|
|
||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const ranges = document.createElement('div') |
|
||||||
ranges.className = 'ranges' |
|
||||||
body.append(ranges) |
|
||||||
|
|
||||||
const inputs = [ |
|
||||||
{ props: ['width'], min: 200, max: 800, value: 250 }, |
|
||||||
{ props: ['fontSize', 'lineHeight'], min: 20, max: 40, value: 25 }, |
|
||||||
{ props: ['background'], min: 20, max: 75, value: 60 }, |
|
||||||
] |
|
||||||
|
|
||||||
export const grid = () => { |
|
||||||
inputs.forEach((input) => createInput(input)) |
|
||||||
createAddGossip() |
|
||||||
gossips.forEach((g) => createGossip(g)) |
|
||||||
} |
|
||||||
|
|
||||||
const createGossip = (g, isNew = false) => { |
|
||||||
const gossip = document.createElement('div') |
|
||||||
const addGossip = document.getElementById('add-gossip') |
|
||||||
const { fontSize, lineHeight, width, background } = addGossip.style |
|
||||||
gossip.className = 'gossip' |
|
||||||
gossip.textContent = g |
|
||||||
if (isNew) { |
|
||||||
gossip.style.fontSize = fontSize |
|
||||||
gossip.style.lineHeight = lineHeight |
|
||||||
gossip.style.width = width |
|
||||||
gossip.style.background = background |
|
||||||
gossip.classList.add('fade-in') |
|
||||||
body.insertBefore(gossip, addGossip.nextElementSibling) |
|
||||||
} else { |
|
||||||
body.append(gossip) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const createAddGossip = () => { |
|
||||||
const addGossip = document.createElement('form') |
|
||||||
addGossip.className = 'gossip' |
|
||||||
addGossip.id = 'add-gossip' |
|
||||||
addGossip.onsubmit = () => false |
|
||||||
|
|
||||||
const newInput = document.createElement('textarea') |
|
||||||
newInput.autofocus = true |
|
||||||
newInput.placeholder = 'Got a gossip to share ?' |
|
||||||
newInput.addEventListener('keyup', (e) => addNewGossip(newInput, e)) |
|
||||||
|
|
||||||
const button = document.createElement('button') |
|
||||||
button.className = 'button' |
|
||||||
button.textContent = 'Share gossip!' |
|
||||||
button.addEventListener('click', (e) => addNewGossip(newInput)) |
|
||||||
|
|
||||||
addGossip.append(newInput, button) |
|
||||||
body.append(addGossip) |
|
||||||
} |
|
||||||
|
|
||||||
const addNewGossip = (input, event) => { |
|
||||||
const noValue = !input.value.trim() |
|
||||||
const notEnterKey = event && event.keyCode !== 13 |
|
||||||
if (notEnterKey || noValue) return |
|
||||||
createGossip(input.value, true) |
|
||||||
gossips.push(input.value) |
|
||||||
input.value = '' |
|
||||||
input.focus() |
|
||||||
} |
|
||||||
|
|
||||||
const createInput = ({ props, min, max, value }) => { |
|
||||||
const range = document.createElement('div') |
|
||||||
range.className = 'range' |
|
||||||
|
|
||||||
const input = document.createElement('input') |
|
||||||
input.type = 'range' |
|
||||||
input.min = min |
|
||||||
input.max = max |
|
||||||
input.value = value |
|
||||||
input.addEventListener('input', (e) => customize(e, ...props)) |
|
||||||
|
|
||||||
const propLabel = document.createElement('label') |
|
||||||
propLabel.textContent = props[0] |
|
||||||
|
|
||||||
const valueLabel = document.createElement('span') |
|
||||||
valueLabel.textContent = value |
|
||||||
|
|
||||||
range.append(propLabel, input, valueLabel) |
|
||||||
ranges.append(range) |
|
||||||
} |
|
||||||
|
|
||||||
const customize = ({ target }, ...props) => { |
|
||||||
for (const card of [...document.querySelectorAll('.gossip')]) { |
|
||||||
for (const prop of props) {
|
|
||||||
const updatedValue = |
|
||||||
(prop === 'lineHeight' && `${Number(target.value) * 1.5}px`) || |
|
||||||
(prop === 'background' && `hsl(280, 50%, ${target.value}%)`) || |
|
||||||
`${target.value}px` |
|
||||||
card.style[prop] = updatedValue |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const valueLabel = target.nextElementSibling |
|
||||||
valueLabel.textContent = target.value |
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|
||||||
|
|
||||||
export const generateLetters = () => { |
|
||||||
body.append(...[...Array(120).keys()].map((c) => { |
|
||||||
const shape = document.createElement('div') |
|
||||||
|
|
||||||
shape.textContent = alphabet[Math.floor(Math.random() * alphabet.length)] |
|
||||||
shape.style.fontSize = `${c + 11}px` |
|
||||||
shape.style.fontWeight = [300,400,600][Math.floor(c / 40)] |
|
||||||
return shape |
|
||||||
})) |
|
||||||
} |
|
@ -1,37 +0,0 @@ |
|||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
export const compose = () => { |
|
||||||
document.addEventListener('keydown', (e) => handleKey(e)) |
|
||||||
setTimeout( |
|
||||||
() => document.removeEventListener('keydown', (e) => handleKey(e)), |
|
||||||
500, |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
const handleKey = (e) => { |
|
||||||
const notes = [...document.querySelectorAll('.note')] |
|
||||||
|
|
||||||
if (e.key === 'Backspace') { |
|
||||||
const last = notes[notes.length - 1] |
|
||||||
last && last.remove() |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if (e.key === 'Escape') { |
|
||||||
if (notes.length) { |
|
||||||
notes.forEach((note) => note.remove()) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
createNote(e) |
|
||||||
} |
|
||||||
|
|
||||||
const createNote = ({ key }) => { |
|
||||||
const number = key.charCodeAt(0) * 2 - 150 |
|
||||||
const note = document.createElement('div') |
|
||||||
note.className = 'note' |
|
||||||
note.textContent = key |
|
||||||
note.style.background = `hsl(270, ${number}%, ${number}%)` |
|
||||||
body.append(note) |
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const box = document.createElement('div') |
|
||||||
box.className = 'box' |
|
||||||
body.append(box) |
|
||||||
|
|
||||||
const { top, bottom, left, right } = box.getBoundingClientRect() |
|
||||||
|
|
||||||
const diameter = 50 |
|
||||||
const radius = diameter / 2 |
|
||||||
|
|
||||||
const insideX = (clientX) => clientX > left + radius && clientX < right - radius |
|
||||||
const insideY = (clientY) => clientY > top + radius && clientY < bottom - radius |
|
||||||
|
|
||||||
let isInside = false |
|
||||||
|
|
||||||
export const createCircle = () => { |
|
||||||
document.addEventListener('click', (e) => create(e)) |
|
||||||
setTimeout(() => document.removeEventListener('click', create), 500) |
|
||||||
} |
|
||||||
|
|
||||||
const create = ({ clientX, clientY }) => { |
|
||||||
const circle = document.createElement('div') |
|
||||||
circle.className = 'circle' |
|
||||||
body.append(circle) |
|
||||||
circle.style.top = `${clientY - radius}px` |
|
||||||
circle.style.left = `${clientX - radius}px` |
|
||||||
circle.style.background = 'white' |
|
||||||
const hasEntered = insideX(clientX) && insideY(clientY) |
|
||||||
if (hasEntered) { |
|
||||||
circle.style.background = 'var(--purple)' |
|
||||||
} |
|
||||||
isInside = false |
|
||||||
} |
|
||||||
|
|
||||||
export const moveCircle = () => { |
|
||||||
document.addEventListener('mousemove', (e) => move(e)) |
|
||||||
setTimeout(() => document.removeEventListener('mousemove', move), 500) |
|
||||||
} |
|
||||||
|
|
||||||
const move = (e) => { |
|
||||||
const circles = [...document.getElementsByClassName('circle')] |
|
||||||
const circle = circles[circles.length - 1] |
|
||||||
if (!circle) return |
|
||||||
position(e, circle) |
|
||||||
} |
|
||||||
|
|
||||||
const position = ({ clientX, clientY }, circle) => { |
|
||||||
const hasEntered = insideX(clientX) && insideY(clientY) |
|
||||||
|
|
||||||
if (hasEntered) { |
|
||||||
isInside = true |
|
||||||
circle.style.background = 'var(--purple)' |
|
||||||
} |
|
||||||
|
|
||||||
if (isInside) { |
|
||||||
if (insideY(clientY)) { |
|
||||||
circle.style.top = `${clientY - radius}px` |
|
||||||
} |
|
||||||
if (insideX(clientX)) { |
|
||||||
circle.style.left = `${clientX - radius}px` |
|
||||||
} |
|
||||||
} else { |
|
||||||
circle.style.top = `${clientY - radius}px` |
|
||||||
circle.style.left = `${clientX - radius}px` |
|
||||||
} |
|
||||||
} |
|
@ -1,9 +1,3 @@ |
|||||||
{ |
{ |
||||||
"type": "module", |
"type": "module" |
||||||
"scripts": { |
|
||||||
"test": "node --unhandled-rejections=strict test" |
|
||||||
}, |
|
||||||
"dependencies": { |
|
||||||
"puppeteer-core": "^3.3.0" |
|
||||||
} |
|
||||||
} |
} |
||||||
|
@ -1,107 +0,0 @@ |
|||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
const hslValue = document.createElement('div') |
|
||||||
hslValue.className = 'hsl' |
|
||||||
hslValue.textContent = 'hsl(0, 50%, 0%)' |
|
||||||
|
|
||||||
const hueValue = document.createElement('div') |
|
||||||
hueValue.className = 'text hue' |
|
||||||
hueValue.textContent = 'hue' |
|
||||||
|
|
||||||
const luminosityValue = document.createElement('div') |
|
||||||
luminosityValue.className = 'text luminosity' |
|
||||||
luminosityValue.textContent = 'luminosity' |
|
||||||
|
|
||||||
const origin = document.createElement('div') |
|
||||||
origin.className = 'text origin' |
|
||||||
|
|
||||||
const picked = document.createElement('div') |
|
||||||
picked.className = 'text picked' |
|
||||||
picked.textContent = 'Color successfully picked!' |
|
||||||
|
|
||||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') |
|
||||||
svg.setAttributeNS( |
|
||||||
'http://www.w3.org/2000/xmlns/', |
|
||||||
'xmlns:xlink', |
|
||||||
'http://www.w3.org/1999/xlink', |
|
||||||
) |
|
||||||
svg.setAttribute('width', window.innerWidth) |
|
||||||
svg.setAttribute('height', window.innerHeight) |
|
||||||
svg.setAttribute('viewBox', `0 0 ${window.innerWidth} ${window.innerHeight}`) |
|
||||||
|
|
||||||
const axisX = document.createElementNS('http://www.w3.org/2000/svg', 'line') |
|
||||||
axisX.setAttribute('y1', window.innerHeight) |
|
||||||
axisX.setAttribute('y2', 0) |
|
||||||
axisX.id = 'axisX' |
|
||||||
svg.append(axisX) |
|
||||||
|
|
||||||
const axisY = document.createElementNS('http://www.w3.org/2000/svg', 'line') |
|
||||||
axisY.setAttribute('x1', window.innerWidth) |
|
||||||
axisY.setAttribute('x2', 0) |
|
||||||
axisY.id = 'axisY' |
|
||||||
svg.append(axisY) |
|
||||||
|
|
||||||
body.append(hslValue, hueValue, luminosityValue, origin, picked, svg) |
|
||||||
|
|
||||||
export const pick = () => { |
|
||||||
document.addEventListener('mousemove', (e) => set(e)) |
|
||||||
setTimeout( |
|
||||||
() => document.removeEventListener('mousemove', (e) => set(e)), |
|
||||||
500, |
|
||||||
) |
|
||||||
|
|
||||||
body.addEventListener('click', click) |
|
||||||
setTimeout(() => document.removeEventListener('click', click), 500) |
|
||||||
|
|
||||||
body.addEventListener('copy', copy) |
|
||||||
setTimeout(() => document.removeEventListener('copy', copy), 500) |
|
||||||
} |
|
||||||
|
|
||||||
const click = (e) => { |
|
||||||
document.execCommand('copy') |
|
||||||
const wave = document.createElement('div') |
|
||||||
wave.className = 'click-wave' |
|
||||||
wave.style.top = `${e.clientY - 10}px` |
|
||||||
wave.style.left = `${e.clientX - 10}px` |
|
||||||
body.append(wave) |
|
||||||
setTimeout(() => wave.remove(), 150) |
|
||||||
} |
|
||||||
|
|
||||||
const copy = (event) => { |
|
||||||
event.preventDefault() |
|
||||||
if (event.clipboardData) { |
|
||||||
event.clipboardData.setData('text/plain', hslValue.textContent) |
|
||||||
picked.classList.add('fade-in') |
|
||||||
setTimeout(() => picked.classList.remove('fade-in'), 1000) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const calc = (number, max) => |
|
||||||
Math.round(Math.min(max, Math.max(0, max * number))) |
|
||||||
|
|
||||||
const set = ({ clientX, clientY }) => { |
|
||||||
const { innerWidth, innerHeight } = window |
|
||||||
const padding = 100 |
|
||||||
const mouseX = clientX - padding |
|
||||||
const mouseY = clientY - padding |
|
||||||
|
|
||||||
const hue = calc(mouseX / (innerWidth - padding * 2), 360) |
|
||||||
const luminosity = calc(mouseY / (innerHeight - padding * 2), 100) |
|
||||||
const color = `hsl(${hue}, 50%, ${luminosity}%)` |
|
||||||
|
|
||||||
axisX.setAttribute('x1', clientX) |
|
||||||
axisX.setAttribute('x2', clientX) |
|
||||||
axisY.setAttribute('y1', clientY) |
|
||||||
axisY.setAttribute('y2', clientY) |
|
||||||
|
|
||||||
axisX.setAttribute('stroke', color) |
|
||||||
axisY.setAttribute('stroke', color) |
|
||||||
|
|
||||||
body.style.color = color |
|
||||||
body.style.background = color |
|
||||||
origin.style.background = color |
|
||||||
hslValue.textContent = color |
|
||||||
|
|
||||||
hueValue.textContent = `hue\n${hue}` |
|
||||||
luminosityValue.textContent = `${luminosity}\nluminosity` |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
import { styles } from './data.js' |
|
||||||
|
|
||||||
let count = 0 |
|
||||||
let increment = 1 |
|
||||||
|
|
||||||
export const pimp = () => { |
|
||||||
const button = document.querySelector('.button') |
|
||||||
|
|
||||||
const ceiling = count === styles.length - 1 |
|
||||||
const floor = !count |
|
||||||
|
|
||||||
const increasing = increment > 0 |
|
||||||
|
|
||||||
if (increasing || (floor && !increment)) { |
|
||||||
button.classList.add(styles[count]) |
|
||||||
} else { |
|
||||||
button.classList.remove(styles[count]) |
|
||||||
} |
|
||||||
|
|
||||||
if (ceiling) { |
|
||||||
increment = increment ? 0 : -1 |
|
||||||
} |
|
||||||
if (floor) { |
|
||||||
increment = increment < 0 ? 0 : 1 |
|
||||||
} |
|
||||||
|
|
||||||
button.classList.toggle('unpimp', increment < 0 || (!increment && ceiling)) |
|
||||||
|
|
||||||
count += increment |
|
||||||
} |
|
@ -1,72 +0,0 @@ |
|||||||
import { places } from './data.js' |
|
||||||
|
|
||||||
const body = document.querySelector('body') |
|
||||||
|
|
||||||
export const explore = () => { |
|
||||||
createSections() |
|
||||||
|
|
||||||
const location = document.createElement('div') |
|
||||||
location.className = 'location' |
|
||||||
setLocation(location) |
|
||||||
|
|
||||||
const direction = document.createElement('div') |
|
||||||
direction.className = 'direction' |
|
||||||
|
|
||||||
body.append(location, direction) |
|
||||||
|
|
||||||
document.addEventListener('wheel', (event) => |
|
||||||
setLocation(location, direction, event), |
|
||||||
) |
|
||||||
setTimeout(() => |
|
||||||
document.removeEventListener('wheel', (event) => |
|
||||||
setLocation(location, direction, event), |
|
||||||
), |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
const createSections = () => { |
|
||||||
const sorted = places.sort( |
|
||||||
(a, b) => getDegree(b.coordinates) - getDegree(a.coordinates), |
|
||||||
) |
|
||||||
|
|
||||||
sorted.map(({ name, color }) => { |
|
||||||
const nameDashCase = name |
|
||||||
.toLowerCase() |
|
||||||
.split(',')[0] |
|
||||||
.split(' ') |
|
||||||
.join('-') |
|
||||||
|
|
||||||
const url = `https://raw.githubusercontent.com/MarieMalarme/dom-js/master/assets/images/${nameDashCase}.jpg` |
|
||||||
|
|
||||||
const section = document.createElement('section') |
|
||||||
section.style.background = `center / cover url(${url})` |
|
||||||
body.append(section) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
const getDegree = (coordinates) => { |
|
||||||
const north = coordinates.includes('N') |
|
||||||
const degree = coordinates.split("'")[0].replace('°', '.') |
|
||||||
return north ? degree : -degree |
|
||||||
} |
|
||||||
|
|
||||||
const setLocation = (location, direction, event) => { |
|
||||||
const { name, coordinates, color } = getLocation() |
|
||||||
location.textContent = `${name}\n${coordinates}` |
|
||||||
location.style.color = color |
|
||||||
location.onclick = () => { |
|
||||||
window.open(`https://www.google.com/maps/place/${coordinates}`, '_blank') |
|
||||||
} |
|
||||||
|
|
||||||
if (!event) return |
|
||||||
const scrollUp = event.deltaY < 0 |
|
||||||
direction.innerHTML = `<div style="transform: rotate(${ |
|
||||||
scrollUp ? -90 : 90 |
|
||||||
}deg)">➢</div><div>${scrollUp ? 'N' : 'S'}</div>` |
|
||||||
} |
|
||||||
|
|
||||||
const getLocation = () => { |
|
||||||
const { innerHeight, scrollY } = window |
|
||||||
const index = Math.ceil((scrollY - innerHeight / 2) / innerHeight) |
|
||||||
return places[index] |
|
||||||
} |
|
Loading…
Reference in new issue