Files
jmartgraphix.com/server/prisma/seed.ts
T
jmartin af4e658e72 Load home portfolio views from API; improve resume PDF layout
Stop hardcoding deleted audience views and re-seeding them on boot.
Tighten resume print CSS with professional fonts and page-break rules
for a cleaner 1–2 page Letter PDF.
2026-08-01 11:28:51 -04:00

204 lines
6.3 KiB
TypeScript

import { PrismaClient } from "@prisma/client";
import slugify from "slugify";
const prisma = new PrismaClient();
const CATEGORIES = [
"3D Modeling",
"3D Animation",
"CAD",
"3D Sculpting",
"AI Generated Content",
"Video",
"Photography",
"Graphic Design",
"Illustration",
];
function slug(s: string) {
return slugify(s, { lower: true, strict: true });
}
async function main() {
console.log("Seeding categories…");
for (let i = 0; i < CATEGORIES.length; i++) {
const name = CATEGORIES[i];
await prisma.category.upsert({
where: { slug: slug(name) },
create: { name, slug: slug(name), sortOrder: i },
update: { name, sortOrder: i },
});
}
// Convenience slugs for URL filters (/portfolio/3d, /portfolio/ai, etc.)
const aliases: Record<string, string> = {
"3d-modeling": "3d",
"3d-animation": "animation",
"ai-generated-content": "ai",
"graphic-design": "design",
};
// We keep canonical slugs; PortfolioView can use short names
// Seed portfolio views only on a fresh DB. Do not re-create views after the admin deletes them.
const viewCount = await prisma.portfolioView.count();
if (viewCount === 0) {
console.log("Seeding default portfolio views (empty table)…");
const cats = await prisma.category.findMany();
const bySlug = Object.fromEntries(cats.map((c) => [c.slug, c]));
async function createView(
name: string,
viewSlug: string,
description: string,
orderedSlugs: string[]
) {
const view = await prisma.portfolioView.create({
data: { name, slug: viewSlug, description, showOthers: true },
});
for (let i = 0; i < orderedSlugs.length; i++) {
const cat = bySlug[orderedSlugs[i]];
if (!cat) continue;
await prisma.portfolioViewCategory.create({
data: { viewId: view.id, categoryId: cat.id, priority: i },
});
}
}
await createView(
"3D",
"3d",
"All 3D work front and center.",
["3d-modeling", "3d-animation", "3d-sculpting", "cad"]
);
await createView("Animation", "animation", "Animation-focused portfolio.", [
"3d-animation",
"video",
]);
await createView("CAD", "cad", "CAD and technical design.", ["cad", "3d-modeling"]);
await createView("AI", "ai", "AI-generated creative work.", [
"ai-generated-content",
"illustration",
"graphic-design",
]);
for (const [canonical, short] of Object.entries(aliases)) {
if (short === "3d" || short === "animation" || short === "ai") continue;
await createView(bySlug[canonical]?.name ?? short, short, `Filter: ${short}`, [
canonical,
]);
}
} else {
console.log(`Skipping portfolio view seed (${viewCount} existing views).`);
}
const existingResume = await prisma.resume.findFirst({ where: { isActive: true } });
if (!existingResume) {
console.log("Seeding sample resume…");
await prisma.resume.create({
data: {
isActive: true,
fullName: "J. Martin",
title: "3D Artist · Designer · Creative Technologist",
email: "contact@jmartgraphix.com",
website: "https://jmartgraphix.com",
location: "United States",
summary:
"Creative professional specializing in 3D modeling, CAD, animation, and visual design. Building polished digital experiences and production-ready assets for games, product visualization, and media.",
sections: [
{
type: "experience",
title: "Experience",
items: [
{
title: "Independent Creative / jmartgraphix",
organization: "Freelance",
location: "Remote",
startDate: "2018",
endDate: "Present",
description:
"Delivered 3D models, animations, CAD designs, and graphic work for clients across game development, product design, and marketing.",
highlights: [
"End-to-end 3D pipeline: modeling, sculpting, texturing, rendering",
"CAD and product visualization for engineering collaborators",
"Motion graphics and short-form video production",
],
},
],
},
{
type: "skills",
title: "Software & Tools",
items: [
{
group: "3D & CAD",
skills: [
"Blender",
"Maya",
"ZBrush",
"SolidWorks",
"Fusion 360",
"Substance Painter",
],
},
{
group: "Design & Video",
skills: [
"Photoshop",
"Illustrator",
"After Effects",
"Premiere Pro",
"DaVinci Resolve",
],
},
{
group: "Other",
skills: ["AI image/video tools", "Git", "Web (HTML/CSS)"],
},
],
},
{
type: "links",
title: "Links",
items: [
{ label: "Portfolio", url: "https://jmartgraphix.com" },
{ label: "ArtStation", url: "https://jmartgraphix.artstation.com/" },
{ label: "YouTube", url: "https://www.youtube.com/@samuraijkm" },
{ label: "Vimeo", url: "https://vimeo.com/jmartgraphix" },
],
},
],
},
});
}
await prisma.siteSetting.upsert({
where: { key: "site" },
create: {
key: "site",
value: {
name: "jmartgraphix",
tagline: "Creative Professional Portfolio",
about:
"I create 3D art, technical design, animation, and visual media — from concept through polished delivery.",
social: {
artstation: "https://jmartgraphix.artstation.com/",
youtube: "https://www.youtube.com/@samuraijkm",
vimeo: "https://vimeo.com/jmartgraphix",
},
heroTitle: "",
heroSubtitle: "3D · Design · Motion · Craft",
},
},
update: {},
});
console.log("Seed complete.");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(() => prisma.$disconnect());