@float.js/core 2.0.7 → 2.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/cli/index.js CHANGED
@@ -730,7 +730,7 @@ function generateAPIResponse(state) {
730
730
  function createDevDashboard(options = {}) {
731
731
  const {
732
732
  enabled = process.env.NODE_ENV !== "production",
733
- path: path7 = "/__float",
733
+ path: path9 = "/__float",
734
734
  auth
735
735
  } = options;
736
736
  if (!enabled) {
@@ -738,7 +738,7 @@ function createDevDashboard(options = {}) {
738
738
  }
739
739
  return (req, res, next) => {
740
740
  const url = req.url || "";
741
- if (!url.startsWith(path7)) {
741
+ if (!url.startsWith(path9)) {
742
742
  return next();
743
743
  }
744
744
  if (auth) {
@@ -757,7 +757,7 @@ function createDevDashboard(options = {}) {
757
757
  return;
758
758
  }
759
759
  }
760
- const subPath = url.slice(path7.length);
760
+ const subPath = url.slice(path9.length);
761
761
  if (subPath === "" || subPath === "/") {
762
762
  res.setHeader("Content-Type", "text/html");
763
763
  res.end(generateDashboardHTML(dashboardState));
@@ -868,14 +868,14 @@ var init_devtools = __esm({
868
868
  // src/cli/index.ts
869
869
  init_esm_shims();
870
870
  import { cac } from "cac";
871
- import pc4 from "picocolors";
871
+ import pc5 from "picocolors";
872
872
 
873
873
  // src/server/dev-server.ts
874
874
  init_esm_shims();
875
875
  import http from "http";
876
- import fs2 from "fs";
877
- import path4 from "path";
878
- import pc from "picocolors";
876
+ import fs4 from "fs";
877
+ import path6 from "path";
878
+ import pc2 from "picocolors";
879
879
  import chokidar from "chokidar";
880
880
  import { WebSocketServer, WebSocket } from "ws";
881
881
  import mime from "mime-types";
@@ -2464,11 +2464,214 @@ function generateExamplesPage() {
2464
2464
  ` + footer;
2465
2465
  }
2466
2466
 
2467
+ // src/build/css-processor.ts
2468
+ init_esm_shims();
2469
+ import fs3 from "fs";
2470
+ import path5 from "path";
2471
+
2472
+ // src/build/tailwind-setup.ts
2473
+ init_esm_shims();
2474
+ import fs2 from "fs";
2475
+ import path4 from "path";
2476
+ import pc from "picocolors";
2477
+ function checkTailwindSetup(rootDir) {
2478
+ const possibleConfigs = [
2479
+ "tailwind.config.js",
2480
+ "tailwind.config.ts",
2481
+ "tailwind.config.mjs",
2482
+ "tailwind.config.cjs"
2483
+ ];
2484
+ let configPath = null;
2485
+ for (const config of possibleConfigs) {
2486
+ const fullPath = path4.join(rootDir, config);
2487
+ if (fs2.existsSync(fullPath)) {
2488
+ configPath = fullPath;
2489
+ break;
2490
+ }
2491
+ }
2492
+ const globalsPath = path4.join(rootDir, "app", "globals.css");
2493
+ const hasGlobals = fs2.existsSync(globalsPath);
2494
+ return {
2495
+ hasTailwind: !!configPath,
2496
+ configPath,
2497
+ globalsPath: hasGlobals ? globalsPath : null,
2498
+ needsSetup: !configPath || !hasGlobals
2499
+ };
2500
+ }
2501
+ async function setupTailwind(rootDir, options = {}) {
2502
+ const { force = false, silent = false } = options;
2503
+ const config = checkTailwindSetup(rootDir);
2504
+ if (!force && !config.needsSetup) {
2505
+ return;
2506
+ }
2507
+ if (!silent) {
2508
+ console.log(pc.cyan("\n\u{1F3A8} Setting up Tailwind CSS..."));
2509
+ }
2510
+ if (!config.configPath || force) {
2511
+ const tailwindConfig = `/** @type {import('tailwindcss').Config} */
2512
+ export default {
2513
+ content: [
2514
+ './app/**/*.{js,ts,jsx,tsx}',
2515
+ './components/**/*.{js,ts,jsx,tsx}',
2516
+ ],
2517
+ theme: {
2518
+ extend: {},
2519
+ },
2520
+ plugins: [],
2521
+ }
2522
+ `;
2523
+ const configPath = path4.join(rootDir, "tailwind.config.js");
2524
+ fs2.writeFileSync(configPath, tailwindConfig);
2525
+ if (!silent) {
2526
+ console.log(pc.green(" \u2713 Created tailwind.config.js"));
2527
+ }
2528
+ }
2529
+ const postcssPath = path4.join(rootDir, "postcss.config.js");
2530
+ if (!fs2.existsSync(postcssPath) || force) {
2531
+ const postcssConfig = `export default {
2532
+ plugins: {
2533
+ tailwindcss: {},
2534
+ autoprefixer: {},
2535
+ },
2536
+ }
2537
+ `;
2538
+ fs2.writeFileSync(postcssPath, postcssConfig);
2539
+ if (!silent) {
2540
+ console.log(pc.green(" \u2713 Created postcss.config.js"));
2541
+ }
2542
+ }
2543
+ const appDir = path4.join(rootDir, "app");
2544
+ if (!fs2.existsSync(appDir)) {
2545
+ fs2.mkdirSync(appDir, { recursive: true });
2546
+ }
2547
+ const globalsPath = path4.join(appDir, "globals.css");
2548
+ if (!fs2.existsSync(globalsPath) || force) {
2549
+ const globalsCss = `@tailwind base;
2550
+ @tailwind components;
2551
+ @tailwind utilities;
2552
+ `;
2553
+ fs2.writeFileSync(globalsPath, globalsCss);
2554
+ if (!silent) {
2555
+ console.log(pc.green(" \u2713 Created app/globals.css"));
2556
+ }
2557
+ }
2558
+ const layoutPath = path4.join(appDir, "layout.tsx");
2559
+ if (!fs2.existsSync(layoutPath)) {
2560
+ const layoutContent = `import './globals.css'
2561
+
2562
+ export default function RootLayout({
2563
+ children,
2564
+ }: {
2565
+ children: React.ReactNode
2566
+ }) {
2567
+ return (
2568
+ <html lang="en">
2569
+ <body>{children}</body>
2570
+ </html>
2571
+ )
2572
+ }
2573
+ `;
2574
+ fs2.writeFileSync(layoutPath, layoutContent);
2575
+ if (!silent) {
2576
+ console.log(pc.green(" \u2713 Created app/layout.tsx"));
2577
+ }
2578
+ }
2579
+ if (!silent) {
2580
+ console.log(pc.green("\n\u2728 Tailwind CSS ready!\n"));
2581
+ }
2582
+ }
2583
+ function checkTailwindDeps(rootDir) {
2584
+ const packageJsonPath = path4.join(rootDir, "package.json");
2585
+ if (!fs2.existsSync(packageJsonPath)) {
2586
+ return {
2587
+ hasPackageJson: false,
2588
+ hasTailwind: false,
2589
+ hasPostCSS: false,
2590
+ hasAutoprefixer: false
2591
+ };
2592
+ }
2593
+ const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
2594
+ const allDeps = {
2595
+ ...packageJson.dependencies,
2596
+ ...packageJson.devDependencies
2597
+ };
2598
+ return {
2599
+ hasPackageJson: true,
2600
+ hasTailwind: !!allDeps["tailwindcss"],
2601
+ hasPostCSS: !!allDeps["postcss"],
2602
+ hasAutoprefixer: !!allDeps["autoprefixer"]
2603
+ };
2604
+ }
2605
+ function getTailwindInstallCommand(rootDir) {
2606
+ const deps = checkTailwindDeps(rootDir);
2607
+ if (!deps.hasPackageJson) {
2608
+ return null;
2609
+ }
2610
+ const missing = [];
2611
+ if (!deps.hasTailwind) missing.push("tailwindcss");
2612
+ if (!deps.hasPostCSS) missing.push("postcss");
2613
+ if (!deps.hasAutoprefixer) missing.push("autoprefixer");
2614
+ if (missing.length === 0) {
2615
+ return null;
2616
+ }
2617
+ const hasYarnLock = fs2.existsSync(path4.join(rootDir, "yarn.lock"));
2618
+ const hasPnpmLock = fs2.existsSync(path4.join(rootDir, "pnpm-lock.yaml"));
2619
+ const hasBunLock = fs2.existsSync(path4.join(rootDir, "bun.lockb"));
2620
+ let pm = "npm install -D";
2621
+ if (hasBunLock) pm = "bun add -d";
2622
+ else if (hasPnpmLock) pm = "pnpm add -D";
2623
+ else if (hasYarnLock) pm = "yarn add -D";
2624
+ return `${pm} ${missing.join(" ")}`;
2625
+ }
2626
+
2627
+ // src/build/css-processor.ts
2628
+ async function processCSS(filePath, rootDir = process.cwd()) {
2629
+ const content = fs3.readFileSync(filePath, "utf-8");
2630
+ const tailwindConfig = checkTailwindSetup(rootDir);
2631
+ if (!tailwindConfig.hasTailwind) {
2632
+ return { code: content };
2633
+ }
2634
+ try {
2635
+ const postcss = await import("postcss").then((m) => m.default);
2636
+ const tailwindcss = await import("tailwindcss").then((m) => m.default);
2637
+ const autoprefixer = await import("autoprefixer").then((m) => m.default);
2638
+ const configPath = tailwindConfig.configPath || path5.join(rootDir, "tailwind.config.js");
2639
+ let tailwindConfigModule = {};
2640
+ if (fs3.existsSync(configPath)) {
2641
+ const configUrl = new URL(`file://${configPath}`);
2642
+ tailwindConfigModule = await import(configUrl.href).then((m) => m.default || m);
2643
+ }
2644
+ const result = await postcss([
2645
+ tailwindcss(tailwindConfigModule),
2646
+ autoprefixer()
2647
+ ]).process(content, {
2648
+ from: filePath,
2649
+ to: filePath,
2650
+ map: { inline: false }
2651
+ });
2652
+ return {
2653
+ code: result.css,
2654
+ map: result.map?.toString()
2655
+ };
2656
+ } catch (error) {
2657
+ console.warn("CSS processing failed, serving raw CSS:", error);
2658
+ return { code: content };
2659
+ }
2660
+ }
2661
+ function needsCSSProcessing(filePath, rootDir) {
2662
+ const config = checkTailwindSetup(rootDir);
2663
+ if (!config.hasTailwind) {
2664
+ return false;
2665
+ }
2666
+ const content = fs3.readFileSync(filePath, "utf-8");
2667
+ return content.includes("@tailwind") || content.includes("@apply");
2668
+ }
2669
+
2467
2670
  // src/server/dev-server.ts
2468
2671
  async function createDevServer(options) {
2469
2672
  const { port, host, open } = options;
2470
2673
  const rootDir = process.cwd();
2471
- const publicDir = path4.join(rootDir, "public");
2674
+ const publicDir = path6.join(rootDir, "public");
2472
2675
  let routes = [];
2473
2676
  let server = null;
2474
2677
  let wss = null;
@@ -2476,9 +2679,20 @@ async function createDevServer(options) {
2476
2679
  async function refreshRoutes() {
2477
2680
  try {
2478
2681
  routes = await scanRoutes(rootDir);
2479
- console.log(pc.dim(` \u{1F4C1} Found ${routes.length} routes`));
2682
+ console.log(pc2.dim(` \u{1F4C1} Found ${routes.length} routes`));
2683
+ const tailwindConfig = checkTailwindSetup(rootDir);
2684
+ if (tailwindConfig.needsSetup) {
2685
+ console.log(pc2.yellow(" \u26A0\uFE0F Tailwind not configured"));
2686
+ const installCmd = getTailwindInstallCommand(rootDir);
2687
+ if (installCmd) {
2688
+ console.log(pc2.dim(` \u{1F4A1} Run: ${installCmd}`));
2689
+ console.log(pc2.dim(` \u{1F4A1} Then: npx float dev`));
2690
+ } else {
2691
+ await setupTailwind(rootDir);
2692
+ }
2693
+ }
2480
2694
  } catch (error) {
2481
- console.error(pc.red("Failed to scan routes:"), error);
2695
+ console.error(pc2.red("Failed to scan routes:"), error);
2482
2696
  }
2483
2697
  }
2484
2698
  function notifyClients(type, data) {
@@ -2539,16 +2753,46 @@ ${FLOAT_ERROR_OVERLAY}
2539
2753
  async function handleRequest(req, res) {
2540
2754
  const url = new URL(req.url || "/", `http://${host}:${port}`);
2541
2755
  const pathname = url.pathname;
2542
- console.log(pc.dim(` ${req.method} ${pathname}`));
2756
+ console.log(pc2.dim(` ${req.method} ${pathname}`));
2543
2757
  try {
2544
- const publicFilePath = path4.join(publicDir, pathname);
2545
- if (fs2.existsSync(publicFilePath) && fs2.statSync(publicFilePath).isFile()) {
2546
- const content = fs2.readFileSync(publicFilePath);
2758
+ const publicFilePath = path6.join(publicDir, pathname);
2759
+ if (fs4.existsSync(publicFilePath) && fs4.statSync(publicFilePath).isFile()) {
2760
+ const content = fs4.readFileSync(publicFilePath);
2547
2761
  const contentType = mime.lookup(publicFilePath) || "application/octet-stream";
2548
2762
  res.writeHead(200, { "Content-Type": contentType });
2549
2763
  res.end(content);
2550
2764
  return;
2551
2765
  }
2766
+ if (pathname.endsWith(".css")) {
2767
+ const cssPath = path6.join(rootDir, "app", pathname.replace(/^\//, ""));
2768
+ if (fs4.existsSync(cssPath)) {
2769
+ try {
2770
+ const needsProcessing = needsCSSProcessing(cssPath, rootDir);
2771
+ if (needsProcessing) {
2772
+ const result = await processCSS(cssPath, rootDir);
2773
+ res.writeHead(200, {
2774
+ "Content-Type": "text/css",
2775
+ "Cache-Control": "no-cache"
2776
+ });
2777
+ res.end(result.code);
2778
+ } else {
2779
+ const content = fs4.readFileSync(cssPath, "utf-8");
2780
+ res.writeHead(200, {
2781
+ "Content-Type": "text/css",
2782
+ "Cache-Control": "no-cache"
2783
+ });
2784
+ res.end(content);
2785
+ }
2786
+ return;
2787
+ } catch (error) {
2788
+ console.error(pc2.red("CSS processing error:"), error);
2789
+ const content = fs4.readFileSync(cssPath, "utf-8");
2790
+ res.writeHead(200, { "Content-Type": "text/css" });
2791
+ res.end(content);
2792
+ return;
2793
+ }
2794
+ }
2795
+ }
2552
2796
  if (pathname.startsWith("/_float/")) {
2553
2797
  res.writeHead(200, { "Content-Type": "application/javascript" });
2554
2798
  res.end("// Float.js internal asset");
@@ -2613,7 +2857,7 @@ ${FLOAT_ERROR_OVERLAY}
2613
2857
  });
2614
2858
  res.end(html);
2615
2859
  } catch (error) {
2616
- console.error(pc.red("Request error:"), error);
2860
+ console.error(pc2.red("Request error:"), error);
2617
2861
  res.writeHead(500, { "Content-Type": "text/html" });
2618
2862
  res.end(createErrorPage(error));
2619
2863
  }
@@ -2642,7 +2886,7 @@ ${FLOAT_ERROR_OVERLAY}
2642
2886
  const responseBody = await response.text();
2643
2887
  res.end(responseBody);
2644
2888
  } catch (error) {
2645
- console.error(pc.red("API route error:"), error);
2889
+ console.error(pc2.red("API route error:"), error);
2646
2890
  res.writeHead(500, { "Content-Type": "application/json" });
2647
2891
  res.end(JSON.stringify({ error: "Internal server error" }));
2648
2892
  }
@@ -2657,9 +2901,9 @@ ${FLOAT_ERROR_OVERLAY}
2657
2901
  });
2658
2902
  const watcher = chokidar.watch(
2659
2903
  [
2660
- path4.join(rootDir, "app/**/*.{ts,tsx,js,jsx}"),
2661
- path4.join(rootDir, "components/**/*.{ts,tsx,js,jsx}"),
2662
- path4.join(rootDir, "lib/**/*.{ts,tsx,js,jsx}")
2904
+ path6.join(rootDir, "app/**/*.{ts,tsx,js,jsx}"),
2905
+ path6.join(rootDir, "components/**/*.{ts,tsx,js,jsx}"),
2906
+ path6.join(rootDir, "lib/**/*.{ts,tsx,js,jsx}")
2663
2907
  ],
2664
2908
  {
2665
2909
  ignored: /node_modules/,
@@ -2667,8 +2911,8 @@ ${FLOAT_ERROR_OVERLAY}
2667
2911
  }
2668
2912
  );
2669
2913
  watcher.on("change", async (filePath) => {
2670
- console.log(pc.yellow(`
2671
- \u26A1 File changed: ${path4.relative(rootDir, filePath)}`));
2914
+ console.log(pc2.yellow(`
2915
+ \u26A1 File changed: ${path6.relative(rootDir, filePath)}`));
2672
2916
  if (filePath.includes("/app/")) {
2673
2917
  await refreshRoutes();
2674
2918
  }
@@ -2676,31 +2920,31 @@ ${FLOAT_ERROR_OVERLAY}
2676
2920
  });
2677
2921
  watcher.on("add", async (filePath) => {
2678
2922
  if (filePath.includes("/app/")) {
2679
- console.log(pc.green(`
2680
- \u2795 File added: ${path4.relative(rootDir, filePath)}`));
2923
+ console.log(pc2.green(`
2924
+ \u2795 File added: ${path6.relative(rootDir, filePath)}`));
2681
2925
  await refreshRoutes();
2682
2926
  notifyClients("reload");
2683
2927
  }
2684
2928
  });
2685
2929
  watcher.on("unlink", async (filePath) => {
2686
2930
  if (filePath.includes("/app/")) {
2687
- console.log(pc.red(`
2688
- \u2796 File removed: ${path4.relative(rootDir, filePath)}`));
2931
+ console.log(pc2.red(`
2932
+ \u2796 File removed: ${path6.relative(rootDir, filePath)}`));
2689
2933
  await refreshRoutes();
2690
2934
  notifyClients("reload");
2691
2935
  }
2692
2936
  });
2693
2937
  return new Promise((resolve, reject) => {
2694
2938
  server.listen(port, host, () => {
2695
- console.log(pc.green(` \u2705 Server running at ${pc.cyan(`http://${host}:${port}`)}`));
2696
- console.log(pc.dim(` \u26A1 HMR enabled on ws://${host}:${port + 1}
2939
+ console.log(pc2.green(` \u2705 Server running at ${pc2.cyan(`http://${host}:${port}`)}`));
2940
+ console.log(pc2.dim(` \u26A1 HMR enabled on ws://${host}:${port + 1}
2697
2941
  `));
2698
- console.log(pc.bold(" Routes:"));
2942
+ console.log(pc2.bold(" Routes:"));
2699
2943
  routes.forEach((route) => {
2700
2944
  if (route.type === "page") {
2701
- console.log(pc.dim(` ${pc.green("\u25CF")} ${route.path}`));
2945
+ console.log(pc2.dim(` ${pc2.green("\u25CF")} ${route.path}`));
2702
2946
  } else if (route.type === "api") {
2703
- console.log(pc.dim(` ${pc.blue("\u25C6")} ${route.path} (API)`));
2947
+ console.log(pc2.dim(` ${pc2.blue("\u25C6")} ${route.path} (API)`));
2704
2948
  }
2705
2949
  });
2706
2950
  console.log("");
@@ -2820,9 +3064,9 @@ function escapeHtml2(text) {
2820
3064
  // src/build/index.ts
2821
3065
  init_esm_shims();
2822
3066
  import * as esbuild2 from "esbuild";
2823
- import fs3 from "fs";
2824
- import path5 from "path";
2825
- import pc2 from "picocolors";
3067
+ import fs5 from "fs";
3068
+ import path7 from "path";
3069
+ import pc3 from "picocolors";
2826
3070
  var DEFAULT_BUILD_OPTIONS = {
2827
3071
  analyze: false,
2828
3072
  minify: true,
@@ -2832,27 +3076,27 @@ async function build2(options = {}) {
2832
3076
  const opts = { ...DEFAULT_BUILD_OPTIONS, ...options };
2833
3077
  const startTime = Date.now();
2834
3078
  const rootDir = process.cwd();
2835
- const outputDir = path5.join(rootDir, ".float");
2836
- if (fs3.existsSync(outputDir)) {
2837
- fs3.rmSync(outputDir, { recursive: true });
3079
+ const outputDir = path7.join(rootDir, ".float");
3080
+ if (fs5.existsSync(outputDir)) {
3081
+ fs5.rmSync(outputDir, { recursive: true });
2838
3082
  }
2839
- fs3.mkdirSync(outputDir, { recursive: true });
2840
- fs3.mkdirSync(path5.join(outputDir, "pages"), { recursive: true });
2841
- fs3.mkdirSync(path5.join(outputDir, "static"), { recursive: true });
2842
- fs3.mkdirSync(path5.join(outputDir, "server"), { recursive: true });
2843
- console.log(pc2.dim(" Scanning routes..."));
3083
+ fs5.mkdirSync(outputDir, { recursive: true });
3084
+ fs5.mkdirSync(path7.join(outputDir, "pages"), { recursive: true });
3085
+ fs5.mkdirSync(path7.join(outputDir, "static"), { recursive: true });
3086
+ fs5.mkdirSync(path7.join(outputDir, "server"), { recursive: true });
3087
+ console.log(pc3.dim(" Scanning routes..."));
2844
3088
  const routes = await scanRoutes(rootDir);
2845
3089
  const pageRoutes = routes.filter((r) => r.type === "page" && !r.params.length);
2846
3090
  const dynamicRoutes = routes.filter((r) => r.type === "page" && r.params.length > 0);
2847
3091
  const apiRoutes = routes.filter((r) => r.type === "api");
2848
- console.log(pc2.dim(` Found ${pageRoutes.length} static pages, ${dynamicRoutes.length} dynamic routes, ${apiRoutes.length} API routes`));
2849
- console.log(pc2.dim(" Building client bundle..."));
3092
+ console.log(pc3.dim(` Found ${pageRoutes.length} static pages, ${dynamicRoutes.length} dynamic routes, ${apiRoutes.length} API routes`));
3093
+ console.log(pc3.dim(" Building client bundle..."));
2850
3094
  const clientEntryPoints = routes.filter((r) => r.type === "page").map((r) => r.absolutePath);
2851
3095
  if (clientEntryPoints.length > 0) {
2852
3096
  await esbuild2.build({
2853
3097
  entryPoints: clientEntryPoints,
2854
3098
  bundle: true,
2855
- outdir: path5.join(outputDir, "static", "_float"),
3099
+ outdir: path7.join(outputDir, "static", "_float"),
2856
3100
  format: "esm",
2857
3101
  splitting: true,
2858
3102
  minify: opts.minify,
@@ -2874,13 +3118,13 @@ async function build2(options = {}) {
2874
3118
  metafile: opts.analyze
2875
3119
  });
2876
3120
  }
2877
- console.log(pc2.dim(" Building server bundle..."));
3121
+ console.log(pc3.dim(" Building server bundle..."));
2878
3122
  const serverEntryPoints = routes.map((r) => r.absolutePath);
2879
3123
  if (serverEntryPoints.length > 0) {
2880
3124
  await esbuild2.build({
2881
3125
  entryPoints: serverEntryPoints,
2882
3126
  bundle: true,
2883
- outdir: path5.join(outputDir, "server"),
3127
+ outdir: path7.join(outputDir, "server"),
2884
3128
  format: "esm",
2885
3129
  platform: "node",
2886
3130
  target: ["node18"],
@@ -2897,26 +3141,26 @@ async function build2(options = {}) {
2897
3141
  external: ["react", "react-dom", "@float/core"]
2898
3142
  });
2899
3143
  }
2900
- console.log(pc2.dim(" Pre-rendering static pages..."));
3144
+ console.log(pc3.dim(" Pre-rendering static pages..."));
2901
3145
  const prerenderedPages = [];
2902
3146
  for (const route of pageRoutes) {
2903
3147
  try {
2904
3148
  const html = await renderPage(route, {}, { isDev: false });
2905
- const outputPath = route.path === "/" ? path5.join(outputDir, "pages", "index.html") : path5.join(outputDir, "pages", route.path, "index.html");
2906
- fs3.mkdirSync(path5.dirname(outputPath), { recursive: true });
2907
- fs3.writeFileSync(outputPath, html);
3149
+ const outputPath = route.path === "/" ? path7.join(outputDir, "pages", "index.html") : path7.join(outputDir, "pages", route.path, "index.html");
3150
+ fs5.mkdirSync(path7.dirname(outputPath), { recursive: true });
3151
+ fs5.writeFileSync(outputPath, html);
2908
3152
  prerenderedPages.push(route.path);
2909
- console.log(pc2.dim(` \u2713 ${route.path}`));
3153
+ console.log(pc3.dim(` \u2713 ${route.path}`));
2910
3154
  } catch (error) {
2911
- console.log(pc2.yellow(` \u26A0 ${route.path} (will render at runtime)`));
3155
+ console.log(pc3.yellow(` \u26A0 ${route.path} (will render at runtime)`));
2912
3156
  }
2913
3157
  }
2914
- console.log(pc2.dim(" Building API routes..."));
3158
+ console.log(pc3.dim(" Building API routes..."));
2915
3159
  for (const route of apiRoutes) {
2916
3160
  await esbuild2.build({
2917
3161
  entryPoints: [route.absolutePath],
2918
3162
  bundle: true,
2919
- outfile: path5.join(outputDir, "server", "api", `${route.path.replace(/\//g, "_")}.js`),
3163
+ outfile: path7.join(outputDir, "server", "api", `${route.path.replace(/\//g, "_")}.js`),
2920
3164
  format: "esm",
2921
3165
  platform: "neutral",
2922
3166
  // Edge compatible
@@ -2924,10 +3168,10 @@ async function build2(options = {}) {
2924
3168
  minify: true
2925
3169
  });
2926
3170
  }
2927
- const publicDir = path5.join(rootDir, "public");
2928
- if (fs3.existsSync(publicDir)) {
2929
- console.log(pc2.dim(" Copying public assets..."));
2930
- copyDir(publicDir, path5.join(outputDir, "static"));
3171
+ const publicDir = path7.join(rootDir, "public");
3172
+ if (fs5.existsSync(publicDir)) {
3173
+ console.log(pc3.dim(" Copying public assets..."));
3174
+ copyDir(publicDir, path7.join(outputDir, "static"));
2931
3175
  }
2932
3176
  const manifest = {
2933
3177
  version: 1,
@@ -2936,19 +3180,19 @@ async function build2(options = {}) {
2936
3180
  path: r.path,
2937
3181
  type: r.type,
2938
3182
  filePath: r.filePath,
2939
- absolutePath: path5.relative(rootDir, r.absolutePath),
3183
+ absolutePath: path7.relative(rootDir, r.absolutePath),
2940
3184
  params: r.params,
2941
3185
  isCatchAll: r.isCatchAll,
2942
3186
  isOptionalCatchAll: r.isOptionalCatchAll,
2943
- layouts: r.layouts.map((l) => path5.relative(rootDir, l)),
3187
+ layouts: r.layouts.map((l) => path7.relative(rootDir, l)),
2944
3188
  prerendered: prerenderedPages.includes(r.path)
2945
3189
  })),
2946
3190
  staticPages: prerenderedPages,
2947
3191
  dynamicRoutes: dynamicRoutes.map((r) => r.path),
2948
3192
  apiRoutes: apiRoutes.map((r) => r.path)
2949
3193
  };
2950
- fs3.writeFileSync(
2951
- path5.join(outputDir, "routes-manifest.json"),
3194
+ fs5.writeFileSync(
3195
+ path7.join(outputDir, "routes-manifest.json"),
2952
3196
  JSON.stringify(manifest, null, 2)
2953
3197
  );
2954
3198
  const duration = Date.now() - startTime;
@@ -2958,16 +3202,16 @@ async function build2(options = {}) {
2958
3202
  routes: routes.length,
2959
3203
  pages: prerenderedPages.length
2960
3204
  };
2961
- fs3.writeFileSync(
2962
- path5.join(outputDir, "build-info.json"),
3205
+ fs5.writeFileSync(
3206
+ path7.join(outputDir, "build-info.json"),
2963
3207
  JSON.stringify(buildInfo, null, 2)
2964
3208
  );
2965
3209
  console.log("");
2966
- console.log(pc2.bold(" Build Summary:"));
2967
- console.log(pc2.dim(` Static Pages: ${prerenderedPages.length}`));
2968
- console.log(pc2.dim(` Dynamic Routes: ${dynamicRoutes.length}`));
2969
- console.log(pc2.dim(` API Routes: ${apiRoutes.length}`));
2970
- console.log(pc2.dim(` Output: .float/`));
3210
+ console.log(pc3.bold(" Build Summary:"));
3211
+ console.log(pc3.dim(` Static Pages: ${prerenderedPages.length}`));
3212
+ console.log(pc3.dim(` Dynamic Routes: ${dynamicRoutes.length}`));
3213
+ console.log(pc3.dim(` API Routes: ${apiRoutes.length}`));
3214
+ console.log(pc3.dim(` Output: .float/`));
2971
3215
  return {
2972
3216
  routes,
2973
3217
  duration,
@@ -2977,15 +3221,15 @@ async function build2(options = {}) {
2977
3221
  };
2978
3222
  }
2979
3223
  function copyDir(src, dest) {
2980
- fs3.mkdirSync(dest, { recursive: true });
2981
- const entries = fs3.readdirSync(src, { withFileTypes: true });
3224
+ fs5.mkdirSync(dest, { recursive: true });
3225
+ const entries = fs5.readdirSync(src, { withFileTypes: true });
2982
3226
  for (const entry of entries) {
2983
- const srcPath = path5.join(src, entry.name);
2984
- const destPath = path5.join(dest, entry.name);
3227
+ const srcPath = path7.join(src, entry.name);
3228
+ const destPath = path7.join(dest, entry.name);
2985
3229
  if (entry.isDirectory()) {
2986
3230
  copyDir(srcPath, destPath);
2987
3231
  } else {
2988
- fs3.copyFileSync(srcPath, destPath);
3232
+ fs5.copyFileSync(srcPath, destPath);
2989
3233
  }
2990
3234
  }
2991
3235
  }
@@ -2993,45 +3237,45 @@ function copyDir(src, dest) {
2993
3237
  // src/server/prod-server.ts
2994
3238
  init_esm_shims();
2995
3239
  import http2 from "http";
2996
- import fs4 from "fs";
2997
- import path6 from "path";
2998
- import pc3 from "picocolors";
3240
+ import fs6 from "fs";
3241
+ import path8 from "path";
3242
+ import pc4 from "picocolors";
2999
3243
  import mime2 from "mime-types";
3000
3244
  var cachedRoutes = [];
3001
3245
  var pageCache = /* @__PURE__ */ new Map();
3002
3246
  async function startProductionServer(options) {
3003
3247
  const { port, host } = options;
3004
3248
  const rootDir = process.cwd();
3005
- const distDir = path6.join(rootDir, ".float");
3006
- const publicDir = path6.join(rootDir, "public");
3007
- const manifestPath = path6.join(distDir, "routes-manifest.json");
3008
- if (fs4.existsSync(manifestPath)) {
3009
- const manifest = JSON.parse(fs4.readFileSync(manifestPath, "utf-8"));
3249
+ const distDir = path8.join(rootDir, ".float");
3250
+ const publicDir = path8.join(rootDir, "public");
3251
+ const manifestPath = path8.join(distDir, "routes-manifest.json");
3252
+ if (fs6.existsSync(manifestPath)) {
3253
+ const manifest = JSON.parse(fs6.readFileSync(manifestPath, "utf-8"));
3010
3254
  cachedRoutes = manifest.routes;
3011
- console.log(pc3.dim(` \u{1F4E6} Loaded ${cachedRoutes.length} routes from manifest`));
3255
+ console.log(pc4.dim(` \u{1F4E6} Loaded ${cachedRoutes.length} routes from manifest`));
3012
3256
  } else {
3013
- console.error(pc3.red(" \u274C No build manifest found. Run `float build` first."));
3257
+ console.error(pc4.red(" \u274C No build manifest found. Run `float build` first."));
3014
3258
  process.exit(1);
3015
3259
  }
3016
- const pagesDir = path6.join(distDir, "pages");
3017
- if (fs4.existsSync(pagesDir)) {
3018
- const prerenderedFiles = fs4.readdirSync(pagesDir, { recursive: true });
3260
+ const pagesDir = path8.join(distDir, "pages");
3261
+ if (fs6.existsSync(pagesDir)) {
3262
+ const prerenderedFiles = fs6.readdirSync(pagesDir, { recursive: true });
3019
3263
  for (const file of prerenderedFiles) {
3020
3264
  if (file.endsWith(".html")) {
3021
3265
  const routePath = "/" + file.replace(/\.html$/, "").replace(/index$/, "");
3022
- const content = fs4.readFileSync(path6.join(pagesDir, file), "utf-8");
3266
+ const content = fs6.readFileSync(path8.join(pagesDir, file), "utf-8");
3023
3267
  pageCache.set(routePath, content);
3024
3268
  }
3025
3269
  }
3026
- console.log(pc3.dim(` \u{1F4C4} Loaded ${pageCache.size} pre-rendered pages`));
3270
+ console.log(pc4.dim(` \u{1F4C4} Loaded ${pageCache.size} pre-rendered pages`));
3027
3271
  }
3028
3272
  const server = http2.createServer(async (req, res) => {
3029
3273
  const url = new URL(req.url || "/", `http://${host}:${port}`);
3030
3274
  const pathname = url.pathname;
3031
3275
  try {
3032
- const staticPath = path6.join(distDir, "static", pathname);
3033
- if (fs4.existsSync(staticPath) && fs4.statSync(staticPath).isFile()) {
3034
- const content = fs4.readFileSync(staticPath);
3276
+ const staticPath = path8.join(distDir, "static", pathname);
3277
+ if (fs6.existsSync(staticPath) && fs6.statSync(staticPath).isFile()) {
3278
+ const content = fs6.readFileSync(staticPath);
3035
3279
  const contentType = mime2.lookup(staticPath) || "application/octet-stream";
3036
3280
  res.writeHead(200, {
3037
3281
  "Content-Type": contentType,
@@ -3040,9 +3284,9 @@ async function startProductionServer(options) {
3040
3284
  res.end(content);
3041
3285
  return;
3042
3286
  }
3043
- const publicFilePath = path6.join(publicDir, pathname);
3044
- if (fs4.existsSync(publicFilePath) && fs4.statSync(publicFilePath).isFile()) {
3045
- const content = fs4.readFileSync(publicFilePath);
3287
+ const publicFilePath = path8.join(publicDir, pathname);
3288
+ if (fs6.existsSync(publicFilePath) && fs6.statSync(publicFilePath).isFile()) {
3289
+ const content = fs6.readFileSync(publicFilePath);
3046
3290
  const contentType = mime2.lookup(publicFilePath) || "application/octet-stream";
3047
3291
  res.writeHead(200, { "Content-Type": contentType });
3048
3292
  res.end(content);
@@ -3075,13 +3319,13 @@ async function startProductionServer(options) {
3075
3319
  });
3076
3320
  res.end(html);
3077
3321
  } catch (error) {
3078
- console.error(pc3.red("Request error:"), error);
3322
+ console.error(pc4.red("Request error:"), error);
3079
3323
  res.writeHead(500, { "Content-Type": "text/html" });
3080
3324
  res.end("<h1>500 - Internal Server Error</h1>");
3081
3325
  }
3082
3326
  });
3083
3327
  server.listen(port, host, () => {
3084
- console.log(pc3.green(` \u2705 Production server running at ${pc3.cyan(`http://${host}:${port}`)}
3328
+ console.log(pc4.green(` \u2705 Production server running at ${pc4.cyan(`http://${host}:${port}`)}
3085
3329
  `));
3086
3330
  });
3087
3331
  }
@@ -3093,14 +3337,14 @@ var VERSION = "2.0.4";
3093
3337
  // src/cli/index.ts
3094
3338
  var cli = cac("float");
3095
3339
  var banner = `
3096
- ${pc4.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
3097
- ${pc4.cyan("\u2551")} ${pc4.bold(pc4.magenta("\u26A1 Float.js"))} ${pc4.dim(`v${VERSION}`)} ${pc4.cyan("\u2551")}
3098
- ${pc4.cyan("\u2551")} ${pc4.dim("Ultra Modern Web Framework")} ${pc4.cyan("\u2551")}
3099
- ${pc4.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")}
3340
+ ${pc5.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
3341
+ ${pc5.cyan("\u2551")} ${pc5.bold(pc5.magenta("\u26A1 Float.js"))} ${pc5.dim(`v${VERSION}`)} ${pc5.cyan("\u2551")}
3342
+ ${pc5.cyan("\u2551")} ${pc5.dim("Ultra Modern Web Framework")} ${pc5.cyan("\u2551")}
3343
+ ${pc5.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")}
3100
3344
  `;
3101
3345
  cli.command("dev", "Start development server").option("-p, --port <port>", "Port to listen on", { default: 3e3 }).option("-h, --host <host>", "Host to bind to", { default: "localhost" }).option("--open", "Open browser on start", { default: false }).action(async (options) => {
3102
3346
  console.log(banner);
3103
- console.log(pc4.cyan("\u{1F680} Starting development server...\n"));
3347
+ console.log(pc5.cyan("\u{1F680} Starting development server...\n"));
3104
3348
  try {
3105
3349
  const server = await createDevServer({
3106
3350
  port: Number(options.port),
@@ -3109,45 +3353,45 @@ cli.command("dev", "Start development server").option("-p, --port <port>", "Port
3109
3353
  });
3110
3354
  await server.start();
3111
3355
  } catch (error) {
3112
- console.error(pc4.red("\u274C Failed to start dev server:"), error);
3356
+ console.error(pc5.red("\u274C Failed to start dev server:"), error);
3113
3357
  process.exit(1);
3114
3358
  }
3115
3359
  });
3116
3360
  cli.command("build", "Build for production").option("--analyze", "Analyze bundle size", { default: false }).action(async (options) => {
3117
3361
  console.log(banner);
3118
- console.log(pc4.cyan("\u{1F4E6} Building for production...\n"));
3362
+ console.log(pc5.cyan("\u{1F4E6} Building for production...\n"));
3119
3363
  try {
3120
3364
  const startTime = Date.now();
3121
3365
  await build2({ analyze: options.analyze });
3122
3366
  const duration = Date.now() - startTime;
3123
- console.log(pc4.green(`
3367
+ console.log(pc5.green(`
3124
3368
  \u2705 Build completed in ${duration}ms`));
3125
3369
  } catch (error) {
3126
- console.error(pc4.red("\u274C Build failed:"), error);
3370
+ console.error(pc5.red("\u274C Build failed:"), error);
3127
3371
  process.exit(1);
3128
3372
  }
3129
3373
  });
3130
3374
  cli.command("start", "Start production server").option("-p, --port <port>", "Port to listen on", { default: 3e3 }).option("-h, --host <host>", "Host to bind to", { default: "0.0.0.0" }).action(async (options) => {
3131
3375
  console.log(banner);
3132
- console.log(pc4.cyan("\u{1F310} Starting production server...\n"));
3376
+ console.log(pc5.cyan("\u{1F310} Starting production server...\n"));
3133
3377
  try {
3134
3378
  await startProductionServer({
3135
3379
  port: Number(options.port),
3136
3380
  host: options.host
3137
3381
  });
3138
3382
  } catch (error) {
3139
- console.error(pc4.red("\u274C Failed to start server:"), error);
3383
+ console.error(pc5.red("\u274C Failed to start server:"), error);
3140
3384
  process.exit(1);
3141
3385
  }
3142
3386
  });
3143
3387
  cli.command("info", "Show environment information").action(() => {
3144
3388
  console.log(banner);
3145
- console.log(pc4.bold("Environment Info:\n"));
3146
- console.log(` ${pc4.dim("Float.js:")} v${VERSION}`);
3147
- console.log(` ${pc4.dim("Node.js:")} ${process.version}`);
3148
- console.log(` ${pc4.dim("Platform:")} ${process.platform}`);
3149
- console.log(` ${pc4.dim("Arch:")} ${process.arch}`);
3150
- console.log(` ${pc4.dim("CWD:")} ${process.cwd()}`);
3389
+ console.log(pc5.bold("Environment Info:\n"));
3390
+ console.log(` ${pc5.dim("Float.js:")} v${VERSION}`);
3391
+ console.log(` ${pc5.dim("Node.js:")} ${process.version}`);
3392
+ console.log(` ${pc5.dim("Platform:")} ${process.platform}`);
3393
+ console.log(` ${pc5.dim("Arch:")} ${process.arch}`);
3394
+ console.log(` ${pc5.dim("CWD:")} ${process.cwd()}`);
3151
3395
  });
3152
3396
  cli.help();
3153
3397
  cli.version(VERSION);