diff options
| author | Yuval Adam <_@yuv.al> | 2024-09-23 10:10:19 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2024-09-23 10:10:19 +0200 |
| commit | af060f85a7bc13a5bb05e453c411f5807589e6c6 (patch) | |
| tree | 8527870ee8daaf3fa30bde7dd7090c647b706144 /src | |
| parent | befc9ba3e4a9b24cdd0397663c04c98688d98d9b (diff) | |
Move most components into new path
Diffstat (limited to 'src')
| -rw-r--r-- | src/Datetime.tsx | 28 | ||||
| -rw-r--r-- | src/Geshem.tsx | 80 | ||||
| -rw-r--r-- | src/Map.tsx | 99 | ||||
| -rw-r--r-- | src/Slider.tsx | 45 | ||||
| -rw-r--r-- | src/config.tsx | 19 |
5 files changed, 0 insertions, 271 deletions
diff --git a/src/Datetime.tsx b/src/Datetime.tsx deleted file mode 100644 index 0a8fbcf..0000000 --- a/src/Datetime.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -import { DateTime as LuxonDateTime } from "luxon"; - -interface DateTimeProps { - images: string[], - slider: number -} - -export function DateTime({ images, slider }: DateTimeProps) { - let datetime = null; - - if (images.length > 0) { - const ds = images[slider].substring(5, 18); - datetime = LuxonDateTime.fromFormat(ds, "yyyyMMdd/HHmm", { - zone: "utc", - }).setZone("Asia/Jerusalem"); - } - - const date = datetime ? datetime.toFormat("dd/MM/y") : ""; - const time = datetime ? datetime.toFormat("HH:mm") : ""; - - return ( - <div id="datetime"> - <div id="date">{date}</div> - <div id="time">{time}</div> - </div> - ); -} diff --git a/src/Geshem.tsx b/src/Geshem.tsx deleted file mode 100644 index 6e88f19..0000000 --- a/src/Geshem.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { BrowserRouter, Route, Routes } from "react-router-dom"; - -import { Map } from "./Map"; -import { Slider } from "./Slider"; -import { DateTime } from "./Datetime"; - -import { IMAGES_BASE_URL, PLAYBACK_HOURS, PLAYBACK_SLOTS } from "./config"; - -import "./Geshem.css"; -import "rc-slider/assets/index.css"; - -export function App() { - return ( - <BrowserRouter> - <Routes> - <Route path="/" element={<Geshem />} /> - <Route path="/history/:date" element={<Geshem />} /> - </Routes> - </BrowserRouter> - ); -} - -interface GeshemProps { - date?: string -} - - -export function Geshem({ date }: GeshemProps) { - const [images, setImages] = useState<string[]>([]); - const [playback] = useState( - date || - new URL(window.location.toString()).searchParams.get("history") || - undefined - ); - const [slider, setSlider] = useState(playback ? PLAYBACK_SLOTS : 9); - - useEffect(() => { - const fetchImages = async () => - fetch(`${IMAGES_BASE_URL}/imgs.json`) - .then(res => res.json()) - .then(imgs => imgs["280"]) - .then(setImages); - - const buildPlayback = async () => { - const date = playback; - const hours = Array.from(Array(PLAYBACK_HOURS).keys()).map( - h => `${String(h).padStart(2, "0")}` - ); - const minutes = Array.from(Array(6).keys()).map( - m => `${String(m * 10).padStart(2, "0")}` - ); - const paths = hours.reduce<string[]>( - (acc, h) => - acc.concat(minutes.map(m => `imgs/${date}/${h}${m}/280.png`)), - [] - ); - setImages(paths); - }; - - let timer: number; - if (playback) buildPlayback(); - else { - fetchImages(); - timer = window.setInterval(fetchImages, 60 * 1000); - } - - return () => { - if (timer !== undefined) clearInterval(timer); - }; - }, [playback]); - - return ( - <> - <Map images={images} slider={slider} /> - <DateTime images={images} slider={slider} /> - <Slider slider={slider} playback={playback} setSlider={setSlider} /> - </> - ); -} diff --git a/src/Map.tsx b/src/Map.tsx deleted file mode 100644 index 39f28fa..0000000 --- a/src/Map.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useState, useEffect, useRef } from "react"; -// @ts-ignore -import mapboxgl from '!mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax - -import { - MAPBOX_ACCESS_TOKEN, - IMAGE_COORDINATES, - IMAGES_BASE_URL -} from "./config"; - -import "mapbox-gl/dist/mapbox-gl.css"; - -interface MapProps { - slider: number, - images: string[], -} - -export function Map({ slider, images }: MapProps) { - const mapContainer = useRef(null); - const map = useRef<mapboxgl.Map>(null); - - const [lng] = useState(35); - const [lat] = useState(31.9); - const [zoom] = useState(6.3); - const [loaded, setLoaded] = useState(false); - - const prevImages = useRef(images).current; - - useEffect(() => { - if (map.current) return; - - map.current = new mapboxgl.Map({ - accessToken: MAPBOX_ACCESS_TOKEN, - container: mapContainer.current, - style: "mapbox://styles/mapbox/dark-v9", - center: [lng, lat], - zoom: zoom, - minZoom: 5, - maxZoom: 10, - hash: false, - }); - - map.current.on("style.load", () => { - setLoaded(true); - }); - }); - - useEffect(() => { - if (!loaded) return; - - // remove old layers - prevImages.forEach((img) => { - if (!images.includes(img)) { - map.current.removeLayer(`layer-${img}`); - map.current.removeSource(`source-${img}`); - } - }); - - // add new layers - images.forEach((img, i) => { - if (!prevImages.includes(img) && !map.current.getSource(`source-${img}`)) { - map.current.addSource(`source-${img}`, { - type: "image", - url: `${IMAGES_BASE_URL}/${img}`, - coordinates: IMAGE_COORDINATES - }); - map.current.addLayer({ - id: `layer-${img}`, - source: `source-${img}`, - type: "raster", - paint: { - "raster-opacity": 0, - "raster-opacity-transition": { - duration: 0 - } - } - }); - } - }); - }, [loaded, prevImages, images]); - - useEffect(() => { - if (!loaded || !images.length) return; - images[slider] && map.current.setPaintProperty(`layer-${images[slider]}`, "raster-opacity", 0.85); - return () => { - // callback will hide the previous layer with the previous slider value - map.current.setPaintProperty(`layer-${images[slider]}`, "raster-opacity", 0); - } - }, [loaded, slider, images]); - - return ( - <div> - <div ref={mapContainer} className="map-container" style={{ - height: "100vh", - width: "100vw" - }} /> - </div> - ); -} diff --git a/src/Slider.tsx b/src/Slider.tsx deleted file mode 100644 index 50223fc..0000000 --- a/src/Slider.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import RcSlider, { SliderProps, SliderRef } from 'rc-slider/lib/Slider'; -import { PLAYBACK_SLOTS } from "./config"; - -// use workaround from: https://github.com/react-component/slider/issues/835#issuecomment-1201805736 -const CustomSlider = RcSlider as React.ForwardRefExoticComponent<SliderProps<number> & React.RefAttributes<SliderRef>>; - -interface GeshemSliderProps { - playback?: string, - slider: number, - setSlider: React.Dispatch<React.SetStateAction<number>> -} - -export function Slider({ playback, slider, setSlider }: GeshemSliderProps) { - const handleStyle = { - height: 40, - width: 40, - border: 0, - marginTop: -10, - boxShadow: ".5px .5px 2px 1px rgba(0,0,0,.32)" - }; - - const railStyle = { - height: 20, - backgroundColor: "#3498db" - }; - - const trackStyle = { - display: "none" - }; - - return ( - <div id="slider"> - <CustomSlider - min={0} - max={playback ? PLAYBACK_SLOTS : 9} - defaultValue={slider} - handleStyle={handleStyle} - railStyle={railStyle} - trackStyle={trackStyle} - onChange={val => setSlider(val)} - /> - </div> - ); -} diff --git a/src/config.tsx b/src/config.tsx deleted file mode 100644 index 4ca4578..0000000 --- a/src/config.tsx +++ /dev/null @@ -1,19 +0,0 @@ -const hostname = window && window.location && window.location.hostname; - -const PRODUCTION = hostname.includes("geshem"); - -export const IMAGES_BASE_URL = PRODUCTION ? "https://imgs.geshem.space" : ""; - -export const MAPBOX_ACCESS_TOKEN = - "pk.eyJ1IjoieXV2YWRtIiwiYSI6ImNpcnMxbzBuaTAwZWdoa25oczlzZmkwbHcifQ.UHtLngbKm9O8945pJm23Nw"; - -export const IMAGE_COORDINATES = [ - [31.7503896894, 34.4878044232], - [37.8574239563, 34.5078463729], - [37.7157066403, 29.4538271687], - [31.9347389087, 29.4373462909] -]; - -export const PLAYBACK_HOURS = 2; - -export const PLAYBACK_SLOTS = (PLAYBACK_HOURS * 6) - 1;
\ No newline at end of file |
