/* global React, window */
// ============================================================
// RISOGRAPH pages + STUDIO + CONTACT + case-study modal
// ============================================================
function ProjectCard({ p, lang, t, openCase, small }) {
const d = p[lang] || p.en;
if (p.placeholder) {
return (
{lang === "ar" ? "شاغر" : "open slot"}
{d.title}
);
}
return (
openCase(p)} role="button" tabIndex={0}
onKeyDown={(e) => e.key === "Enter" && openCase(p)}>
{p.comingSoon &&
{lang === "ar" ? "قريباً" : "coming soon"} }
{p.img &&
}
{d.tagline}
);
}
function PgRisoIntro({ t, lang, openCase }) {
const { PROJECTS, PixelTuxedoCat } = window;
const feat = PROJECTS.filter(p => ["weddingjo", "potatohead"].includes(p.id));
return (
02 · {lang === "ar" ? "الريزوغراف" : "Risograph"}
{t.projectsTitle}
{t.projectsLede}
vii
);
}
function PgProjects({ t, lang, openCase }) {
const { PROJECTS } = window;
const rest = PROJECTS.filter(p => ["election", "loveseed", "nabtaty", "cloudette"].includes(p.id));
return (
{lang === "ar" ? "مطبوع في غرفة الريزو" : "Printed in the riso room"}
viii
);
}
// ---------- STUDIO ----------
function PgStudio({ t, lang }) {
const { REALMS, PixelTuxedoCat } = window;
const glyph = (i) => i % 3 === 0
?
: i % 3 === 1
?
: ;
return (
{t.studioTitle}
{t.studioTitle}
{t.studioLede}
{REALMS.map((r, i) => (
{glyph(i)}
{lang === "ar" ? r.ar : r.en}
))}
ix
);
}
// ---------- CONTACT ----------
function PgContact({ t, lang, onLang }) {
const [v, setV] = React.useState({ name: "", email: "", type: t.types[0], msg: "", lang: t.langs[0], hp: "" });
const [err, setErr] = React.useState({});
const [sent, setSent] = React.useState(false);
const set = (k) => (e) => setV(s => ({ ...s, [k]: e.target.value }));
const submit = (e) => {
e.preventDefault();
if (v.hp) return; // honeypot
const er = {};
if (!v.name.trim()) er.name = t.req;
if (!v.email.trim()) er.email = t.req;
else if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v.email)) er.email = t.bademail;
if (!v.msg.trim()) er.msg = t.req;
setErr(er);
if (Object.keys(er).length === 0) setSent(true);
};
return (
{t.contactTitle}
{t.contactTitle}
{t.contactLede}
{sent && (
)}
x
);
}
// ---------- Case study modal ----------
function CaseStudy({ p, lang, t, onClose }) {
const d = p[lang] || p.en;
React.useEffect(() => {
const k = (e) => e.key === "Escape" && onClose();
window.addEventListener("keydown", k);
return () => window.removeEventListener("keydown", k);
}, []);
return (
e.stopPropagation()}>
×
{p.img
?
:
800 × 600 — {d.title}
}
{d.disc}
{d.title}
{t.builtWith}: {d.stack}
{d.desc}
{t.role_label}: {d.role}
{p.metrics && (
{p.metrics.map((m, i) => (
{m.n} {m.l[lang] || m.l.en}
))}
)}
{p.links && (
)}
);
}
// ---------- COLOPHON (closing page) ----------
function PgColophon({ t, lang }) {
const { PixelTuxedoCat } = window;
return (
{lang === "ar" ? "تمّت" : "fin"}
{lang === "ar" ? "شكراً للقراءة" : "Thank you for reading"}
{lang === "ar"
? "أُغلق الكتاب الآن. إن أعجبك ما رأيت، فلنصنع شيئاً معاً."
: "The book closes here. If you liked what you saw, let's make something together."}
{t.name} · {t.place}
ruhufatefruhuf@gmail.com
xii
);
}
window.RisoPages = { ProjectCard, PgRisoIntro, PgProjects, PgStudio, PgContact, PgColophon, CaseStudy };