webcake-landing-mcp 1.0.41 → 1.0.43
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/changelog.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"v": "1.0.43",
|
|
4
|
+
"d": "09/06/2026",
|
|
5
|
+
"type": "Changed",
|
|
6
|
+
"en": "The GET / web guide page has refreshed copy throughout: updated page title and meta description, simplified FAQ answers in both English and…",
|
|
7
|
+
"vi": "Trang hướng dẫn GET / được làm mới toàn bộ nội dung: cập nhật tiêu đề trang và meta description, đơn giản hóa câu trả lời FAQ bằng cả tiếng Anh và…"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"v": "1.0.42",
|
|
11
|
+
"d": "09/06/2026",
|
|
12
|
+
"type": "Fixed",
|
|
13
|
+
"en": "validate_page now raises an error when a countdown element's specials.language is set to a value outside the eight supported word-values (vietnam,…",
|
|
14
|
+
"vi": "validate_page nay phát lỗi khi element countdown có specials.language là giá trị nằm ngoài tám word-value được hỗ trợ (vietnam, english, filipino,…"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"v": "1.0.41",
|
|
4
18
|
"d": "09/06/2026",
|
|
@@ -26,19 +40,5 @@
|
|
|
26
40
|
"type": "Added",
|
|
27
41
|
"en": "New add_section tool appends one or more sections to an existing page without re-sending the full source: the server fetches the current page,…",
|
|
28
42
|
"vi": "Công cụ add_section mới cho phép gắn thêm một hoặc nhiều section vào trang hiện có mà không cần gửi lại toàn bộ source: server lấy trang hiện tại,…"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"v": "1.0.37",
|
|
32
|
-
"d": "08/06/2026",
|
|
33
|
-
"type": "Changed",
|
|
34
|
-
"en": "get_generation_guide now includes a HEADER section build hint directing the agent to place every header child (logo, brand text, CTA button) on a…",
|
|
35
|
-
"vi": "get_generation_guide nay bổ sung gợi ý dựng section HEADER yêu cầu agent đặt mọi phần tử con trong header (logo, tên thương hiệu, nút CTA) trên cùng…"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"v": "1.0.36",
|
|
39
|
-
"d": "08/06/2026",
|
|
40
|
-
"type": "Changed",
|
|
41
|
-
"en": "The GET / web guide page now lists \"Claude · Codex · Cursor, etc.\" instead of only \"Claude · Cursor\" in the AI assistant flow diagram, reflecting…",
|
|
42
|
-
"vi": "Trang hướng dẫn GET / nay hiển thị \"Claude · Codex · Cursor, v.v.\" thay vì chỉ \"Claude · Cursor\" trong sơ đồ luồng AI assistant, phản ánh danh sách…"
|
|
43
43
|
}
|
|
44
44
|
]
|
|
@@ -16,8 +16,8 @@ export const MARKETING = [
|
|
|
16
16
|
showDay: "boolean — show the days segment.",
|
|
17
17
|
showSecond: "boolean — show the seconds segment.",
|
|
18
18
|
showText: "boolean — show unit labels (days/hours/minutes/seconds).",
|
|
19
|
-
language: "locale
|
|
20
|
-
customTranslation: "object —
|
|
19
|
+
language: "unit-label locale — MUST be one of: vietnam | english | filipino | khmer | lao | indonesian | thai | malay | custom. NOT a code like 'vi'/'en' (that crashes the renderer). For any other language use 'custom' + customTranslation.",
|
|
20
|
+
customTranslation: "object {day,hour,minute,second} of label strings — used (and required) when language='custom'. e.g. {day:'Ngày',hour:'Giờ',minute:'Phút',second:'Giây'}.",
|
|
21
21
|
},
|
|
22
22
|
seed: (el) => {
|
|
23
23
|
seedPosition(el);
|
|
@@ -25,7 +25,7 @@ export const MARKETING = [
|
|
|
25
25
|
setStyle(el, "color", "rgba(255, 255, 255, 1)");
|
|
26
26
|
setStyle(el, "background", "rgba(0, 0, 0, 1)");
|
|
27
27
|
setStyle(el, "fontSize", 20);
|
|
28
|
-
el.specials = { type: "minute", duration: "60", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
|
|
28
|
+
el.specials = { type: "minute", duration: "60", language: "english", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
{
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
},
|
|
231
231
|
"specials": {
|
|
232
232
|
"type": "object",
|
|
233
|
-
"description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language,customTranslation}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
|
|
233
|
+
"description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language(vietnam|english|filipino|khmer|lao|indonesian|thai|malay|custom — NOT a locale code; 'custom' uses customTranslation),customTranslation{day,hour,minute,second}}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
|
|
234
234
|
"additionalProperties": true,
|
|
235
235
|
"properties": {
|
|
236
236
|
"text": { "type": "string", "description": "text-block/button label/list-paragraph (may contain HTML)." },
|
|
@@ -36,6 +36,11 @@ const OPTION_NAME_FIELDS = new Set(["select", "radio", "checkbox-group"]);
|
|
|
36
36
|
// field_placeholder throws "Cannot read properties of undefined (reading 'replace')"
|
|
37
37
|
// and the whole page fails to render.
|
|
38
38
|
const PLACEHOLDER_REQUIRED_FIELDS = new Set(["select", "country-select", "group-select-item"]);
|
|
39
|
+
// countdown's renderer indexes a fixed `lang` table by specials.language and then
|
|
40
|
+
// destructures the result: `const [d,h,m,s] = lang[language]`. Any value outside
|
|
41
|
+
// this set (e.g. a locale code like "vi"/"en") yields undefined → "is not iterable"
|
|
42
|
+
// and the whole page fails to render. 'custom' instead reads specials.customTranslation.
|
|
43
|
+
const COUNTDOWN_LANGUAGES = new Set(["vietnam", "english", "filipino", "khmer", "lao", "indonesian", "thai", "malay", "custom"]);
|
|
39
44
|
// Fixed canvas reference (matches vocab CANVAS) used for the layout/bounds check.
|
|
40
45
|
const CANVAS_DESKTOP = 960;
|
|
41
46
|
const CANVAS_MOBILE = 420;
|
|
@@ -149,6 +154,15 @@ export function validatePage(input) {
|
|
|
149
154
|
});
|
|
150
155
|
}
|
|
151
156
|
}
|
|
157
|
+
// countdown.language must be a key the renderer's lang table knows (or 'custom');
|
|
158
|
+
// anything else (e.g. a locale code "vi"/"en") crashes the renderer with
|
|
159
|
+
// "is not iterable" when it destructures lang[language].
|
|
160
|
+
if (type === "countdown") {
|
|
161
|
+
const lang = node.specials?.language;
|
|
162
|
+
if (typeof lang === "string" && !COUNTDOWN_LANGUAGES.has(lang)) {
|
|
163
|
+
errors.push(`${path} (countdown): specials.language="${lang}" is not supported and crashes the renderer. Use one of: ${[...COUNTDOWN_LANGUAGES].join(", ")} (use "custom" + specials.customTranslation for other languages).`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
152
166
|
// collect events
|
|
153
167
|
if (Array.isArray(node.events)) {
|
|
154
168
|
for (const ev of node.events) {
|
package/dist/web-guide.js
CHANGED
|
@@ -78,14 +78,14 @@ function tile(name) {
|
|
|
78
78
|
// ── i18n: per-language SEO metadata ───────────────────────────────────────────
|
|
79
79
|
const META = {
|
|
80
80
|
vi: {
|
|
81
|
-
title: "Webcake Landing MCP — AI dựng landing page Webcake
|
|
82
|
-
desc: "
|
|
81
|
+
title: "Webcake Landing MCP — AI tự dựng landing page Webcake cho bạn",
|
|
82
|
+
desc: "Bạn chỉ cần mô tả bằng lời, AI (Claude, Cursor, Windsurf…) sẽ tự dựng, tự kiểm tra và lưu landing page Webcake cho bạn. Không cần kéo-thả, không cần biết code, kết nối một lần là xong.",
|
|
83
83
|
keywords: "Webcake, landing page, MCP, Model Context Protocol, AI, Claude, Cursor, Windsurf, tạo landing page bằng AI, no-code, COD, lead generation",
|
|
84
84
|
locale: "vi_VN",
|
|
85
85
|
},
|
|
86
86
|
en: {
|
|
87
|
-
title: "Webcake Landing MCP — let AI build Webcake landing pages
|
|
88
|
-
desc: "
|
|
87
|
+
title: "Webcake Landing MCP — let AI build Webcake landing pages for you",
|
|
88
|
+
desc: "Just describe it in plain words and AI (Claude, Cursor, Windsurf…) builds, checks and saves a Webcake landing page for you. No drag-and-drop, no coding — connect once and you're set.",
|
|
89
89
|
keywords: "Webcake, landing page, MCP, Model Context Protocol, AI, Claude, Cursor, Windsurf, AI website builder, no-code, COD, lead generation",
|
|
90
90
|
locale: "en_US",
|
|
91
91
|
},
|
|
@@ -95,210 +95,210 @@ const FAQ = {
|
|
|
95
95
|
vi: [
|
|
96
96
|
{
|
|
97
97
|
q: "Webcake Landing MCP là gì?",
|
|
98
|
-
a: "
|
|
98
|
+
a: "Là một công cụ giúp AI (như Claude, Cursor) tự dựng landing page Webcake cho bạn từ một câu mô tả, tự kiểm tra rồi lưu vào tài khoản Webcake của bạn. Công cụ lo phần khó; bạn chỉ cần mô tả và xem lại.",
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
101
|
q: "Tôi có cần biết lập trình không?",
|
|
102
|
-
a: "Không. Bạn chỉ cần mô tả trang bằng
|
|
102
|
+
a: "Không. Bạn chỉ cần mô tả trang bằng lời, ngay trong ứng dụng AI mà bạn đang dùng. Mọi phần kỹ thuật để công cụ tự lo.",
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
q: "Có miễn phí không?",
|
|
106
|
-
a: "Có.
|
|
106
|
+
a: "Có. Công cụ miễn phí và mã nguồn mở. Bạn chỉ cần một tài khoản Webcake để lưu trang.",
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
|
-
q: "Dùng được với
|
|
110
|
-
a: "Claude
|
|
109
|
+
q: "Dùng được với ứng dụng nào?",
|
|
110
|
+
a: "Claude (máy tính, web, Claude Code), Cursor, Windsurf, Augment, Codex — và bất kỳ ứng dụng AI nào hỗ trợ chuẩn kết nối MCP.",
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
|
-
q: "
|
|
114
|
-
a: "Có.
|
|
113
|
+
q: "Thông tin của tôi có an toàn không?",
|
|
114
|
+
a: "Có. Mã đăng nhập là của riêng bạn và không bị lưu lại. Ngoài ra, mỗi lần lưu trang công cụ đều cho bạn xem trước, chắc chắn rồi mới thực hiện.",
|
|
115
115
|
},
|
|
116
116
|
],
|
|
117
117
|
en: [
|
|
118
118
|
{
|
|
119
119
|
q: "What is Webcake Landing MCP?",
|
|
120
|
-
a: "
|
|
120
|
+
a: "It's a tool that lets AI (like Claude or Cursor) build a Webcake landing page for you from a single description, check it, then save it to your Webcake account. The tool does the hard part; you just describe and review.",
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
q: "Do I need to know how to code?",
|
|
124
|
-
a: "No. You just describe the page in
|
|
124
|
+
a: "No. You just describe the page in plain words, right inside the AI app you already use. The tool handles all the technical parts.",
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
q: "Is it free?",
|
|
128
|
-
a: "Yes. The
|
|
128
|
+
a: "Yes. The tool is free and open-source. You only need a Webcake account to save pages.",
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
|
-
q: "Which
|
|
132
|
-
a: "Claude
|
|
131
|
+
q: "Which apps work with it?",
|
|
132
|
+
a: "Claude (desktop, web, Claude Code), Cursor, Windsurf, Augment, Codex — and any AI app that supports the MCP connection standard.",
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
|
-
q: "Is my
|
|
136
|
-
a: "Yes.
|
|
135
|
+
q: "Is my information safe?",
|
|
136
|
+
a: "Yes. Your login code is yours alone and is never stored. On top of that, every save shows you a preview first, so nothing happens until you're sure.",
|
|
137
137
|
},
|
|
138
138
|
],
|
|
139
139
|
};
|
|
140
140
|
const T = {
|
|
141
141
|
vi: {
|
|
142
|
-
sub: "
|
|
143
|
-
running: "
|
|
144
|
-
leadPre: "Bạn gõ yêu cầu, AI (Claude, Cursor…) dựng
|
|
142
|
+
sub: "Để AI tự dựng & sửa landing page Webcake cho bạn, chỉ bằng lời nói",
|
|
143
|
+
running: "Đang hoạt động",
|
|
144
|
+
leadPre: "Bạn gõ yêu cầu, AI (như Claude, Cursor…) tự dựng cả trang landing page rồi ",
|
|
145
145
|
leadGrad: "lưu thẳng vào tài khoản Webcake",
|
|
146
|
-
leadPost: " của bạn. Không kéo thả, không cài
|
|
146
|
+
leadPost: " của bạn. Không cần kéo thả, không cần cài đặt phức tạp — kết nối một lần là xong.",
|
|
147
147
|
ctaStart: "Bắt đầu kết nối",
|
|
148
|
-
ctaStar: "
|
|
149
|
-
flowH2: "
|
|
148
|
+
ctaStar: "Tặng sao trên GitHub",
|
|
149
|
+
flowH2: "Mọi thứ diễn ra thế nào",
|
|
150
150
|
flow: [
|
|
151
|
-
{ icon: "bulb", t: "Bạn", s: "ý tưởng" },
|
|
152
|
-
{ icon: "brain", t: "Trợ lý AI", s: "Claude ·
|
|
153
|
-
{ icon: "server", t: "MCP", s: "
|
|
154
|
-
{ icon: "window", t: "
|
|
151
|
+
{ icon: "bulb", t: "Bạn", s: "ý tưởng của bạn" },
|
|
152
|
+
{ icon: "brain", t: "Trợ lý AI", s: "Claude · Cursor · Codex…" },
|
|
153
|
+
{ icon: "server", t: "Webcake MCP", s: "cầu nối thông minh" },
|
|
154
|
+
{ icon: "window", t: "Webcake", s: "trang web thật" },
|
|
155
155
|
],
|
|
156
|
-
flowCap: "Bạn
|
|
157
|
-
howH2: "
|
|
156
|
+
flowCap: "Bạn nói ý tưởng → AI hiểu cách Webcake hoạt động → tự dựng trang và tự kiểm tra → trang được lưu thật vào Webcake. Bạn nhận link, mở lên xem và đăng trang.",
|
|
157
|
+
howH2: "Vì sao bạn không cần biết kỹ thuật",
|
|
158
158
|
how: [
|
|
159
159
|
{
|
|
160
160
|
icon: "brain",
|
|
161
|
-
t: "AI
|
|
162
|
-
d:
|
|
161
|
+
t: "AI lo phần dựng trang",
|
|
162
|
+
d: "AI tự sắp xếp chữ, hình ảnh, nút bấm, biểu mẫu… theo đúng chuẩn của Webcake. Bạn không phải đụng tới.",
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
icon: "check2",
|
|
166
|
-
t: "
|
|
167
|
-
d: "
|
|
166
|
+
t: "Hệ thống tự kiểm tra",
|
|
167
|
+
d: "Trang được dựng và kiểm tra tự động trước khi lưu, nên hiếm khi lỗi — bạn không cần biết gì về kỹ thuật.",
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
icon: "edit",
|
|
171
|
-
t: "Bạn chỉ
|
|
172
|
-
d: "Mở trang trong
|
|
171
|
+
t: "Bạn chỉ việc xem lại",
|
|
172
|
+
d: "Mở trang trong trình chỉnh sửa Webcake, sửa vài chỗ nếu thích, bấm lưu là trang hiển thị. Vậy là xong.",
|
|
173
173
|
},
|
|
174
174
|
],
|
|
175
|
-
buildH2: "Bạn
|
|
175
|
+
buildH2: "Bạn có thể tạo những gì",
|
|
176
176
|
uses: [
|
|
177
177
|
{
|
|
178
178
|
icon: "magnet",
|
|
179
|
-
t: "Trang thu
|
|
180
|
-
e: '"Trang
|
|
179
|
+
t: "Trang thu khách tiềm năng",
|
|
180
|
+
e: '"Trang đăng ký nhận tin cho ứng dụng — phần đầu nổi bật, 3 lợi ích, ô nhập email."',
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
183
|
icon: "cart",
|
|
184
|
-
t: "Bán hàng COD / online",
|
|
185
|
-
e: '"Trang một sản phẩm —
|
|
184
|
+
t: "Bán hàng (COD / online)",
|
|
185
|
+
e: '"Trang bán một sản phẩm — ảnh, giá, lựa chọn mẫu mã, form đặt hàng."',
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
icon: "ticket",
|
|
189
|
-
t: "Sự kiện /
|
|
190
|
-
e: '"Trang đăng ký — đếm ngược,
|
|
189
|
+
t: "Sự kiện / hội thảo",
|
|
190
|
+
e: '"Trang đăng ký tham gia — đồng hồ đếm ngược, lịch trình, form đăng ký."',
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
193
|
icon: "mail",
|
|
194
194
|
t: "Thiệp mời",
|
|
195
|
-
e: '"Thiệp cưới — tên
|
|
195
|
+
e: '"Thiệp cưới — tên cô dâu chú rể, ngày giờ, bản đồ, form xác nhận tham dự."',
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
icon: "phone",
|
|
199
|
-
t: "
|
|
200
|
-
e: '"
|
|
199
|
+
t: "Giới thiệu ứng dụng",
|
|
200
|
+
e: '"Ảnh điện thoại, danh sách tính năng, nút tải trên App Store và Google Play."',
|
|
201
201
|
},
|
|
202
202
|
{
|
|
203
203
|
icon: "flame",
|
|
204
|
-
t: "
|
|
205
|
-
e: '"Đồng hồ đếm ngược
|
|
204
|
+
t: "Sale chớp nhoáng",
|
|
205
|
+
e: '"Đồng hồ đếm ngược cỡ lớn, lưới sản phẩm giảm giá, nút Mua luôn nổi."',
|
|
206
206
|
},
|
|
207
207
|
],
|
|
208
208
|
connectH2: "Kết nối — chọn 1 trong 2 cách",
|
|
209
|
-
m1Tag: "Cách ① ·
|
|
210
|
-
m1Sub: "
|
|
209
|
+
m1Tag: "Cách ① · Cài trên máy của bạn",
|
|
210
|
+
m1Sub: "Phù hợp khi bạn tự dùng và muốn chủ động. Cần có sẵn Node.js (một phần mềm miễn phí giúp chạy lệnh).",
|
|
211
211
|
m1Steps: [
|
|
212
|
-
|
|
213
|
-
"<b>Mở Terminal
|
|
214
|
-
'<b>Làm theo
|
|
215
|
-
'<b>
|
|
212
|
+
"<b>Cài Node.js</b> (miễn phí) nếu máy chưa có — tải tại <b>nodejs.org</b>. Đây là phần mềm giúp máy chạy được công cụ ở bước sau.",
|
|
213
|
+
"<b>Mở Terminal</b> (cửa sổ gõ lệnh — trên Mac tìm “Terminal”, trên Windows tìm “Command Prompt”), dán dòng dưới đây rồi nhấn Enter:<pre>npx -y webcake-landing-mcp install</pre>",
|
|
214
|
+
'<b>Làm theo hướng dẫn hiện ra:</b> chọn <code class="inl">prod</code> → đăng nhập Webcake bằng trình duyệt → chọn ứng dụng AI bạn đang dùng (Claude, Cursor…).',
|
|
215
|
+
'<b>Mở lại ứng dụng AI.</b> Thấy chữ <code class="inl">webcake-landing</code> xuất hiện là đã kết nối thành công.',
|
|
216
216
|
],
|
|
217
|
-
m1Note: "Muốn
|
|
218
|
-
m2Tag: "Cách ② ·
|
|
219
|
-
m2Sub: "
|
|
217
|
+
m1Note: "Muốn cài cho tất cả ứng dụng cùng lúc, dùng dòng lệnh này:",
|
|
218
|
+
m2Tag: "Cách ② · Dùng link — không cần cài gì",
|
|
219
|
+
m2Sub: "Phù hợp khi máy không cài được phần mềm, dùng theo nhóm, hoặc dùng Claude trên web (claude.ai).",
|
|
220
220
|
m2Steps: [
|
|
221
|
-
'<b>Lấy link
|
|
222
|
-
'<b>
|
|
223
|
-
"<b>Dán link</b> vừa copy (
|
|
224
|
-
"<b>Bấm Add</b> (hoặc lưu file)
|
|
221
|
+
'<b>Lấy link riêng của bạn</b> (đã gắn sẵn mã đăng nhập) — mở trang dưới đây rồi bấm <b>Copy</b>:<a class="btn" href="{REMOTE}">Mở {REMOTE_HOST} {ARROW}</a>',
|
|
222
|
+
'<b>Vào nơi thêm kết nối</b> trong ứng dụng:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: mở file <code class="inl">.mcp.json</code>',
|
|
223
|
+
"<b>Dán link</b> bạn vừa copy (trông giống như):<pre>{ENDPOINT}?jwt=<MÃ CỦA BẠN></pre>",
|
|
224
|
+
"<b>Bấm Add</b> (hoặc lưu file) rồi chờ một chút. Khi biểu tượng Webcake chuyển xanh là dùng được.",
|
|
225
225
|
],
|
|
226
|
-
m2Note: "⚠️ Link chứa
|
|
227
|
-
afterH2: "
|
|
226
|
+
m2Note: "⚠️ Link có chứa mã đăng nhập riêng của bạn — hãy coi như mật khẩu, đừng chia sẻ cho ai.",
|
|
227
|
+
afterH2: "Kết nối xong, bạn chỉ cần nói",
|
|
228
228
|
examples: [
|
|
229
229
|
{
|
|
230
230
|
icon: "wand",
|
|
231
|
-
t: '"Dựng
|
|
231
|
+
t: '"Dựng trang bán khóa học, tông màu xanh, có form đăng ký và nút Zalo."',
|
|
232
232
|
},
|
|
233
233
|
{
|
|
234
234
|
icon: "edit",
|
|
235
|
-
t: "\"Mở trang <i>sale-hè</i>, đổi tiêu đề thành 'Giảm 50%', nút sang màu đỏ.\"",
|
|
235
|
+
t: "\"Mở trang <i>sale-hè</i>, đổi tiêu đề thành 'Giảm 50%', đổi nút sang màu đỏ.\"",
|
|
236
236
|
},
|
|
237
237
|
{
|
|
238
238
|
icon: "clock",
|
|
239
|
-
t: '"Thêm
|
|
239
|
+
t: '"Thêm phần đếm ngược và 3 lời nhận xét của khách vào cuối trang."',
|
|
240
240
|
},
|
|
241
241
|
],
|
|
242
242
|
newH2: "Có gì mới",
|
|
243
243
|
newBadge: "MỚI",
|
|
244
|
-
clMore: "Xem
|
|
244
|
+
clMore: "Xem tất cả thay đổi",
|
|
245
245
|
faqH2: "Câu hỏi thường gặp",
|
|
246
|
-
starH2: "Thấy hữu ích?
|
|
247
|
-
starP: "Đây là dự án mã nguồn mở — mỗi
|
|
248
|
-
starBtn: "
|
|
246
|
+
starH2: "Thấy hữu ích? Tặng dự án một ngôi sao nhé",
|
|
247
|
+
starP: "Đây là dự án miễn phí, mã nguồn mở — mỗi ngôi sao là một lời động viên để dự án tiếp tục phát triển và giúp nhiều người biết đến hơn.",
|
|
248
|
+
starBtn: "Tặng sao trên GitHub",
|
|
249
249
|
footGuide: "Hướng dẫn",
|
|
250
250
|
switchLabel: "English",
|
|
251
251
|
},
|
|
252
252
|
en: {
|
|
253
|
-
sub: "Let AI build & edit Webcake landing pages
|
|
254
|
-
running: "
|
|
255
|
-
leadPre: "You type
|
|
253
|
+
sub: "Let AI build & edit your Webcake landing pages, just by talking to it",
|
|
254
|
+
running: "Up and running",
|
|
255
|
+
leadPre: "You type what you want, AI (like Claude or Cursor) builds the whole landing page and ",
|
|
256
256
|
leadGrad: "saves it straight to your Webcake account",
|
|
257
|
-
leadPost: ". No drag-and-drop, no
|
|
257
|
+
leadPost: ". No drag-and-drop, no complicated setup — connect once and you're done.",
|
|
258
258
|
ctaStart: "Get connected",
|
|
259
259
|
ctaStar: "Star on GitHub",
|
|
260
|
-
flowH2: "How it
|
|
260
|
+
flowH2: "How it all happens",
|
|
261
261
|
flow: [
|
|
262
262
|
{ icon: "bulb", t: "You", s: "your idea" },
|
|
263
|
-
{ icon: "brain", t: "AI assistant", s: "Claude ·
|
|
264
|
-
{ icon: "server", t: "MCP", s: "
|
|
265
|
-
{ icon: "window", t: "
|
|
263
|
+
{ icon: "brain", t: "AI assistant", s: "Claude · Cursor · Codex…" },
|
|
264
|
+
{ icon: "server", t: "Webcake MCP", s: "the smart bridge" },
|
|
265
|
+
{ icon: "window", t: "Webcake", s: "a real page" },
|
|
266
266
|
],
|
|
267
|
-
flowCap: "You
|
|
268
|
-
howH2: "
|
|
267
|
+
flowCap: "You say your idea → the AI learns how Webcake works → it builds the page and checks it → the page is saved for real in Webcake. You get a link, open it, and publish.",
|
|
268
|
+
howH2: "Why you don't need to be techy",
|
|
269
269
|
how: [
|
|
270
270
|
{
|
|
271
271
|
icon: "brain",
|
|
272
|
-
t: "AI
|
|
273
|
-
d: "
|
|
272
|
+
t: "AI does the building",
|
|
273
|
+
d: "The AI arranges the text, images, buttons and forms the way Webcake expects. You never have to touch any of it.",
|
|
274
274
|
},
|
|
275
275
|
{
|
|
276
276
|
icon: "check2",
|
|
277
|
-
t: "
|
|
278
|
-
d: "
|
|
277
|
+
t: "It checks itself",
|
|
278
|
+
d: "Every page is built and checked automatically before it's saved, so things rarely break — no technical know-how needed.",
|
|
279
279
|
},
|
|
280
280
|
{
|
|
281
281
|
icon: "edit",
|
|
282
282
|
t: "You just review",
|
|
283
|
-
d: "Open the page in the Webcake editor, tweak
|
|
283
|
+
d: "Open the page in the Webcake editor, tweak anything you like, hit save and it goes live. That's it.",
|
|
284
284
|
},
|
|
285
285
|
],
|
|
286
286
|
buildH2: "What you can build",
|
|
287
287
|
uses: [
|
|
288
288
|
{
|
|
289
289
|
icon: "magnet",
|
|
290
|
-
t: "Lead-
|
|
291
|
-
e: '"A
|
|
290
|
+
t: "Lead-capture page",
|
|
291
|
+
e: '"A waitlist for an app — a bold header, 3 benefits, an email box."',
|
|
292
292
|
},
|
|
293
293
|
{
|
|
294
294
|
icon: "cart",
|
|
295
|
-
t: "COD / online
|
|
296
|
-
e: '"A one-product page —
|
|
295
|
+
t: "Sell products (COD / online)",
|
|
296
|
+
e: '"A one-product page — photos, price, options, an order form."',
|
|
297
297
|
},
|
|
298
298
|
{
|
|
299
299
|
icon: "ticket",
|
|
300
300
|
t: "Event / webinar",
|
|
301
|
-
e: '"A
|
|
301
|
+
e: '"A sign-up page — a countdown, the agenda, a registration form."',
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
icon: "mail",
|
|
@@ -308,38 +308,38 @@ const T = {
|
|
|
308
308
|
{
|
|
309
309
|
icon: "phone",
|
|
310
310
|
t: "App promo",
|
|
311
|
-
e: '"Phone
|
|
311
|
+
e: '"Phone photos, a feature list, App Store and Google Play buttons."',
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
314
|
icon: "flame",
|
|
315
315
|
t: "Flash sale",
|
|
316
|
-
e: '"A big countdown, a discounted
|
|
316
|
+
e: '"A big countdown, a grid of discounted products, a Buy button that follows you."',
|
|
317
317
|
},
|
|
318
318
|
],
|
|
319
319
|
connectH2: "Connect — pick one of two ways",
|
|
320
|
-
m1Tag: "Way ① ·
|
|
321
|
-
m1Sub: "Best for
|
|
320
|
+
m1Tag: "Way ① · Install on your computer",
|
|
321
|
+
m1Sub: "Best when it's just for you and you want full control. Needs Node.js (a free program that runs commands).",
|
|
322
322
|
m1Steps: [
|
|
323
|
-
|
|
324
|
-
"<b>Open a terminal and
|
|
325
|
-
'<b>Follow the prompts:</b>
|
|
326
|
-
'<b>
|
|
323
|
+
"<b>Install Node.js</b> (free) if you don't have it — get it at <b>nodejs.org</b>. It's the program that lets your computer run the tool in the next step.",
|
|
324
|
+
"<b>Open a terminal</b> (the command window — “Terminal” on Mac, “Command Prompt” on Windows), paste the line below and press Enter:<pre>npx -y webcake-landing-mcp install</pre>",
|
|
325
|
+
'<b>Follow the prompts:</b> choose <code class="inl">prod</code> → sign in to Webcake in your browser → pick the AI app you use (Claude, Cursor…).',
|
|
326
|
+
'<b>Reopen your AI app.</b> When you see <code class="inl">webcake-landing</code> listed, you\'re connected.',
|
|
327
327
|
],
|
|
328
|
-
m1Note: "
|
|
329
|
-
m2Tag: "Way ② ·
|
|
330
|
-
m2Sub: "Best when you
|
|
328
|
+
m1Note: "Set it up for every app at once with this command:",
|
|
329
|
+
m2Tag: "Way ② · Use a link — nothing to install",
|
|
330
|
+
m2Sub: "Best when you can't install software, work in a team, or use Claude on the web (claude.ai).",
|
|
331
331
|
m2Steps: [
|
|
332
|
-
'<b>Get your personal link</b> (
|
|
333
|
-
'<b>
|
|
334
|
-
"<b>Paste the link</b> you copied (looks like):<pre>{ENDPOINT}?jwt=<
|
|
335
|
-
"<b>Hit Add</b> (or save the file)
|
|
332
|
+
'<b>Get your personal link</b> (your login is built in) — open the page below and hit <b>Copy</b>:<a class="btn" href="{REMOTE}">Open {REMOTE_HOST} {ARROW}</a>',
|
|
333
|
+
'<b>Go to where you add a connection</b> in your app:<br>• claude.ai: <i>Settings → Connectors → Add custom connector</i><br>• Cursor / Claude Code: open <code class="inl">.mcp.json</code>',
|
|
334
|
+
"<b>Paste the link</b> you just copied (it looks like):<pre>{ENDPOINT}?jwt=<YOUR CODE></pre>",
|
|
335
|
+
"<b>Hit Add</b> (or save the file) and wait a moment. When the Webcake icon turns green, you're good to go.",
|
|
336
336
|
],
|
|
337
|
-
m2Note: "⚠️ The link
|
|
338
|
-
afterH2: "Once connected,
|
|
337
|
+
m2Note: "⚠️ The link contains your personal login code — treat it like a password and never share it.",
|
|
338
|
+
afterH2: "Once connected, just say",
|
|
339
339
|
examples: [
|
|
340
340
|
{
|
|
341
341
|
icon: "wand",
|
|
342
|
-
t: '"Build a
|
|
342
|
+
t: '"Build a page to sell a course, green theme, with a sign-up form and a Zalo button."',
|
|
343
343
|
},
|
|
344
344
|
{
|
|
345
345
|
icon: "edit",
|
|
@@ -347,15 +347,15 @@ const T = {
|
|
|
347
347
|
},
|
|
348
348
|
{
|
|
349
349
|
icon: "clock",
|
|
350
|
-
t: '"Add a countdown
|
|
350
|
+
t: '"Add a countdown and 3 customer reviews to the bottom of the page."',
|
|
351
351
|
},
|
|
352
352
|
],
|
|
353
353
|
newH2: "What's new",
|
|
354
354
|
newBadge: "NEW",
|
|
355
|
-
clMore: "See
|
|
355
|
+
clMore: "See all changes",
|
|
356
356
|
faqH2: "FAQ",
|
|
357
|
-
starH2: "Find it useful?
|
|
358
|
-
starP: "It's
|
|
357
|
+
starH2: "Find it useful? Give the project a star",
|
|
358
|
+
starP: "It's a free, open-source project — every star is a little encouragement to keep it growing and helps more people find it.",
|
|
359
359
|
starBtn: "Star on GitHub",
|
|
360
360
|
footGuide: "Docs",
|
|
361
361
|
switchLabel: "Tiếng Việt",
|
|
@@ -456,7 +456,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
456
456
|
<html lang="${L}"><head>
|
|
457
457
|
<meta charset="utf-8">
|
|
458
458
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
459
|
-
<script>(function(){try{var t=localStorage.getItem('wc-theme');if(t==='dark'||t==='light')document.documentElement.setAttribute('data-theme',t);}catch(e){}try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}})();</script>
|
|
459
|
+
<script>(function(){document.documentElement.classList.add('js');try{var t=localStorage.getItem('wc-theme');if(t==='dark'||t==='light')document.documentElement.setAttribute('data-theme',t);}catch(e){}try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}})();</script>
|
|
460
460
|
<title>${m.title}</title>
|
|
461
461
|
<meta name="description" content="${m.desc}">
|
|
462
462
|
<meta name="keywords" content="${m.keywords}">
|
|
@@ -692,10 +692,14 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
692
692
|
.flow .wire .pkt{display:none}
|
|
693
693
|
}
|
|
694
694
|
@media(prefers-reduced-motion:no-preference){
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
695
|
+
/* One-shot reveal: JS adds .in the first time an element scrolls into view and
|
|
696
|
+
never removes it. Gated on .js so content is always visible without
|
|
697
|
+
JavaScript. We deliberately DON'T use a scroll-driven (animation-timeline)
|
|
698
|
+
reveal here — that ties opacity to scroll position and fades content back
|
|
699
|
+
out when you scroll up, which reads as the page flickering. */
|
|
700
|
+
.js .reveal{opacity:0;transform:translateY(24px);
|
|
701
|
+
transition:opacity .6s ease,transform .6s cubic-bezier(.2,.7,.2,1)}
|
|
702
|
+
.js .reveal.in{opacity:1;transform:none}
|
|
699
703
|
.hero-in{animation:rise2 .8s cubic-bezier(.2,.7,.2,1) both}
|
|
700
704
|
@keyframes rise2{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}}
|
|
701
705
|
}
|
|
@@ -843,6 +847,20 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
843
847
|
window.addEventListener('beforeunload',saveScroll);
|
|
844
848
|
window.addEventListener('pagehide',saveScroll);
|
|
845
849
|
|
|
850
|
+
// One-shot reveal-on-scroll. Each .reveal fades in once when it enters the
|
|
851
|
+
// viewport and then keeps its class forever — replacing the old scroll-driven
|
|
852
|
+
// CSS reveal that re-ran (and flickered) when scrolling back up. Falls back to
|
|
853
|
+
// showing everything if IntersectionObserver is missing.
|
|
854
|
+
var reveals=[].slice.call(document.querySelectorAll('.reveal'));
|
|
855
|
+
if(window.IntersectionObserver&&reveals.length){
|
|
856
|
+
var io=new IntersectionObserver(function(entries){
|
|
857
|
+
entries.forEach(function(en){if(en.isIntersecting){en.target.classList.add('in');io.unobserve(en.target);}});
|
|
858
|
+
},{rootMargin:'0px 0px -8% 0px'});
|
|
859
|
+
reveals.forEach(function(el){io.observe(el);});
|
|
860
|
+
}else{
|
|
861
|
+
reveals.forEach(function(el){el.classList.add('in');});
|
|
862
|
+
}
|
|
863
|
+
|
|
846
864
|
// Enable smooth scrolling only after the browser has restored scroll position
|
|
847
865
|
// on (re)load — applying it globally animates that restore into a jerky scroll.
|
|
848
866
|
window.addEventListener('load',function(){requestAnimationFrame(function(){html.classList.add('smooth');});});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-landing-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
4
4
|
"description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
|
|
5
5
|
"mcpName": "io.github.vuluu2k/webcake-landing-mcp",
|
|
6
6
|
"type": "module",
|
|
@@ -14,10 +14,15 @@
|
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=18"
|
|
16
16
|
},
|
|
17
|
+
"author": "vuluu2k (https://github.com/vuluu2k)",
|
|
18
|
+
"homepage": "https://mcp.toolvn.io.vn",
|
|
17
19
|
"repository": {
|
|
18
20
|
"type": "git",
|
|
19
21
|
"url": "git+https://github.com/vuluu2k/webcake-landing-mcp.git"
|
|
20
22
|
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/vuluu2k/webcake-landing-mcp/issues"
|
|
25
|
+
},
|
|
21
26
|
"scripts": {
|
|
22
27
|
"build": "node scripts/gen-changelog.mjs && tsc && node scripts/copy-assets.mjs",
|
|
23
28
|
"start": "node dist/index.js",
|