@brightsideoy/kama 0.1.0-alpha.120 → 0.1.0-alpha.121
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/assets/{index-BlmOgxC3.js → index-C6GoXL-R.js} +2 -2
- package/dist/assets/{index-RJKUlAE_.css → index-Drmp3h6P.css} +1 -1
- package/dist/index.html +2 -2
- package/dist/index.js +994 -999
- package/package.json +1 -1
- package/templates/astro-starter/public/css/standard-theme.css +157 -0
- package/templates/astro-starter/public/robots.txt +23 -1
- package/templates/astro-starter/src/components/blocks/BlockRenderer.astro +4 -5
- package/templates/astro-starter/src/layouts/StandardLayout.astro +52 -0
- package/templates/astro-starter/src/pages/404.astro +3 -3
- package/templates/astro-starter/src/pages/[...slug].astro +3 -55
- package/templates/astro-starter/src/pages/llms-full.txt.ts +161 -0
- package/templates/astro-starter/src/pages/llms.txt.ts +42 -32
- package/templates/astro-starter/src/utils/tiptap.ts +113 -0
- package/definitions/_page.yaml +0 -52
- package/templates/astro-starter/src/layouts/Layout.astro +0 -151
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/utils/tiptap.ts
|
|
2
|
+
|
|
3
|
+
export interface TiptapNode {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
attrs?: Record<string, any>;
|
|
7
|
+
marks?: Array<{ type: string; attrs?: Record<string, any> }>;
|
|
8
|
+
content?: TiptapNode[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Traverses a ProseMirror / Tiptap AST node and converts it into HTML.
|
|
13
|
+
*/
|
|
14
|
+
export function renderTiptapNode(node?: TiptapNode | null): string {
|
|
15
|
+
if (!node) return "";
|
|
16
|
+
if (typeof node === "string") return node;
|
|
17
|
+
|
|
18
|
+
// 1. Text Node Handling (with Marks)
|
|
19
|
+
if (node.type === "text") {
|
|
20
|
+
let text = escapeHtml(node.text || "");
|
|
21
|
+
if (node.marks && Array.isArray(node.marks)) {
|
|
22
|
+
node.marks.forEach((mark) => {
|
|
23
|
+
switch (mark.type) {
|
|
24
|
+
case "bold":
|
|
25
|
+
case "strong":
|
|
26
|
+
text = `<strong>${text}</strong>`;
|
|
27
|
+
break;
|
|
28
|
+
case "italic":
|
|
29
|
+
case "em":
|
|
30
|
+
text = `<em>${text}</em>`;
|
|
31
|
+
break;
|
|
32
|
+
case "underline":
|
|
33
|
+
text = `<u>${text}</u>`;
|
|
34
|
+
break;
|
|
35
|
+
case "strike":
|
|
36
|
+
text = `<s>${text}</s>`;
|
|
37
|
+
break;
|
|
38
|
+
case "code":
|
|
39
|
+
text = `<code>${text}</code>`;
|
|
40
|
+
break;
|
|
41
|
+
case "link": {
|
|
42
|
+
const href = mark.attrs?.href ? escapeHtml(mark.attrs.href) : "#";
|
|
43
|
+
const target = mark.attrs?.target ? ` target="${escapeHtml(mark.attrs.target)}"` : "";
|
|
44
|
+
const rel = mark.attrs?.target === "_blank" ? ' rel="noopener noreferrer"' : "";
|
|
45
|
+
text = `<a href="${href}"${target}${rel}>${text}</a>`;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 2. Traversal of Child Nodes
|
|
55
|
+
const childrenHtml = Array.isArray(node.content)
|
|
56
|
+
? node.content.map(renderTiptapNode).join("")
|
|
57
|
+
: "";
|
|
58
|
+
|
|
59
|
+
// 3. Block Level Mapping
|
|
60
|
+
switch (node.type) {
|
|
61
|
+
case "doc":
|
|
62
|
+
return childrenHtml;
|
|
63
|
+
case "paragraph":
|
|
64
|
+
return childrenHtml.trim() ? `<p>${childrenHtml}</p>` : "";
|
|
65
|
+
case "heading": {
|
|
66
|
+
const level = Math.min(Math.max(node.attrs?.level || 2, 1), 6);
|
|
67
|
+
return `<h${level}>${childrenHtml}</h${level}>`;
|
|
68
|
+
}
|
|
69
|
+
case "bulletList":
|
|
70
|
+
return `<ul>${childrenHtml}</ul>`;
|
|
71
|
+
case "orderedList": {
|
|
72
|
+
const start = node.attrs?.start ? ` start="${node.attrs.start}"` : "";
|
|
73
|
+
return `<ol${start}>${childrenHtml}</ol>`;
|
|
74
|
+
}
|
|
75
|
+
case "listItem":
|
|
76
|
+
return `<li>${childrenHtml}</li>`;
|
|
77
|
+
case "blockquote":
|
|
78
|
+
return `<blockquote>${childrenHtml}</blockquote>`;
|
|
79
|
+
case "codeBlock": {
|
|
80
|
+
const lang = node.attrs?.language ? ` class="language-${escapeHtml(node.attrs.language)}"` : "";
|
|
81
|
+
return `<pre><code${lang}>${childrenHtml}</code></pre>`;
|
|
82
|
+
}
|
|
83
|
+
case "horizontalRule":
|
|
84
|
+
return "<hr />";
|
|
85
|
+
case "hardBreak":
|
|
86
|
+
return "<br />";
|
|
87
|
+
default:
|
|
88
|
+
return childrenHtml;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Universal helper that handles plain strings, legacy objects, and Tiptap ASTs safely.
|
|
94
|
+
*/
|
|
95
|
+
export function extractHtml(value: any): string {
|
|
96
|
+
if (!value) return "";
|
|
97
|
+
if (typeof value === "string") return value; // Already HTML/string
|
|
98
|
+
if (typeof value === "object") {
|
|
99
|
+
if (value.type === "doc") return renderTiptapNode(value);
|
|
100
|
+
if (value.html) return value.html;
|
|
101
|
+
if (value.markup) return value.markup;
|
|
102
|
+
}
|
|
103
|
+
return String(value);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function escapeHtml(str: string): string {
|
|
107
|
+
return str
|
|
108
|
+
.replace(/&/g, "&")
|
|
109
|
+
.replace(/</g, "<")
|
|
110
|
+
.replace(/>/g, ">")
|
|
111
|
+
.replace(/"/g, """)
|
|
112
|
+
.replace(/'/g, "'");
|
|
113
|
+
}
|
package/definitions/_page.yaml
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
id: _page
|
|
2
|
-
label: Page Old
|
|
3
|
-
inTree: true
|
|
4
|
-
inVault: true
|
|
5
|
-
hasCanvas: true
|
|
6
|
-
|
|
7
|
-
layout:
|
|
8
|
-
columns: "10fr 4fr"
|
|
9
|
-
areas:
|
|
10
|
-
- ["header", "header"]
|
|
11
|
-
- ["main", "sidebar"]
|
|
12
|
-
- ["footer", "footer"]
|
|
13
|
-
|
|
14
|
-
regions:
|
|
15
|
-
header:
|
|
16
|
-
label: Header
|
|
17
|
-
inherit: parent
|
|
18
|
-
main:
|
|
19
|
-
label: Content
|
|
20
|
-
sidebar:
|
|
21
|
-
label: Sidebar
|
|
22
|
-
footer:
|
|
23
|
-
label: Footer
|
|
24
|
-
inherit: parent
|
|
25
|
-
|
|
26
|
-
allowedBlocks:
|
|
27
|
-
- header
|
|
28
|
-
- hero
|
|
29
|
-
- text
|
|
30
|
-
- image_card
|
|
31
|
-
|
|
32
|
-
# 👉 TABS DEFINITION
|
|
33
|
-
tabs:
|
|
34
|
-
settings:
|
|
35
|
-
label: "Page"
|
|
36
|
-
fields:
|
|
37
|
-
# Imports core fields: title, slug, isHidden
|
|
38
|
-
- fieldSet: page-base
|
|
39
|
-
|
|
40
|
-
# Overrides & custom properties
|
|
41
|
-
- menuTitle:
|
|
42
|
-
label: Menu Title
|
|
43
|
-
type: text
|
|
44
|
-
dbType: text
|
|
45
|
-
public: true
|
|
46
|
-
placeholder: "Short title for navigation menus"
|
|
47
|
-
|
|
48
|
-
# SEO / OpenGraph metadata
|
|
49
|
-
- fieldSet: meta
|
|
50
|
-
|
|
51
|
-
# Role permissions & access control
|
|
52
|
-
- fieldSet: access
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// src/layouts/Layout.astro
|
|
3
|
-
import Header from "@/components/global/Header.astro";
|
|
4
|
-
import Footer from "@/components/global/Footer.astro";
|
|
5
|
-
import SeoHead from "@/components/seo/SeoHead.astro";
|
|
6
|
-
import type { TreeNode, ContentBlock } from "@/lib/cms";
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
node: Record<string, any>;
|
|
10
|
-
content: Record<string, ContentBlock[]>;
|
|
11
|
-
normalizedSlug: string;
|
|
12
|
-
isHomePage: boolean;
|
|
13
|
-
hasSidebar?: boolean;
|
|
14
|
-
headerBlocks?: ContentBlock[];
|
|
15
|
-
tree?: TreeNode[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
node = {},
|
|
20
|
-
content = {},
|
|
21
|
-
normalizedSlug,
|
|
22
|
-
isHomePage,
|
|
23
|
-
headerBlocks = [],
|
|
24
|
-
tree,
|
|
25
|
-
} = Astro.props;
|
|
26
|
-
|
|
27
|
-
const footerBlocks = content?.footer || [];
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
<html lang="en">
|
|
31
|
-
<head>
|
|
32
|
-
<!-- 🎯 All the heavy SEO math is securely isolated in this component -->
|
|
33
|
-
<SeoHead
|
|
34
|
-
node={node}
|
|
35
|
-
content={content}
|
|
36
|
-
normalizedSlug={normalizedSlug}
|
|
37
|
-
isHomePage={isHomePage}
|
|
38
|
-
headerBlocks={headerBlocks}
|
|
39
|
-
/>
|
|
40
|
-
</head>
|
|
41
|
-
<body>
|
|
42
|
-
<Header node={node} tree={tree} />
|
|
43
|
-
|
|
44
|
-
<main class="content-block">
|
|
45
|
-
<div class="content-container">
|
|
46
|
-
<slot />
|
|
47
|
-
</div>
|
|
48
|
-
</main>
|
|
49
|
-
|
|
50
|
-
<Footer blocks={footerBlocks} contentMap={content} />
|
|
51
|
-
</body>
|
|
52
|
-
</html>
|
|
53
|
-
|
|
54
|
-
<style is:global>
|
|
55
|
-
*,
|
|
56
|
-
*::before,
|
|
57
|
-
*::after {
|
|
58
|
-
box-sizing: border-box;
|
|
59
|
-
border-radius: 0 !important;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
html {
|
|
63
|
-
font-size: 16px;
|
|
64
|
-
-webkit-text-size-adjust: 100%;
|
|
65
|
-
-webkit-font-smoothing: antialiased;
|
|
66
|
-
-moz-osx-font-smoothing: grayscale;
|
|
67
|
-
text-rendering: optimizeLegibility;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
body {
|
|
71
|
-
margin: 0;
|
|
72
|
-
padding: 0;
|
|
73
|
-
font-family:
|
|
74
|
-
system-ui,
|
|
75
|
-
-apple-system,
|
|
76
|
-
BlinkMacSystemFont,
|
|
77
|
-
"Segoe UI",
|
|
78
|
-
Roboto,
|
|
79
|
-
Helvetica,
|
|
80
|
-
Arial,
|
|
81
|
-
sans-serif;
|
|
82
|
-
font-display: swap;
|
|
83
|
-
background-color: #ffffff;
|
|
84
|
-
color: #1e293b;
|
|
85
|
-
min-height: 100vh;
|
|
86
|
-
display: flex;
|
|
87
|
-
flex-direction: column;
|
|
88
|
-
line-height: 1.65;
|
|
89
|
-
letter-spacing: -0.011em;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
h1,
|
|
93
|
-
h2,
|
|
94
|
-
h3,
|
|
95
|
-
h4,
|
|
96
|
-
h5,
|
|
97
|
-
h6 {
|
|
98
|
-
color: #0f172a;
|
|
99
|
-
font-weight: 700;
|
|
100
|
-
line-height: 1.25;
|
|
101
|
-
letter-spacing: -0.022em;
|
|
102
|
-
margin-top: 1.6em;
|
|
103
|
-
margin-bottom: 0.6em;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
h1 {
|
|
107
|
-
font-size: 2.25rem;
|
|
108
|
-
}
|
|
109
|
-
h2 {
|
|
110
|
-
font-size: 1.65rem;
|
|
111
|
-
}
|
|
112
|
-
h3 {
|
|
113
|
-
font-size: 1.35rem;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
p {
|
|
117
|
-
margin-top: 0;
|
|
118
|
-
margin-bottom: 1.25em;
|
|
119
|
-
color: #334155;
|
|
120
|
-
font-size: 1.03rem;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
a {
|
|
124
|
-
color: #0284c7;
|
|
125
|
-
text-decoration-thickness: 1px;
|
|
126
|
-
text-underline-offset: 3px;
|
|
127
|
-
transition: color 0.15s ease;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
a:hover {
|
|
131
|
-
color: #0369a1;
|
|
132
|
-
}
|
|
133
|
-
li > p:last-child {
|
|
134
|
-
margin-bottom: 0;
|
|
135
|
-
}
|
|
136
|
-
</style>
|
|
137
|
-
|
|
138
|
-
<style>
|
|
139
|
-
.content-block {
|
|
140
|
-
flex: 1;
|
|
141
|
-
padding: 40px 0 64px 0;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.content-container {
|
|
145
|
-
max-width: 1400px;
|
|
146
|
-
margin: 0 auto;
|
|
147
|
-
padding: 0 24px;
|
|
148
|
-
width: 100%;
|
|
149
|
-
box-sizing: border-box;
|
|
150
|
-
}
|
|
151
|
-
</style>
|