diff --git a/package-lock.json b/package-lock.json
index 899270a..d314d1a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,8 @@
"prism-react-renderer": "^2.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
- "react-scroll-parallax": "^3.4.5"
+ "react-scroll-parallax": "^3.4.5",
+ "react-virtualized-auto-sizer": "^1.0.24"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.1",
@@ -12737,6 +12738,15 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/react-virtualized-auto-sizer": {
+ "version": "1.0.24",
+ "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz",
+ "integrity": "sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==",
+ "peerDependencies": {
+ "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0",
+ "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
diff --git a/package.json b/package.json
index a887b03..62f6e08 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
"prism-react-renderer": "^2.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
- "react-scroll-parallax": "^3.4.5"
+ "react-scroll-parallax": "^3.4.5",
+ "react-virtualized-auto-sizer": "^1.0.24"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.1",
diff --git a/src/components/AppBar.tsx b/src/components/AppBar.tsx
index 9104f74..0be0b5d 100644
--- a/src/components/AppBar.tsx
+++ b/src/components/AppBar.tsx
@@ -8,7 +8,6 @@ import {
import {
Box,
Button,
- Fade,
IconButton,
Stack,
Typography,
@@ -17,9 +16,9 @@ import {
import PopupState, { bindTrigger } from "material-ui-popup-state";
import { createPortal } from "react-dom";
import l10n from "../pages/en-au.json";
-import { space } from "./space";
import { Logo } from "./Logo";
import { useMode } from "./ModeContext";
+import { space } from "./space";
import { usePaper } from "./theme";
import { useSm } from "./useSm";
@@ -73,84 +72,79 @@ export function AppBar() {
zIndex: (t) => t.zIndex.appBar,
}}
>
-
-
-
-
-
- {sm ? (
- <>
-
- {openPosthoc}
-
- {(state) => (
- <>
-
-
-
- {createPortal(
-
- t.transitions.create([
- "opacity",
- "backdrop-filter",
- ]),
- position: "fixed",
- zIndex: (t) => t.zIndex.modal,
- top: 0,
- left: 0,
- width: "100dvw",
- height: "100vh",
- borderRadius: 0,
- }}
- >
-
-
-
-
- {darkToggle}
- {menu}
- {openPosthoc}
-
- ,
- document.body
- )}
- >
- )}
-
- >
- ) : (
- <>
- {menu}
- {space()}
- {openPosthoc}
- {darkToggle}
- >
- )}
-
-
+
+
+
+
+ {sm ? (
+ <>
+
+ {openPosthoc}
+
+ {(state) => (
+ <>
+
+
+
+ {createPortal(
+
+ t.transitions.create(["opacity", "backdrop-filter"]),
+ position: "fixed",
+ zIndex: (t) => t.zIndex.modal,
+ top: 0,
+ left: 0,
+ width: "100dvw",
+ height: "100vh",
+ borderRadius: 0,
+ }}
+ >
+
+
+
+
+ {darkToggle}
+ {menu}
+ {openPosthoc}
+
+ ,
+ document.body
+ )}
+ >
+ )}
+
+ >
+ ) : (
+ <>
+ {menu}
+ {space()}
+ {openPosthoc}
+ {darkToggle}
+ >
+ )}
+
);
}
diff --git a/src/components/Gallery.tsx b/src/components/Gallery.tsx
index f2ad57e..f5b4ef9 100644
--- a/src/components/Gallery.tsx
+++ b/src/components/Gallery.tsx
@@ -1,43 +1,283 @@
-import { Box, Stack, Tab, Tabs } from "@mui/material";
-import { map } from "lodash";
-import { useState } from "react";
-import { usePaper } from "./theme";
+import { WorkspacesOutlined } from "@mui/icons-material";
+import {
+ Avatar,
+ Box,
+ Button,
+ ButtonBase,
+ Stack,
+ Typography,
+} from "@mui/material";
+import { useEffect, useState } from "react";
+import ReactVirtualizedAutoSizer from "react-virtualized-auto-sizer";
import l10n from "../pages/en-au.json";
+import { useMode } from "./ModeContext";
+import { useSm } from "./useSm";
+import { clamp } from "lodash";
+import { usePaper } from "./theme";
+
+const isVisible = (d: HTMLDivElement) => {
+ var rect = d.getBoundingClientRect();
+ var viewHeight = Math.max(
+ document.documentElement.clientHeight,
+ window.innerHeight
+ );
+ return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
+};
+
+const center = (d: HTMLDivElement) => {
+ const box = d.getBoundingClientRect();
+ return box.left + box.width / 2;
+};
+
+const SCROLL_FAC_NEAR = 1 / 500;
export function Gallery() {
+ const [mode] = useMode();
const paper = usePaper();
- const [selected, setSelected] = useState(0);
+ const sm = useSm();
+ const [ref, setRef] = useState(null);
+ useEffect(() => {
+ if (ref) {
+ const nodes = new Set();
+ let cancelled = false;
+ const f = () => {
+ const basis = center(ref);
+ nodes.forEach((c) => {
+ const a = center(c);
+ c.style.setProperty(
+ "--factor-near",
+ `${clamp(-(((a - basis) * SCROLL_FAC_NEAR) ** 2) + 1, 0, 1)}`
+ );
+ c.style.setProperty("--factor", `${a - basis}`);
+ });
+ if (!cancelled) {
+ requestAnimationFrame(f);
+ }
+ };
+ const observer = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) {
+ if (entry.isIntersecting) {
+ nodes.add(entry.target as HTMLDivElement);
+ } else {
+ nodes.delete(entry.target as HTMLDivElement);
+ }
+ }
+ },
+ { root: ref }
+ );
+ ref.childNodes.forEach((c) => {
+ observer.observe(c as HTMLDivElement);
+ });
+
+ requestAnimationFrame(f);
+ return () => {
+ observer.disconnect();
+ cancelled = true;
+ };
+ }
+ }, [ref]);
return (
-
-
-
-
- setSelected(i)}
- sx={{
- ...paper(0),
- borderRadius: 32,
- mt: 4,
- mx: 2,
- " button.Mui-selected": { color: "text.primary" },
- }}
- >
- {map(l10n.gallery, ({ label, url }, i) => (
-
- ))}
-
-
+
+ {({ width }) => (
+
+
+
+ {l10n.gallery.map(
+ ({ label, url, description, workspace, author }) => (
+ {
+ (e.target as HTMLDivElement).scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ });
+ }}
+ sx={{
+ p: sm ? 1 : 4,
+ minWidth: width + (sm ? 1 : 4) * 8 * 2,
+ scrollSnapAlign: "center",
+ }}
+ >
+
+ {sm ? (
+
+ ) : (
+
+ )}
+
+
+ {label}
+
+
+
+
+ {author ?? "Anonymous"}
+
+
+
+ {description}
+
+
+
+
+
+ )
+ )}
+ {
+ (e.target as HTMLDivElement).scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ });
+ }}
+ sx={{
+ p: sm ? 1 : 4,
+ minWidth: width + (sm ? 1 : 4) * 8 * 2,
+ scrollSnapAlign: "center",
+ }}
+ >
+
+
+ See more examples
+
+
+
+
+
+
+
+ )}
+
);
}
diff --git a/src/components/theme.ts b/src/components/theme.ts
index 7e60b28..a486d0a 100644
--- a/src/components/theme.ts
+++ b/src/components/theme.ts
@@ -78,7 +78,7 @@ export const makeTheme = (mode: "light" | "dark", theme?: AccentColor) =>
},
h2: {
fontSize: "max(26px, min(32px, 4vw))",
- fontWeight: mode === "dark" ? 400 : 500,
+ fontWeight: mode === "dark" ? 400 : 420,
fontFamily: headingFamily,
},
h3: {
diff --git a/src/css/custom.css b/src/css/custom.css
index edaca98..d63c978 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -370,7 +370,7 @@ b {
@media (pointer: fine) {
*::-webkit-scrollbar {
width: 6px;
- height: 14px;
+ height: 6px;
background-color: transparent;
}
*::-webkit-scrollbar-track {
@@ -379,9 +379,9 @@ b {
*::-webkit-scrollbar-thumb {
transition: background-color 300ms ease;
background-color: color-mix(in srgb, currentColor 45%, transparent);
- min-height: 64px;
padding: 2px;
background-clip: padding-box;
+ border-radius: 6px;
}
*::-webkit-scrollbar-thumb:hover {
background-color: color-mix(in srgb, currentColor 60%, transparent);
diff --git a/src/pages/en-au.json b/src/pages/en-au.json
index a608e48..edd247d 100644
--- a/src/pages/en-au.json
+++ b/src/pages/en-au.json
@@ -24,6 +24,7 @@
"gallery": [
{
"url": "/img/gallery/complex-view.png",
+ "workspace": "content/dps.workspace",
"label": "Post-game analysis, StarCraft"
},
{
@@ -32,7 +33,10 @@
},
{
"url": "/img/gallery/image-7.png",
- "label": "Compression algorithm analysis, RLE"
+ "label": "Compression algorithm analysis",
+ "workspace": null,
+ "author": "Mark Carlson",
+ "description": "Mark used Posthoc to showcase an encoding scheme for black-and-white video based on run-length encoding."
},
{
"url": "/img/gallery/image-3.png",
diff --git a/static/content/dps.workspace b/static/content/dps.workspace
new file mode 100644
index 0000000..af022d7
Binary files /dev/null and b/static/content/dps.workspace differ