feat: complete Phase 1 foundation scaffold
Some checks failed
CI / Lint (push) Has been cancelled
CI / TypeCheck (push) Has been cancelled
CI / Test (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/api/Dockerfile name:api]) (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/cms/Dockerfile name:cms]) (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/web/Dockerfile name:web]) (push) Has been cancelled
CI / Build (push) Has been cancelled
Deploy / Deploy (push) Has been cancelled
Some checks failed
CI / Lint (push) Has been cancelled
CI / TypeCheck (push) Has been cancelled
CI / Test (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/api/Dockerfile name:api]) (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/cms/Dockerfile name:cms]) (push) Has been cancelled
Deploy / Docker Build & Push (map[context:. dockerfile:apps/web/Dockerfile name:web]) (push) Has been cancelled
CI / Build (push) Has been cancelled
Deploy / Deploy (push) Has been cancelled
- Monorepo: Turborepo + pnpm workspaces with 7 apps/packages - Backend: NestJS scaffold with 9 modules (auth, tenant, curriculum, simulation, portfolio, ai-coach, analytics, classroom, gamification) - Frontend: React 18 + Vite + TailwindCSS + shadcn/ui with 10 pages, 14 UI primitives, 3 Zustand stores - Database: Prisma schema with 19 models, 13 enums, seed script, multi-tenant ready - Docker: Dev, production, and Portainer Compose files with Traefik reverse proxy - Configuration: .env.example (47 vars), Zod validation, frontend-safe env exposure - i18n: English + Greek locale files (10 files), ICU MessageFormat, react-i18next - Shared packages: @investplay/types, @investplay/ui, @investplay/i18n, @investplay/utils - CI/CD: GitHub Actions (lint, typecheck, test, build, deploy, PR checks) - Documentation: CONTEXT.md, ARCHITECTURE.md (10 Mermaid diagrams), API.md, LOCALIZATION.md, DEVELOPMENT-ROADMAP.md - Infrastructure: Dockerfiles (dev + prod), nginx configs, backup/healthcheck scripts - Security: JWT auth guards, role-based access, rate limiting, Helmet, CORS, PII sanitization
This commit is contained in:
41
packages/ui/package.json
Normal file
41
packages/ui/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@investplay/ui",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "InvestPlay shared UI component library",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint \"src/**/*.{ts,tsx}\" --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rimraf .turbo"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.0",
|
||||
"react-dom": "^18.3.0",
|
||||
"tailwindcss": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.0",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"@radix-ui/react-dialog": "^1.1.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.0",
|
||||
"@radix-ui/react-tabs": "^1.1.0",
|
||||
"@radix-ui/react-tooltip": "^1.1.0",
|
||||
"@radix-ui/react-popover": "^1.1.0",
|
||||
"@radix-ui/react-select": "^2.1.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-toast": "^1.2.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-avatar": "^1.1.0",
|
||||
"lucide-react": "^0.490.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.3.0",
|
||||
"react-dom": "^18.3.0",
|
||||
"typescript": "^5.8.0",
|
||||
"eslint": "^8.57.0",
|
||||
"rimraf": "^6.0.0"
|
||||
}
|
||||
}
|
||||
1
packages/ui/src/index.ts
Normal file
1
packages/ui/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { cn, formatCurrency, formatXP, formatPercentage } from "./lib/utils.js";
|
||||
50
packages/ui/src/lib/utils.ts
Normal file
50
packages/ui/src/lib/utils.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]): string {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function formatCurrency(
|
||||
amount: number,
|
||||
currency = "EUR",
|
||||
locale = "en",
|
||||
): string {
|
||||
try {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: "currency",
|
||||
currency,
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(amount);
|
||||
} catch {
|
||||
return `${currency} ${amount.toFixed(2)}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatXP(xp: number, locale = "en"): string {
|
||||
try {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
notation: "compact",
|
||||
maximumFractionDigits: 1,
|
||||
}).format(xp);
|
||||
} catch {
|
||||
return `${xp}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatPercentage(
|
||||
value: number,
|
||||
locale = "en",
|
||||
decimals = 1,
|
||||
): string {
|
||||
try {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: "percent",
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals,
|
||||
}).format(value / 100);
|
||||
} catch {
|
||||
return `${value.toFixed(decimals)}%`;
|
||||
}
|
||||
}
|
||||
12
packages/ui/tsconfig.json
Normal file
12
packages/ui/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext"
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "dist", ".turbo"]
|
||||
}
|
||||
Reference in New Issue
Block a user