Skip to content

Commit 459533c

Browse files
Tony Espinozaclaude
andcommitted
Add image gallery pattern with chronological scrolling
Pattern allows uploading multiple images from local filesystem and displays them in a scrolling list sorted by timestamp (newest first). Uses ct-image-input component with lift() for reactive sorting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 2256b75 commit 459533c

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/// <cts-enable />
2+
import { Cell, cell, ImageData, lift, NAME, recipe, UI } from "commontools";
3+
4+
interface Input {
5+
images: Cell<ImageData[]>;
6+
}
7+
8+
// Sorting function lifted for reactivity
9+
const sortByTimestamp = lift((imgs: ImageData[]) =>
10+
[...imgs].sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0))
11+
);
12+
13+
export default recipe<Input>("Image Gallery", ({ images }) => {
14+
// Sort images by timestamp (newest first)
15+
const sortedImages = sortByTimestamp(images);
16+
17+
return {
18+
[NAME]: "Image Gallery",
19+
[UI]: (
20+
<div style={{ padding: "1rem", maxWidth: "600px", margin: "0 auto" }}>
21+
<h2 style={{ marginBottom: "1rem" }}>Image Gallery</h2>
22+
23+
<ct-image-input
24+
multiple
25+
maxImages={50}
26+
showPreview={false}
27+
buttonText="Add Photos"
28+
$images={images}
29+
/>
30+
31+
<div
32+
style={{
33+
marginTop: "1rem",
34+
maxHeight: "70vh",
35+
overflowY: "auto",
36+
display: "flex",
37+
flexDirection: "column",
38+
gap: "1rem",
39+
}}
40+
>
41+
{sortedImages.map((img) => (
42+
<div
43+
key={img.id}
44+
style={{
45+
borderRadius: "8px",
46+
overflow: "hidden",
47+
backgroundColor: "#f5f5f5",
48+
flexShrink: 0,
49+
}}
50+
>
51+
<img
52+
src={img.url}
53+
alt={img.name}
54+
style={{
55+
width: "100%",
56+
height: "auto",
57+
display: "block",
58+
}}
59+
/>
60+
<div
61+
style={{
62+
padding: "0.5rem",
63+
fontSize: "0.85rem",
64+
color: "#666",
65+
}}
66+
>
67+
{img.name}
68+
{img.timestamp && (
69+
<span style={{ marginLeft: "0.5rem" }}>
70+
{new Date(img.timestamp).toLocaleString()}
71+
</span>
72+
)}
73+
</div>
74+
</div>
75+
))}
76+
</div>
77+
</div>
78+
),
79+
images,
80+
};
81+
});

0 commit comments

Comments
 (0)