Add an admin page for managing gallery images and artist names
Introduce a new admin route at `/admin/gallery` enabling users to set focal points and artist names for gallery images, with corresponding API endpoints and data management. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 70b6b9df-7da9-46f3-afd7-dbcd9aac1855 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/ncMMRQ9 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -362,6 +362,92 @@ export async function registerRoutes(
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/api/gallery/focal-points", (_req, res) => {
|
||||
try {
|
||||
const fpPath = path.join(process.cwd(), "server/gallery-focal-points.json");
|
||||
if (fs.existsSync(fpPath)) {
|
||||
res.json(JSON.parse(fs.readFileSync(fpPath, "utf-8")));
|
||||
} else {
|
||||
res.json({});
|
||||
}
|
||||
} catch {
|
||||
res.json({});
|
||||
}
|
||||
});
|
||||
|
||||
app.put("/api/gallery/focal-points/:fileName", (req, res) => {
|
||||
try {
|
||||
const { fileName } = req.params;
|
||||
const { x, y } = req.body;
|
||||
if (typeof x !== "number" || typeof y !== "number") {
|
||||
return res.status(400).json({ message: "x and y must be numbers (0-100)" });
|
||||
}
|
||||
const fpPath = path.join(process.cwd(), "server/gallery-focal-points.json");
|
||||
let data: Record<string, { x: number; y: number }> = {};
|
||||
if (fs.existsSync(fpPath)) {
|
||||
data = JSON.parse(fs.readFileSync(fpPath, "utf-8"));
|
||||
}
|
||||
data[fileName] = { x: Math.round(x), y: Math.round(y) };
|
||||
fs.writeFileSync(fpPath, JSON.stringify(data, null, 2));
|
||||
res.json({ ok: true, fileName, x: data[fileName].x, y: data[fileName].y });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete("/api/gallery/focal-points/:fileName", (req, res) => {
|
||||
try {
|
||||
const { fileName } = req.params;
|
||||
const fpPath = path.join(process.cwd(), "server/gallery-focal-points.json");
|
||||
let data: Record<string, { x: number; y: number }> = {};
|
||||
if (fs.existsSync(fpPath)) {
|
||||
data = JSON.parse(fs.readFileSync(fpPath, "utf-8"));
|
||||
}
|
||||
delete data[fileName];
|
||||
fs.writeFileSync(fpPath, JSON.stringify(data, null, 2));
|
||||
res.json({ ok: true });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/api/gallery/artists", (_req, res) => {
|
||||
try {
|
||||
const aPath = path.join(process.cwd(), "server/gallery-artist-overrides.json");
|
||||
if (fs.existsSync(aPath)) {
|
||||
res.json(JSON.parse(fs.readFileSync(aPath, "utf-8")));
|
||||
} else {
|
||||
res.json({});
|
||||
}
|
||||
} catch {
|
||||
res.json({});
|
||||
}
|
||||
});
|
||||
|
||||
app.put("/api/gallery/artists/:fileName", (req, res) => {
|
||||
try {
|
||||
const { fileName } = req.params;
|
||||
const { artist } = req.body;
|
||||
if (typeof artist !== "string") {
|
||||
return res.status(400).json({ message: "artist must be a string" });
|
||||
}
|
||||
const aPath = path.join(process.cwd(), "server/gallery-artist-overrides.json");
|
||||
let data: Record<string, string> = {};
|
||||
if (fs.existsSync(aPath)) {
|
||||
data = JSON.parse(fs.readFileSync(aPath, "utf-8"));
|
||||
}
|
||||
if (artist.trim() === "") {
|
||||
delete data[fileName];
|
||||
} else {
|
||||
data[fileName] = artist.trim();
|
||||
}
|
||||
fs.writeFileSync(aPath, JSON.stringify(data, null, 2));
|
||||
res.json({ ok: true, fileName, artist: artist.trim() });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Gallery API - serves optimized photos from Dropbox/Cloudinary
|
||||
app.get("/api/gallery", async (req, res) => {
|
||||
try {
|
||||
@@ -376,6 +462,18 @@ export async function registerRoutes(
|
||||
data = JSON.parse(fs.readFileSync(galleryPath, "utf-8"));
|
||||
}
|
||||
|
||||
const aPath = path.join(process.cwd(), "server/gallery-artist-overrides.json");
|
||||
let artistOverrides: Record<string, string> = {};
|
||||
if (fs.existsSync(aPath)) {
|
||||
artistOverrides = JSON.parse(fs.readFileSync(aPath, "utf-8"));
|
||||
}
|
||||
data = data.map((img: any) => {
|
||||
if (artistOverrides[img.fileName]) {
|
||||
return { ...img, artist: artistOverrides[img.fileName] };
|
||||
}
|
||||
return img;
|
||||
});
|
||||
|
||||
const shuffled = [...data];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
|
||||
Reference in New Issue
Block a user