@proofkit/cli 2.0.0-beta.21 → 2.0.0-beta.23

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 (114) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/add-DrcID6d6.js +57 -0
  3. package/dist/add-DrcID6d6.js.map +1 -0
  4. package/dist/addPackageDependency-BGZl7xc5.js +4 -0
  5. package/dist/addPackageDependency-BGZl7xc5.js.map +1 -0
  6. package/dist/consts-BZnOMxpW.js +10 -0
  7. package/dist/consts-BZnOMxpW.js.map +1 -0
  8. package/dist/deploy-D25sPO7K.js +34 -0
  9. package/dist/deploy-D25sPO7K.js.map +1 -0
  10. package/dist/fmdapi-BO4QL0F8.js +2 -0
  11. package/dist/fmdapi-BO4QL0F8.js.map +1 -0
  12. package/dist/fmdapi-DyRYZWzI.js +3 -0
  13. package/dist/fmdapi-DyRYZWzI.js.map +1 -0
  14. package/dist/getUserPkgManager-Cph_6l1P.js +2 -0
  15. package/dist/getUserPkgManager-Cph_6l1P.js.map +1 -0
  16. package/dist/globalOptions-CkqEi9uC.js +2 -0
  17. package/dist/globalOptions-CkqEi9uC.js.map +1 -0
  18. package/dist/index-DALPpGd1.d.ts +366 -0
  19. package/dist/index-DALPpGd1.d.ts.map +1 -0
  20. package/dist/index.js +10 -157
  21. package/dist/index.js.map +1 -1
  22. package/dist/logger-DCEXcH26.js +2 -0
  23. package/dist/logger-DCEXcH26.js.map +1 -0
  24. package/dist/parseSettings-DJ2m9sgJ.js +2 -0
  25. package/dist/parseSettings-DJ2m9sgJ.js.map +1 -0
  26. package/dist/proofkit-webviewer-73IB1OBU.js +2 -0
  27. package/dist/proofkit-webviewer-73IB1OBU.js.map +1 -0
  28. package/dist/remove-BOCU6In3.js +2 -0
  29. package/dist/remove-BOCU6In3.js.map +1 -0
  30. package/dist/state-BVEcvFT3.js +41 -0
  31. package/dist/state-BVEcvFT3.js.map +1 -0
  32. package/dist/typegen-DyXaif5O.js +2 -0
  33. package/dist/typegen-DyXaif5O.js.map +1 -0
  34. package/dist/update-FX71y5b3.js +7 -0
  35. package/dist/update-FX71y5b3.js.map +1 -0
  36. package/dist/utils-DymV7zmv.js +3 -0
  37. package/dist/utils-DymV7zmv.js.map +1 -0
  38. package/package.json +18 -8
  39. package/template/fm-addon/ProofKitWV/de.xml +517 -20
  40. package/template/fm-addon/ProofKitWV/en.xml +517 -20
  41. package/template/fm-addon/ProofKitWV/es.xml +517 -20
  42. package/template/fm-addon/ProofKitWV/fr.xml +517 -20
  43. package/template/fm-addon/ProofKitWV/icon.png +0 -0
  44. package/template/fm-addon/ProofKitWV/icon@2x.png +0 -0
  45. package/template/fm-addon/ProofKitWV/info.json +9 -6
  46. package/template/fm-addon/ProofKitWV/info_de.json +12 -5
  47. package/template/fm-addon/ProofKitWV/info_en.json +16 -5
  48. package/template/fm-addon/ProofKitWV/info_es.json +12 -5
  49. package/template/fm-addon/ProofKitWV/info_fr.json +12 -5
  50. package/template/fm-addon/ProofKitWV/info_it.json +12 -5
  51. package/template/fm-addon/ProofKitWV/info_ja.json +12 -5
  52. package/template/fm-addon/ProofKitWV/info_ko.json +12 -5
  53. package/template/fm-addon/ProofKitWV/info_nl.json +12 -5
  54. package/template/fm-addon/ProofKitWV/info_pt.json +12 -5
  55. package/template/fm-addon/ProofKitWV/info_sv.json +12 -5
  56. package/template/fm-addon/ProofKitWV/info_zh.json +12 -5
  57. package/template/fm-addon/ProofKitWV/it.xml +517 -20
  58. package/template/fm-addon/ProofKitWV/ja.xml +517 -20
  59. package/template/fm-addon/ProofKitWV/ko.xml +517 -20
  60. package/template/fm-addon/ProofKitWV/nl.xml +517 -20
  61. package/template/fm-addon/ProofKitWV/preview.png +0 -0
  62. package/template/fm-addon/ProofKitWV/pt.xml +517 -20
  63. package/template/fm-addon/ProofKitWV/records_de.xml +0 -0
  64. package/template/fm-addon/ProofKitWV/records_en.xml +0 -0
  65. package/template/fm-addon/ProofKitWV/records_es.xml +0 -0
  66. package/template/fm-addon/ProofKitWV/records_fr.xml +0 -0
  67. package/template/fm-addon/ProofKitWV/records_it.xml +0 -0
  68. package/template/fm-addon/ProofKitWV/records_ja.xml +0 -0
  69. package/template/fm-addon/ProofKitWV/records_ko.xml +0 -0
  70. package/template/fm-addon/ProofKitWV/records_nl.xml +0 -0
  71. package/template/fm-addon/ProofKitWV/records_pt.xml +0 -0
  72. package/template/fm-addon/ProofKitWV/records_sv.xml +0 -0
  73. package/template/fm-addon/ProofKitWV/records_zh.xml +0 -0
  74. package/template/fm-addon/ProofKitWV/sv.xml +517 -20
  75. package/template/fm-addon/ProofKitWV/template.xml +0 -0
  76. package/template/fm-addon/ProofKitWV/zh.xml +517 -20
  77. package/template/nextjs-mantine/AGENTS.md +1 -0
  78. package/template/nextjs-mantine/package.json +2 -3
  79. package/template/nextjs-shadcn/AGENTS.md +1 -0
  80. package/template/nextjs-shadcn/package.json +3 -4
  81. package/template/vite-wv/.claude/launch.json +18 -0
  82. package/template/vite-wv/AGENTS.md +1 -0
  83. package/template/vite-wv/_gitignore +1 -0
  84. package/template/vite-wv/components.json +6 -6
  85. package/template/vite-wv/index.html +2 -2
  86. package/template/vite-wv/package.json +20 -37
  87. package/template/vite-wv/proofkit-typegen.config.jsonc +18 -0
  88. package/template/vite-wv/proofkit.json +4 -1
  89. package/template/vite-wv/scripts/filemaker.js +96 -0
  90. package/template/vite-wv/scripts/launch-fm.js +19 -0
  91. package/template/vite-wv/scripts/upload.js +17 -14
  92. package/template/vite-wv/src/App.tsx +84 -0
  93. package/template/vite-wv/src/index.css +96 -0
  94. package/template/vite-wv/src/lib/utils.ts +6 -0
  95. package/template/vite-wv/src/main.tsx +14 -35
  96. package/template/vite-wv/src/router.tsx +57 -0
  97. package/template/vite-wv/src/routes/query-demo.tsx +37 -0
  98. package/template/vite-wv/tsconfig.json +3 -1
  99. package/template/vite-wv/vite.config.ts +5 -5
  100. package/dist/index-JtcdNmdz.d.ts +0 -1
  101. package/template/vite-wv/pnpm-lock.yaml +0 -2294
  102. package/template/vite-wv/postcss.config.cjs +0 -15
  103. package/template/vite-wv/scripts/launch-fm.sh +0 -3
  104. package/template/vite-wv/src/components/AppLogo.tsx +0 -5
  105. package/template/vite-wv/src/components/full-screen-loader.tsx +0 -9
  106. package/template/vite-wv/src/config/env.ts +0 -16
  107. package/template/vite-wv/src/config/theme/globals.css +0 -125
  108. package/template/vite-wv/src/config/theme/mantine-theme.ts +0 -22
  109. package/template/vite-wv/src/routeTree.gen.ts +0 -111
  110. package/template/vite-wv/src/routes/__root.tsx +0 -21
  111. package/template/vite-wv/src/routes/index.tsx +0 -51
  112. package/template/vite-wv/src/routes/secondary.tsx +0 -26
  113. package/template/vite-wv/src/utils/notification-helpers.ts +0 -32
  114. package/template/vite-wv/src/utils/styles.ts +0 -6
@@ -0,0 +1 @@
1
+ __AGENT_INSTRUCTIONS__
@@ -6,8 +6,8 @@
6
6
  "dev": "next dev --turbopack",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
- "lint": "biome check",
10
- "format": "biome format --write",
9
+ "lint": "ultracite check .",
10
+ "format": "ultracite fix .",
11
11
  "proofkit": "proofkit",
12
12
  "typegen": "proofkit typegen",
13
13
  "deploy": "proofkit deploy"
@@ -35,7 +35,6 @@
35
35
  "@types/node": "^20",
36
36
  "@types/react": "npm:types-react@19.0.12",
37
37
  "@types/react-dom": "npm:types-react-dom@19.0.4",
38
- "@biomejs/biome": "2.3.11",
39
38
  "postcss": "^8.4.41",
40
39
  "ultracite": "7.0.8",
41
40
  "postcss-preset-mantine": "^1.17.0",
@@ -0,0 +1 @@
1
+ __AGENT_INSTRUCTIONS__
@@ -7,8 +7,8 @@
7
7
  "build": "next build --turbopack",
8
8
  "proofkit": "proofkit",
9
9
  "start": "next start",
10
- "lint": "biome check",
11
- "format": "biome format --write"
10
+ "lint": "ultracite check .",
11
+ "format": "ultracite fix ."
12
12
  },
13
13
  "dependencies": {
14
14
  "@radix-ui/react-slot": "^1.2.3",
@@ -25,7 +25,6 @@
25
25
  "tailwind-merge": "^3.3.1"
26
26
  },
27
27
  "devDependencies": {
28
- "@biomejs/biome": "2.3.11",
29
28
  "@tailwindcss/postcss": "^4",
30
29
  "@types/node": "^22",
31
30
  "@types/react": "^19",
@@ -33,6 +32,6 @@
33
32
  "tailwindcss": "^4",
34
33
  "tw-animate-css": "^1.3.7",
35
34
  "typescript": "^5",
36
- "ultracite": "5.4.5"
35
+ "ultracite": "7.0.8"
37
36
  }
38
37
  }
@@ -0,0 +1,18 @@
1
+ {
2
+ "configurations": [
3
+ {
4
+ "name": "Preview",
5
+ "runtimeExecutable": "__PACKAGE_MANAGER__",
6
+ "runtimeArgs": ["run", "dev"],
7
+ "cwd": "${workspaceFolder}",
8
+ "autoPort": true,
9
+ "port": 5175
10
+ },
11
+ {
12
+ "name": "Typegen",
13
+ "runtimeExecutable": "__PACKAGE_MANAGER__",
14
+ "runtimeArgs": ["run", "typegen"],
15
+ "cwd": "${workspaceFolder}"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1 @@
1
+ __AGENT_INSTRUCTIONS__
@@ -2,6 +2,7 @@
2
2
  .DS_Store
3
3
  *.local
4
4
  *.log*
5
+ .env*
5
6
 
6
7
  # Dist
7
8
  node_modules
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "$schema": "https://ui.shadcn.com/schema.json",
3
3
  "style": "new-york",
4
- "rsc": true,
4
+ "rsc": false,
5
5
  "tsx": true,
6
6
  "tailwind": {
7
7
  "config": "",
8
- "css": "src/config/theme/globals.css",
8
+ "css": "src/index.css",
9
9
  "baseColor": "neutral",
10
10
  "cssVariables": true,
11
- "prefix": "tw:"
11
+ "prefix": ""
12
12
  },
13
13
  "aliases": {
14
14
  "components": "@/components",
15
- "utils": "@/utils/styles",
15
+ "utils": "@/lib/utils",
16
16
  "ui": "@/components/ui",
17
- "lib": "@/utils",
18
- "hooks": "@/utils/hooks"
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
19
  },
20
20
  "iconLibrary": "lucide"
21
21
  }
@@ -3,11 +3,11 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>ProofKit WebViewer</title>
6
+ <title>ProofKit WebViewer Starter</title>
7
7
  </head>
8
8
 
9
9
  <body>
10
- <div id="app"></div>
10
+ <div id="root"></div>
11
11
  <script type="module" src="/src/main.tsx"></script>
12
12
  </body>
13
13
  </html>
@@ -5,51 +5,34 @@
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "vite build",
8
- "build:upload": "pnpm build && pnpm upload",
8
+ "build:upload": "__PNPM_COMMAND__ build && __PNPM_COMMAND__ upload",
9
9
  "dev": "vite",
10
- "launch-fm": "./scripts/launch-fm.sh",
10
+ "launch-fm": "node ./scripts/launch-fm.js",
11
11
  "proofkit": "proofkit",
12
12
  "serve": "vite preview",
13
13
  "start": "vite",
14
- "typegen": "proofkit typegen",
15
- "upload": "node scripts/upload.js",
16
- "lint": "biome check",
17
- "format": "biome format --write"
14
+ "typegen": "typegen",
15
+ "typegen:ui": "typegen ui",
16
+ "upload": "node ./scripts/upload.js",
17
+ "lint": "ultracite check .",
18
+ "format": "ultracite fix ."
18
19
  },
19
20
  "dependencies": {
20
- "@mantine/core": "^7.15.1",
21
- "@mantine/dates": "^7.15.1",
22
- "@mantine/hooks": "^7.15.1",
23
- "@mantine/modals": "^7.15.1",
24
- "@mantine/notifications": "^7.15.1",
25
- "@proofkit/webviewer": "^3.0.0",
26
- "@proofkit/fmdapi": "^5.0.0",
27
- "@t3-oss/env-core": "^0.12.0",
28
- "@tabler/icons-react": "^3.26.0",
29
- "@tanstack/react-query": "^5.69.0",
30
- "@tanstack/react-router": "^1.114.27",
31
- "mantine-react-table": "2.0.0-beta.7",
32
- "react": "^19.0.0",
33
- "react-dom": "^19.0.0",
34
- "vite-plugin-singlefile": "^2.1.0",
35
- "zod": "^3.24.1"
21
+ "@tanstack/react-query": "^5.90.21",
22
+ "@tanstack/react-router": "^1.167.4",
23
+ "react": "^19.2.4",
24
+ "react-dom": "^19.2.4"
36
25
  },
37
26
  "devDependencies": {
38
- "@biomejs/biome": "2.3.11",
39
- "@tanstack/react-query-devtools": "^5.69.0",
27
+ "@proofkit/typegen": "^1.1.0-beta.16",
28
+ "@types/react": "^19.2.14",
29
+ "@types/react-dom": "^19.2.3",
30
+ "@vitejs/plugin-react": "^5.2.0",
31
+ "dotenv": "^17.3.1",
32
+ "open": "^11.0.0",
33
+ "typescript": "^5.9.3",
40
34
  "ultracite": "7.0.8",
41
- "@tanstack/react-router-devtools": "^1.114.27",
42
- "@tanstack/router-plugin": "^1.114.27",
43
- "@types/node": "^22.13.13",
44
- "@types/react": "^19.0.12",
45
- "@types/react-dom": "^19.0.4",
46
- "@vitejs/plugin-react": "^4.3.4",
47
- "dotenv": "^16.4.7",
48
- "open": "^10.1.0",
49
- "postcss": "^8.5.3",
50
- "postcss-preset-mantine": "^1.17.0",
51
- "postcss-simple-vars": "^7.0.1",
52
- "typescript": "^5",
53
- "vite": "^6.2.3"
35
+ "vite": "^7.3.1",
36
+ "vite-plugin-singlefile": "^2.3.2"
54
37
  }
55
38
  }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://proofkit.dev/typegen-config-schema.json",
3
+ "config": {
4
+ "type": "fmdapi",
5
+ "path": "./src/config/schemas/filemaker",
6
+ "clearOldFiles": true,
7
+ "clientSuffix": "Layout",
8
+ "validator": "zod/v4",
9
+ "webviewerScriptName": "ExecuteDataApi",
10
+ "fmMcp": {
11
+ "enabled": true
12
+ },
13
+ "layouts": [
14
+ // Add layouts here when you're ready to generate clients.
15
+ // { "layoutName": "API_Customers", "schemaName": "Customers" }
16
+ ]
17
+ }
18
+ }
@@ -1,6 +1,9 @@
1
1
  {
2
+ "ui": "shadcn",
2
3
  "auth": { "type": "none" },
3
4
  "envFile": ".env",
4
5
  "appType": "webviewer",
5
- "appliedUpgrades": ["shadcn"]
6
+ "dataSources": [],
7
+ "replacedMainPage": false,
8
+ "registryTemplates": []
6
9
  }
@@ -0,0 +1,96 @@
1
+ import { resolve } from "node:path";
2
+ import dotenv from "dotenv";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const currentDirectory = fileURLToPath(new URL(".", import.meta.url));
6
+ const envPath = resolve(currentDirectory, "../.env");
7
+
8
+ dotenv.config({ path: envPath });
9
+
10
+ const defaultFmMcpBaseUrl = process.env.FM_MCP_BASE_URL ?? "http://127.0.0.1:1365";
11
+
12
+ function stripFileExtension(fileName) {
13
+ return fileName.replace(/\.fmp12$/i, "");
14
+ }
15
+
16
+ async function getConnectedFiles(baseUrl = defaultFmMcpBaseUrl) {
17
+ const healthResponse = await fetch(`${baseUrl}/health`).catch(() => null);
18
+ if (!healthResponse?.ok) {
19
+ return [];
20
+ }
21
+
22
+ const connectedFiles = await fetch(`${baseUrl}/connectedFiles`)
23
+ .then((response) => (response.ok ? response.json() : []))
24
+ .catch(() => []);
25
+
26
+ return Array.isArray(connectedFiles) ? connectedFiles : [];
27
+ }
28
+
29
+ function normalizeTarget(fileName) {
30
+ return stripFileExtension(fileName).toLowerCase();
31
+ }
32
+
33
+ export async function resolveFileMakerTarget() {
34
+ const connectedFiles = await getConnectedFiles();
35
+ const targetFromEnv = process.env.FM_DATABASE ? normalizeTarget(process.env.FM_DATABASE) : undefined;
36
+
37
+ if (targetFromEnv) {
38
+ const matches = connectedFiles.filter((connectedFile) => normalizeTarget(connectedFile) === targetFromEnv);
39
+ if (matches.length === 1) {
40
+ return {
41
+ fileName: stripFileExtension(matches[0]),
42
+ host: "$",
43
+ source: "fm-mcp",
44
+ };
45
+ }
46
+
47
+ if (connectedFiles.length > 0) {
48
+ throw new Error(
49
+ `FM_DATABASE is set to "${process.env.FM_DATABASE}" but no matching connected file was found via FM MCP.`,
50
+ );
51
+ }
52
+ }
53
+
54
+ if (connectedFiles.length === 1) {
55
+ return {
56
+ fileName: stripFileExtension(connectedFiles[0]),
57
+ host: "$",
58
+ source: "fm-mcp",
59
+ };
60
+ }
61
+
62
+ if (connectedFiles.length > 1) {
63
+ throw new Error(
64
+ `Multiple FileMaker files are connected via FM MCP (${connectedFiles.join(", ")}). Set FM_DATABASE to choose one.`,
65
+ );
66
+ }
67
+
68
+ const serverValue = process.env.FM_SERVER;
69
+ const databaseValue = process.env.FM_DATABASE;
70
+
71
+ if (serverValue && databaseValue) {
72
+ let hostname;
73
+ try {
74
+ hostname = new URL(serverValue).hostname;
75
+ } catch {
76
+ hostname = serverValue.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
77
+ }
78
+
79
+ return {
80
+ fileName: stripFileExtension(databaseValue),
81
+ host: hostname,
82
+ source: "env",
83
+ };
84
+ }
85
+
86
+ return null;
87
+ }
88
+
89
+ export function buildFmpUrl({ host, fileName, scriptName, parameter }) {
90
+ const params = new URLSearchParams({ script: scriptName });
91
+ if (parameter) {
92
+ params.set("param", parameter);
93
+ }
94
+
95
+ return `fmp://${host}/${encodeURIComponent(fileName)}?${params.toString()}`;
96
+ }
@@ -0,0 +1,19 @@
1
+ import open from "open";
2
+ import { buildFmpUrl, resolveFileMakerTarget } from "./filemaker.js";
3
+
4
+ const target = await resolveFileMakerTarget();
5
+
6
+ if (!target) {
7
+ console.error(
8
+ "Could not resolve a FileMaker file. Start the local FM MCP proxy with a connected file, or set FM_SERVER and FM_DATABASE in .env.",
9
+ );
10
+ process.exit(1);
11
+ }
12
+
13
+ await open(
14
+ buildFmpUrl({
15
+ host: target.host,
16
+ fileName: target.fileName,
17
+ scriptName: "Launch Web Viewer for Dev",
18
+ }),
19
+ );
@@ -1,21 +1,24 @@
1
1
  import open from "open";
2
2
  import { resolve } from "path";
3
- import dotenv from "dotenv";
4
3
  import { fileURLToPath } from "url";
4
+ import { buildFmpUrl, resolveFileMakerTarget } from "./filemaker.js";
5
5
 
6
6
  const currentDirectory = fileURLToPath(new URL(".", import.meta.url));
7
-
8
- const { parsed } = dotenv.config({
9
- path: resolve(currentDirectory, "../.env"),
10
- });
11
-
12
- const server = new URL(parsed.FM_SERVER).hostname;
13
- const file = parsed.FM_DATABASE.replace(/\.fmp12$/, "");
14
- const uploadScript = "UploadWebviewerWidget";
15
-
16
7
  const thePath = resolve(currentDirectory, "../dist", "index.html");
17
- const url = `fmp://${server}/${file}?script=${uploadScript}&param=${encodeURIComponent(
18
- thePath
19
- )}`;
8
+ const target = await resolveFileMakerTarget();
9
+
10
+ if (!target) {
11
+ console.error(
12
+ "Could not resolve a FileMaker file. Start the local FM MCP proxy with a connected file, or set FM_SERVER and FM_DATABASE in .env.",
13
+ );
14
+ process.exit(1);
15
+ }
20
16
 
21
- open(url);
17
+ await open(
18
+ buildFmpUrl({
19
+ host: target.host,
20
+ fileName: target.fileName,
21
+ scriptName: "UploadWebviewerWidget",
22
+ parameter: thePath,
23
+ }),
24
+ );
@@ -0,0 +1,84 @@
1
+ import { globalSettings } from "@proofkit/webviewer";
2
+ import type { LucideIcon } from "lucide-react";
3
+ import { Database, Layers, Sparkles } from "lucide-react";
4
+
5
+ type Step = {
6
+ readonly icon: LucideIcon;
7
+ readonly title: string;
8
+ readonly body: string;
9
+ };
10
+
11
+ globalSettings.setWebViewerName("web");
12
+
13
+ const steps: readonly Step[] = [
14
+ {
15
+ icon: Database,
16
+ title: "Connect FileMaker later",
17
+ body: "This starter renders safely in a normal browser. When you are ready, wire in FM MCP or hosted FileMaker setup with ProofKit commands.",
18
+ },
19
+ {
20
+ icon: Layers,
21
+ title: "Generate clients when ready",
22
+ body: "Add layouts to proofkit-typegen.config.jsonc, then run your typegen script to create strongly typed layout clients.",
23
+ },
24
+ {
25
+ icon: Sparkles,
26
+ title: "Add shadcn components fast",
27
+ body: "Tailwind v4 and shadcn are already initialized, so agents and developers can add components without extra setup.",
28
+ },
29
+ ] as const;
30
+
31
+ export default function App() {
32
+ return (
33
+ <main>
34
+ <div className="mx-auto flex min-h-screen w-full max-w-5xl flex-col px-6 py-10 sm:px-10">
35
+ <div className="mb-10 flex-1">
36
+ <div className="inline-flex items-center gap-2 rounded-full border border-border bg-card px-3 py-1 text-sm text-muted-foreground shadow-sm">
37
+ <span className="h-2 w-2 rounded-full bg-primary" />
38
+ ProofKit WebViewer Starter
39
+ </div>
40
+
41
+ <div className="mt-8 grid gap-8 lg:grid-cols-[1.2fr_0.8fr]">
42
+ <section className="rounded-3xl border border-border bg-card/80 p-8 shadow-sm">
43
+ <p className="text-sm font-medium uppercase tracking-[0.2em] text-muted-foreground">
44
+ React + TypeScript + Vite
45
+ </p>
46
+ <h1 className="mt-4 max-w-xl text-4xl font-semibold tracking-tight text-balance sm:text-5xl">
47
+ Build browser-safe FileMaker WebViewer apps without scaffolding against a hosted server.
48
+ </h1>
49
+ <p className="mt-6 max-w-2xl text-lg leading-8 text-muted-foreground">
50
+ This starter stays intentionally small, but it is already ready for Tailwind v4, shadcn component
51
+ installs, hash-based TanStack Router navigation, React Query, and later ProofKit typegen output.
52
+ </p>
53
+
54
+ <div className="mt-8 flex flex-wrap gap-3 text-sm">
55
+ <code className="rounded-full border border-border bg-background px-3 py-1.5">pnpm dev</code>
56
+ <code className="rounded-full border border-border bg-background px-3 py-1.5">pnpm typegen</code>
57
+ <code className="rounded-full border border-border bg-background px-3 py-1.5">pnpm launch-fm</code>
58
+ </div>
59
+ </section>
60
+
61
+ <aside className="rounded-3xl border border-border bg-gradient-to-br from-card via-card to-muted/50 p-8 shadow-sm">
62
+ <p className="text-sm font-medium uppercase tracking-[0.2em] text-muted-foreground">Starter notes</p>
63
+ <div className="mt-5 space-y-4 text-sm text-muted-foreground">
64
+ <p>Update the default WebViewer name in <code>src/App.tsx</code> to match your FileMaker layout object.</p>
65
+ <p>When the app runs inside FileMaker, you can start using <code>fmFetch</code> or generated clients right away.</p>
66
+ <p>The local helper scripts prefer FM MCP connected files before falling back to hosted server env vars.</p>
67
+ </div>
68
+ </aside>
69
+ </div>
70
+
71
+ <section className="mt-8 grid gap-4 md:grid-cols-3">
72
+ {steps.map((step) => (
73
+ <article key={step.title} className="rounded-2xl border border-border bg-card p-6 shadow-sm">
74
+ <step.icon className="h-5 w-5 text-primary" />
75
+ <h2 className="mt-4 text-lg font-semibold">{step.title}</h2>
76
+ <p className="mt-3 text-sm leading-6 text-muted-foreground">{step.body}</p>
77
+ </article>
78
+ ))}
79
+ </section>
80
+ </div>
81
+ </div>
82
+ </main>
83
+ );
84
+ }
@@ -0,0 +1,96 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ :root {
5
+ --background: hsl(42 33% 98%);
6
+ --foreground: hsl(222 47% 11%);
7
+ --card: hsl(0 0% 100%);
8
+ --card-foreground: hsl(222 47% 11%);
9
+ --popover: hsl(0 0% 100%);
10
+ --popover-foreground: hsl(222 47% 11%);
11
+ --primary: hsl(197 82% 44%);
12
+ --primary-foreground: hsl(210 40% 98%);
13
+ --secondary: hsl(210 20% 93%);
14
+ --secondary-foreground: hsl(222 47% 11%);
15
+ --muted: hsl(42 21% 94%);
16
+ --muted-foreground: hsl(215 16% 40%);
17
+ --accent: hsl(32 88% 92%);
18
+ --accent-foreground: hsl(24 10% 10%);
19
+ --destructive: hsl(0 72% 51%);
20
+ --destructive-foreground: hsl(210 40% 98%);
21
+ --border: hsl(30 14% 86%);
22
+ --input: hsl(30 14% 86%);
23
+ --ring: hsl(197 82% 44%);
24
+ --radius: 1rem;
25
+ }
26
+
27
+ .dark {
28
+ color-scheme: dark;
29
+ --background: hsl(221 39% 11%);
30
+ --foreground: hsl(44 23% 92%);
31
+ --card: hsl(222 33% 15%);
32
+ --card-foreground: hsl(44 23% 92%);
33
+ --popover: hsl(222 33% 15%);
34
+ --popover-foreground: hsl(44 23% 92%);
35
+ --primary: hsl(190 82% 62%);
36
+ --primary-foreground: hsl(222 47% 11%);
37
+ --secondary: hsl(219 19% 22%);
38
+ --secondary-foreground: hsl(44 23% 92%);
39
+ --muted: hsl(219 19% 22%);
40
+ --muted-foreground: hsl(215 20% 72%);
41
+ --accent: hsl(27 42% 28%);
42
+ --accent-foreground: hsl(44 23% 92%);
43
+ --destructive: hsl(0 63% 54%);
44
+ --destructive-foreground: hsl(210 40% 98%);
45
+ --border: hsl(219 19% 26%);
46
+ --input: hsl(219 19% 26%);
47
+ --ring: hsl(190 82% 62%);
48
+ }
49
+
50
+ @theme inline {
51
+ --color-background: var(--background);
52
+ --color-foreground: var(--foreground);
53
+ --color-card: var(--card);
54
+ --color-card-foreground: var(--card-foreground);
55
+ --color-popover: var(--popover);
56
+ --color-popover-foreground: var(--popover-foreground);
57
+ --color-primary: var(--primary);
58
+ --color-primary-foreground: var(--primary-foreground);
59
+ --color-secondary: var(--secondary);
60
+ --color-secondary-foreground: var(--secondary-foreground);
61
+ --color-muted: var(--muted);
62
+ --color-muted-foreground: var(--muted-foreground);
63
+ --color-accent: var(--accent);
64
+ --color-accent-foreground: var(--accent-foreground);
65
+ --color-destructive: var(--destructive);
66
+ --color-destructive-foreground: var(--destructive-foreground);
67
+ --color-border: var(--border);
68
+ --color-input: var(--input);
69
+ --color-ring: var(--ring);
70
+ --radius-sm: calc(var(--radius) - 4px);
71
+ --radius-md: calc(var(--radius) - 2px);
72
+ --radius-lg: var(--radius);
73
+ --radius-xl: calc(var(--radius) + 4px);
74
+ }
75
+
76
+ @layer base {
77
+ * {
78
+ @apply border-border;
79
+ }
80
+
81
+ html {
82
+ color-scheme: light;
83
+ }
84
+
85
+ body {
86
+ background-color: var(--background);
87
+ color: var(--foreground);
88
+ font-family:
89
+ "Instrument Sans",
90
+ Inter,
91
+ ui-sans-serif,
92
+ system-ui,
93
+ sans-serif;
94
+ min-width: 320px;
95
+ }
96
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -1,42 +1,21 @@
1
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2
+ import { RouterProvider } from "@tanstack/react-router";
1
3
  import React from "react";
2
4
  import ReactDOM from "react-dom/client";
3
- import {
4
- RouterProvider,
5
- createHashHistory,
6
- createRouter,
7
- } from "@tanstack/react-router";
8
- import { routeTree } from "./routeTree.gen";
9
- import { MantineProvider } from "@mantine/core";
10
- import { theme } from "./config/theme/mantine-theme";
5
+ import "./index.css";
6
+ import { router } from "./router";
11
7
 
12
- import "@mantine/core/styles.css";
13
- import "mantine-react-table/styles.css";
14
- import "./config/theme/globals.css";
8
+ const queryClient = new QueryClient();
15
9
 
16
- // Hash history is used since we are using a single file build
17
- const hashHistory = createHashHistory();
18
-
19
- // Set up a Router instance
20
- const router = createRouter({
21
- routeTree,
22
- defaultPreload: "intent",
23
- history: hashHistory,
24
- });
25
-
26
- // Register things for typesafety
27
- declare module "@tanstack/react-router" {
28
- interface Register {
29
- router: typeof router;
30
- }
10
+ const rootElement = document.getElementById("root");
11
+ if (!rootElement) {
12
+ throw new Error("Root element with id 'root' not found");
31
13
  }
32
14
 
33
- const rootElement = document.getElementById("app")!;
34
-
35
- if (!rootElement.innerHTML) {
36
- const root = ReactDOM.createRoot(rootElement);
37
- root.render(
38
- <MantineProvider theme={theme} forceColorScheme="light">
15
+ ReactDOM.createRoot(rootElement).render(
16
+ <React.StrictMode>
17
+ <QueryClientProvider client={queryClient}>
39
18
  <RouterProvider router={router} />
40
- </MantineProvider>,
41
- );
42
- }
19
+ </QueryClientProvider>
20
+ </React.StrictMode>,
21
+ );