@chiselandco/nexus 2.2.6 → 2.5.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.
- package/README.md +286 -298
- package/dist/FilterSidebar.d.ts +20 -0
- package/dist/FilterSidebar.d.ts.map +1 -0
- package/dist/FilterSidebar.js +266 -0
- package/dist/FilteredPortfolio.d.ts +45 -0
- package/dist/FilteredPortfolio.d.ts.map +1 -0
- package/dist/FilteredPortfolio.js +134 -0
- package/dist/GalleryCarousel.d.ts +9 -2
- package/dist/GalleryCarousel.d.ts.map +1 -1
- package/dist/GalleryCarousel.js +363 -63
- package/dist/ProjectDetail.d.ts +3 -1
- package/dist/ProjectDetail.d.ts.map +1 -1
- package/dist/ProjectDetail.js +46 -20
- package/dist/ProjectMenu.d.ts +9 -4
- package/dist/ProjectMenu.d.ts.map +1 -1
- package/dist/ProjectMenu.js +13 -17
- package/dist/ProjectMenuClient.d.ts +4 -2
- package/dist/ProjectMenuClient.d.ts.map +1 -1
- package/dist/ProjectMenuClient.js +6 -7
- package/dist/ProjectPortfolio.d.ts +4 -2
- package/dist/ProjectPortfolio.d.ts.map +1 -1
- package/dist/ProjectPortfolio.js +5 -5
- package/dist/ProjectPortfolioClient.d.ts +3 -1
- package/dist/ProjectPortfolioClient.d.ts.map +1 -1
- package/dist/ProjectPortfolioClient.js +4 -6
- package/dist/SimilarProjects.d.ts +3 -1
- package/dist/SimilarProjects.d.ts.map +1 -1
- package/dist/SimilarProjects.js +11 -9
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -6
- package/dist/ProjectFilters.d.ts +0 -11
- package/dist/ProjectFilters.d.ts.map +0 -1
- package/dist/ProjectFilters.js +0 -49
- package/dist/ProjectGrid.d.ts +0 -10
- package/dist/ProjectGrid.d.ts.map +0 -1
- package/dist/ProjectGrid.js +0 -8
package/dist/ProjectMenu.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface ProjectMenuProps {
|
|
|
4
4
|
clientSlug: string;
|
|
5
5
|
/** API base URL e.g. "https://nexus.chiselandco.com" */
|
|
6
6
|
apiBase: string;
|
|
7
|
+
/** Client API key — pass via environment variable, never hardcode */
|
|
8
|
+
apiKey: string;
|
|
7
9
|
/**
|
|
8
10
|
* Optional menu ID to fetch a specific curated menu instead of all projects.
|
|
9
11
|
* When provided, fetches from /api/v1/clients/{clientSlug}/menus/{menuId}
|
|
@@ -41,7 +43,7 @@ export interface ProjectMenuProps {
|
|
|
41
43
|
*
|
|
42
44
|
* @example
|
|
43
45
|
* // app/api/chisel-menu/route.ts
|
|
44
|
-
* import { createMenuHandler } from "
|
|
46
|
+
* import { createMenuHandler } from "@chiselandco/nexus"
|
|
45
47
|
* export const GET = createMenuHandler({ clientSlug: "my-client", apiBase: "https://nexus.chiselandco.com" })
|
|
46
48
|
*
|
|
47
49
|
* // Bust the cache manually (one request):
|
|
@@ -51,16 +53,19 @@ export interface ProjectMenuProps {
|
|
|
51
53
|
* import { revalidateTag } from "next/cache"
|
|
52
54
|
* revalidateTag("chisel-menu-my-client")
|
|
53
55
|
*/
|
|
54
|
-
export declare function createMenuHandler({ clientSlug, apiBase, menuId, revalidate, }: {
|
|
56
|
+
export declare function createMenuHandler({ clientSlug, apiBase, apiKey, menuId, revalidate, }: {
|
|
55
57
|
clientSlug: string;
|
|
56
58
|
apiBase: string;
|
|
59
|
+
/** Client API key — pass via environment variable, never hardcode */
|
|
60
|
+
apiKey: string;
|
|
57
61
|
/** Optional menu ID to fetch a specific curated menu instead of all projects */
|
|
58
62
|
menuId?: string;
|
|
59
63
|
revalidate?: number;
|
|
60
64
|
}): (request: Request) => Promise<Response>;
|
|
61
|
-
export declare function fetchProjectMenuData({ apiBase, clientSlug, menuId, revalidate, noCache, }: {
|
|
65
|
+
export declare function fetchProjectMenuData({ apiBase, clientSlug, apiKey, menuId, revalidate, noCache, }: {
|
|
62
66
|
apiBase: string;
|
|
63
67
|
clientSlug: string;
|
|
68
|
+
apiKey: string;
|
|
64
69
|
menuId?: string;
|
|
65
70
|
revalidate?: number;
|
|
66
71
|
noCache?: boolean;
|
|
@@ -75,5 +80,5 @@ export declare function fetchProjectMenuData({ apiBase, clientSlug, menuId, reva
|
|
|
75
80
|
filterFieldName: string;
|
|
76
81
|
fieldOptionsMap: Record<string, Record<string, string>>;
|
|
77
82
|
}>;
|
|
78
|
-
export declare function ProjectMenu({ clientSlug, apiBase, menuId, basePath, viewAllPath, subtitle, font, maxProjects, revalidate, noCache, }: ProjectMenuProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
83
|
+
export declare function ProjectMenu({ clientSlug, apiBase, apiKey, menuId, basePath, viewAllPath, subtitle, font, maxProjects, revalidate, noCache, }: ProjectMenuProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
79
84
|
//# sourceMappingURL=ProjectMenu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectMenu.d.ts","sourceRoot":"","sources":["../src/ProjectMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"ProjectMenu.d.ts","sourceRoot":"","sources":["../src/ProjectMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAGzD,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,OAAO,EACP,MAAM,EACN,MAAM,EACN,UAAkB,GACnB,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,aACoC,OAAO,uBAmE3C;AAED,wBAAsB,oBAAoB,CAAC,EACzC,OAAO,EACP,UAAU,EACV,MAAM,EACN,MAAM,EACN,UAAkB,EAClB,OAAe,GAChB,EAAE;IACD,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,aAAa,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC9C,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACxD,CAAC,CAqBD;AAwDD,wBAAsB,WAAW,CAAC,EAChC,UAAU,EACV,OAAO,EACP,MAAM,EACN,MAAM,EACN,QAAsB,EACtB,WAAW,EACX,QAAQ,EACR,IAA0E,EAC1E,WAAe,EACf,UAAkB,EAClB,OAAe,GAChB,EAAE,gBAAgB,oDAiClB"}
|
package/dist/ProjectMenu.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cache } from "react";
|
|
3
3
|
import { ProjectMenuClient } from "./ProjectMenuClient";
|
|
4
|
-
const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
5
4
|
/**
|
|
6
5
|
* createMenuHandler
|
|
7
6
|
*
|
|
@@ -16,7 +15,7 @@ const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
|
16
15
|
*
|
|
17
16
|
* @example
|
|
18
17
|
* // app/api/chisel-menu/route.ts
|
|
19
|
-
* import { createMenuHandler } from "
|
|
18
|
+
* import { createMenuHandler } from "@chiselandco/nexus"
|
|
20
19
|
* export const GET = createMenuHandler({ clientSlug: "my-client", apiBase: "https://nexus.chiselandco.com" })
|
|
21
20
|
*
|
|
22
21
|
* // Bust the cache manually (one request):
|
|
@@ -26,7 +25,7 @@ const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
|
26
25
|
* import { revalidateTag } from "next/cache"
|
|
27
26
|
* revalidateTag("chisel-menu-my-client")
|
|
28
27
|
*/
|
|
29
|
-
export function createMenuHandler({ clientSlug, apiBase, menuId, revalidate = 86400, }) {
|
|
28
|
+
export function createMenuHandler({ clientSlug, apiBase, apiKey, menuId, revalidate = 86400, }) {
|
|
30
29
|
return async function GET(request) {
|
|
31
30
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
32
31
|
const bypass = process.env.CHISEL_CACHE_BYPASS === "true" ||
|
|
@@ -41,10 +40,10 @@ export function createMenuHandler({ clientSlug, apiBase, menuId, revalidate = 86
|
|
|
41
40
|
// Without menuId: 1 call — /projects for everything.
|
|
42
41
|
const fetches = menuId
|
|
43
42
|
? [
|
|
44
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${
|
|
45
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
43
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${apiKey}`, fetchOpts),
|
|
44
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts),
|
|
46
45
|
]
|
|
47
|
-
: [fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
46
|
+
: [fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts)];
|
|
48
47
|
const [primaryRes, schemaRes] = await Promise.all(fetches);
|
|
49
48
|
const primaryJson = primaryRes.ok ? await primaryRes.json() : {};
|
|
50
49
|
const schemaJson = schemaRes ? (schemaRes.ok ? await schemaRes.json() : {}) : primaryJson;
|
|
@@ -87,9 +86,9 @@ export function createMenuHandler({ clientSlug, apiBase, menuId, revalidate = 86
|
|
|
87
86
|
}
|
|
88
87
|
};
|
|
89
88
|
}
|
|
90
|
-
export async function fetchProjectMenuData({ apiBase, clientSlug, menuId, revalidate = 86400, noCache = false, }) {
|
|
89
|
+
export async function fetchProjectMenuData({ apiBase, clientSlug, apiKey, menuId, revalidate = 86400, noCache = false, }) {
|
|
91
90
|
var _a, _b, _c, _d;
|
|
92
|
-
const raw = await _fetchMenuData(apiBase, clientSlug, menuId, revalidate, noCache);
|
|
91
|
+
const raw = await _fetchMenuData(apiBase, clientSlug, apiKey, menuId, revalidate, noCache);
|
|
93
92
|
const filterField = (_a = raw.schema.find((f) => f.is_filterable && (f.type === "select" || f.type === "multi-select"))) !== null && _a !== void 0 ? _a : null;
|
|
94
93
|
const filterOptions = filterField
|
|
95
94
|
? ((_b = filterField.options) !== null && _b !== void 0 ? _b : []).map((opt) => {
|
|
@@ -109,21 +108,18 @@ export async function fetchProjectMenuData({ apiBase, clientSlug, menuId, revali
|
|
|
109
108
|
fieldOptionsMap: raw.fieldOptionsMap,
|
|
110
109
|
};
|
|
111
110
|
}
|
|
112
|
-
const _fetchMenuData = cache(async (apiBase, clientSlug, menuId, revalidate, noCache = false) => {
|
|
111
|
+
const _fetchMenuData = cache(async (apiBase, clientSlug, apiKey, menuId, revalidate, noCache = false) => {
|
|
113
112
|
var _a, _b, _c, _d, _e;
|
|
114
113
|
const fetchOpts = noCache
|
|
115
114
|
? { cache: "no-store" }
|
|
116
115
|
: { next: { revalidate } };
|
|
117
116
|
try {
|
|
118
|
-
// /projects always returns schema + options. Use it in both cases.
|
|
119
|
-
// When menuId provided: 2 calls — /menus/{slug} for projects, /projects for schema.
|
|
120
|
-
// Without menuId: 1 call — /projects for everything.
|
|
121
117
|
const fetches = menuId
|
|
122
118
|
? [
|
|
123
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${
|
|
124
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
119
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${apiKey}`, fetchOpts),
|
|
120
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts),
|
|
125
121
|
]
|
|
126
|
-
: [fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
122
|
+
: [fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts)];
|
|
127
123
|
const [primaryRes, schemaRes] = await Promise.all(fetches);
|
|
128
124
|
if (!primaryRes.ok)
|
|
129
125
|
return { projects: [], schema: [], fieldOptionsMap: {} };
|
|
@@ -151,9 +147,9 @@ const _fetchMenuData = cache(async (apiBase, clientSlug, menuId, revalidate, noC
|
|
|
151
147
|
return { projects: [], schema: [], fieldOptionsMap: {} };
|
|
152
148
|
}
|
|
153
149
|
});
|
|
154
|
-
export async function ProjectMenu({ clientSlug, apiBase, menuId, basePath = "/projects", viewAllPath, subtitle, font = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", maxProjects = 6, revalidate = 86400, noCache = false, }) {
|
|
150
|
+
export async function ProjectMenu({ clientSlug, apiBase, apiKey, menuId, basePath = "/projects", viewAllPath, subtitle, font = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", maxProjects = 6, revalidate = 86400, noCache = false, }) {
|
|
155
151
|
var _a, _b, _c, _d;
|
|
156
|
-
const { projects, schema, fieldOptionsMap } = await _fetchMenuData(apiBase, clientSlug, menuId, revalidate, noCache);
|
|
152
|
+
const { projects, schema, fieldOptionsMap } = await _fetchMenuData(apiBase, clientSlug, apiKey, menuId, revalidate, noCache);
|
|
157
153
|
// Find the filterable select field (badge_overlay is our category field)
|
|
158
154
|
const filterField = (_a = schema.find((f) => f.is_filterable && (f.type === "select" || f.type === "multi-select"))) !== null && _a !== void 0 ? _a : null;
|
|
159
155
|
// Build filter option list from schema
|
|
@@ -8,12 +8,14 @@ export interface ProjectMenuClientProps {
|
|
|
8
8
|
*/
|
|
9
9
|
dataUrl?: string;
|
|
10
10
|
/**
|
|
11
|
-
* Pass clientSlug + apiBase to have the component fetch its own data directly.
|
|
11
|
+
* Pass clientSlug + apiBase + apiKey to have the component fetch its own data directly.
|
|
12
12
|
* Use this for quick setup or non-Next.js environments.
|
|
13
13
|
* For production Next.js apps, prefer dataUrl + createMenuHandler instead.
|
|
14
14
|
*/
|
|
15
15
|
clientSlug?: string;
|
|
16
16
|
apiBase?: string;
|
|
17
|
+
/** Client API key — required when using clientSlug/apiBase direct-fetch mode */
|
|
18
|
+
apiKey?: string;
|
|
17
19
|
/**
|
|
18
20
|
* Optional menu slug to fetch a specific curated menu instead of all projects.
|
|
19
21
|
* When provided, fetches from /api/v1/clients/{clientSlug}/menus/{slug}
|
|
@@ -40,5 +42,5 @@ export interface ProjectMenuClientProps {
|
|
|
40
42
|
font?: string;
|
|
41
43
|
maxProjects?: number;
|
|
42
44
|
}
|
|
43
|
-
export declare function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCache, projects: projectsProp, schema: schemaProp, filterOptions: filterOptionsProp, filterFieldKey: filterFieldKeyProp, filterFieldName: filterFieldNameProp, fieldOptionsMap: fieldOptionsMapProp, subtitle, basePath, viewAllPath, font, maxProjects, }: ProjectMenuClientProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
export declare function ProjectMenuClient({ dataUrl, clientSlug, apiBase, apiKey, menuId, noCache, projects: projectsProp, schema: schemaProp, filterOptions: filterOptionsProp, filterFieldKey: filterFieldKeyProp, filterFieldName: filterFieldNameProp, fieldOptionsMap: fieldOptionsMapProp, subtitle, basePath, viewAllPath, font, maxProjects, }: ProjectMenuClientProps): import("react/jsx-runtime").JSX.Element;
|
|
44
46
|
//# sourceMappingURL=ProjectMenuClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectMenuClient.d.ts","sourceRoot":"","sources":["../src/ProjectMenuClient.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAoB,MAAM,SAAS,CAAA;AAa3E,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC5B,aAAa,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC/C,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;
|
|
1
|
+
{"version":3,"file":"ProjectMenuClient.d.ts","sourceRoot":"","sources":["../src/ProjectMenuClient.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAoB,MAAM,SAAS,CAAA;AAa3E,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC5B,aAAa,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC/C,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAkBD,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,UAAU,EACV,OAAO,EACP,MAAM,EACN,MAAM,EACN,OAAe,EACf,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,UAAU,EAClB,aAAa,EAAE,iBAAiB,EAChC,cAAc,EAAE,kBAAkB,EAClC,eAAe,EAAE,mBAAoC,EACrD,eAAe,EAAE,mBAAwB,EACzC,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,IAAmB,EACnB,WAAe,GAChB,EAAE,sBAAsB,2CAqfxB"}
|
|
@@ -14,10 +14,9 @@ function parseMultiValue(raw) {
|
|
|
14
14
|
return [];
|
|
15
15
|
}
|
|
16
16
|
const ACCENT = "oklch(0.78 0.16 85)";
|
|
17
|
-
const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
18
17
|
const DEFAULT_FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
19
18
|
const menuDataCache = new Map();
|
|
20
|
-
export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCache = false, projects: projectsProp, schema: schemaProp, filterOptions: filterOptionsProp, filterFieldKey: filterFieldKeyProp, filterFieldName: filterFieldNameProp = "Project Type", fieldOptionsMap: fieldOptionsMapProp = {}, subtitle, basePath, viewAllPath, font = DEFAULT_FONT, maxProjects = 6, }) {
|
|
19
|
+
export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, apiKey, menuId, noCache = false, projects: projectsProp, schema: schemaProp, filterOptions: filterOptionsProp, filterFieldKey: filterFieldKeyProp, filterFieldName: filterFieldNameProp = "Project Type", fieldOptionsMap: fieldOptionsMapProp = {}, subtitle, basePath, viewAllPath, font = DEFAULT_FONT, maxProjects = 6, }) {
|
|
21
20
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
22
21
|
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
23
22
|
const [hoveredCard, setHoveredCard] = useState(null);
|
|
@@ -32,7 +31,7 @@ export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCach
|
|
|
32
31
|
return;
|
|
33
32
|
let cancelled = false;
|
|
34
33
|
const fetchOpts = noCache ? { cache: "no-store" } : {};
|
|
35
|
-
const cacheKey = dataUrl !== null && dataUrl !== void 0 ? dataUrl : `${clientSlug}:${apiBase}:${menuId !== null && menuId !== void 0 ? menuId : "all"}`;
|
|
34
|
+
const cacheKey = dataUrl !== null && dataUrl !== void 0 ? dataUrl : `${clientSlug}:${apiBase}:${apiKey}:${menuId !== null && menuId !== void 0 ? menuId : "all"}`;
|
|
36
35
|
async function fetchAndCache() {
|
|
37
36
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
38
37
|
// dataUrl mode: fetch from local API route (server-cached, no API key exposed)
|
|
@@ -51,8 +50,8 @@ export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCach
|
|
|
51
50
|
// Menu endpoint mode: /menus/{slug} for projects, /projects for schema+options.
|
|
52
51
|
if (menuId) {
|
|
53
52
|
const [menuRes, projectsRes] = await Promise.all([
|
|
54
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${
|
|
55
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
53
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/menus/${menuId}?api_key=${apiKey}`, fetchOpts),
|
|
54
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts),
|
|
56
55
|
]);
|
|
57
56
|
const menuJson = menuRes.ok ? await menuRes.json() : {};
|
|
58
57
|
const projectsJson = projectsRes.ok ? await projectsRes.json() : {};
|
|
@@ -88,7 +87,7 @@ export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCach
|
|
|
88
87
|
};
|
|
89
88
|
}
|
|
90
89
|
// Direct fetch mode — single call, /projects returns everything.
|
|
91
|
-
const res = await fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
90
|
+
const res = await fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts);
|
|
92
91
|
const json = res.ok ? await res.json() : {};
|
|
93
92
|
const projects = ((_q = json === null || json === void 0 ? void 0 : json.data) !== null && _q !== void 0 ? _q : []).filter((p) => p.is_published !== false);
|
|
94
93
|
const schema = (_s = (_r = json === null || json === void 0 ? void 0 : json.client) === null || _r === void 0 ? void 0 : _r.custom_fields_schema) !== null && _s !== void 0 ? _s : [];
|
|
@@ -135,7 +134,7 @@ export function ProjectMenuClient({ dataUrl, clientSlug, apiBase, menuId, noCach
|
|
|
135
134
|
// silently fail — render nothing
|
|
136
135
|
});
|
|
137
136
|
return () => { cancelled = true; };
|
|
138
|
-
}, [dataUrl, clientSlug, apiBase, menuId, noCache]);
|
|
137
|
+
}, [dataUrl, clientSlug, apiBase, apiKey, menuId, noCache]);
|
|
139
138
|
// Resolve data: prefer self-fetched, fall back to props
|
|
140
139
|
const projects = (_b = (_a = fetched === null || fetched === void 0 ? void 0 : fetched.projects) !== null && _a !== void 0 ? _a : projectsProp) !== null && _b !== void 0 ? _b : [];
|
|
141
140
|
const schema = (_d = (_c = fetched === null || fetched === void 0 ? void 0 : fetched.schema) !== null && _c !== void 0 ? _c : schemaProp) !== null && _d !== void 0 ? _d : [];
|
|
@@ -3,6 +3,8 @@ export interface ProjectPortfolioProps {
|
|
|
3
3
|
clientSlug: string;
|
|
4
4
|
/** Base URL of the projects API */
|
|
5
5
|
apiBase: string;
|
|
6
|
+
/** Client API key — pass via environment variable, never hardcode */
|
|
7
|
+
apiKey: string;
|
|
6
8
|
/** Base path for project detail links. Defaults to "/projects" */
|
|
7
9
|
basePath?: string;
|
|
8
10
|
/**
|
|
@@ -31,12 +33,12 @@ export interface ProjectPortfolioProps {
|
|
|
31
33
|
* - Production: next.revalidate caches across requests for `revalidate` seconds
|
|
32
34
|
*
|
|
33
35
|
* Usage:
|
|
34
|
-
* import { ProjectPortfolio } from "
|
|
36
|
+
* import { ProjectPortfolio } from "@chiselandco/nexus"
|
|
35
37
|
*
|
|
36
38
|
* <ProjectPortfolio
|
|
37
39
|
* clientSlug="my-client"
|
|
38
40
|
* apiBase="https://your-api.com"
|
|
39
41
|
* />
|
|
40
42
|
*/
|
|
41
|
-
export declare function ProjectPortfolio({ clientSlug, apiBase, basePath, searchParams, revalidate, noCache, }: ProjectPortfolioProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
43
|
+
export declare function ProjectPortfolio({ clientSlug, apiBase, apiKey, basePath, searchParams, revalidate, noCache, }: ProjectPortfolioProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
42
44
|
//# sourceMappingURL=ProjectPortfolio.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectPortfolio.d.ts","sourceRoot":"","sources":["../src/ProjectPortfolio.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IAC5D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;
|
|
1
|
+
{"version":3,"file":"ProjectPortfolio.d.ts","sourceRoot":"","sources":["../src/ProjectPortfolio.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IAC5D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AA0ED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,OAAO,EACP,MAAM,EACN,QAAsB,EACtB,YAAiB,EACjB,UAAe,EACf,OAAe,GAChB,EAAE,qBAAqB,oDA+HvB"}
|
package/dist/ProjectPortfolio.js
CHANGED
|
@@ -6,14 +6,14 @@ import { ProjectCard } from "./ProjectCard";
|
|
|
6
6
|
// If this component appears twice on one page, the API is only hit once.
|
|
7
7
|
// 2. next: { revalidate } — Next.js Data Cache, caches across multiple requests
|
|
8
8
|
// on production deployments. Silently ignored in preview/local.
|
|
9
|
-
const fetchPortfolioData = cache(async (apiBase, clientSlug, revalidate, filtersKey = "{}", noCache = false) => {
|
|
9
|
+
const fetchPortfolioData = cache(async (apiBase, clientSlug, apiKey, revalidate, filtersKey = "{}", noCache = false) => {
|
|
10
10
|
var _a, _b, _c, _d, _e, _f;
|
|
11
11
|
const fetchOpts = noCache
|
|
12
12
|
? { cache: "no-store" }
|
|
13
13
|
: { next: { revalidate } };
|
|
14
14
|
// Build URL with filter[key]=value as required by the API
|
|
15
15
|
const filters = JSON.parse(filtersKey);
|
|
16
|
-
const params = new URLSearchParams({ api_key:
|
|
16
|
+
const params = new URLSearchParams({ api_key: apiKey });
|
|
17
17
|
Object.entries(filters).forEach(([key, val]) => {
|
|
18
18
|
if (val)
|
|
19
19
|
params.append(`filter[${key}]`, val);
|
|
@@ -58,14 +58,14 @@ const fetchPortfolioData = cache(async (apiBase, clientSlug, revalidate, filters
|
|
|
58
58
|
* - Production: next.revalidate caches across requests for `revalidate` seconds
|
|
59
59
|
*
|
|
60
60
|
* Usage:
|
|
61
|
-
* import { ProjectPortfolio } from "
|
|
61
|
+
* import { ProjectPortfolio } from "@chiselandco/nexus"
|
|
62
62
|
*
|
|
63
63
|
* <ProjectPortfolio
|
|
64
64
|
* clientSlug="my-client"
|
|
65
65
|
* apiBase="https://your-api.com"
|
|
66
66
|
* />
|
|
67
67
|
*/
|
|
68
|
-
export async function ProjectPortfolio({ clientSlug, apiBase, basePath = "/projects", searchParams = {}, revalidate = 60, noCache = false, }) {
|
|
68
|
+
export async function ProjectPortfolio({ clientSlug, apiBase, apiKey, basePath = "/projects", searchParams = {}, revalidate = 60, noCache = false, }) {
|
|
69
69
|
// Parse filter[key]=value from searchParams into { key: value }
|
|
70
70
|
const filters = {};
|
|
71
71
|
Object.entries(searchParams).forEach(([key, val]) => {
|
|
@@ -76,7 +76,7 @@ export async function ProjectPortfolio({ clientSlug, apiBase, basePath = "/proje
|
|
|
76
76
|
filters[match[1]] = Array.isArray(val) ? val[0] : val;
|
|
77
77
|
});
|
|
78
78
|
const filtersKey = JSON.stringify(filters);
|
|
79
|
-
const { projects, schema, fieldOptionsMap } = await fetchPortfolioData(apiBase, clientSlug, revalidate, filtersKey, noCache);
|
|
79
|
+
const { projects, schema, fieldOptionsMap } = await fetchPortfolioData(apiBase, clientSlug, apiKey, revalidate, filtersKey, noCache);
|
|
80
80
|
const hasFilters = Object.keys(filters).length > 0;
|
|
81
81
|
const activeFilterLabels = Object.entries(filters)
|
|
82
82
|
.map(([key, val]) => {
|
|
@@ -3,6 +3,8 @@ export interface ProjectPortfolioClientProps {
|
|
|
3
3
|
clientSlug: string;
|
|
4
4
|
/** Base URL of the projects API */
|
|
5
5
|
apiBase: string;
|
|
6
|
+
/** Client API key — pass via environment variable, never hardcode */
|
|
7
|
+
apiKey: string;
|
|
6
8
|
/** Base path for project detail links. Defaults to "/projects" */
|
|
7
9
|
basePath?: string;
|
|
8
10
|
/**
|
|
@@ -17,5 +19,5 @@ export interface ProjectPortfolioClientProps {
|
|
|
17
19
|
/** Max columns in the grid. 2 or 3. Defaults to 3 */
|
|
18
20
|
columns?: 2 | 3;
|
|
19
21
|
}
|
|
20
|
-
export declare function ProjectPortfolioClient({ clientSlug, apiBase, basePath, filters, font, columns, }: ProjectPortfolioClientProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function ProjectPortfolioClient({ clientSlug, apiBase, apiKey, basePath, filters, font, columns, }: ProjectPortfolioClientProps): import("react/jsx-runtime").JSX.Element;
|
|
21
23
|
//# sourceMappingURL=ProjectPortfolioClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectPortfolioClient.d.ts","sourceRoot":"","sources":["../src/ProjectPortfolioClient.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,2BAA2B;IAC1C,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CAChB;
|
|
1
|
+
{"version":3,"file":"ProjectPortfolioClient.d.ts","sourceRoot":"","sources":["../src/ProjectPortfolioClient.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,2BAA2B;IAC1C,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CAChB;AAyDD,wBAAgB,sBAAsB,CAAC,EACrC,UAAU,EACV,OAAO,EACP,MAAM,EACN,QAAsB,EACtB,OAAY,EACZ,IAAmB,EACnB,OAAW,GACZ,EAAE,2BAA2B,2CAmJ7B"}
|
|
@@ -3,7 +3,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useEffect, useMemo } from "react";
|
|
4
4
|
import { ProjectCard } from "./ProjectCard";
|
|
5
5
|
const portfolioDataCache = new Map();
|
|
6
|
-
const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
7
6
|
const DEFAULT_FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
8
7
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
9
8
|
function parseMultiValue(raw) {
|
|
@@ -40,16 +39,15 @@ function matchesFilters(project, filters, schema, fieldOptionsMap) {
|
|
|
40
39
|
});
|
|
41
40
|
}
|
|
42
41
|
// ─── Component ───────────────────────────────────────────────────────────────
|
|
43
|
-
export function ProjectPortfolioClient({ clientSlug, apiBase, basePath = "/projects", filters = {}, font = DEFAULT_FONT, columns = 3, }) {
|
|
42
|
+
export function ProjectPortfolioClient({ clientSlug, apiBase, apiKey, basePath = "/projects", filters = {}, font = DEFAULT_FONT, columns = 3, }) {
|
|
44
43
|
const [data, setData] = useState(null);
|
|
45
|
-
// Self-fetch on mount — uses module-level cache so the API is only called once per page load
|
|
46
44
|
useEffect(() => {
|
|
47
|
-
const cacheKey = `${clientSlug}:${apiBase}`;
|
|
45
|
+
const cacheKey = `${clientSlug}:${apiBase}:${apiKey}`;
|
|
48
46
|
async function fetchAndCache() {
|
|
49
47
|
var _a, _b, _c, _d, _e;
|
|
50
48
|
const [projectsRes, fieldsRes] = await Promise.all([
|
|
51
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${
|
|
52
|
-
fetch(`${apiBase}/api/v1/clients/${clientSlug}/fields?api_key=${
|
|
49
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`),
|
|
50
|
+
fetch(`${apiBase}/api/v1/clients/${clientSlug}/fields?api_key=${apiKey}`),
|
|
53
51
|
]);
|
|
54
52
|
const json = projectsRes.ok ? await projectsRes.json() : {};
|
|
55
53
|
const projects = ((_a = json === null || json === void 0 ? void 0 : json.data) !== null && _a !== void 0 ? _a : []).filter((p) => p.is_published !== false);
|
|
@@ -14,6 +14,8 @@ export interface SimilarProjectsProps {
|
|
|
14
14
|
clientSlug: string;
|
|
15
15
|
/** Base URL of the projects API */
|
|
16
16
|
apiBase: string;
|
|
17
|
+
/** Client API key — pass via environment variable, never hardcode */
|
|
18
|
+
apiKey: string;
|
|
17
19
|
/** Base path used to build individual project detail URLs e.g. "/projects" */
|
|
18
20
|
basePath?: string;
|
|
19
21
|
/** Maximum number of projects to show. Defaults to 3 */
|
|
@@ -42,5 +44,5 @@ export interface SimilarProjectsProps {
|
|
|
42
44
|
/** Small label above the heading. Defaults to "More Work" */
|
|
43
45
|
subtitle?: string;
|
|
44
46
|
}
|
|
45
|
-
export declare function SimilarProjects({ filters, excludeSlug, clientSlug, apiBase, basePath, maxItems, revalidate, noCache, variant, projectSlugs, title, subtitle, }: SimilarProjectsProps): Promise<import("react/jsx-runtime").JSX.Element | null>;
|
|
47
|
+
export declare function SimilarProjects({ filters, excludeSlug, clientSlug, apiBase, apiKey, basePath, maxItems, revalidate, noCache, variant, projectSlugs, title, subtitle, }: SimilarProjectsProps): Promise<import("react/jsx-runtime").JSX.Element | null>;
|
|
46
48
|
//# sourceMappingURL=SimilarProjects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SimilarProjects.d.ts","sourceRoot":"","sources":["../src/SimilarProjects.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SimilarProjects.d.ts","sourceRoot":"","sources":["../src/SimilarProjects.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AA6DD,wBAAsB,eAAe,CAAC,EACpC,OAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,MAAM,EACN,QAAsB,EACtB,QAAY,EACZ,UAAe,EACf,OAAe,EACf,OAAgB,EAChB,YAAY,EACZ,KAA0B,EAC1B,QAAsB,GACvB,EAAE,oBAAoB,2DAoKtB"}
|
package/dist/SimilarProjects.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cache } from "react";
|
|
3
2
|
import { ProjectCard } from "./ProjectCard";
|
|
4
3
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
5
4
|
function parseMultiValue(raw) {
|
|
@@ -19,17 +18,16 @@ function dedupeByKey(arr) {
|
|
|
19
18
|
});
|
|
20
19
|
}
|
|
21
20
|
// ─── Data fetching ────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
21
|
+
async function fetchSimilarData(apiBase, clientSlug, apiKey, revalidate, noCache) {
|
|
23
22
|
var _a, _b, _c, _d;
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
24
|
const fetchOpts = noCache
|
|
25
25
|
? { cache: "no-store" }
|
|
26
26
|
: revalidate > 0
|
|
27
27
|
? { next: { revalidate } }
|
|
28
28
|
: {};
|
|
29
|
-
const API_KEY = "pk_live_crmsuTIm7NNfb9uEWBCyv88F6kj2YQUR";
|
|
30
29
|
try {
|
|
31
|
-
|
|
32
|
-
const res = await fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${API_KEY}`, fetchOpts);
|
|
30
|
+
const res = await fetch(`${apiBase}/api/v1/clients/${clientSlug}/projects?api_key=${apiKey}`, fetchOpts);
|
|
33
31
|
const json = res.ok ? await res.json() : null;
|
|
34
32
|
const allProjects = ((_a = json === null || json === void 0 ? void 0 : json.data) !== null && _a !== void 0 ? _a : []).filter((p) => p.is_published !== false);
|
|
35
33
|
const schema = dedupeByKey((_c = (_b = json === null || json === void 0 ? void 0 : json.client) === null || _b === void 0 ? void 0 : _b.custom_fields_schema) !== null && _c !== void 0 ? _c : []);
|
|
@@ -49,10 +47,10 @@ const fetchSimilarData = cache(async (apiBase, clientSlug, revalidate, noCache)
|
|
|
49
47
|
catch (_e) {
|
|
50
48
|
return { allProjects: [], schema: [], fieldOptionsMap: {} };
|
|
51
49
|
}
|
|
52
|
-
}
|
|
50
|
+
}
|
|
53
51
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
54
|
-
export async function SimilarProjects({ filters = {}, excludeSlug, clientSlug, apiBase, basePath = "/projects", maxItems = 3, revalidate = 60, noCache = false, variant = "list", projectSlugs, title = "Similar Projects", subtitle = "More Work", }) {
|
|
55
|
-
const { allProjects, schema, fieldOptionsMap } = await fetchSimilarData(apiBase, clientSlug, revalidate, noCache);
|
|
52
|
+
export async function SimilarProjects({ filters = {}, excludeSlug, clientSlug, apiBase, apiKey, basePath = "/projects", maxItems = 3, revalidate = 60, noCache = false, variant = "list", projectSlugs, title = "Similar Projects", subtitle = "More Work", }) {
|
|
53
|
+
const { allProjects, schema, fieldOptionsMap } = await fetchSimilarData(apiBase, clientSlug, apiKey, revalidate, noCache);
|
|
56
54
|
const badgeField = schema.find((f) => f.display_position === "badge_overlay");
|
|
57
55
|
const locationField = schema.find((f) => f.type === "location");
|
|
58
56
|
const font = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
@@ -67,12 +65,16 @@ export async function SimilarProjects({ filters = {}, excludeSlug, clientSlug, a
|
|
|
67
65
|
.slice(0, maxItems);
|
|
68
66
|
}
|
|
69
67
|
else {
|
|
70
|
-
// Filter mode — match by custom field values
|
|
68
|
+
// Filter mode — match by custom field values.
|
|
69
|
+
// clientSlug guard is the hard wall: only projects belonging to this exact client
|
|
70
|
+
// are ever eligible regardless of what the API returns.
|
|
71
71
|
const filterEntries = Object.entries(filters);
|
|
72
72
|
similar = allProjects
|
|
73
73
|
.filter((p) => {
|
|
74
74
|
if (excludeSlug && p.slug === excludeSlug)
|
|
75
75
|
return false;
|
|
76
|
+
if (filterEntries.length === 0)
|
|
77
|
+
return true;
|
|
76
78
|
return filterEntries.every(([key, value]) => {
|
|
77
79
|
const fieldValues = parseMultiValue(p.custom_field_values[key]);
|
|
78
80
|
return fieldValues.some((v) => v.toLowerCase() === value.toLowerCase());
|
package/dist/index.d.ts
CHANGED
|
@@ -14,5 +14,9 @@ export { ProjectMenuClient } from "./ProjectMenuClient";
|
|
|
14
14
|
export type { ProjectMenuClientProps } from "./ProjectMenuClient";
|
|
15
15
|
export { ProjectCard } from "./ProjectCard";
|
|
16
16
|
export type { CardVariant } from "./ProjectCard";
|
|
17
|
+
export { FilterSidebar } from "./FilterSidebar";
|
|
18
|
+
export type { FilterSidebarProps } from "./FilterSidebar";
|
|
19
|
+
export { FilteredPortfolio } from "./FilteredPortfolio";
|
|
20
|
+
export type { FilteredPortfolioProps } from "./FilteredPortfolio";
|
|
17
21
|
export type { Project, CustomFieldSchema, CustomFieldValue, LocationValue, Media, } from "./types";
|
|
18
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,YAAY,EACV,OAAO,EACP,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,KAAK,GACN,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,YAAY,EACV,OAAO,EACP,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,KAAK,GACN,MAAM,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -6,3 +6,5 @@ export { GalleryCarousel } from "./GalleryCarousel";
|
|
|
6
6
|
export { ProjectMenu, fetchProjectMenuData, createMenuHandler } from "./ProjectMenu";
|
|
7
7
|
export { ProjectMenuClient } from "./ProjectMenuClient";
|
|
8
8
|
export { ProjectCard } from "./ProjectCard";
|
|
9
|
+
export { FilterSidebar } from "./FilterSidebar";
|
|
10
|
+
export { FilteredPortfolio } from "./FilteredPortfolio";
|
package/dist/types.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface Media {
|
|
|
22
22
|
description?: string | null;
|
|
23
23
|
is_primary: boolean;
|
|
24
24
|
sort_order: number;
|
|
25
|
+
/** Per-image custom field values — keys are field keys, values are slugs or arrays of slugs */
|
|
26
|
+
custom_field_values?: Record<string, string | string[] | null>;
|
|
25
27
|
}
|
|
26
28
|
export interface LocationValue {
|
|
27
29
|
city?: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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;IAClB,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;CAC/D;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,11 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chiselandco/nexus",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
},
|
|
7
|
-
"description": "Self-contained project portfolio components for Next.js App Router. Includes ProjectPortfolio, ProjectPortfolioClient (with built-in filtering), ProjectDetail, SimilarProjects, ProjectMenu, ProjectMenuClient, and GalleryCarousel. Pass a clientSlug and apiBase — done.",
|
|
8
|
-
"keywords": ["nextjs", "react", "portfolio", "projects", "megamenu", "gallery", "filtering"],
|
|
3
|
+
"version": "2.5.0",
|
|
4
|
+
"description": "Self-contained project portfolio components for Next.js App Router. Includes ProjectPortfolio, ProjectPortfolioClient, ProjectDetail, SimilarProjects, ProjectMenu, ProjectMenuClient, GalleryCarousel, FilterSidebar, and FilteredPortfolio. Pass a clientSlug and apiBase — done.",
|
|
5
|
+
"keywords": ["nextjs", "react", "portfolio", "projects", "megamenu", "gallery", "filtering", "chiselandco", "nexus"],
|
|
9
6
|
"license": "MIT",
|
|
10
7
|
"type": "module",
|
|
11
8
|
"main": "./dist/index.js",
|
|
@@ -30,6 +27,7 @@
|
|
|
30
27
|
"devDependencies": {
|
|
31
28
|
"@types/react": "^18.0.0",
|
|
32
29
|
"@types/react-dom": "^18.0.0",
|
|
30
|
+
"next": "^15.0.0",
|
|
33
31
|
"typescript": "^5.0.0"
|
|
34
32
|
}
|
|
35
33
|
}
|
package/dist/ProjectFilters.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { CustomFieldSchema } from "./types";
|
|
2
|
-
interface ProjectFiltersProps {
|
|
3
|
-
fields: CustomFieldSchema[];
|
|
4
|
-
filters: Record<string, string>;
|
|
5
|
-
onFilterChange: (key: string, value: string) => void;
|
|
6
|
-
onClearFilters: () => void;
|
|
7
|
-
hasActiveFilters: boolean;
|
|
8
|
-
}
|
|
9
|
-
export declare function ProjectFilters({ fields, filters, onFilterChange, onClearFilters, hasActiveFilters, }: ProjectFiltersProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
export {};
|
|
11
|
-
//# sourceMappingURL=ProjectFilters.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/ProjectFilters.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export function ProjectFilters({ fields, filters, onFilterChange, onClearFilters, hasActiveFilters, }) {
|
|
3
|
-
const deduped = fields.filter((f, i, arr) => arr.findIndex((x) => x.key === f.key) === i);
|
|
4
|
-
return (_jsxs("div", { style: {
|
|
5
|
-
marginBottom: "2rem",
|
|
6
|
-
paddingBottom: "2rem",
|
|
7
|
-
borderBottom: "1px solid #e4e4e7",
|
|
8
|
-
display: "flex",
|
|
9
|
-
flexWrap: "wrap",
|
|
10
|
-
alignItems: "flex-end",
|
|
11
|
-
gap: "1rem",
|
|
12
|
-
}, children: [deduped.map((field, fieldIndex) => {
|
|
13
|
-
if (field.type === "select" || field.type === "multi-select") {
|
|
14
|
-
return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [_jsx("label", { style: { fontSize: "13px", fontWeight: 500, color: "#71717a" }, children: field.name }), _jsxs("select", { value: filters[field.key] || "all", onChange: (e) => onFilterChange(field.key, e.target.value === "all" ? "" : e.target.value), style: {
|
|
15
|
-
width: "180px",
|
|
16
|
-
padding: "8px 12px",
|
|
17
|
-
border: "1px solid #e4e4e7",
|
|
18
|
-
borderRadius: "6px",
|
|
19
|
-
fontSize: "14px",
|
|
20
|
-
backgroundColor: "#fff",
|
|
21
|
-
color: "#18181b",
|
|
22
|
-
outline: "none",
|
|
23
|
-
cursor: "pointer",
|
|
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}`));
|
|
25
|
-
}
|
|
26
|
-
if (field.type === "text" || field.type === "location") {
|
|
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: {
|
|
28
|
-
width: "180px",
|
|
29
|
-
padding: "8px 12px",
|
|
30
|
-
border: "1px solid #e4e4e7",
|
|
31
|
-
borderRadius: "6px",
|
|
32
|
-
fontSize: "14px",
|
|
33
|
-
color: "#18181b",
|
|
34
|
-
outline: "none",
|
|
35
|
-
} })] }, `filter-${fieldIndex}-${field.key}`));
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}), hasActiveFilters && (_jsx("button", { onClick: onClearFilters, style: {
|
|
39
|
-
display: "flex",
|
|
40
|
-
alignItems: "center",
|
|
41
|
-
gap: "4px",
|
|
42
|
-
padding: "8px 12px",
|
|
43
|
-
background: "none",
|
|
44
|
-
border: "none",
|
|
45
|
-
fontSize: "14px",
|
|
46
|
-
color: "#71717a",
|
|
47
|
-
cursor: "pointer",
|
|
48
|
-
}, children: "\u00D7 Clear filters" }))] }));
|
|
49
|
-
}
|
package/dist/ProjectGrid.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Project, CustomFieldSchema } from "./types";
|
|
2
|
-
interface ProjectGridProps {
|
|
3
|
-
projects: Project[];
|
|
4
|
-
schema: CustomFieldSchema[];
|
|
5
|
-
/** Base path for project detail links. Defaults to "/projects" */
|
|
6
|
-
basePath?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function ProjectGrid({ projects, schema, basePath }: ProjectGridProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|
|
10
|
-
//# sourceMappingURL=ProjectGrid.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectGrid.d.ts","sourceRoot":"","sources":["../src/ProjectGrid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEzD,UAAU,gBAAgB;IACxB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAsB,EAAE,EAAE,gBAAgB,2CAsBzF"}
|
package/dist/ProjectGrid.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ProjectCard } from "./ProjectCard";
|
|
3
|
-
export function ProjectGrid({ projects, schema, basePath = "/projects" }) {
|
|
4
|
-
if (projects.length === 0) {
|
|
5
|
-
return (_jsx("div", { style: { textAlign: "center", padding: "4rem 0" }, children: _jsx("p", { style: { color: "#71717a" }, children: "No projects found." }) }));
|
|
6
|
-
}
|
|
7
|
-
return (_jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: "2rem" }, children: projects.map((project, index) => (_jsx(ProjectCard, { project: project, schema: schema, priority: index === 0, basePath: basePath }, project.id))) }));
|
|
8
|
-
}
|