project-portfolio 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectCard.d.ts","sourceRoot":"","sources":["../src/ProjectCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAmC,MAAM,SAAS,CAAA;AAE1F,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAA;AAE5C,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAeD,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,MAAM,EACN,eAAoB,EACpB,QAAQ,EACR,OAAgB,EAChB,QAAsB,GACvB,EAAE,gBAAgB,2CA4PlB"}
1
+ {"version":3,"file":"ProjectCard.d.ts","sourceRoot":"","sources":["../src/ProjectCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAmC,MAAM,SAAS,CAAA;AAE1F,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAA;AAE5C,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAeD,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,MAAM,EACN,eAAoB,EACpB,QAAQ,EACR,OAAgB,EAChB,QAAsB,GACvB,EAAE,gBAAgB,2CA6PlB"}
@@ -19,6 +19,7 @@ export function ProjectCard({ project, schema, fieldOptionsMap = {}, priority, v
19
19
  const tagFields = schema
20
20
  .filter((f) => f.display_position === "tags" && f.type !== "number")
21
21
  .filter((f, i, arr) => arr.findIndex((x) => x.key === f.key) === i);
22
+ // Numeric field for footer stat — the first visible number field (year completed)
22
23
  const numericField = schema.find((f) => f.type === "number" && f.display_position !== "hidden");
23
24
  const locationField = schema.find((f) => f.type === "location");
24
25
  const badgeValue = badgeField
@@ -34,11 +35,11 @@ export function ProjectCard({ project, schema, fieldOptionsMap = {}, priority, v
34
35
  if (!numericField)
35
36
  return null;
36
37
  const val = project.custom_field_values[numericField.key];
37
- if (val === undefined || val === null)
38
+ if (val === undefined || val === null || val === "")
38
39
  return null;
39
- const numVal = typeof val === "number" ? val : parseFloat(String(val));
40
- const formatted = isNaN(numVal) ? String(val) : `${numVal.toLocaleString()} SF`;
41
40
  const label = numericField.name.replace(/\s*\([^)]+\)/, "");
41
+ const numVal = typeof val === "number" ? val : parseFloat(String(val));
42
+ const formatted = isNaN(numVal) ? String(val) : String(Math.round(numVal));
42
43
  return { label, formatted };
43
44
  })();
44
45
  const compactTags = tagFields.flatMap((field) => parseMultiValue(project.custom_field_values[field.key]));
@@ -5,10 +5,16 @@ export interface ProjectDetailProps {
5
5
  clientSlug: string;
6
6
  /** Base URL of the projects API */
7
7
  apiBase: string;
8
- /** Base path for the "back" link. Defaults to "/projects" */
8
+ /** Base path for the "back" link and "View All" link. Defaults to "/projects" */
9
9
  backPath?: string;
10
10
  /** Label for the "back" link. Defaults to "All Projects" */
11
11
  backLabel?: string;
12
+ /**
13
+ * Base path used to build individual project detail URLs in similar project cards.
14
+ * Defaults to backPath if not provided, then "/projects".
15
+ * e.g. if backPath="/" set projectBasePath="/projects"
16
+ */
17
+ projectBasePath?: string;
12
18
  /**
13
19
  * Seconds to cache via Next.js Data Cache on production deployments.
14
20
  * React.cache() always deduplicates within a single render in all environments.
@@ -16,5 +22,5 @@ export interface ProjectDetailProps {
16
22
  */
17
23
  revalidate?: number;
18
24
  }
19
- export declare function ProjectDetail({ slug, clientSlug, apiBase, backPath, backLabel, revalidate, }: ProjectDetailProps): Promise<import("react/jsx-runtime").JSX.Element>;
25
+ export declare function ProjectDetail({ slug, clientSlug, apiBase, backPath, backLabel, projectBasePath, revalidate, }: ProjectDetailProps): Promise<import("react/jsx-runtime").JSX.Element>;
20
26
  //# sourceMappingURL=ProjectDetail.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectDetail.d.ts","sourceRoot":"","sources":["../src/ProjectDetail.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAkLD,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,UAAU,EACV,OAAO,EACP,QAAsB,EACtB,SAA0B,EAC1B,UAAe,GAChB,EAAE,kBAAkB,oDAkLpB"}
1
+ {"version":3,"file":"ProjectDetail.d.ts","sourceRoot":"","sources":["../src/ProjectDetail.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAkLD,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,UAAU,EACV,OAAO,EACP,QAAsB,EACtB,SAA0B,EAC1B,eAAe,EACf,UAAe,GAChB,EAAE,kBAAkB,oDA0MpB"}
@@ -82,8 +82,11 @@ function SimilarProjects({ allProjects, currentSlug, badgeValue, badgeField, loc
82
82
  }) })] }));
83
83
  }
84
84
  // ─── Component ───────────────────────────────────────────────────────────────
85
- export async function ProjectDetail({ slug, clientSlug, apiBase, backPath = "/projects", backLabel = "All Projects", revalidate = 60, }) {
86
- var _a, _b, _c, _d, _e, _f, _g, _h;
85
+ export async function ProjectDetail({ slug, clientSlug, apiBase, backPath = "/projects", backLabel = "All Projects", projectBasePath, revalidate = 60, }) {
86
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
87
+ // projectBasePath is for individual project card links in the similar projects section.
88
+ // Falls back to backPath so existing integrations work without any changes.
89
+ const resolvedProjectBasePath = projectBasePath !== null && projectBasePath !== void 0 ? projectBasePath : backPath;
87
90
  const { project, schema, allProjects } = await fetchProjectDetail(apiBase, clientSlug, slug, revalidate);
88
91
  if (!project) {
89
92
  return (_jsxs("div", { style: { textAlign: "center", padding: "6rem 1.5rem", fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" }, children: [_jsx("p", { style: { color: "#71717a", fontSize: "18px" }, children: "Project not found." }), _jsxs("a", { href: backPath, style: { color: "#f18a00", fontWeight: 600, fontSize: "14px", textDecoration: "none", marginTop: "1rem", display: "inline-block" }, children: ["\u2190 ", backLabel] })] }));
@@ -94,9 +97,16 @@ export async function ProjectDetail({ slug, clientSlug, apiBase, backPath = "/pr
94
97
  : ((_g = (_f = project.media) === null || _f === void 0 ? void 0 : _f.slice(1)) !== null && _g !== void 0 ? _g : []);
95
98
  const badgeField = schema.find((f) => f.display_position === "badge_overlay");
96
99
  const locationField = schema.find((f) => f.type === "location");
97
- const numericField = schema.find((f) => f.type === "number" && f.display_position !== "hidden");
100
+ // Year field: any number field whose key or name contains "year"
101
+ const yearField = schema.find((f) => f.type === "number" && f.display_position !== "hidden" &&
102
+ (/year/i.test(f.key) || /year/i.test(f.name)));
103
+ // Sq footage field: any field (text or number) whose key or name matches common area/coverage terms
104
+ // Falls back to the first non-year number field so it works regardless of client field naming
105
+ const sqftField = (_h = schema.find((f) => f.display_position !== "hidden" &&
106
+ (/coverage|sq.?ft|square.?foot|area|footage/i.test(f.key) || /coverage|sq.?ft|square.?foot|area|footage/i.test(f.name)))) !== null && _h !== void 0 ? _h : schema.find((f) => f.type === "number" && f.display_position !== "hidden" &&
107
+ !(/year/i.test(f.key) || /year/i.test(f.name)));
98
108
  const badgeValue = badgeField
99
- ? ((_h = parseMultiValue(project.custom_field_values[badgeField.key])[0]) !== null && _h !== void 0 ? _h : null)
109
+ ? ((_j = parseMultiValue(project.custom_field_values[badgeField.key])[0]) !== null && _j !== void 0 ? _j : null)
100
110
  : null;
101
111
  const locationValue = locationField
102
112
  ? project.custom_field_values[locationField.key]
@@ -104,15 +114,24 @@ export async function ProjectDetail({ slug, clientSlug, apiBase, backPath = "/pr
104
114
  const locationString = locationValue
105
115
  ? [locationValue.city, locationValue.state].filter(Boolean).join(", ")
106
116
  : null;
107
- const rawCoverage = numericField ? project.custom_field_values[numericField.key] : null;
108
117
  const coverageFormatted = (() => {
109
- if (rawCoverage === null || rawCoverage === undefined)
118
+ const raw = sqftField ? project.custom_field_values[sqftField.key] : null;
119
+ if (raw === null || raw === undefined || raw === "")
110
120
  return null;
111
- const n = typeof rawCoverage === "number" ? rawCoverage : parseFloat(String(rawCoverage));
112
- return isNaN(n) ? String(rawCoverage) : `${n.toLocaleString()} SF`;
121
+ if (typeof raw === "string")
122
+ return raw; // already formatted e.g. "225 SF"
123
+ const n = typeof raw === "number" ? raw : parseFloat(String(raw));
124
+ return isNaN(n) ? String(raw) : `${n.toLocaleString()} SF`;
125
+ })();
126
+ const yearCompleted = (() => {
127
+ const raw = yearField ? project.custom_field_values[yearField.key] : null;
128
+ if (raw === null || raw === undefined)
129
+ return null;
130
+ const n = typeof raw === "number" ? raw : parseFloat(String(raw));
131
+ return isNaN(n) ? String(raw) : String(Math.round(n));
113
132
  })();
114
133
  const font = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
115
- return (_jsxs("main", { style: { minHeight: "100vh", backgroundColor: "#fff", fontFamily: font }, children: [_jsxs("section", { className: "chisel-hero-img", style: { position: "relative", width: "100%", overflow: "hidden" }, children: [imageUrl ? (_jsx("img", { src: imageUrl, alt: project.title, style: { width: "100%", height: "100%", objectFit: "cover", display: "block" } })) : (_jsx("div", { style: { position: "absolute", inset: 0, backgroundColor: "#27272a" } })), _jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.82) 0%, rgba(0,0,0,0.38) 50%, rgba(0,0,0,0.12) 100%)" } }), _jsx("div", { style: { position: "absolute", top: "1.5rem", left: 0, right: 0, padding: "0 1.5rem" }, children: _jsxs("a", { href: backPath, style: { display: "inline-flex", alignItems: "center", gap: "6px", color: "rgba(255,255,255,0.7)", fontSize: "14px", textDecoration: "none", fontFamily: font }, children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M19 12H5M12 5l-7 7 7 7" }) }), backLabel] }) }), _jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: "0 1.5rem 2.5rem", maxWidth: "900px" }, children: [(badgeValue || project.year) && (_jsx("p", { style: { color: "#f18a00", fontSize: "11px", fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", margin: "0 0 10px 0" }, children: [badgeValue, project.year].filter(Boolean).join(" · ") })), _jsx("h1", { style: { color: "#fff", fontWeight: 700, fontSize: "clamp(28px, 4vw, 52px)", lineHeight: 1.1, margin: "0 0 12px 0", fontFamily: font }, children: project.title }), locationString && (_jsxs("p", { style: { display: "flex", alignItems: "center", gap: "6px", color: "rgba(255,255,255,0.75)", fontSize: "15px", margin: 0 }, children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { flexShrink: 0 }, children: [_jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), _jsx("circle", { cx: "12", cy: "10", r: "3" })] }), locationString] }))] })] }), _jsxs("section", { style: { borderBottom: "1px solid #e4e4e7", backgroundColor: "#fff" }, children: [_jsx("style", { children: `
134
+ return (_jsxs("main", { style: { minHeight: "100vh", backgroundColor: "#fff", fontFamily: font }, children: [_jsxs("section", { className: "chisel-hero-img", style: { position: "relative", width: "100%", overflow: "hidden" }, children: [imageUrl ? (_jsx("img", { src: imageUrl, alt: project.title, style: { width: "100%", height: "100%", objectFit: "cover", display: "block" } })) : (_jsx("div", { style: { position: "absolute", inset: 0, backgroundColor: "#27272a" } })), _jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.82) 0%, rgba(0,0,0,0.38) 50%, rgba(0,0,0,0.12) 100%)" } }), _jsx("div", { style: { position: "absolute", top: "1.5rem", left: 0, right: 0, padding: "0 1.5rem" }, children: _jsxs("a", { href: backPath, style: { display: "inline-flex", alignItems: "center", gap: "6px", color: "rgba(255,255,255,0.7)", fontSize: "14px", textDecoration: "none", fontFamily: font }, children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M19 12H5M12 5l-7 7 7 7" }) }), backLabel] }) }), _jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: "0 1.5rem 2.5rem", maxWidth: "900px" }, children: [badgeValue && (_jsx("p", { style: { color: "#f18a00", fontSize: "11px", fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", margin: "0 0 10px 0" }, children: badgeValue })), _jsx("h1", { style: { color: "#fff", fontWeight: 700, fontSize: "clamp(28px, 4vw, 52px)", lineHeight: 1.1, margin: "0 0 12px 0", fontFamily: font }, children: project.title }), locationString && (_jsxs("p", { style: { display: "flex", alignItems: "center", gap: "6px", color: "rgba(255,255,255,0.75)", fontSize: "15px", margin: 0 }, children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { flexShrink: 0 }, children: [_jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), _jsx("circle", { cx: "12", cy: "10", r: "3" })] }), locationString] }))] })] }), _jsxs("section", { style: { borderBottom: "1px solid #e4e4e7", backgroundColor: "#fff" }, children: [_jsx("style", { children: `
116
135
  .chisel-stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.25rem; }
117
136
  @media (min-width: 768px) { .chisel-stats-grid { grid-template-columns: repeat(4, 1fr); gap: 2rem; } }
118
137
  .chisel-similar-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@@ -126,8 +145,8 @@ export async function ProjectDetail({ slug, clientSlug, apiBase, backPath = "/pr
126
145
  { label: "Location", value: locationString !== null && locationString !== void 0 ? locationString : "—" },
127
146
  { label: "Project Type", value: badgeValue !== null && badgeValue !== void 0 ? badgeValue : "—" },
128
147
  { label: "Sq. Footage", value: coverageFormatted !== null && coverageFormatted !== void 0 ? coverageFormatted : "—" },
129
- { label: "Completed", value: project.year ? String(project.year) : "—" },
148
+ { label: "Completed", value: yearCompleted !== null && yearCompleted !== void 0 ? yearCompleted : "—" },
130
149
  ].map(({ label, value }) => (_jsxs("div", { children: [_jsx("p", { style: { fontSize: "10px", fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.1em", color: "#a1a1aa", margin: "0 0 6px 0" }, children: label }), _jsx("p", { style: { color: "#18181b", fontWeight: 600, fontSize: "15px", margin: 0 }, children: value })] }, label))) })] }), _jsxs("article", { style: { maxWidth: "1280px", margin: "0 auto", padding: "2rem 1rem", boxSizing: "border-box", display: "flex", flexDirection: "column", gap: "2.5rem" }, children: [(project.blurb || project.description) && (_jsxs("section", { style: { maxWidth: "720px" }, children: [_jsx("h2", { style: { color: "#18181b", fontWeight: 700, fontSize: "22px", margin: "0 0 16px 0", fontFamily: font }, children: "Project Overview" }), project.blurb && (_jsx("p", { style: { color: "#3f3f46", fontSize: "16px", lineHeight: 1.7, margin: "0 0 16px 0" }, children: project.blurb })), project.description && project.description !== project.blurb && (_jsx("p", { style: { color: "#3f3f46", fontSize: "16px", lineHeight: 1.7, margin: 0 }, children: project.description }))] })), _jsxs("section", { children: [_jsx("h2", { style: { color: "#18181b", fontWeight: 700, fontSize: "22px", margin: "0 0 1.5rem 0", fontFamily: font }, children: "Project Gallery" }), galleryImages.length > 0 ? (_jsx(GalleryCarousel, { images: galleryImages, projectTitle: project.title })) : (
131
150
  /* Placeholder */
132
- _jsx("div", { className: "chisel-gallery-placeholder", children: [0, 1, 2].map((i) => (_jsxs("div", { style: { aspectRatio: "4/3", borderRadius: "4px", backgroundColor: "#f9f9f9", border: "1px solid #e4e4e7", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "8px" }, children: [_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#a1a1aa", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909M3.75 19.5h16.5" }) }), _jsx("p", { style: { color: "#a1a1aa", fontSize: "12px", margin: 0 }, children: "Photos coming soon" })] }, i))) }))] }), _jsx(SimilarProjects, { allProjects: allProjects, currentSlug: slug, badgeValue: badgeValue, badgeField: badgeField !== null && badgeField !== void 0 ? badgeField : null, locationField: locationField !== null && locationField !== void 0 ? locationField : null, basePath: backPath, font: font })] })] }));
151
+ _jsx("div", { className: "chisel-gallery-placeholder", children: [0, 1, 2].map((i) => (_jsxs("div", { style: { aspectRatio: "4/3", borderRadius: "4px", backgroundColor: "#f9f9f9", border: "1px solid #e4e4e7", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "8px" }, children: [_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#a1a1aa", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909M3.75 19.5h16.5" }) }), _jsx("p", { style: { color: "#a1a1aa", fontSize: "12px", margin: 0 }, children: "Photos coming soon" })] }, i))) }))] }), _jsx(SimilarProjects, { allProjects: allProjects, currentSlug: slug, badgeValue: badgeValue, badgeField: badgeField !== null && badgeField !== void 0 ? badgeField : null, locationField: locationField !== null && locationField !== void 0 ? locationField : null, basePath: resolvedProjectBasePath, font: font })] })] }));
133
152
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectFilters.d.ts","sourceRoot":"","sources":["../src/ProjectFilters.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAehD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpD,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAO,EACP,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,EAAE,mBAAmB,2CA8FrB"}
1
+ {"version":3,"file":"ProjectFilters.d.ts","sourceRoot":"","sources":["../src/ProjectFilters.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpD,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAO,EACP,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,EAAE,mBAAmB,2CAgGrB"}
@@ -1,17 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- function selectOptionsForField(field) {
3
- const out = [];
4
- const seen = new Set();
5
- for (const opt of field.options) {
6
- const value = typeof opt === "string" ? opt : opt.id;
7
- const label = typeof opt === "string" ? opt : opt.label;
8
- if (seen.has(value))
9
- continue;
10
- seen.add(value);
11
- out.push({ value, label });
12
- }
13
- return out;
14
- }
15
2
  export function ProjectFilters({ fields, filters, onFilterChange, onClearFilters, hasActiveFilters, }) {
16
3
  const deduped = fields.filter((f, i, arr) => arr.findIndex((x) => x.key === f.key) === i);
17
4
  return (_jsxs("div", { style: {
@@ -34,7 +21,7 @@ export function ProjectFilters({ fields, filters, onFilterChange, onClearFilters
34
21
  color: "#18181b",
35
22
  outline: "none",
36
23
  cursor: "pointer",
37
- }, children: [_jsxs("option", { value: "all", children: ["All ", field.name] }), selectOptionsForField(field).map(({ value, label }, i) => (_jsx("option", { value: value, children: label }, `${field.key}-opt-${i}`)))] })] }, `filter-${fieldIndex}-${field.key}`));
24
+ }, children: [_jsxs("option", { value: "all", children: ["All ", field.name] }), [...new Set(field.options.map((o) => typeof o === "string" ? o : o.label))].map((option, i) => (_jsx("option", { value: option, children: option }, `${field.key}-opt-${i}`)))] })] }, `filter-${fieldIndex}-${field.key}`));
38
25
  }
39
26
  if (field.type === "text" || field.type === "location") {
40
27
  return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [_jsx("label", { style: { fontSize: "13px", fontWeight: 500, color: "#71717a" }, children: field.name }), _jsx("input", { type: "text", placeholder: `Search ${field.name.toLowerCase()}...`, value: filters[field.key] || "", onChange: (e) => onFilterChange(field.key, e.target.value), style: {
@@ -48,7 +48,7 @@ export async function ProjectMenu({ clientSlug, apiBase, basePath = "/projects",
48
48
  if (typeof opt === "string") {
49
49
  return { id: opt.toLowerCase().replace(/\s+/g, "-"), label: opt };
50
50
  }
51
- return { id: (_a = opt.id) !== null && _a !== void 0 ? _a : String((_b = opt.label) !== null && _b !== void 0 ? _b : "").toLowerCase().replace(/\s+/g, "-"), label: (_c = opt.label) !== null && _c !== void 0 ? _c : String(opt) };
51
+ return { id: (_a = opt.id) !== null && _a !== void 0 ? _a : String((_b = opt.label) !== null && _b !== void 0 ? _b : "").toLowerCase().replace(/\s+/g, "-"), label: (_c = opt.label) !== null && _c !== void 0 ? _c : "" };
52
52
  })
53
53
  : [];
54
54
  return (_jsx(ProjectMenuClient, { projects: projects, schema: schema, filterOptions: filterOptions, filterFieldKey: (_c = filterField === null || filterField === void 0 ? void 0 : filterField.key) !== null && _c !== void 0 ? _c : null, filterFieldName: (_d = filterField === null || filterField === void 0 ? void 0 : filterField.name) !== null && _d !== void 0 ? _d : "Project Type", fieldOptionsMap: fieldOptionsMap, subtitle: subtitle, basePath: basePath, viewAllPath: viewAllPath !== null && viewAllPath !== void 0 ? viewAllPath : basePath, font: font, maxProjects: maxProjects }));
package/dist/types.d.ts CHANGED
@@ -37,8 +37,6 @@ export interface Project {
37
37
  image_url: string | null;
38
38
  is_featured: boolean;
39
39
  is_published?: boolean;
40
- /** Completion or project year when provided by the API */
41
- year?: number | string | null;
42
40
  custom_field_values: Record<string, CustomFieldValue>;
43
41
  created_at: string;
44
42
  updated_at: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,UAAU,CAAA;IAChE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAA;CACpE;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,aAAa,GAAG,IAAI,CAAA;AAEhF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAC7B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACrD,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,KAAK,EAAE,CAAA;CACf"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,UAAU,CAAA;IAChE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAA;CACpE;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,aAAa,GAAG,IAAI,CAAA;AAEhF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACrD,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,KAAK,EAAE,CAAA;CACf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-portfolio",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Self-contained project portfolio components for Next.js App Router. Includes ProjectPortfolio, ProjectDetail, ProjectMenu (megamenu), and GalleryCarousel. Pass a clientSlug and apiBase — done.",
5
5
  "keywords": ["nextjs", "react", "portfolio", "projects", "megamenu", "gallery"],
6
6
  "license": "MIT",