diff --git a/package-lock.json b/package-lock.json
index d314d1a..4f747c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,7 +23,8 @@
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-scroll-parallax": "^3.4.5",
- "react-virtualized-auto-sizer": "^1.0.24"
+ "react-virtualized-auto-sizer": "^1.0.24",
+ "resolve-url": "^0.2.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.1",
@@ -13177,6 +13178,12 @@
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
+ "node_modules/resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+ "deprecated": "https://github.com/lydell/resolve-url#deprecated"
+ },
"node_modules/responselike": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
diff --git a/package.json b/package.json
index 62f6e08..a245fe4 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,8 @@
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-scroll-parallax": "^3.4.5",
- "react-virtualized-auto-sizer": "^1.0.24"
+ "react-virtualized-auto-sizer": "^1.0.24",
+ "resolve-url": "^0.2.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.1",
diff --git a/src/components/AppBar.tsx b/src/components/AppBar.tsx
index 0be0b5d..5065026 100644
--- a/src/components/AppBar.tsx
+++ b/src/components/AppBar.tsx
@@ -85,6 +85,7 @@ export function AppBar() {
maxWidth: "100%",
height: 64,
borderRadius: 32,
+ boxShadow: (t) => t.shadows[4],
}}
>
diff --git a/src/components/Gallery.tsx b/src/components/Gallery.tsx
index 6b1ddd0..2221cee 100644
--- a/src/components/Gallery.tsx
+++ b/src/components/Gallery.tsx
@@ -1,4 +1,4 @@
-import { WorkspacesOutlined } from "@mui/icons-material";
+import { LaunchOutlined, WorkspacesOutlined } from "@mui/icons-material";
import {
Avatar,
Box,
@@ -6,277 +6,323 @@ import {
ButtonBase,
Stack,
Typography,
+ alpha,
+ useMediaQuery,
} from "@mui/material";
-import { useEffect, useState } from "react";
+import { clamp, defer, delay, floor } from "lodash";
+import { useEffect, useRef, 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);
-};
+import { useSm } from "./useSm";
+import resolve from "resolve-url";
const center = (d: HTMLDivElement) => {
const box = d.getBoundingClientRect();
return box.left + box.width / 2;
};
-const SCROLL_FAC_NEAR = 1 / 500;
+const SCROLL_FAC_NEAR = 1 / 1000;
export function Gallery() {
- const [mode] = useMode();
const paper = usePaper();
const sm = useSm();
+ const lg = useMediaQuery("(min-width: 1200px)");
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}`);
+ let basis: number;
+ let intersectionObserver: IntersectionObserver;
+ const nodes = new Set();
+ const positions = new Map();
+ const init = () => {
+ nodes.clear();
+ const observer = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) {
+ if (entry.target instanceof HTMLDivElement) {
+ if (entry.isIntersecting) {
+ entry.target.style.visibility = "visible";
+ nodes.add(entry.target);
+ } else {
+ entry.target.style.visibility = "hidden";
+ nodes.delete(entry.target);
+ }
+ }
+ }
+ },
+ { root: ref }
+ );
+ ref.childNodes.forEach((c) => {
+ if (c instanceof HTMLDivElement) {
+ observer.observe(c);
+ positions.set(c, c.offsetLeft + c.clientWidth / 2);
+ }
});
+ return observer;
+ };
+ const refresh = () => {
+ intersectionObserver?.disconnect?.();
+ intersectionObserver = init();
+ basis = center(ref);
+ };
+ const f = () => {
if (!cancelled) {
+ nodes.forEach((c) => {
+ const a = basis - positions.get(c) + ref.scrollLeft;
+ c.style.setProperty(
+ "--factor-near",
+ `${clamp(-((a * SCROLL_FAC_NEAR) ** 2) + 1, 0, 1)}`
+ );
+ c.style.setProperty("--factor", `${a}`);
+ });
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);
- });
-
+ const mutationObserver = new MutationObserver(refresh);
+ const resizeObserver = new ResizeObserver(refresh);
+ window.addEventListener("resize", refresh);
+ resizeObserver.observe(ref);
+ mutationObserver.observe(ref, { childList: true });
+ refresh();
requestAnimationFrame(f);
+
return () => {
- observer.disconnect();
+ intersectionObserver.disconnect();
+ mutationObserver.disconnect();
+ resizeObserver.disconnect();
+ window.removeEventListener("resize", refresh);
cancelled = true;
};
}
}, [ref]);
+ useEffect(() => {
+ if (ref) {
+ ref.scrollLeft = (
+ ref.childNodes.item(floor(ref.childNodes.length / 2)) as HTMLDivElement
+ ).offsetLeft;
+ }
+ }, [ref]);
+ const a = (width: number) => (
+ {
+ (e.target as HTMLDivElement).scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ });
+ }}
+ sx={{
+ p: lg ? 0 : width * 0.001,
+ minWidth: width + (lg ? 0 : width * 0.001) * 8 * 2,
+ scrollSnapAlign: "center",
+ }}
+ >
+
+
+ {l10n.galleryCallToAction}
+
+
+
+
+ );
return (
{({ width }) => (
-
-
-
- {l10n.gallery.map(
- ({ label, url, description, workspace, author }) => (
- {
- (e.target as HTMLDivElement).scrollIntoView({
- behavior: "smooth",
- block: "nearest",
- });
- }}
+
+
+ {a(width)}
+ {l10n.gallery.map(
+ ({ label, url, description, workspace, author, tagline }, i) => (
+ {
+ (e.target as HTMLDivElement).scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ });
+ }}
+ sx={{
+ p: lg ? 0 : width * 0.001,
+ minWidth: width + (lg ? 0 : width * 0.001) * 8 * 2,
+ scrollSnapAlign: "center",
+ }}
+ >
+
+ `0px 16px 32px ${alpha(
+ t.palette.background.default,
+ 0.25
+ )}`,
+ aspectRatio: sm ? 10 / 16 : 16 / 10,
+ width: "100%",
+ borderRadius: 4,
+ position: "relative",
+ overflow: "hidden",
+ backgroundImage: `url(${url})`,
+ backgroundSize: "cover",
+ backgroundPosition:
+ "calc(50% + calc(var(--factor) * -0.5px)) 50%",
+ transform: lg
+ ? `scale(calc(90% + calc(10% * var(--factor-near))))`
+ : "none",
}}
>
-
- {sm ? (
-
- ) : (
-
- )}
-
+ ) : (
+
+ )}
+
+
+ {tagline}
+
+
+ {label}
+
+
-
- {label}
-
-
-
-
- {author ?? "Anonymous"}
-
-
-
- {description}
+
+
+ {author ?? "Anonymous"}
-
-
-
- )
- )}
- {
- (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
-
-
-
-
-
-
+
+ {description}
+
+
+
+
+
+ )
+ )}
+ {a(width)}
+
)}
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index 37eb563..3b62e04 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -14,7 +14,7 @@ export function Hero() {
alignItems="center"
sx={{
maxWidth: "100dvw",
- height: "80svh",
+ height: "60svh",
minHeight: 520,
textAlign: "center",
pt: 24,
diff --git a/src/components/theme.ts b/src/components/theme.ts
index a486d0a..7e60b28 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 : 420,
+ fontWeight: mode === "dark" ? 400 : 500,
fontFamily: headingFamily,
},
h3: {
diff --git a/src/pages/en-au.json b/src/pages/en-au.json
index edd247d..93c9a17 100644
--- a/src/pages/en-au.json
+++ b/src/pages/en-au.json
@@ -23,36 +23,44 @@
],
"gallery": [
{
+ "tagline": "Analysis",
"url": "/img/gallery/complex-view.png",
- "workspace": "content/dps.workspace",
"label": "Post-game analysis, StarCraft"
},
{
- "url": "/img/gallery/astar.png",
- "label": "Demonstration, A* search"
- },
- {
+ "tagline": "Showcase",
"url": "/img/gallery/image-7.png",
- "label": "Compression algorithm analysis",
+ "label": "Video compression",
"workspace": null,
"author": "Mark Carlson",
- "description": "Mark used Posthoc to showcase an encoding scheme for black-and-white video based on run-length encoding."
+ "description": "A simple encoding scheme for binary video based on run-length encoding."
+ },
+ {
+ "tagline": "Demonstration",
+ "url": "/img/gallery/astar.png",
+ "label": "A* search",
+ "author": "ShortestPathLab",
+ "description": "Get to know Posthoc by taking apart and inspecting the classic A* algorithm on a small grid map."
},
{
+ "tagline": "Validation",
"url": "/img/gallery/image-3.png",
- "label": "Debugging, duel euclidean path search"
+ "workspace": "/content/dps.workspace",
+ "label": "Duel euclidean path search"
},
{
+ "tagline": "Debugging",
"url": "/img/gallery/room-detection.png",
- "label": "Debugging, room detection algorithm"
+ "label": "Room detection"
}
],
+ "galleryCallToAction": "See more examples in Posthoc",
"heroTitle": "Explore decision-making in search",
"heroSubtitle": "Posthoc is a way to create simple and effective visualisations from logs to help you understand search.",
"heroCallToAction": "Get started",
"heroCallToActionUrl": "./docs/get-started",
"endCallToActionTitle": "Ready to try Posthoc?",
- "demoSectionTitle": "Watch our ICAPS 24 demo",
+ "demoSectionTitle": "Showcased @ ICAPS24",
"demoSectionSubtitle": "We're excited to present Posthoc to the search and planning community",
"featuresSectionTitle": "Features",
"featuresSectionSubtitle": "featuresSectionSubtitle",
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index a8bdbb3..d04039b 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -38,9 +38,9 @@ function Content() {
t.transitions.create("background-color", {
@@ -74,11 +74,12 @@ function Content() {
width: 1000,
mx: "auto",
maxWidth: "100%",
- aspectRatio: "16 / 10",
+ aspectRatio: sm ? 10 / 16 : 16 / 10,
overflow: "hidden",
borderRadius: 4,
backgroundImage: `url(${l10n.demoVideoThumbnail})`,
backgroundSize: "cover",
+ backgroundPosition: "center",
}}
>