@lambda-development/erp-core 0.1.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/dist/App.d.ts +1 -0
- package/dist/api/client.d.ts +256 -0
- package/dist/assets/report-runtime.worker-DrBTCfV6.js +5 -0
- package/dist/assets/report-runtime.worker-DrBTCfV6.js.map +1 -0
- package/dist/bootstrap.d.ts +16 -0
- package/dist/components/auth/protected-route.d.ts +3 -0
- package/dist/components/chat/chat-provider.d.ts +62 -0
- package/dist/components/document/child-table-editor.d.ts +9 -0
- package/dist/components/document/document-actions.d.ts +14 -0
- package/dist/components/document/link-field.d.ts +9 -0
- package/dist/components/document/status-badge.d.ts +5 -0
- package/dist/components/layout/app-shell.d.ts +1 -0
- package/dist/components/layout/sidebar.d.ts +7 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/card.d.ts +10 -0
- package/dist/components/ui/date-range-presets.d.ts +9 -0
- package/dist/components/ui/hint-tooltip.d.ts +3 -0
- package/dist/components/ui/input.d.ts +9 -0
- package/dist/components/ui/language-select.d.ts +8 -0
- package/dist/components/ui/select.d.ts +15 -0
- package/dist/contexts/auth-context.d.ts +19 -0
- package/dist/hooks/use-base-currency.d.ts +7 -0
- package/dist/hooks/use-currencies.d.ts +10 -0
- package/dist/hooks/use-document-list.d.ts +16 -0
- package/dist/hooks/use-document.d.ts +14 -0
- package/dist/hooks/use-report.d.ts +139 -0
- package/dist/hooks/use-url-state.d.ts +23 -0
- package/dist/i18n/index.d.ts +15 -0
- package/dist/i18n/locales/de.json.d.ts +542 -0
- package/dist/i18n/locales/en.json.d.ts +602 -0
- package/dist/i18n/locales/fr.json.d.ts +542 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +6583 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/branding.d.ts +28 -0
- package/dist/lib/component-registry.d.ts +4 -0
- package/dist/lib/doctypes.d.ts +56 -0
- package/dist/lib/nav.d.ts +21 -0
- package/dist/lib/utils.d.ts +10 -0
- package/dist/main.d.ts +0 -0
- package/dist/pages/admin/settings.d.ts +1 -0
- package/dist/pages/admin/users.d.ts +1 -0
- package/dist/pages/chat.d.ts +1 -0
- package/dist/pages/dashboard.d.ts +1 -0
- package/dist/pages/demo.d.ts +6 -0
- package/dist/pages/documents/document-form.d.ts +2 -0
- package/dist/pages/documents/document-list.d.ts +1 -0
- package/dist/pages/login.d.ts +1 -0
- package/dist/pages/masters/master-form.d.ts +1 -0
- package/dist/pages/masters/master-list.d.ts +1 -0
- package/dist/pages/opening-balances.d.ts +1 -0
- package/dist/pages/reports/analytics.d.ts +1 -0
- package/dist/pages/reports/ap-aging.d.ts +1 -0
- package/dist/pages/reports/ar-aging.d.ts +1 -0
- package/dist/pages/reports/balance-sheet.d.ts +1 -0
- package/dist/pages/reports/general-ledger.d.ts +1 -0
- package/dist/pages/reports/profit-loss.d.ts +1 -0
- package/dist/pages/reports/stock-balance.d.ts +1 -0
- package/dist/pages/reports/trial-balance.d.ts +1 -0
- package/dist/pages/setup.d.ts +1 -0
- package/dist/pages/tutorial.d.ts +1 -0
- package/dist/routes.d.ts +19 -0
- package/dist/workers/report-runtime.worker.d.ts +1 -0
- package/package.json +61 -0
- package/src/index.css +105 -0
- package/tailwind.preset.ts +70 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branding / theme configuration.
|
|
3
|
+
*
|
|
4
|
+
* The visual theme is already CSS-variable based (see index.css `:root`
|
|
5
|
+
* tokens, surfaced to Tailwind as `brand`, `surface`, `fg`, `line`, …). A
|
|
6
|
+
* customer deployment built on the published library rebrands by calling
|
|
7
|
+
* `configureBranding` at startup: override the product name, point at a logo,
|
|
8
|
+
* and/or override any of the `:root` design tokens at runtime.
|
|
9
|
+
*
|
|
10
|
+
* For deeper restyling the customer's own Tailwind build (which scans this
|
|
11
|
+
* package — the "consumer scans source" model) can add utilities freely; this
|
|
12
|
+
* helper covers the common case of swapping name/logo/colors without a custom
|
|
13
|
+
* stylesheet.
|
|
14
|
+
*/
|
|
15
|
+
export interface Branding {
|
|
16
|
+
/** Product name — used for the document title and as the sidebar fallback. */
|
|
17
|
+
appName: string;
|
|
18
|
+
/** Optional logo URL (falls back to the core CSS-mask logo when unset). */
|
|
19
|
+
logoUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* CSS custom properties to set on :root, e.g. { "--brand": "260 80% 55%" }.
|
|
22
|
+
* The leading "--" is optional. Values follow the token format in index.css
|
|
23
|
+
* (HSL channel triplets for color tokens).
|
|
24
|
+
*/
|
|
25
|
+
tokens?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
export declare function configureBranding(next: Partial<Branding>): void;
|
|
28
|
+
export declare function getBranding(): Branding;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
export declare function registerComponent(name: string, component: ComponentType<any>): void;
|
|
3
|
+
/** Resolve a registered override, falling back to the core default. */
|
|
4
|
+
export declare function getComponent<P>(name: string, fallback: ComponentType<P>): ComponentType<P>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctype metadata registry.
|
|
3
|
+
*
|
|
4
|
+
* This drives the generic list and form pages. Instead of coding 8 separate
|
|
5
|
+
* pages, a single registry defines the fields, columns, and actions for each
|
|
6
|
+
* document type.
|
|
7
|
+
*/
|
|
8
|
+
export interface FieldDef {
|
|
9
|
+
name: string;
|
|
10
|
+
label: string;
|
|
11
|
+
type: "text" | "number" | "currency" | "date" | "link" | "select" | "textarea";
|
|
12
|
+
required?: boolean;
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
linkDoctype?: string;
|
|
15
|
+
linkDoctypeField?: string;
|
|
16
|
+
options?: Array<string | {
|
|
17
|
+
value: string;
|
|
18
|
+
label: string;
|
|
19
|
+
}>;
|
|
20
|
+
optionsSource?: "currency";
|
|
21
|
+
default?: any;
|
|
22
|
+
hint?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ChildTableDef {
|
|
25
|
+
label: string;
|
|
26
|
+
key: string;
|
|
27
|
+
fields: FieldDef[];
|
|
28
|
+
}
|
|
29
|
+
export interface ConversionDef {
|
|
30
|
+
label: string;
|
|
31
|
+
targetDoctype: string;
|
|
32
|
+
}
|
|
33
|
+
export interface DoctypeConfig {
|
|
34
|
+
slug: string;
|
|
35
|
+
label: string;
|
|
36
|
+
dateField: string;
|
|
37
|
+
partyField?: string;
|
|
38
|
+
partyLabel?: string;
|
|
39
|
+
amountField?: string;
|
|
40
|
+
fields: FieldDef[];
|
|
41
|
+
childTables: ChildTableDef[];
|
|
42
|
+
listColumns: string[];
|
|
43
|
+
canSubmit: boolean;
|
|
44
|
+
canCancel: boolean;
|
|
45
|
+
conversions: ConversionDef[];
|
|
46
|
+
}
|
|
47
|
+
export declare function getDoctypeConfig(slug: string): DoctypeConfig | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Register (or override) a doctype config. A customer deployment built on the
|
|
50
|
+
* published library calls this at startup to add a new document type or swap
|
|
51
|
+
* the form/list schema of a core one. The list/form pages read CONFIGS live
|
|
52
|
+
* via getDoctypeConfig, so a registration takes effect immediately.
|
|
53
|
+
*/
|
|
54
|
+
export declare function registerDoctype(config: DoctypeConfig): void;
|
|
55
|
+
export declare function getAllDoctypeConfigs(): DoctypeConfig[];
|
|
56
|
+
export declare const DOCTYPE_SLUGS: string[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface NavItem {
|
|
3
|
+
label: string;
|
|
4
|
+
path: string;
|
|
5
|
+
}
|
|
6
|
+
export interface NavGroup {
|
|
7
|
+
label: string;
|
|
8
|
+
icon: ReactNode;
|
|
9
|
+
items: NavItem[];
|
|
10
|
+
}
|
|
11
|
+
/** Live list the sidebar renders from. */
|
|
12
|
+
export declare function getNavGroups(): NavGroup[];
|
|
13
|
+
/**
|
|
14
|
+
* Add a nav group, or replace an existing one with the same label. Pass
|
|
15
|
+
* `index` to control placement (default: appended at the end).
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerNavGroup(group: NavGroup, opts?: {
|
|
18
|
+
index?: number;
|
|
19
|
+
}): void;
|
|
20
|
+
/** Append an item to an existing group (creating the group if absent). */
|
|
21
|
+
export declare function registerNavItem(groupLabel: string, item: NavItem): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Merge class names (simplified clsx). */
|
|
2
|
+
export declare function cn(...classes: (string | false | null | undefined)[]): string;
|
|
3
|
+
/** Format a number as currency. */
|
|
4
|
+
export declare function formatCurrency(value: number | null | undefined, currency?: string): string;
|
|
5
|
+
/** Format a number with commas. */
|
|
6
|
+
export declare function formatNumber(value: number | null | undefined, decimals?: number): string;
|
|
7
|
+
/** Format a date string for display. */
|
|
8
|
+
export declare function formatDate(value: string | null | undefined): string;
|
|
9
|
+
/** Safely parse a float, defaulting to 0. */
|
|
10
|
+
export declare function flt(value: unknown, precision?: number): number;
|
package/dist/main.d.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function SettingsPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function UsersPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ChatPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function DashboardPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shareable entry point that mirrors the "Enter Live Demo" button on /login.
|
|
3
|
+
* Creates a fresh chat session (as the public_manager fallback user if the
|
|
4
|
+
* visitor has no cookie) and redirects to /chat/{id}?demo=1 for replay.
|
|
5
|
+
*/
|
|
6
|
+
export default function DemoPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function DocumentListPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function LoginPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function MasterFormPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function MasterListPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function OpeningBalancesPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function AnalyticsPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ApAgingPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ArAgingPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function BalanceSheetPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function GeneralLedgerPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ProfitLossPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function StockBalancePage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function TrialBalancePage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function SetupPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function TutorialPage(): import("react/jsx-runtime").JSX.Element;
|
package/dist/routes.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RouteObject } from 'react-router-dom';
|
|
2
|
+
/**
|
|
3
|
+
* Register a route from a customer deployment.
|
|
4
|
+
* - area "app" (default): added under the protected app shell (sidebar +
|
|
5
|
+
* header), so it's an authenticated page like the core ones.
|
|
6
|
+
* - area "top": added at the root (e.g. a public/unauthenticated page).
|
|
7
|
+
*
|
|
8
|
+
* A registered route whose `path` (or index) matches a core route replaces
|
|
9
|
+
* it — that's how you override a core page wholesale.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerRoute(route: RouteObject, opts?: {
|
|
12
|
+
area?: "app" | "top";
|
|
13
|
+
}): void;
|
|
14
|
+
/**
|
|
15
|
+
* Build the full route table, merging any customer-registered routes over the
|
|
16
|
+
* core ones. Call this when constructing the router (the demo does so via
|
|
17
|
+
* bootstrap) — after plugins have registered, so overrides take effect.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildRoutes(): RouteObject[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lambda-development/erp-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./styles.css": "./src/index.css",
|
|
14
|
+
"./tailwind-preset": "./tailwind.preset.ts"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src/index.css",
|
|
19
|
+
"tailwind.preset.ts"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": [
|
|
22
|
+
"**/*.css"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "vite",
|
|
26
|
+
"build": "tsc -b && vite build",
|
|
27
|
+
"build:lib": "vite build --config vite.lib.config.ts",
|
|
28
|
+
"preview": "vite preview"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@tanstack/react-query": "^5.60.0",
|
|
32
|
+
"@tanstack/react-table": "^8.20.0",
|
|
33
|
+
"i18next": "^26.2.0",
|
|
34
|
+
"lucide-react": "^0.460.0",
|
|
35
|
+
"react": "^19.0.0",
|
|
36
|
+
"react-dom": "^19.0.0",
|
|
37
|
+
"react-i18next": "^17.0.8",
|
|
38
|
+
"react-router-dom": "^7.0.0",
|
|
39
|
+
"recharts": "^3.8.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@tanstack/react-query": "^5.60.0",
|
|
43
|
+
"@tanstack/react-table": "^8.20.0",
|
|
44
|
+
"@types/react": "^19.0.0",
|
|
45
|
+
"@types/react-dom": "^19.0.0",
|
|
46
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
47
|
+
"autoprefixer": "^10.4.20",
|
|
48
|
+
"i18next": "^26.2.0",
|
|
49
|
+
"lucide-react": "^0.460.0",
|
|
50
|
+
"postcss": "^8.4.49",
|
|
51
|
+
"react": "^19.0.0",
|
|
52
|
+
"react-dom": "^19.0.0",
|
|
53
|
+
"react-i18next": "^17.0.8",
|
|
54
|
+
"react-router-dom": "^7.0.0",
|
|
55
|
+
"recharts": "^3.8.1",
|
|
56
|
+
"tailwindcss": "^3.4.0",
|
|
57
|
+
"typescript": "~5.6.0",
|
|
58
|
+
"vite": "^6.0.0",
|
|
59
|
+
"vite-plugin-dts": "^4.3.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/index.css
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
/* ───────────────────────────────────────────────────────────────────
|
|
6
|
+
Design tokens. Values are space-separated HSL components so they
|
|
7
|
+
plug into Tailwind via `hsl(var(--token) / <alpha-value>)` and
|
|
8
|
+
support opacity modifiers like `bg-brand/90`.
|
|
9
|
+
|
|
10
|
+
Anchored to the Lambda logo gradient: brand sits between the cyan
|
|
11
|
+
(#66D4FF) and pink (#ff6eb4) gradient stops.
|
|
12
|
+
─────────────────────────────────────────────────────────────────── */
|
|
13
|
+
:root {
|
|
14
|
+
/* Brand */
|
|
15
|
+
--brand: 220 78% 57%; /* ≈ #2f6ff0 — saturated cobalt blue */
|
|
16
|
+
--brand-fg: 0 0% 100%;
|
|
17
|
+
|
|
18
|
+
/* Surfaces */
|
|
19
|
+
--surface: 0 0% 100%; /* primary card / panel */
|
|
20
|
+
--surface-muted: 220 14% 98%; /* page background — slightly cooler than white */
|
|
21
|
+
--surface-subtle: 220 14% 96%; /* hovered rows, secondary cards, sidebar active */
|
|
22
|
+
|
|
23
|
+
/* Lines & text */
|
|
24
|
+
--border: 220 13% 91%;
|
|
25
|
+
--text: 222 47% 11%;
|
|
26
|
+
--text-muted: 220 9% 46%;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@layer base {
|
|
30
|
+
body {
|
|
31
|
+
/* `bg-surface-muted` and `text-fg` are the new defaults but applying
|
|
32
|
+
them at the body level avoids touching every page component on
|
|
33
|
+
day 1. Tailwind's `bg-gray-50` on <body> is replaced here. */
|
|
34
|
+
@apply bg-surface-muted text-fg antialiased;
|
|
35
|
+
font-feature-settings: "cv02", "cv03", "cv04", "cv11"; /* Inter polish */
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Fluid easing app-wide. Hover/transition properties feel less
|
|
39
|
+
mechanical with this curve. */
|
|
40
|
+
* {
|
|
41
|
+
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* iOS Safari auto-zooms when a focused input/textarea has font-size
|
|
46
|
+
below 16px and doesn't zoom back out, making the whole page feel
|
|
47
|
+
broken after the keyboard closes. 16px is the minimum that
|
|
48
|
+
suppresses it. !important is needed because most of our inputs
|
|
49
|
+
use Tailwind's `text-sm` (14px), which is a class selector and
|
|
50
|
+
beats a plain element selector on specificity. Mobile-only — desktop
|
|
51
|
+
keeps its 14px. */
|
|
52
|
+
@media (max-width: 768px) {
|
|
53
|
+
input,
|
|
54
|
+
textarea,
|
|
55
|
+
select {
|
|
56
|
+
font-size: 16px !important;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Sidebar Lambda ERP logo — PNG silhouette used as a mask with an animated
|
|
61
|
+
multi-colour gradient showing through. */
|
|
62
|
+
.lambda-logo-icon {
|
|
63
|
+
width: 70px;
|
|
64
|
+
height: 15px;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
background: linear-gradient(135deg, #cbd5e1, #b0bacb, #c2ccd8, #94a3b8, #cbd5e1);
|
|
67
|
+
background-size: 300% 300%;
|
|
68
|
+
animation: lambda-logo-gradient 12s ease infinite;
|
|
69
|
+
-webkit-mask-image: url('/logo_lad_erp.png');
|
|
70
|
+
-webkit-mask-size: contain;
|
|
71
|
+
-webkit-mask-repeat: no-repeat;
|
|
72
|
+
-webkit-mask-position: center;
|
|
73
|
+
mask-image: url('/logo_lad_erp.png');
|
|
74
|
+
mask-size: contain;
|
|
75
|
+
mask-repeat: no-repeat;
|
|
76
|
+
mask-position: center;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@keyframes lambda-logo-gradient {
|
|
80
|
+
0% { background-position: 0% 50%; }
|
|
81
|
+
50% { background-position: 100% 50%; }
|
|
82
|
+
100% { background-position: 0% 50%; }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Thin, Claude.ai-style scrollbar applied app-wide. Firefox honours
|
|
86
|
+
`scrollbar-width` / `scrollbar-color`; Chromium/Safari need the
|
|
87
|
+
`::-webkit-scrollbar-*` pseudo-elements to match. */
|
|
88
|
+
* {
|
|
89
|
+
scrollbar-width: thin;
|
|
90
|
+
scrollbar-color: rgba(31, 31, 30, 0.35) transparent;
|
|
91
|
+
}
|
|
92
|
+
*::-webkit-scrollbar {
|
|
93
|
+
width: 8px;
|
|
94
|
+
height: 8px;
|
|
95
|
+
}
|
|
96
|
+
*::-webkit-scrollbar-track {
|
|
97
|
+
background: transparent;
|
|
98
|
+
}
|
|
99
|
+
*::-webkit-scrollbar-thumb {
|
|
100
|
+
background-color: rgba(31, 31, 30, 0.35);
|
|
101
|
+
border-radius: 4px;
|
|
102
|
+
}
|
|
103
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
104
|
+
background-color: rgba(31, 31, 30, 0.5);
|
|
105
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Config } from "tailwindcss";
|
|
2
|
+
|
|
3
|
+
// Shared Tailwind theme for the ERP core, published as a preset so the demo
|
|
4
|
+
// app and any customer deployment get identical design tokens. Add it with
|
|
5
|
+
// `presets: [erpPreset]` in tailwind.config. Colours are backed by the CSS
|
|
6
|
+
// variables defined in src/index.css (shipped as `@lambda-development/erp-core/styles.css`)
|
|
7
|
+
// — rebrand by overriding those variables, not by editing this preset.
|
|
8
|
+
const preset: Partial<Config> = {
|
|
9
|
+
theme: {
|
|
10
|
+
extend: {
|
|
11
|
+
// Token-backed colours. Values come from CSS variables in index.css,
|
|
12
|
+
// which means swapping themes (e.g. dark mode later) means changing
|
|
13
|
+
// the variables, not editing every component.
|
|
14
|
+
//
|
|
15
|
+
// Using `hsl(var(--x) / <alpha-value>)` lets Tailwind opacity
|
|
16
|
+
// modifiers work: `bg-brand/90`, `text-fg-muted/70`, etc.
|
|
17
|
+
colors: {
|
|
18
|
+
brand: {
|
|
19
|
+
DEFAULT: "hsl(var(--brand) / <alpha-value>)",
|
|
20
|
+
fg: "hsl(var(--brand-fg) / <alpha-value>)",
|
|
21
|
+
},
|
|
22
|
+
surface: {
|
|
23
|
+
DEFAULT: "hsl(var(--surface) / <alpha-value>)",
|
|
24
|
+
muted: "hsl(var(--surface-muted) / <alpha-value>)",
|
|
25
|
+
subtle: "hsl(var(--surface-subtle) / <alpha-value>)",
|
|
26
|
+
},
|
|
27
|
+
fg: {
|
|
28
|
+
DEFAULT: "hsl(var(--text) / <alpha-value>)",
|
|
29
|
+
muted: "hsl(var(--text-muted) / <alpha-value>)",
|
|
30
|
+
},
|
|
31
|
+
line: "hsl(var(--border) / <alpha-value>)",
|
|
32
|
+
},
|
|
33
|
+
fontFamily: {
|
|
34
|
+
sans: [
|
|
35
|
+
"Inter",
|
|
36
|
+
"system-ui",
|
|
37
|
+
"-apple-system",
|
|
38
|
+
"Segoe UI",
|
|
39
|
+
"Roboto",
|
|
40
|
+
"sans-serif",
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
boxShadow: {
|
|
44
|
+
// Multi-layer soft shadows — closer in feel to Linear / Vercel
|
|
45
|
+
// than Tailwind's default. The card-hover variant is for
|
|
46
|
+
// interactive cards (hover, focus-within).
|
|
47
|
+
card: "0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.03)",
|
|
48
|
+
"card-hover": "0 1px 2px rgba(0,0,0,0.05), 0 8px 24px rgba(0,0,0,0.05)",
|
|
49
|
+
// Subtle inset highlight for primary buttons — gives the
|
|
50
|
+
// top edge a 1px lift that's almost invisible but reads as depth.
|
|
51
|
+
"button-highlight": "inset 0 1px 0 rgba(255,255,255,0.16)",
|
|
52
|
+
// Saturated colored surfaces (user chat bubble, brand CTAs) need
|
|
53
|
+
// a different shadow recipe than neutral cards: a black drop
|
|
54
|
+
// shadow alone barely registers on a vivid purple. Combining
|
|
55
|
+
// 1) a 1px inset top highlight — reads as polished glass,
|
|
56
|
+
// 2) a tight dark drop — defines the bubble edge,
|
|
57
|
+
// 3) a soft brand-tinted glow — makes the bubble feel like
|
|
58
|
+
// it's casting its own colour onto the page (kept subtle),
|
|
59
|
+
// gives the bubble physical presence without looking gimmicky.
|
|
60
|
+
"bubble-user": [
|
|
61
|
+
"inset 0 1px 0 rgba(255,255,255,0.22)",
|
|
62
|
+
"0 1px 2px rgba(0,0,0,0.05)",
|
|
63
|
+
"0 3px 8px -2px hsl(var(--brand) / 0.18)",
|
|
64
|
+
].join(", "),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default preset;
|