From 1cc630da4247e75a18629d960768d06239b0175b Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 24 Aug 2021 18:40:19 +0200 Subject: details and gallery --- .babelrc | 27 ++++++ load_spreadsheet.js | 1 + public/assets/css/css.css | 97 +++++++++++++++++++++ public/assets/css/fonts.css | 11 +++ .../fonts/merriweather/Merriweather-Italic.ttf | Bin 0 -> 142548 bytes .../fonts/merriweather/Merriweather-Regular.ttf | Bin 0 -> 149092 bytes public/assets/img/arrow-back.svg | 1 + public/assets/img/arrow-forward.svg | 1 + public/assets/img/close.svg | 1 + src/graph.js | 2 +- src/index.js | 21 ++--- src/views/App.js | 42 +++++++++ src/views/Detail.js | 65 ++++++++++---- src/views/Gallery.js | 75 ++++++++++++++++ templates/_header.liquid | 1 - 15 files changed, 308 insertions(+), 37 deletions(-) create mode 100644 .babelrc create mode 100644 public/assets/css/fonts.css create mode 100644 public/assets/fonts/merriweather/Merriweather-Italic.ttf create mode 100644 public/assets/fonts/merriweather/Merriweather-Regular.ttf create mode 100644 public/assets/img/arrow-back.svg create mode 100644 public/assets/img/arrow-forward.svg create mode 100644 public/assets/img/close.svg create mode 100644 src/views/App.js create mode 100644 src/views/Gallery.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..ca2b68b --- /dev/null +++ b/.babelrc @@ -0,0 +1,27 @@ +{ + "presets": [ + ["@babel/preset-env", { + "debug": false, + "modules": false, + "useBuiltIns": false + }], + "@babel/preset-react" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + ["@babel/plugin-proposal-private-property-in-object", { "loose": true }], + ["@babel/plugin-proposal-private-methods", { "loose": true }], + [ "@babel/plugin-proposal-class-properties", { "loose": true } ], + "transform-async-to-generator", + ["module-resolver", { + "root": ["./frontend"], + "alias": { + } + }] + ], + "env": { + "production": { + "presets": [] + } + } +} diff --git a/load_spreadsheet.js b/load_spreadsheet.js index 3bada97..7c06477 100644 --- a/load_spreadsheet.js +++ b/load_spreadsheet.js @@ -40,6 +40,7 @@ async function main() { __index: index, id: "page_" + index, title: row.Title, + type: "image", }; // loop over the tags... let tagIndex = 0; diff --git a/public/assets/css/css.css b/public/assets/css/css.css index 3d4f9e0..fd62f45 100644 --- a/public/assets/css/css.css +++ b/public/assets/css/css.css @@ -6,6 +6,7 @@ body { height: 100%; overflow: hidden; background: black; + font-family: "Merriweather", serif; } .scene-tooltip { background: black; @@ -17,3 +18,99 @@ body { line-height: 1.3; font-family: serif !important; } + +/** Detail view */ + +.detail { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + pointer-events: none; + transition: opacity 0.2s; + opacity: 0; + background: rgba(0, 0, 0, 0.75); + color: white; + display: flex; + flex-direction: row; +} +.detail.visible { + opacity: 1; + pointer-events: auto; +} +.detail > div { + height: 100vh; + width: 50vw; +} +.detail .content > div { + padding: 3rem 5rem 6rem 5rem; +} +.detail .media { + padding: 3rem 5rem; +} + +.detail .content { + overflow-x: hidden; + overflow-y: scroll; +} +.detail .content::-webkit-scrollbar { + width: 0; + opacity: 0; +} +.detail .content > div { + max-width: 600px; +} +.detail .title { + font-size: 1.25rem; + line-height: 1.5; + margin-bottom: 2rem; + text-transform: capitalize; + font-variant: small-caps; +} +.detail .title .index { + margin-bottom: 1rem; +} +.detail .citation { + font-size: 1rem; + line-height: 1.5; + margin-bottom: 2rem; +} +.detail .description { + font-size: 1rem; + line-height: 1.75; +} +.detail .description p { + text-indent: 2rem; +} +.detail .description p:first-of-type { + text-indent: 0; +} + +/** Image galleries */ +.gallery { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; +} +.gallery .image img { + cursor: pointer; + max-height: calc(100vh - 12rem); + max-width: 100%; + transition: opacity 100ms; +} +.buttons { + width: 100%; + text-align: right; +} +.buttons.close { + margin-bottom: 1rem; +} +.buttons img { + cursor: pointer; + height: 1.5rem; +} +.gallery .buttons { + margin-top: 1rem; +} diff --git a/public/assets/css/fonts.css b/public/assets/css/fonts.css new file mode 100644 index 0000000..f1e8429 --- /dev/null +++ b/public/assets/css/fonts.css @@ -0,0 +1,11 @@ +@font-face { + font-family: "Merriweather"; + src: url("../fonts/merriweather/Merriweather-Regular.ttf"); + font-style: normal; +} + +@font-face { + font-family: "Merriweather"; + src: url("../fonts/merriweather/Merriweather-Italic.ttf"); + font-style: italic; +} diff --git a/public/assets/fonts/merriweather/Merriweather-Italic.ttf b/public/assets/fonts/merriweather/Merriweather-Italic.ttf new file mode 100644 index 0000000..179acf3 Binary files /dev/null and b/public/assets/fonts/merriweather/Merriweather-Italic.ttf differ diff --git a/public/assets/fonts/merriweather/Merriweather-Regular.ttf b/public/assets/fonts/merriweather/Merriweather-Regular.ttf new file mode 100644 index 0000000..18da9e5 Binary files /dev/null and b/public/assets/fonts/merriweather/Merriweather-Regular.ttf differ diff --git a/public/assets/img/arrow-back.svg b/public/assets/img/arrow-back.svg new file mode 100644 index 0000000..6d00888 --- /dev/null +++ b/public/assets/img/arrow-back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/img/arrow-forward.svg b/public/assets/img/arrow-forward.svg new file mode 100644 index 0000000..6bd4748 --- /dev/null +++ b/public/assets/img/arrow-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/img/close.svg b/public/assets/img/close.svg new file mode 100644 index 0000000..0b3a55f --- /dev/null +++ b/public/assets/img/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/graph.js b/src/graph.js index fdac979..4ed953a 100644 --- a/src/graph.js +++ b/src/graph.js @@ -105,7 +105,7 @@ export default function buildGraph(db, handlers) { // graph.d3Force("charge").strength(-150); // camera orbit - const distance = 250; + const distance = 415; let angle = 0; graph.cameraPosition({ x: distance * Math.sin(angle), diff --git a/src/index.js b/src/index.js index c51ecd1..c084565 100644 --- a/src/index.js +++ b/src/index.js @@ -2,23 +2,12 @@ * No.6092 site for Charles Stankievech */ -import buildGraph from "./graph.js"; +import React from "react"; +import ReactDOM from "react-dom"; +import App from "./views/App.js"; -async function main() { - const db = await loadDB(); - - function handleClick(node) { - console.log(node); - } - - buildGraph(db, { - click: handleClick, - }); -} - -async function loadDB() { - const request = await fetch("/assets/db.json"); - return await request.json(); +function main() { + ReactDOM.render(, document.querySelector("#app")); } main(); diff --git a/src/views/App.js b/src/views/App.js new file mode 100644 index 0000000..c5a7f83 --- /dev/null +++ b/src/views/App.js @@ -0,0 +1,42 @@ +/** + * Main React app logic + */ + +import React, { useState, useEffect, useCallback } from "react"; + +import Detail from "./Detail.js"; +import buildGraph from "../graph.js"; + +export default function App() { + const [db, setDb] = useState(null); + const [node, setNode] = useState(null); + const [detailVisible, setDetailVisible] = useState(null); + + useEffect(async () => { + const newDb = await loadDB(); + setDb(newDb); + buildGraph(newDb, { + click: handleClick, + }); + }, []); + + const handleClick = useCallback((node) => { + setNode(node); + setDetailVisible(true); + }); + + const handleClose = useCallback((node) => { + setDetailVisible(false); + }); + + return ( +
+ +
+ ); +} + +async function loadDB() { + const request = await fetch("/assets/db.json"); + return await request.json(); +} diff --git a/src/views/Detail.js b/src/views/Detail.js index 51598c1..0a756c9 100644 --- a/src/views/Detail.js +++ b/src/views/Detail.js @@ -2,30 +2,57 @@ * Detail view, displaying text plus media */ -export default function Detail({ node }) { - const index = id + 1; +import React from "react"; + +import Gallery from "./Gallery.js"; + +export default function Detail({ node, visible, onClose }) { + if (!node) { + return
; + } + const { id, data } = node; + const index = id + 1; return ( -
+
-
- {index} -
- {data.author} -
- {data.title} -
+
+
+
{pad(index)}
+ {data.author && ( +
+ )} +
+
+
+
+
+
+
+
+
-
-
+ {node.type === "video" ? ( + "video" + ) : ( + + )}
-
); } + +const pad = (value) => (value < 10 ? "0" + value : value); +const capitalizeWord = (text = "") => + text ? text.charAt(0).toUpperCase() + text.slice(1) : ""; +const capitalize = (text = "") => + String(text || "") + .split(" ") + .map(capitalizeWord) + .join(" "); diff --git a/src/views/Gallery.js b/src/views/Gallery.js new file mode 100644 index 0000000..7bdf18b --- /dev/null +++ b/src/views/Gallery.js @@ -0,0 +1,75 @@ +/** + * Detail view, displaying text plus media + */ + +import React, { useState, useEffect } from "react"; + +export default function Gallery({ images, visible }) { + const hasItems = !!images?.length; + const oneItem = images?.length === 1; + + const [index, setIndex] = useState(0); + const [opacity, setOpacity] = useState(0); + useEffect(() => { + setIndex(0); + setOpacity(0); + setTimeout(() => setOpacity(1), 500); + }, [images]); + + function previous() { + setOpacity(0); + setTimeout(() => setIndex(Math.max(0, index - 1)), 100); + // setTimeout(() => setOpacity(1), 500); + } + function next() { + setOpacity(0); + setTimeout(() => setIndex(Math.min(images.length - 1, index + 1)), 100); + // setTimeout(() => setOpacity(1), 500); + } + function nextOrWrap() { + if (oneItem) return; + setOpacity(0); + setTimeout(() => setIndex(mod(index + 1, images.length)), 100); + // setTimeout(() => setOpacity(1), 500); + } + function appear() { + setOpacity(1); + } + + if (!hasItems) { + return
; + } + + return ( +
+
+ {visible && !!images[index] && ( + + )} +
+
+ {!oneItem && ( + 0 ? 1 : 0 }} + /> + )} + {!oneItem && ( + + )} +
+
+ ); +} + +const mod = (n, m) => n - m * Math.floor(n / m); diff --git a/templates/_header.liquid b/templates/_header.liquid index 349ab58..0634722 100644 --- a/templates/_header.liquid +++ b/templates/_header.liquid @@ -23,7 +23,6 @@ - {% if meta.production %} {% else %} -- cgit v1.2.3-70-g09d2