Add guided tours and unify left-to-right hall wall hang.
Visitors walk published tours in a 3D hall with stop notes; curators edit drafts via Tour editor. All galleries (artist, movement, tour) place the first work left of the entrance view and the last on the right. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
48bd17e985
commit
5ddc3fd7f0
@@ -1,6 +1,5 @@
|
||||
import type { Painting } from '../types';
|
||||
import type { GalleryWindowSpec, MovementInteriorStyle } from '../data/movement-interior-styles';
|
||||
import { comparePaintingsChronological } from './paintingUtils';
|
||||
|
||||
/** Target capacity per movement wing (50–60 works). */
|
||||
export const MOVEMENT_PAINTINGS_PER_HALL = 55;
|
||||
@@ -92,10 +91,6 @@ function layoutRow(paintings: Painting[], span: number) {
|
||||
return { slots, spanNeeded: Math.max(span, rowWidth + WALL_PADDING) };
|
||||
}
|
||||
|
||||
function orderForWall(paintings: Painting[]) {
|
||||
return [...paintings].sort(comparePaintingsChronological).reverse();
|
||||
}
|
||||
|
||||
function formatYearLabel(paintings: Painting[]) {
|
||||
const years = paintings.map((p) => p.year).filter((y): y is number => y != null);
|
||||
if (years.length === 0) return 'Undated works';
|
||||
@@ -104,22 +99,27 @@ function formatYearLabel(paintings: Painting[]) {
|
||||
return min === max ? `${min}` : `${min} – ${max}`;
|
||||
}
|
||||
|
||||
/** Preserve caller order (chrono for movements, stop order for tours). */
|
||||
export function splitPaintingsIntoMovementHalls(paintings: Painting[]): Painting[][] {
|
||||
const sorted = [...paintings].sort(comparePaintingsChronological);
|
||||
if (sorted.length === 0) return [[]];
|
||||
if (paintings.length === 0) return [[]];
|
||||
const chunks: Painting[][] = [];
|
||||
for (let i = 0; i < sorted.length; i += MOVEMENT_PAINTINGS_PER_HALL) {
|
||||
chunks.push(sorted.slice(i, i + MOVEMENT_PAINTINGS_PER_HALL));
|
||||
for (let i = 0; i < paintings.length; i += MOVEMENT_PAINTINGS_PER_HALL) {
|
||||
chunks.push(paintings.slice(i, i + MOVEMENT_PAINTINGS_PER_HALL));
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* First half → left wall, second half → right.
|
||||
* Callers pass paintings already in visit order; first work hangs near the
|
||||
* entrance on the left, last work near the entrance on the right.
|
||||
*/
|
||||
function distributeToSideWalls(paintings: Painting[]) {
|
||||
const left: Painting[] = [];
|
||||
const right: Painting[] = [];
|
||||
const sorted = [...paintings].sort(comparePaintingsChronological);
|
||||
sorted.forEach((p, i) => (i % 2 === 0 ? left : right).push(p));
|
||||
return { left: orderForWall(left), right: orderForWall(right) };
|
||||
const mid = Math.ceil(paintings.length / 2);
|
||||
return {
|
||||
left: paintings.slice(0, mid),
|
||||
right: paintings.slice(mid),
|
||||
};
|
||||
}
|
||||
|
||||
function layoutSideSlots(
|
||||
@@ -132,16 +132,21 @@ function layoutSideSlots(
|
||||
if (paintings.length === 0) return [];
|
||||
const { slots: rowSlots } = layoutRow(paintings, span);
|
||||
const y = EYE_HEIGHT;
|
||||
return rowSlots.map((s) => ({
|
||||
maxW: s.maxW,
|
||||
maxH: s.maxH,
|
||||
rotationY: side === 'left' ? Math.PI / 2 : -Math.PI / 2,
|
||||
side,
|
||||
position:
|
||||
side === 'left'
|
||||
? ([-halfW + inset + WALL_STANDOFF, y, s.offset] as [number, number, number])
|
||||
: ([halfW - inset - WALL_STANDOFF, y, s.offset] as [number, number, number]),
|
||||
}));
|
||||
return rowSlots.map((s) => {
|
||||
// layoutRow places index 0 at negative offset. Flip on the left wall so
|
||||
// the first painting sits at the entrance (+Z), left of the starting view.
|
||||
const alongWall = side === 'left' ? -s.offset : s.offset;
|
||||
return {
|
||||
maxW: s.maxW,
|
||||
maxH: s.maxH,
|
||||
rotationY: side === 'left' ? Math.PI / 2 : -Math.PI / 2,
|
||||
side,
|
||||
position:
|
||||
side === 'left'
|
||||
? ([-halfW + inset + WALL_STANDOFF, y, alongWall] as [number, number, number])
|
||||
: ([halfW - inset - WALL_STANDOFF, y, alongWall] as [number, number, number]),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function buildMovementHallLayout(
|
||||
|
||||
Reference in New Issue
Block a user