Initial monorepo: shared package and DBIS, ICCC, OMNL, XOM portals

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-13 10:27:01 -08:00
parent 0cd7701e93
commit f5e217efcd
240 changed files with 8161 additions and 0 deletions

View 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"
]
}

View 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",
},
};

View 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
View 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;
}

View 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;

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}