Initial monorepo: shared package and DBIS, ICCC, OMNL, XOM portals
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
22
packages/shared/package.json
Normal file
22
packages/shared/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@public-web-portals/shared",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"import": "./src/index.ts",
|
||||
"require": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"files": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
54
packages/shared/src/design-tokens.ts
Normal file
54
packages/shared/src/design-tokens.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Design tokens for Tailwind. Merge this into each portal's tailwind.config.
|
||||
* TECH_STACK: shared design tokens (colors, spacing, typography).
|
||||
*/
|
||||
|
||||
export const designTokens = {
|
||||
colors: {
|
||||
primary: {
|
||||
50: "#eff6ff",
|
||||
100: "#dbeafe",
|
||||
200: "#bfdbfe",
|
||||
300: "#93c5fd",
|
||||
400: "#60a5fa",
|
||||
500: "#3b82f6",
|
||||
600: "#2563eb",
|
||||
700: "#1d4ed8",
|
||||
800: "#1e40af",
|
||||
900: "#1e3a8a",
|
||||
950: "#172554",
|
||||
},
|
||||
neutral: {
|
||||
50: "#fafafa",
|
||||
100: "#f4f4f5",
|
||||
200: "#e4e4e7",
|
||||
300: "#d4d4d8",
|
||||
400: "#a1a1aa",
|
||||
500: "#71717a",
|
||||
600: "#52525b",
|
||||
700: "#3f3f46",
|
||||
800: "#27272a",
|
||||
900: "#18181b",
|
||||
950: "#09090b",
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["var(--font-geist-sans)", "system-ui", "sans-serif"] as string[],
|
||||
mono: ["var(--font-geist-mono)", "monospace"] as string[],
|
||||
},
|
||||
fontSize: {
|
||||
xs: ["0.75rem", { lineHeight: "1rem" }],
|
||||
sm: ["0.875rem", { lineHeight: "1.25rem" }],
|
||||
base: ["1rem", { lineHeight: "1.5rem" }],
|
||||
lg: ["1.125rem", { lineHeight: "1.75rem" }],
|
||||
xl: ["1.25rem", { lineHeight: "1.75rem" }],
|
||||
"2xl": ["1.5rem", { lineHeight: "2rem" }],
|
||||
"3xl": ["1.875rem", { lineHeight: "2.25rem" }],
|
||||
"4xl": ["2.25rem", { lineHeight: "2.5rem" }],
|
||||
},
|
||||
spacing: {
|
||||
"18": "4.5rem",
|
||||
"88": "22rem",
|
||||
"128": "32rem",
|
||||
},
|
||||
};
|
||||
8
packages/shared/src/index.ts
Normal file
8
packages/shared/src/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export type { Role, User, Session, SessionOrNull } from "./types";
|
||||
export type { NavItem, PortalId } from "./nav";
|
||||
export {
|
||||
baseNavItems,
|
||||
getEntityNavAddons,
|
||||
getNavForPortal,
|
||||
} from "./nav";
|
||||
export { designTokens } from "./design-tokens";
|
||||
133
packages/shared/src/nav.ts
Normal file
133
packages/shared/src/nav.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Nav item type and base nav config for all portals.
|
||||
* PORTAL_NAVIGATION §2, §3, §5.
|
||||
*/
|
||||
|
||||
export interface NavItem {
|
||||
href: string;
|
||||
label: string;
|
||||
children?: NavItem[];
|
||||
}
|
||||
|
||||
export const baseNavItems: NavItem[] = [
|
||||
{
|
||||
label: "About",
|
||||
href: "/about",
|
||||
children: [
|
||||
{ label: "Mandate", href: "/about" },
|
||||
{ label: "Governance", href: "/governance" },
|
||||
{ label: "Leadership", href: "/leadership" },
|
||||
{ label: "Org Chart", href: "/org-chart" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Departments & Programs",
|
||||
href: "/departments",
|
||||
children: [
|
||||
{ label: "Departments", href: "/departments" },
|
||||
{ label: "Programs", href: "/programs" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Membership",
|
||||
href: "/membership",
|
||||
children: [
|
||||
{ label: "Accreditation", href: "/accreditation" },
|
||||
{ label: "Directory", href: "/membership" },
|
||||
{ label: "Digital ID", href: "/membership" },
|
||||
{ label: "Onboarding", href: "/apply" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Documents",
|
||||
href: "/documents",
|
||||
children: [
|
||||
{ label: "Standards", href: "/standards" },
|
||||
{ label: "Directives", href: "/documents" },
|
||||
],
|
||||
},
|
||||
{ label: "News & Publications", href: "/news" },
|
||||
{
|
||||
label: "Portals",
|
||||
href: "/submit",
|
||||
children: [
|
||||
{ label: "Submit", href: "/submit" },
|
||||
{ label: "Apply", href: "/apply" },
|
||||
{ label: "Report", href: "/report" },
|
||||
{ label: "Request", href: "/request" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Transparency",
|
||||
href: "/transparency",
|
||||
children: [
|
||||
{ label: "Audit", href: "/transparency/audit" },
|
||||
{ label: "Ethics", href: "/transparency/ethics" },
|
||||
{ label: "Whistleblower", href: "/transparency/whistleblower" },
|
||||
{ label: "Sanctions", href: "/transparency/sanctions" },
|
||||
{ label: "Data Protection", href: "/transparency/data-protection" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Contact",
|
||||
href: "/contact",
|
||||
children: [
|
||||
{ label: "General", href: "/contact" },
|
||||
{ label: "Regional Offices", href: "/regions" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export type PortalId = "DBIS" | "ICCC" | "OMNL" | "XOM";
|
||||
|
||||
/** Entity-specific nav add-ons per PORTAL_NAVIGATION §5 */
|
||||
export function getEntityNavAddons(portal: PortalId): NavItem[] {
|
||||
switch (portal) {
|
||||
case "DBIS":
|
||||
return [
|
||||
{ label: "Financial Bulletins", href: "/documents/bulletins" },
|
||||
{ label: "Monetary Operations", href: "/departments/monetary-operations" },
|
||||
];
|
||||
case "ICCC":
|
||||
return [
|
||||
{ label: "Case Law", href: "/case-law" },
|
||||
{ label: "Registry", href: "/registry" },
|
||||
{ label: "Chambers", href: "/chambers" },
|
||||
{ label: "Judgments", href: "/judgments" },
|
||||
];
|
||||
case "OMNL":
|
||||
return [
|
||||
{ label: "Programs & Impact", href: "/programs" },
|
||||
{ label: "Standards", href: "/documents/standards" },
|
||||
{ label: "Cyber Resilience", href: "/departments/cyber-resilience" },
|
||||
];
|
||||
case "XOM":
|
||||
return [
|
||||
{ label: "Programs & Impact", href: "/programs" },
|
||||
{ label: "Donors", href: "/donors" },
|
||||
{ label: "Get Involved", href: "/get-involved" },
|
||||
{ label: "Hospitaller Services", href: "/departments/hospitaller-services" },
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** Full nav for a portal: base + entity add-ons merged into Documents/Departments where relevant */
|
||||
export function getNavForPortal(portal: PortalId): NavItem[] {
|
||||
const addons = getEntityNavAddons(portal);
|
||||
const docAddons = addons.filter((a) => a.href.startsWith("/documents") || a.href.startsWith("/standards"));
|
||||
const deptAddons = addons.filter((a) => a.href.startsWith("/departments"));
|
||||
const restAddons = addons.filter(
|
||||
(a) => !a.href.startsWith("/documents") && !a.href.startsWith("/departments") && !a.href.startsWith("/standards")
|
||||
);
|
||||
|
||||
const result = baseNavItems.map((item) => {
|
||||
if (item.href === "/documents" && docAddons.length > 0)
|
||||
return { ...item, children: [...(item.children ?? []), ...docAddons] };
|
||||
if (item.label === "Departments & Programs" && deptAddons.length > 0)
|
||||
return { ...item, children: [...(item.children ?? []), ...deptAddons] };
|
||||
return { ...item, children: item.children ? [...item.children] : undefined };
|
||||
});
|
||||
return restAddons.length > 0 ? [...result, ...restAddons] : result;
|
||||
}
|
||||
28
packages/shared/src/types.ts
Normal file
28
packages/shared/src/types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Role and session types for RBAC across all portals.
|
||||
* Aligned with PORTAL_NAVIGATION §4.
|
||||
*/
|
||||
|
||||
export type Role =
|
||||
| "public"
|
||||
| "member"
|
||||
| "judge"
|
||||
| "clerk"
|
||||
| "diplomat"
|
||||
| "donor"
|
||||
| "staff"
|
||||
| "admin";
|
||||
|
||||
export interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string | null;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
user: User;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
export type SessionOrNull = Session | null;
|
||||
8
packages/shared/tsconfig.json
Normal file
8
packages/shared/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user