@llmnative/react 1.19.0 → 1.19.2

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.
Files changed (49) hide show
  1. package/README.md +4 -2
  2. package/dist/index.css +1 -1
  3. package/dist/index.js +10 -10
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +150 -139
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/logHeader-Busbc8OO.mjs.map +1 -1
  8. package/dist/logHeader-CUsdmGAo.js +2 -0
  9. package/dist/{logHeader-CbzOhx-u.js.map → logHeader-CUsdmGAo.js.map} +1 -1
  10. package/dist/vite.js +2 -2
  11. package/dist/vite.js.map +1 -1
  12. package/dist/vite.mjs +1 -1
  13. package/dist/vite.mjs.map +1 -1
  14. package/llms-full.txt +1140 -0
  15. package/llms.txt +82 -0
  16. package/package.json +48 -43
  17. package/scripts/cli/setup-project.js +60 -36
  18. package/templates/_shared/layouts/Default.tsx +23 -0
  19. package/templates/_shared/sections/Footer.tsx +9 -0
  20. package/templates/_shared/sections/Header.tsx +24 -0
  21. package/templates/_shared/sections/PageHeader.tsx +10 -0
  22. package/templates/_shared/sections/Sidebar.tsx +22 -0
  23. package/templates/admin/conf/menu.ts +14 -0
  24. package/templates/admin/data/mockData.ts +21 -0
  25. package/templates/admin/pages/home/HomePage.tsx +32 -0
  26. package/templates/admin/pages/roles/RolesPage.tsx +25 -0
  27. package/templates/admin/pages/settings/SettingsPage.tsx +24 -0
  28. package/templates/admin/pages/users/UsersPage.tsx +54 -0
  29. package/templates/blank/conf/menu.ts +8 -0
  30. package/templates/blank/data/mockData.ts +6 -0
  31. package/templates/blank/pages/home/HomePage.tsx +25 -0
  32. package/templates/crm/conf/menu.ts +14 -0
  33. package/templates/crm/data/mockData.ts +24 -0
  34. package/templates/crm/pages/companies/CompaniesPage.tsx +42 -0
  35. package/templates/crm/pages/contacts/ContactsPage.tsx +48 -0
  36. package/templates/crm/pages/deals/DealsPage.tsx +61 -0
  37. package/templates/crm/pages/home/HomePage.tsx +35 -0
  38. package/templates/inventory/conf/menu.ts +12 -0
  39. package/templates/inventory/data/mockData.ts +16 -0
  40. package/templates/inventory/pages/categories/CategoriesPage.tsx +23 -0
  41. package/templates/inventory/pages/home/HomePage.tsx +35 -0
  42. package/templates/inventory/pages/products/ProductsPage.tsx +56 -0
  43. package/templates/project/conf/menu.ts +14 -0
  44. package/templates/project/data/mockData.ts +21 -0
  45. package/templates/project/pages/home/HomePage.tsx +33 -0
  46. package/templates/project/pages/projects/ProjectsPage.tsx +50 -0
  47. package/templates/project/pages/tasks/TasksPage.tsx +67 -0
  48. package/templates/project/pages/team/TeamPage.tsx +25 -0
  49. package/dist/logHeader-CbzOhx-u.js +0 -2
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { Grid, Badge, Input, Select, type BadgeType } from '@llmnative/react';
3
+
4
+ const roleOptions = [
5
+ { label: 'Administrator', value: 'admin' },
6
+ { label: 'Editor', value: 'editor' },
7
+ { label: 'Viewer', value: 'viewer' },
8
+ ];
9
+
10
+ const statusOptions = [
11
+ { label: 'Active', value: 'active' },
12
+ { label: 'Inactive', value: 'inactive' },
13
+ ];
14
+
15
+ const roleVariant: Record<string, BadgeType> = {
16
+ admin: 'danger',
17
+ editor: 'primary',
18
+ viewer: 'secondary',
19
+ };
20
+
21
+ export default function UsersPage() {
22
+ return (
23
+ <Grid
24
+ path="/users"
25
+ columns={[
26
+ { key: 'name', label: 'Name', sortable: true },
27
+ { key: 'email', label: 'Email' },
28
+ { key: 'role', label: 'Role',
29
+ render: ({ value }) => (
30
+ <Badge variant={roleVariant[String(value)] ?? 'secondary'}>{String(value)}</Badge>
31
+ ),
32
+ },
33
+ { key: 'status', label: 'Status',
34
+ render: ({ value }) => (
35
+ <Badge variant={value === 'active' ? 'success' : 'secondary'}>{String(value)}</Badge>
36
+ ),
37
+ },
38
+ { key: 'createdAt', label: 'Created', render: 'date' },
39
+ ]}
40
+ actions={['add', 'edit', 'delete']}
41
+ view="table"
42
+ sortable
43
+ pagination={{ limit: 25 }}
44
+ form={
45
+ <>
46
+ <Input name="name" label="Full name" required />
47
+ <Input name="email" label="Email" type="email" required />
48
+ <Select name="role" label="Role" options={roleOptions} />
49
+ <Select name="status" label="Status" options={statusOptions} />
50
+ </>
51
+ }
52
+ />
53
+ );
54
+ }
@@ -0,0 +1,8 @@
1
+ import type { MenuConfig } from '@llmnative/react';
2
+ import HomePage from '../pages/home/HomePage';
3
+
4
+ export const menu: MenuConfig = {
5
+ main: [
6
+ { path: '/', title: 'Home', icon: 'home', page: HomePage, end: true },
7
+ ],
8
+ };
@@ -0,0 +1,6 @@
1
+ export const mockData = {
2
+ '/tasks': {
3
+ 'task-1': { title: 'Review scaffold structure', status: 'done' },
4
+ 'task-2': { title: 'Connect your first provider', status: 'next' },
5
+ },
6
+ };
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { Grid } from '@llmnative/react';
3
+
4
+ export default function HomePage() {
5
+ return (
6
+ <div className="mx-auto max-w-5xl space-y-8 px-2 py-4">
7
+ <div className="space-y-1">
8
+ <h1 className="text-2xl font-semibold">Welcome to [projectname]</h1>
9
+ <p className="text-sm text-muted-foreground">
10
+ Scaffolded with LLM Native. Edit this page at <code>src/pages/home/HomePage.tsx</code>.
11
+ </p>
12
+ </div>
13
+
14
+ <Grid
15
+ path="/tasks"
16
+ columns={[
17
+ { key: 'title', label: 'Task' },
18
+ { key: 'status', label: 'Status' },
19
+ ]}
20
+ actions={['add', 'edit', 'delete']}
21
+ view="table"
22
+ />
23
+ </div>
24
+ );
25
+ }
@@ -0,0 +1,14 @@
1
+ import type { MenuConfig } from '@llmnative/react';
2
+ import HomePage from '../pages/home/HomePage';
3
+ import ContactsPage from '../pages/contacts/ContactsPage';
4
+ import CompaniesPage from '../pages/companies/CompaniesPage';
5
+ import DealsPage from '../pages/deals/DealsPage';
6
+
7
+ export const menu: MenuConfig = {
8
+ main: [
9
+ { path: '/', title: 'Dashboard', icon: 'layout-dashboard', page: HomePage, end: true },
10
+ { path: '/contacts', title: 'Contacts', icon: 'users', page: ContactsPage, group: 'Sales' },
11
+ { path: '/companies', title: 'Companies', icon: 'building-2', page: CompaniesPage, group: 'Sales' },
12
+ { path: '/deals', title: 'Deals', icon: 'handshake', page: DealsPage, group: 'Sales' },
13
+ ],
14
+ };
@@ -0,0 +1,24 @@
1
+ export const mockData = {
2
+ '/contacts': {
3
+ 'c-1': { name: 'Alice Martin', email: 'alice@acme.com', company: 'Acme Corp', status: 'active', phone: '+1 555 0101' },
4
+ 'c-2': { name: 'Bob Chen', email: 'bob@globex.com', company: 'Globex', status: 'active', phone: '+1 555 0102' },
5
+ 'c-3': { name: 'Clara Rossi', email: 'clara@initech.it', company: 'Initech', status: 'inactive', phone: '+39 02 0103' },
6
+ 'c-4': { name: 'David Park', email: 'd.park@umbrella.co', company: 'Umbrella', status: 'active', phone: '+1 555 0104' },
7
+ 'c-5': { name: 'Eva Müller', email: 'eva@hooli.de', company: 'Hooli', status: 'lead', phone: '+49 89 0105' },
8
+ },
9
+ '/companies': {
10
+ 'co-1': { name: 'Acme Corp', industry: 'Manufacturing', website: 'acme.com', employees: 320 },
11
+ 'co-2': { name: 'Globex', industry: 'Technology', website: 'globex.com', employees: 85 },
12
+ 'co-3': { name: 'Initech', industry: 'IT Services', website: 'initech.it', employees: 50 },
13
+ 'co-4': { name: 'Umbrella', industry: 'Pharma', website: 'umbrella.co', employees: 1200 },
14
+ 'co-5': { name: 'Hooli', industry: 'Technology', website: 'hooli.de', employees: 600 },
15
+ },
16
+ '/deals': {
17
+ 'd-1': { title: 'Enterprise license', contact: 'Alice Martin', value: 12000, stage: 'qualified', closedAt: '' },
18
+ 'd-2': { title: 'SaaS subscription', contact: 'Bob Chen', value: 4800, stage: 'prospect', closedAt: '' },
19
+ 'd-3': { title: 'Consulting package', contact: 'Clara Rossi', value: 7500, stage: 'proposal', closedAt: '' },
20
+ 'd-4': { title: 'Support renewal', contact: 'David Park', value: 2400, stage: 'won', closedAt: '2025-03-15' },
21
+ 'd-5': { title: 'Migration project', contact: 'Eva Müller', value: 18000, stage: 'prospect', closedAt: '' },
22
+ 'd-6': { title: 'Hardware bundle', contact: 'Alice Martin', value: 5600, stage: 'lost', closedAt: '2025-02-28' },
23
+ },
24
+ };
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { Grid, Input, Select } from '@llmnative/react';
3
+
4
+ const industryOptions = [
5
+ { label: 'Technology', value: 'Technology' },
6
+ { label: 'Manufacturing', value: 'Manufacturing' },
7
+ { label: 'IT Services', value: 'IT Services' },
8
+ { label: 'Pharma', value: 'Pharma' },
9
+ { label: 'Finance', value: 'Finance' },
10
+ { label: 'Retail', value: 'Retail' },
11
+ { label: 'Other', value: 'Other' },
12
+ ];
13
+
14
+ export default function CompaniesPage() {
15
+ return (
16
+ <Grid
17
+ path="/companies"
18
+ columns={[
19
+ { key: 'name', label: 'Company', sortable: true },
20
+ { key: 'industry', label: 'Industry', sortable: true },
21
+ { key: 'website', label: 'Website' },
22
+ {
23
+ key: 'employees',
24
+ label: 'Employees',
25
+ render: ({ value }) => value ? Number(value).toLocaleString() : '-',
26
+ },
27
+ ]}
28
+ actions={['add', 'edit', 'delete']}
29
+ view="table"
30
+ sortable
31
+ pagination={{ limit: 20 }}
32
+ form={
33
+ <>
34
+ <Input name="name" label="Company name" required />
35
+ <Select name="industry" label="Industry" options={industryOptions} />
36
+ <Input name="website" label="Website" />
37
+ <Input name="employees" label="Employees" type="number" />
38
+ </>
39
+ }
40
+ />
41
+ );
42
+ }
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { Grid, Badge, Input, Select, type BadgeType } from '@llmnative/react';
3
+
4
+ const statusOptions = [
5
+ { label: 'Active', value: 'active' },
6
+ { label: 'Inactive', value: 'inactive' },
7
+ { label: 'Lead', value: 'lead' },
8
+ ];
9
+
10
+ const statusVariant: Record<string, BadgeType> = {
11
+ active: 'success',
12
+ inactive: 'secondary',
13
+ lead: 'warning',
14
+ };
15
+
16
+ export default function ContactsPage() {
17
+ return (
18
+ <Grid
19
+ path="/contacts"
20
+ columns={[
21
+ { key: 'name', label: 'Name', sortable: true },
22
+ { key: 'email', label: 'Email' },
23
+ { key: 'company', label: 'Company', sortable: true },
24
+ { key: 'phone', label: 'Phone' },
25
+ {
26
+ key: 'status',
27
+ label: 'Status',
28
+ render: ({ value }) => (
29
+ <Badge variant={statusVariant[String(value)] ?? 'secondary'}>{String(value)}</Badge>
30
+ ),
31
+ },
32
+ ]}
33
+ actions={['add', 'edit', 'delete']}
34
+ view="table"
35
+ sortable
36
+ pagination={{ limit: 20 }}
37
+ form={
38
+ <>
39
+ <Input name="name" label="Full name" required />
40
+ <Input name="email" label="Email" type="email" />
41
+ <Input name="phone" label="Phone" />
42
+ <Input name="company" label="Company" />
43
+ <Select name="status" label="Status" options={statusOptions} />
44
+ </>
45
+ }
46
+ />
47
+ );
48
+ }
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { Grid, Badge, Input, Select, type BadgeType } from '@llmnative/react';
3
+
4
+ const stageOptions = [
5
+ { label: 'Prospect', value: 'prospect' },
6
+ { label: 'Qualified', value: 'qualified' },
7
+ { label: 'Proposal', value: 'proposal' },
8
+ { label: 'Won', value: 'won' },
9
+ { label: 'Lost', value: 'lost' },
10
+ ];
11
+
12
+ const stageVariant: Record<string, BadgeType> = {
13
+ prospect: 'secondary',
14
+ qualified: 'info',
15
+ proposal: 'warning',
16
+ won: 'success',
17
+ lost: 'danger',
18
+ };
19
+
20
+ export default function DealsPage() {
21
+ return (
22
+ <Grid
23
+ path="/deals"
24
+ columns={[
25
+ { key: 'title', label: 'Deal', sortable: true },
26
+ { key: 'contact', label: 'Contact' },
27
+ {
28
+ key: 'value',
29
+ label: 'Value',
30
+ render: ({ value }) => `$ ${Number(value).toLocaleString()}`,
31
+ },
32
+ {
33
+ key: 'stage',
34
+ label: 'Stage',
35
+ render: ({ value }) => (
36
+ <Badge variant={stageVariant[String(value)] ?? 'secondary'}>{String(value)}</Badge>
37
+ ),
38
+ },
39
+ {
40
+ key: 'closedAt',
41
+ label: 'Closed',
42
+ render: ({ value }) => (value ? String(value) : '-'),
43
+ },
44
+ ]}
45
+ actions={['add', 'edit', 'delete']}
46
+ view="table"
47
+ groupBy="stage"
48
+ sortable
49
+ pagination={{ limit: 25 }}
50
+ form={
51
+ <>
52
+ <Input name="title" label="Deal title" required />
53
+ <Input name="contact" label="Contact name" />
54
+ <Input name="value" label="Value ($)" type="number" />
55
+ <Select name="stage" label="Stage" options={stageOptions} />
56
+ <Input name="closedAt" label="Closed date" type="date" />
57
+ </>
58
+ }
59
+ />
60
+ );
61
+ }
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { Card } from '@llmnative/react';
3
+ import { mockData } from '../../data/mockData';
4
+
5
+ function StatCard({ label, value, sub }: { label: string; value: number | string; sub?: string }) {
6
+ return (
7
+ <Card title={label}>
8
+ <p className="text-2xl font-semibold">{value}</p>
9
+ {sub && <p className="text-xs text-muted-foreground">{sub}</p>}
10
+ </Card>
11
+ );
12
+ }
13
+
14
+ export default function HomePage() {
15
+ const contacts = Object.values(mockData['/contacts']);
16
+ const deals = Object.values(mockData['/deals']);
17
+ const openDeals = deals.filter((d) => d.stage !== 'won' && d.stage !== 'lost');
18
+ const pipeline = openDeals.reduce((sum, d) => sum + d.value, 0);
19
+
20
+ return (
21
+ <div className="mx-auto max-w-5xl space-y-8 px-2 py-4">
22
+ <div className="space-y-1">
23
+ <h1 className="text-2xl font-semibold">Dashboard</h1>
24
+ <p className="text-sm text-muted-foreground">Overview of your CRM activity.</p>
25
+ </div>
26
+
27
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
28
+ <StatCard label="Contacts" value={contacts.length} />
29
+ <StatCard label="Active" value={contacts.filter(c => c.status === 'active').length} sub="active contacts" />
30
+ <StatCard label="Open deals" value={openDeals.length} />
31
+ <StatCard label="Pipeline" value={`$ ${pipeline.toLocaleString()}`} sub="total open value" />
32
+ </div>
33
+ </div>
34
+ );
35
+ }
@@ -0,0 +1,12 @@
1
+ import type { MenuConfig } from '@llmnative/react';
2
+ import HomePage from '../pages/home/HomePage';
3
+ import ProductsPage from '../pages/products/ProductsPage';
4
+ import CategoriesPage from '../pages/categories/CategoriesPage';
5
+
6
+ export const menu: MenuConfig = {
7
+ main: [
8
+ { path: '/', title: 'Overview', icon: 'layout-dashboard', page: HomePage, end: true },
9
+ { path: '/products', title: 'Products', icon: 'package', page: ProductsPage, group: 'Catalog' },
10
+ { path: '/categories', title: 'Categories', icon: 'tag', page: CategoriesPage, group: 'Catalog' },
11
+ ],
12
+ };
@@ -0,0 +1,16 @@
1
+ export const mockData = {
2
+ '/categories': {
3
+ 'cat-1': { name: 'Electronics', slug: 'electronics' },
4
+ 'cat-2': { name: 'Clothing', slug: 'clothing' },
5
+ 'cat-3': { name: 'Home & Garden',slug: 'home-garden' },
6
+ 'cat-4': { name: 'Sports', slug: 'sports' },
7
+ },
8
+ '/products': {
9
+ 'p-1': { name: 'Wireless Headphones', category: 'Electronics', price: 79.00, stock: 42, sku: 'EL-001', active: true },
10
+ 'p-2': { name: 'Running Shoes', category: 'Sports', price: 120.00, stock: 18, sku: 'SP-002', active: true },
11
+ 'p-3': { name: 'Desk Lamp', category: 'Home & Garden', price: 35.00, stock: 0, sku: 'HG-003', active: false },
12
+ 'p-4': { name: 'Cotton T-Shirt', category: 'Clothing', price: 15.00, stock: 130, sku: 'CL-004', active: true },
13
+ 'p-5': { name: 'Mechanical Keyboard', category: 'Electronics', price: 99.00, stock: 25, sku: 'EL-005', active: true },
14
+ 'p-6': { name: 'Yoga Mat', category: 'Sports', price: 45.00, stock: 60, sku: 'SP-006', active: true },
15
+ },
16
+ };
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { Grid, Input } from '@llmnative/react';
3
+
4
+ export default function CategoriesPage() {
5
+ return (
6
+ <Grid
7
+ path="/categories"
8
+ columns={[
9
+ { key: 'name', label: 'Category', sortable: true },
10
+ { key: 'slug', label: 'Slug' },
11
+ ]}
12
+ actions={['add', 'edit', 'delete']}
13
+ view="table"
14
+ sortable
15
+ form={
16
+ <>
17
+ <Input name="name" label="Category name" required />
18
+ <Input name="slug" label="Slug (e.g. home-garden)" />
19
+ </>
20
+ }
21
+ />
22
+ );
23
+ }
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { Card } from '@llmnative/react';
3
+ import { mockData } from '../../data/mockData';
4
+
5
+ function StatCard({ label, value, sub }: { label: string; value: number | string; sub?: string }) {
6
+ return (
7
+ <Card title={label}>
8
+ <p className="text-2xl font-semibold">{value}</p>
9
+ {sub && <p className="text-xs text-muted-foreground">{sub}</p>}
10
+ </Card>
11
+ );
12
+ }
13
+
14
+ export default function HomePage() {
15
+ const products = Object.values(mockData['/products']);
16
+ const totalStock = products.reduce((sum, p) => sum + p.stock, 0);
17
+ const outOfStock = products.filter(p => p.stock === 0).length;
18
+ const totalValue = products.reduce((sum, p) => sum + p.price * p.stock, 0);
19
+
20
+ return (
21
+ <div className="mx-auto max-w-5xl space-y-8 px-2 py-4">
22
+ <div className="space-y-1">
23
+ <h1 className="text-2xl font-semibold">Inventory</h1>
24
+ <p className="text-sm text-muted-foreground">Stock overview across all categories.</p>
25
+ </div>
26
+
27
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
28
+ <StatCard label="Products" value={products.length} />
29
+ <StatCard label="Total stock" value={totalStock.toLocaleString()} sub="units" />
30
+ <StatCard label="Out of stock" value={outOfStock} sub="products" />
31
+ <StatCard label="Stock value" value={`$ ${(totalValue / 100).toLocaleString()}`} />
32
+ </div>
33
+ </div>
34
+ );
35
+ }
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { Grid, Badge, Input, Select } from '@llmnative/react';
3
+
4
+ const categoryOptions = [
5
+ { label: 'Electronics', value: 'Electronics' },
6
+ { label: 'Clothing', value: 'Clothing' },
7
+ { label: 'Home & Garden', value: 'Home & Garden' },
8
+ { label: 'Sports', value: 'Sports' },
9
+ ];
10
+
11
+ export default function ProductsPage() {
12
+ return (
13
+ <Grid
14
+ path="/products"
15
+ columns={[
16
+ { key: 'name', label: 'Product', sortable: true },
17
+ { key: 'sku', label: 'SKU' },
18
+ { key: 'category', label: 'Category', sortable: true },
19
+ {
20
+ key: 'price',
21
+ label: 'Price',
22
+ render: ({ value }) => `$ ${Number(value).toFixed(2)}`,
23
+ },
24
+ {
25
+ key: 'stock',
26
+ label: 'Stock',
27
+ render: ({ value }) => (
28
+ <Badge variant={Number(value) === 0 ? 'danger' : Number(value) < 10 ? 'warning' : 'success'}>
29
+ {String(value)}
30
+ </Badge>
31
+ ),
32
+ },
33
+ {
34
+ key: 'active',
35
+ label: 'Active',
36
+ render: ({ value }) => (
37
+ <Badge variant={value ? 'success' : 'secondary'}>{value ? 'Yes' : 'No'}</Badge>
38
+ ),
39
+ },
40
+ ]}
41
+ actions={['add', 'edit', 'delete']}
42
+ view="table"
43
+ sortable
44
+ pagination={{ limit: 25 }}
45
+ form={
46
+ <>
47
+ <Input name="name" label="Product name" required />
48
+ <Input name="sku" label="SKU" />
49
+ <Select name="category" label="Category" options={categoryOptions} />
50
+ <Input name="price" label="Price ($)" type="number" min={0} step={0.01} />
51
+ <Input name="stock" label="Stock (units)" type="number" />
52
+ </>
53
+ }
54
+ />
55
+ );
56
+ }
@@ -0,0 +1,14 @@
1
+ import type { MenuConfig } from '@llmnative/react';
2
+ import HomePage from '../pages/home/HomePage';
3
+ import ProjectsPage from '../pages/projects/ProjectsPage';
4
+ import TasksPage from '../pages/tasks/TasksPage';
5
+ import TeamPage from '../pages/team/TeamPage';
6
+
7
+ export const menu: MenuConfig = {
8
+ main: [
9
+ { path: '/', title: 'Overview', icon: 'layout-dashboard', page: HomePage, end: true },
10
+ { path: '/projects', title: 'Projects', icon: 'folder-open', page: ProjectsPage, group: 'Work' },
11
+ { path: '/tasks', title: 'Tasks', icon: 'check-square', page: TasksPage, group: 'Work' },
12
+ { path: '/team', title: 'Team', icon: 'users', page: TeamPage, group: 'Work' },
13
+ ],
14
+ };
@@ -0,0 +1,21 @@
1
+ export const mockData = {
2
+ '/team': {
3
+ 'tm-1': { name: 'Alice Martin', role: 'Lead developer', email: 'alice@example.com' },
4
+ 'tm-2': { name: 'Bob Chen', role: 'Designer', email: 'bob@example.com' },
5
+ 'tm-3': { name: 'Clara Rossi', role: 'Project manager', email: 'clara@example.com' },
6
+ },
7
+ '/projects': {
8
+ 'pr-1': { name: 'Website redesign', status: 'active', owner: 'Alice Martin', deadline: '2025-08-31', description: 'Full UX and branding overhaul.' },
9
+ 'pr-2': { name: 'Mobile app v2', status: 'active', owner: 'Bob Chen', deadline: '2025-10-15', description: 'React Native rebuild.' },
10
+ 'pr-3': { name: 'API migration', status: 'done', owner: 'Alice Martin', deadline: '2025-04-01', description: 'Move from REST to GraphQL.' },
11
+ 'pr-4': { name: 'Analytics dashboard',status: 'planning', owner: 'Clara Rossi', deadline: '2025-12-01', description: 'Realtime metrics for ops team.' },
12
+ },
13
+ '/tasks': {
14
+ 't-1': { title: 'Define color palette', project: 'Website redesign', assignee: 'Bob Chen', status: 'done', priority: 'high' },
15
+ 't-2': { title: 'Implement auth flow', project: 'Mobile app v2', assignee: 'Alice Martin', status: 'in-progress', priority: 'high' },
16
+ 't-3': { title: 'Write API docs', project: 'API migration', assignee: 'Alice Martin', status: 'done', priority: 'medium' },
17
+ 't-4': { title: 'Design dashboard layout', project: 'Analytics dashboard',assignee: 'Bob Chen', status: 'todo', priority: 'medium' },
18
+ 't-5': { title: 'Homepage wireframes', project: 'Website redesign', assignee: 'Bob Chen', status: 'in-progress', priority: 'medium' },
19
+ 't-6': { title: 'Data model planning', project: 'Analytics dashboard',assignee: 'Clara Rossi', status: 'todo', priority: 'low' },
20
+ },
21
+ };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { Card } from '@llmnative/react';
3
+ import { mockData } from '../../data/mockData';
4
+
5
+ function StatCard({ label, value, sub }: { label: string; value: number | string; sub?: string }) {
6
+ return (
7
+ <Card title={label}>
8
+ <p className="text-2xl font-semibold">{value}</p>
9
+ {sub && <p className="text-xs text-muted-foreground">{sub}</p>}
10
+ </Card>
11
+ );
12
+ }
13
+
14
+ export default function HomePage() {
15
+ const projects = Object.values(mockData['/projects']);
16
+ const tasks = Object.values(mockData['/tasks']);
17
+
18
+ return (
19
+ <div className="mx-auto max-w-5xl space-y-8 px-2 py-4">
20
+ <div className="space-y-1">
21
+ <h1 className="text-2xl font-semibold">Project overview</h1>
22
+ <p className="text-sm text-muted-foreground">Track projects, tasks and team progress.</p>
23
+ </div>
24
+
25
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
26
+ <StatCard label="Projects" value={projects.length} />
27
+ <StatCard label="Active" value={projects.filter(p => p.status === 'active').length} sub="projects" />
28
+ <StatCard label="Open tasks" value={tasks.filter(t => t.status !== 'done').length} />
29
+ <StatCard label="Completed" value={tasks.filter(t => t.status === 'done').length} sub="tasks" />
30
+ </div>
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { Grid, Badge, Input, Select, type BadgeType } from '@llmnative/react';
3
+
4
+ const statusOptions = [
5
+ { label: 'Planning', value: 'planning' },
6
+ { label: 'Active', value: 'active' },
7
+ { label: 'On hold', value: 'on-hold' },
8
+ { label: 'Done', value: 'done' },
9
+ ];
10
+
11
+ const statusVariant: Record<string, BadgeType> = {
12
+ planning: 'secondary',
13
+ active: 'primary',
14
+ 'on-hold': 'warning',
15
+ done: 'success',
16
+ };
17
+
18
+ export default function ProjectsPage() {
19
+ return (
20
+ <Grid
21
+ path="/projects"
22
+ columns={[
23
+ { key: 'name', label: 'Project', sortable: true },
24
+ { key: 'owner', label: 'Owner' },
25
+ {
26
+ key: 'status',
27
+ label: 'Status',
28
+ render: ({ value }) => (
29
+ <Badge variant={statusVariant[String(value)] ?? 'secondary'}>{String(value)}</Badge>
30
+ ),
31
+ },
32
+ { key: 'deadline', label: 'Deadline' },
33
+ { key: 'description', label: 'Description' },
34
+ ]}
35
+ actions={['add', 'edit', 'delete']}
36
+ view="table"
37
+ sortable
38
+ pagination={{ limit: 20 }}
39
+ form={
40
+ <>
41
+ <Input name="name" label="Project name" required />
42
+ <Input name="owner" label="Owner" />
43
+ <Select name="status" label="Status" options={statusOptions} />
44
+ <Input name="deadline" label="Deadline" type="date" />
45
+ <Input name="description" label="Description" />
46
+ </>
47
+ }
48
+ />
49
+ );
50
+ }