@brightsideoy/kama 0.1.0-alpha.113 → 0.1.0-alpha.115

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 (60) hide show
  1. package/bin/cli.js +172 -379
  2. package/content/definitions/blocks/button.yaml +7 -8
  3. package/content/definitions/blocks/header.yaml +7 -9
  4. package/content/definitions/blocks/header_image.yaml +14 -15
  5. package/content/definitions/blocks/hero.yaml +22 -21
  6. package/content/definitions/blocks/image_card.yaml +46 -47
  7. package/content/definitions/blocks/single_image.yaml +19 -20
  8. package/content/definitions/blocks/text.yaml +8 -9
  9. package/content/definitions/channels/ecommerce.yaml +14 -16
  10. package/content/definitions/channels/website.yaml +20 -21
  11. package/content/definitions/field-sets/access.yaml +3 -5
  12. package/content/definitions/field-sets/channel-base.yaml +25 -25
  13. package/content/definitions/field-sets/content-block.yaml +36 -41
  14. package/content/definitions/field-sets/page-base.yaml +40 -45
  15. package/content/definitions/field-sets/page-meta.yaml +1 -4
  16. package/content/definitions/field-sets/page-social.yaml +6 -8
  17. package/content/definitions/field-sets/tree-base.yaml +25 -25
  18. package/content/definitions/nodes/address.yaml +29 -21
  19. package/content/definitions/nodes/article.yaml +24 -19
  20. package/content/definitions/nodes/event.yaml +32 -26
  21. package/content/definitions/nodes/external-link.yaml +20 -17
  22. package/content/definitions/nodes/page.yaml +38 -35
  23. package/content/definitions/nodes/person.yaml +29 -27
  24. package/content/definitions/nodes/product.yaml +52 -49
  25. package/content/definitions/trees/navigation.yaml +26 -21
  26. package/content/definitions/trees/social-links.yaml +5 -2
  27. package/dist/assets/index-8T39DEP3.js +162 -0
  28. package/dist/assets/index-B9oh2_TL.css +1 -0
  29. package/dist/index.html +2 -2
  30. package/dist/index.js +6492 -4249
  31. package/package.json +5 -6
  32. package/schema.sql +5 -13
  33. package/templates/astro-starter/astro.config.mjs +40 -0
  34. package/templates/astro-starter/package.json.template +20 -0
  35. package/templates/astro-starter/src/components/blocks/BlockRenderer.astro +125 -0
  36. package/templates/astro-starter/src/components/blocks/ColumnLayout.astro +66 -0
  37. package/templates/astro-starter/src/components/blocks/HeaderImage.astro +131 -0
  38. package/templates/astro-starter/src/components/blocks/Hero.astro +218 -0
  39. package/templates/astro-starter/src/components/blocks/ImageBlock.astro +160 -0
  40. package/templates/astro-starter/src/components/blocks/TextBlock.astro +13 -0
  41. package/templates/astro-starter/src/components/global/Breadcrumb.astro +62 -0
  42. package/templates/astro-starter/src/components/global/Footer.astro +48 -0
  43. package/templates/astro-starter/src/components/global/Header.astro +92 -0
  44. package/templates/astro-starter/src/components/global/NavigationMenu.astro +450 -0
  45. package/templates/astro-starter/src/components/ui/KamaImage.astro +148 -0
  46. package/templates/astro-starter/src/kama-image-service.ts +41 -0
  47. package/templates/astro-starter/src/layouts/Layout.astro +280 -0
  48. package/templates/astro-starter/src/lib/cms.ts +149 -0
  49. package/templates/astro-starter/src/lib/media-url.ts +34 -0
  50. package/templates/astro-starter/src/middleware.ts +306 -0
  51. package/templates/astro-starter/src/pages/404.astro +46 -0
  52. package/templates/astro-starter/src/pages/[...slug].astro +234 -0
  53. package/templates/astro-starter/src/pages/media/[...path].ts +113 -0
  54. package/templates/astro-starter/tsconfig.json +0 -0
  55. package/test-local.sh +76 -0
  56. package/dist/assets/index-10GEw0KY.css +0 -1
  57. package/dist/assets/index-THJ6BqPP.js +0 -1394
  58. package/kama-worker/bundled-definitions.js +0 -2394
  59. package/kama-worker/bundled-definitions.ts +0 -2395
  60. package/scripts/bundle-definitions.js +0 -224
@@ -0,0 +1,160 @@
1
+ ---
2
+ // src/components/blocks/ImageBlock.astro
3
+ import KamaImage from "@/components/ui/KamaImage.astro";
4
+
5
+ interface CropVariant {
6
+ id?: string;
7
+ url?: string;
8
+ cropCoordinates?: {
9
+ width?: number;
10
+ height?: number;
11
+ };
12
+ }
13
+
14
+ interface Props {
15
+ data: {
16
+ image?: {
17
+ id?: string;
18
+ url?: string;
19
+ path?: string;
20
+ filename?: string;
21
+ alt?: string;
22
+ width?: number | string;
23
+ height?: number | string;
24
+ cropCoordinates?: {
25
+ width?: number;
26
+ height?: number;
27
+ };
28
+ variants?: {
29
+ standard?: CropVariant;
30
+ tablet?: CropVariant;
31
+ mobile?: CropVariant;
32
+ [key: string]: CropVariant | undefined;
33
+ };
34
+ };
35
+
36
+ image_meta?: {
37
+ cropCoordinates?: {
38
+ width?: number;
39
+ height?: number;
40
+ };
41
+ };
42
+
43
+ width?: number | string;
44
+ height?: number | string;
45
+ };
46
+
47
+ region?: string;
48
+ isFirst?: boolean;
49
+ }
50
+
51
+ const { data, region = "main", isFirst = false } = Astro.props;
52
+
53
+ const img = data?.image;
54
+
55
+ if (!img || (!img.url && !img.path && !img.variants)) {
56
+ return null;
57
+ }
58
+
59
+ /**
60
+ * Determine whether this is likely to be LCP.
61
+ */
62
+ const isLcp = region === "header" || (region === "main" && isFirst);
63
+
64
+ /**
65
+ * Determine grid column count from the region name.
66
+ */
67
+ let columnCount = 1;
68
+
69
+ if (region.includes("_")) {
70
+ columnCount = 2;
71
+
72
+ if (region.includes("_middle") || region.includes("_col3")) {
73
+ columnCount = 3;
74
+ }
75
+
76
+ if (region.includes("_col4")) {
77
+ columnCount = 4;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Default single-column layout.
83
+ */
84
+ let maxWidth = "1352";
85
+ let targetColumnWidth = 1352;
86
+ let optimizedWidths = [768, 1352];
87
+ let sizes = "(max-width: 1399px) calc(100vw - 48px), 1352px";
88
+
89
+ /**
90
+ * Two-column layout.
91
+ */
92
+ if (columnCount === 2) {
93
+ maxWidth = "660";
94
+ targetColumnWidth = 660;
95
+ optimizedWidths = [400, 660];
96
+ sizes =
97
+ "(max-width: 767px) calc(100vw - 48px), " +
98
+ "(max-width: 1399px) calc((100vw - 80px) / 2), " +
99
+ "660px";
100
+ }
101
+
102
+ /**
103
+ * Three-column layout.
104
+ */
105
+ else if (columnCount === 3) {
106
+ maxWidth = "429";
107
+ targetColumnWidth = 429;
108
+ optimizedWidths = [300, 429];
109
+ sizes =
110
+ "(max-width: 767px) calc(100vw - 48px), " +
111
+ "(max-width: 1399px) calc((100vw - 112px) / 3), " +
112
+ "429px";
113
+ }
114
+
115
+ /**
116
+ * Four-column layout.
117
+ */
118
+ else if (columnCount === 4) {
119
+ maxWidth = "314";
120
+ targetColumnWidth = 314;
121
+ optimizedWidths = [264, 314];
122
+ sizes =
123
+ "(max-width: 767px) calc(100vw - 48px), " +
124
+ "(max-width: 1399px) calc((100vw - 144px) / 4), " +
125
+ "314px";
126
+ }
127
+ ---
128
+
129
+ <div class="cms-block cms-block-image" style={`--max-w: ${maxWidth}px;`}>
130
+ <KamaImage
131
+ image={img}
132
+ sizes={sizes}
133
+ desktopWidths={optimizedWidths}
134
+ idealWidth={targetColumnWidth}
135
+ width={data.width || data.image_meta?.cropCoordinates?.width || img.width}
136
+ height={data.height ||
137
+ data.image_meta?.cropCoordinates?.height ||
138
+ img.height}
139
+ class="free-crop-image"
140
+ loading={isLcp ? "eager" : "lazy"}
141
+ fetchpriority={isLcp ? "high" : "auto"}
142
+ decoding={isLcp ? "sync" : "async"}
143
+ />
144
+ </div>
145
+
146
+ <style>
147
+ .cms-block-image {
148
+ width: 100%;
149
+ max-width: var(--max-w, 1352px);
150
+ margin: 0 auto 1.5rem auto;
151
+ }
152
+
153
+ :global(.free-crop-image) {
154
+ width: 100%;
155
+ height: auto;
156
+ object-fit: contain;
157
+ display: block;
158
+ border-radius: var(--cms-radius-md, 0.5rem);
159
+ }
160
+ </style>
@@ -0,0 +1,13 @@
1
+ ---
2
+ interface Props {
3
+ data: {
4
+ text?: string;
5
+ content?: string;
6
+ };
7
+ }
8
+ const { data } = Astro.props;
9
+ ---
10
+
11
+ <div class="block-text">
12
+ <Fragment set:html={data.text || data.content || ""} />
13
+ </div>
@@ -0,0 +1,62 @@
1
+ ---
2
+ interface Props {
3
+ title: string;
4
+ slug?: string;
5
+ }
6
+
7
+ const { title, slug } = Astro.props;
8
+ const isHome = !slug || slug === "home";
9
+ ---
10
+
11
+ <nav class="breadcrumb-nav" aria-label="Breadcrumb">
12
+ <ol class="breadcrumb-list">
13
+ <li class="breadcrumb-item">
14
+ <a href="/">Home</a>
15
+ </li>
16
+ {
17
+ !isHome && (
18
+ <li class="breadcrumb-item active" aria-current="page">
19
+ <span class="separator">/</span>
20
+ <span>{title}</span>
21
+ </li>
22
+ )
23
+ }
24
+ </ol>
25
+ </nav>
26
+
27
+ <style>
28
+ .breadcrumb-nav {
29
+ margin-bottom: 16px;
30
+ }
31
+
32
+ .breadcrumb-list {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: 8px;
36
+ list-style: none;
37
+ margin: 0;
38
+ padding: 0;
39
+ font-size: 13px;
40
+ color: #64748b;
41
+ }
42
+
43
+ .breadcrumb-item a {
44
+ color: #334155;
45
+ text-decoration: none;
46
+ }
47
+
48
+ .breadcrumb-item a:hover {
49
+ color: #0f172a;
50
+ text-decoration: underline;
51
+ }
52
+
53
+ .breadcrumb-item.active {
54
+ color: #0f172a;
55
+ font-weight: 500;
56
+ }
57
+
58
+ .separator {
59
+ margin-right: 8px;
60
+ color: #94a3b8;
61
+ }
62
+ </style>
@@ -0,0 +1,48 @@
1
+ ---
2
+ import BlockRenderer from "@/components/blocks/BlockRenderer.astro";
3
+
4
+ interface Props {
5
+ blocks?: any[];
6
+ contentMap?: Record<string, any[]>;
7
+ }
8
+
9
+ const { blocks = [], contentMap = {} } = Astro.props;
10
+ ---
11
+
12
+ <footer class="site-footer">
13
+ <div class="footer-container">
14
+ {
15
+ blocks && blocks.length > 0 ? (
16
+ <BlockRenderer
17
+ blocks={blocks}
18
+ contentMap={contentMap}
19
+ region="footer"
20
+ />
21
+ ) : (
22
+ <div class="footer-default">
23
+ <p>&copy; {new Date().getFullYear()} all rights reserved.</p>
24
+ </div>
25
+ )
26
+ }
27
+ </div>
28
+ </footer>
29
+
30
+ <style>
31
+ .site-footer {
32
+ background: #ffffff;
33
+ border-top: 1px solid #e2e8f0;
34
+ margin-top: auto;
35
+ }
36
+
37
+ .footer-container {
38
+ max-width: 1400px;
39
+ margin: 0 auto;
40
+ padding: 24px 20px;
41
+ }
42
+
43
+ .footer-default p {
44
+ margin: 0;
45
+ font-size: 14px;
46
+ color: #64748b;
47
+ }
48
+ </style>
@@ -0,0 +1,92 @@
1
+ ---
2
+ // src/components/global/Header.astro
3
+ import NavigationMenu from "@/components/global/NavigationMenu.astro";
4
+ import { getTree, getTreeId, getChannelId } from "@/lib/cms";
5
+ import type { TreeNode } from "@/lib/cms";
6
+
7
+ interface Props {
8
+ node?: Record<string, any>;
9
+ tree?: TreeNode[];
10
+ }
11
+
12
+ const { node, tree } = Astro.props;
13
+
14
+ let rawTree = tree;
15
+
16
+ // Fallback: If the layout didn't pass the tree, fetch it directly
17
+ if (!rawTree || rawTree.length === 0) {
18
+ const locals = (Astro.locals as any) || {};
19
+ const runtimeEnv = (locals.runtime?.env as any) || {};
20
+ const cmsWorker = runtimeEnv.CMS_WORKER;
21
+
22
+ // Safely wrap the fetcher for Service Bindings
23
+ const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {
24
+ if (cmsWorker && typeof cmsWorker.fetch === "function") {
25
+ return cmsWorker.fetch(new Request(input, init));
26
+ }
27
+ return fetch(input, init);
28
+ };
29
+
30
+ rawTree = await getTree(getTreeId(), getChannelId(), customFetch);
31
+ }
32
+
33
+ // Automatically use the configured site name for the text logo
34
+ const siteName = import.meta.env.PUBLIC_SITE_NAME || "KAMA";
35
+ ---
36
+
37
+ <header class="site-header">
38
+ <div class="header-container main-header-row">
39
+ <a href="/" class="logo-block">
40
+ <span class="logo-text">{siteName}</span>
41
+ </a>
42
+ <NavigationMenu tree={rawTree} />
43
+ </div>
44
+ </header>
45
+
46
+ <style>
47
+ .site-header {
48
+ background: #ffffff;
49
+ color: #1e293b;
50
+ position: sticky;
51
+ top: 0;
52
+ z-index: 100;
53
+ border-bottom: 1px solid #e2e8f0;
54
+ }
55
+
56
+ .header-container {
57
+ max-width: 1400px;
58
+ margin: 0 auto;
59
+ padding: 0 20px;
60
+ width: 100%;
61
+ box-sizing: border-box;
62
+ }
63
+
64
+ .main-header-row {
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: space-between;
68
+ height: 64px;
69
+ }
70
+
71
+ .logo-block {
72
+ text-decoration: none;
73
+ color: #0f172a;
74
+ font-weight: 700;
75
+ font-size: 20px;
76
+ display: inline-flex;
77
+ align-items: center;
78
+ z-index: 1001;
79
+ }
80
+
81
+ .logo-text {
82
+ white-space: nowrap;
83
+ }
84
+
85
+ @media (min-width: 768px) {
86
+ .main-header-row {
87
+ height: 64px;
88
+ justify-content: space-between;
89
+ gap: 32px;
90
+ }
91
+ }
92
+ </style>