@lolyjs/core 0.3.0-alpha.5 → 0.4.0-alpha.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.
Files changed (40) hide show
  1. package/README.md +162 -0
  2. package/dist/{bootstrap-BfGTMUkj.d.mts → bootstrap-B6W6XoI5.d.mts} +6 -0
  3. package/dist/{bootstrap-BfGTMUkj.d.ts → bootstrap-B6W6XoI5.d.ts} +6 -0
  4. package/dist/cli.cjs +3362 -867
  5. package/dist/cli.cjs.map +1 -1
  6. package/dist/cli.mjs +3442 -952
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/index.cjs +3622 -897
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.mts +27 -1
  11. package/dist/index.d.ts +27 -1
  12. package/dist/index.mjs +3598 -879
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/react/cache.cjs.map +1 -1
  15. package/dist/react/cache.mjs.map +1 -1
  16. package/dist/react/components.cjs +138 -5
  17. package/dist/react/components.cjs.map +1 -1
  18. package/dist/react/components.d.mts +58 -6
  19. package/dist/react/components.d.ts +58 -6
  20. package/dist/react/components.mjs +138 -6
  21. package/dist/react/components.mjs.map +1 -1
  22. package/dist/react/hooks.cjs +24 -0
  23. package/dist/react/hooks.cjs.map +1 -1
  24. package/dist/react/hooks.d.mts +49 -1
  25. package/dist/react/hooks.d.ts +49 -1
  26. package/dist/react/hooks.mjs +22 -0
  27. package/dist/react/hooks.mjs.map +1 -1
  28. package/dist/react/themes.cjs +0 -169
  29. package/dist/react/themes.cjs.map +1 -1
  30. package/dist/react/themes.d.mts +18 -11
  31. package/dist/react/themes.d.ts +18 -11
  32. package/dist/react/themes.mjs +0 -159
  33. package/dist/react/themes.mjs.map +1 -1
  34. package/dist/runtime.cjs +268 -24
  35. package/dist/runtime.cjs.map +1 -1
  36. package/dist/runtime.d.mts +2 -2
  37. package/dist/runtime.d.ts +2 -2
  38. package/dist/runtime.mjs +255 -15
  39. package/dist/runtime.mjs.map +1 -1
  40. package/package.json +4 -2
package/README.md CHANGED
@@ -43,6 +43,7 @@ Loly is a full-stack React framework that combines the simplicity of file-based
43
43
  - 🛡️ **Security First** - Built-in rate limiting, validation, sanitization, and security headers
44
44
  - ⚡ **Performance** - Fast bundling with Rspack and optimized code splitting
45
45
  - 📦 **Full ESM Support** - Native ES modules with top-level await, dynamic imports, and `import.meta.url`
46
+ - 🖼️ **Image Optimization** - Automatic image optimization with WebP/AVIF support, lazy loading, and responsive images
46
47
 
47
48
  ---
48
49
 
@@ -848,6 +849,79 @@ export default {
848
849
  } satisfies Partial<FrameworkConfig>;
849
850
  ```
850
851
 
852
+ ### 🖼️ Image Optimization
853
+
854
+ Loly includes a powerful image optimization system similar to Next.js Image, with automatic optimization, lazy loading, responsive images, and remote image support.
855
+
856
+ **Basic Usage:**
857
+
858
+ ```tsx
859
+ import { Image } from "@lolyjs/core/components";
860
+
861
+ export default function MyPage() {
862
+ return (
863
+ <Image
864
+ src="/assets/hero.jpg"
865
+ alt="Hero image"
866
+ width={800}
867
+ height={600}
868
+ />
869
+ );
870
+ }
871
+ ```
872
+
873
+ **Remote Images:**
874
+
875
+ ```tsx
876
+ <Image
877
+ src="https://images.unsplash.com/photo-123"
878
+ alt="Photo"
879
+ width={1200}
880
+ height={800}
881
+ quality={85}
882
+ format="webp"
883
+ />
884
+ ```
885
+
886
+ **Features:**
887
+
888
+ - ✅ Automatic optimization (resize, compress, format conversion)
889
+ - ✅ Modern formats (WebP, AVIF)
890
+ - ✅ Lazy loading by default
891
+ - ✅ Responsive images with automatic srcset
892
+ - ✅ Remote image support (with domain whitelist)
893
+ - ✅ Cache optimization
894
+ - ✅ CLS prevention
895
+
896
+ **Configuration:**
897
+
898
+ Configure allowed remote domains in `loly.config.ts`:
899
+
900
+ ```tsx
901
+ import type { FrameworkConfig } from "@lolyjs/core";
902
+
903
+ export default {
904
+ images: {
905
+ remotePatterns: [
906
+ {
907
+ protocol: "https",
908
+ hostname: "images.unsplash.com",
909
+ },
910
+ {
911
+ protocol: "https",
912
+ hostname: "**.unsplash.com", // Wildcard for subdomains
913
+ },
914
+ ],
915
+ formats: ["image/webp", "image/avif"],
916
+ quality: 75,
917
+ deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
918
+ imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
919
+ },
920
+ } satisfies Partial<FrameworkConfig>;
921
+ ```
922
+
923
+ For complete documentation, see [Image Optimization Documentation](https://github.com/MenvielleValen/loly-framework/blob/main/docs/17-image-optimization.md).
924
+
851
925
  ### 🔌 API Routes
852
926
 
853
927
  Create RESTful APIs with flexible middleware support:
@@ -1302,6 +1376,94 @@ export default function Navigation() {
1302
1376
  }
1303
1377
  ```
1304
1378
 
1379
+ ### 🎨 Global Theme API
1380
+
1381
+ Loly provides a global theme system that works without React Context, using BroadcastChannel for cross-tab synchronization. The theme is automatically applied to the `<body>` element on the server, and you can update it from anywhere in your application using the global API.
1382
+
1383
+ **Usage:**
1384
+
1385
+ ```tsx
1386
+ // In any client component or vanilla JavaScript
1387
+ export default function ThemeSwitch() {
1388
+ const handleToggle = () => {
1389
+ const current = window.loly?.theme?.get() || "light";
1390
+ const next = current === "dark" ? "light" : "dark";
1391
+ window.loly?.theme?.set(next);
1392
+ };
1393
+
1394
+ return <button onClick={handleToggle}>Toggle Theme</button>;
1395
+ }
1396
+ ```
1397
+
1398
+ **Reading the theme:**
1399
+
1400
+ ```tsx
1401
+ // Get current theme
1402
+ const currentTheme = window.loly?.theme?.get(); // "light" | "dark"
1403
+
1404
+ // Or read from body class (SSR-safe)
1405
+ const themeFromDOM = document.body.classList.contains("dark") ? "dark" : "light";
1406
+ ```
1407
+
1408
+ **Server-side theme:**
1409
+
1410
+ The theme is automatically applied to the `<body>` element on the server. You can pass the theme from your layout server hook:
1411
+
1412
+ ```tsx
1413
+ // app/layout.server.hook.ts
1414
+ import type { ServerLoader } from "@lolyjs/core";
1415
+
1416
+ export const getServerSideProps: ServerLoader = async (ctx) => {
1417
+ // Get theme from cookie, user preference, etc.
1418
+ const theme = ctx.req.cookies?.theme || "light";
1419
+
1420
+ return {
1421
+ props: {},
1422
+ metadata: {
1423
+ // Theme is automatically applied to body via inline script
1424
+ },
1425
+ };
1426
+ };
1427
+ ```
1428
+
1429
+ **Key Features:**
1430
+
1431
+ - ✅ **No React Context required** - Works with server components
1432
+ - ✅ **Cross-tab synchronization** - Uses BroadcastChannel
1433
+ - ✅ **SSR-safe** - Theme applied on server to prevent flash
1434
+ - ✅ **Cookie persistence** - Theme preference saved automatically
1435
+ - ✅ **Simple API** - `window.loly.theme.set()` and `window.loly.theme.get()`
1436
+
1437
+ **React hook example (optional):**
1438
+
1439
+ ```tsx
1440
+ import { useEffect, useState } from "react";
1441
+
1442
+ function useTheme() {
1443
+ const [theme, setTheme] = useState<"light" | "dark">(() => {
1444
+ if (typeof window === "undefined") return "light";
1445
+ return window.loly?.theme?.get() || "light";
1446
+ });
1447
+
1448
+ useEffect(() => {
1449
+ const channel = new BroadcastChannel("loly_theme_channel");
1450
+ channel.onmessage = (event) => {
1451
+ if (event.data?.theme) {
1452
+ setTheme(event.data.theme);
1453
+ }
1454
+ };
1455
+ return () => channel.close();
1456
+ }, []);
1457
+
1458
+ const changeTheme = (newTheme: "light" | "dark") => {
1459
+ window.loly?.theme?.set(newTheme);
1460
+ setTheme(newTheme);
1461
+ };
1462
+
1463
+ return { theme, changeTheme };
1464
+ }
1465
+ ```
1466
+
1305
1467
  ---
1306
1468
 
1307
1469
  ## Configuration
@@ -33,6 +33,12 @@ declare global {
33
33
  type ClientLoadedComponents = {
34
34
  Page: React.ComponentType<any>;
35
35
  layouts: React.ComponentType<any>[];
36
+ isPageClientComponent?: boolean;
37
+ isLayoutClientComponent?: boolean[];
38
+ clientComponentFilePaths?: {
39
+ page?: string;
40
+ layouts?: (string | undefined)[];
41
+ };
36
42
  };
37
43
  type ClientRouteLoaded = {
38
44
  pattern: string;
@@ -33,6 +33,12 @@ declare global {
33
33
  type ClientLoadedComponents = {
34
34
  Page: React.ComponentType<any>;
35
35
  layouts: React.ComponentType<any>[];
36
+ isPageClientComponent?: boolean;
37
+ isLayoutClientComponent?: boolean[];
38
+ clientComponentFilePaths?: {
39
+ page?: string;
40
+ layouts?: (string | undefined)[];
41
+ };
36
42
  };
37
43
  type ClientRouteLoaded = {
38
44
  pattern: string;