@baziapi/widget 1.0.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/README.md +67 -0
- package/dist/widget.cjs +339 -0
- package/dist/widget.d.cts +2 -0
- package/dist/widget.d.mts +2 -0
- package/dist/widget.d.ts +2 -0
- package/dist/widget.mjs +337 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# BaZi API - Embeddable Web Widget (`@baziapi/widget`)
|
|
2
|
+
|
|
3
|
+
A lightweight, zero-dependency, plug-and-play BaZi Four Pillars calculator widget for Webflow, WordPress, Shopify, Next.js, and static HTML websites.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Quick Start (HTML CDN Embed)
|
|
8
|
+
|
|
9
|
+
Add the following snippet anywhere on your website:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<!-- Container element -->
|
|
13
|
+
<div id="bazi-widget" data-api-key="bazi_live_your_api_key_here"></div>
|
|
14
|
+
|
|
15
|
+
<!-- CDN Script -->
|
|
16
|
+
<script src="https://cdn.baziapi.pro/v1/widget.js" async></script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ⚙️ Configuration Attributes
|
|
22
|
+
|
|
23
|
+
| Attribute | Type | Default | Description |
|
|
24
|
+
| :-------------- | :------------------ | :---------------------------------- | :-------------------------------------------- |
|
|
25
|
+
| `data-api-key` | string | **Required** | Your publishable BaZi API Key |
|
|
26
|
+
| `data-base-url` | string | `"https://api.bazi-api.com/api/v1"` | API Base URL (for testing or proxy endpoints) |
|
|
27
|
+
| `data-theme` | `'light' \| 'dark'` | `'light'` | Theme preference |
|
|
28
|
+
| `data-lang` | `'en' \| 'zh'` | `'en'` | Default language for chart outputs |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🎨 Framework Integration Examples
|
|
33
|
+
|
|
34
|
+
### 1. WordPress
|
|
35
|
+
|
|
36
|
+
1. Edit your Page/Post using Gutenberg or Elementor.
|
|
37
|
+
2. Add a **Custom HTML** block.
|
|
38
|
+
3. Paste the HTML snippet above.
|
|
39
|
+
|
|
40
|
+
### 2. Webflow
|
|
41
|
+
|
|
42
|
+
1. Drag an **Embed** element onto your page canvas.
|
|
43
|
+
2. Paste the HTML snippet above.
|
|
44
|
+
3. Publish your Webflow site.
|
|
45
|
+
|
|
46
|
+
### 3. Next.js (App Router)
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
'use client';
|
|
50
|
+
import Script from 'next/script';
|
|
51
|
+
|
|
52
|
+
export default function BaziWidgetPage() {
|
|
53
|
+
return (
|
|
54
|
+
<div className="p-8">
|
|
55
|
+
<h1 className="text-2xl font-bold mb-4">Calculate Your BaZi Reading</h1>
|
|
56
|
+
<div id="bazi-widget" data-api-key={process.env.NEXT_PUBLIC_BAZI_API_KEY} />
|
|
57
|
+
<Script src="https://cdn.bazi-api.com/v1/widget.js" strategy="lazyOnload" />
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 📄 License
|
|
66
|
+
|
|
67
|
+
MIT License.
|
package/dist/widget.cjs
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
(function() {
|
|
4
|
+
const WIDGET_CONTAINER_ID = "bazi-widget";
|
|
5
|
+
const STYLES = `
|
|
6
|
+
.bazi-widget-container {
|
|
7
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
8
|
+
max-width: 520px;
|
|
9
|
+
margin: 0 auto;
|
|
10
|
+
background: linear-gradient(135deg, #111827 0%, #1f2937 100%);
|
|
11
|
+
color: #f9fafb;
|
|
12
|
+
border-radius: 16px;
|
|
13
|
+
padding: 24px;
|
|
14
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
15
|
+
border: 1px solid #374151;
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
.bazi-widget-container * {
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
.bazi-widget-header {
|
|
22
|
+
text-align: center;
|
|
23
|
+
margin-bottom: 20px;
|
|
24
|
+
}
|
|
25
|
+
.bazi-widget-title {
|
|
26
|
+
font-size: 1.35rem;
|
|
27
|
+
font-weight: 700;
|
|
28
|
+
color: #f3f4f6;
|
|
29
|
+
margin: 0 0 6px 0;
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
gap: 8px;
|
|
34
|
+
}
|
|
35
|
+
.bazi-widget-subtitle {
|
|
36
|
+
font-size: 0.85rem;
|
|
37
|
+
color: #9ca3af;
|
|
38
|
+
margin: 0;
|
|
39
|
+
}
|
|
40
|
+
.bazi-widget-form {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
gap: 14px;
|
|
44
|
+
}
|
|
45
|
+
.bazi-form-row {
|
|
46
|
+
display: flex;
|
|
47
|
+
gap: 12px;
|
|
48
|
+
}
|
|
49
|
+
.bazi-form-group {
|
|
50
|
+
flex: 1;
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: 6px;
|
|
54
|
+
}
|
|
55
|
+
.bazi-label {
|
|
56
|
+
font-size: 0.8rem;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
color: #d1d5db;
|
|
59
|
+
text-transform: uppercase;
|
|
60
|
+
letter-spacing: 0.05em;
|
|
61
|
+
}
|
|
62
|
+
.bazi-input, .bazi-select {
|
|
63
|
+
background: #111827;
|
|
64
|
+
border: 1px solid #4b5563;
|
|
65
|
+
color: #f9fafb;
|
|
66
|
+
border-radius: 8px;
|
|
67
|
+
padding: 10px 12px;
|
|
68
|
+
font-size: 0.95rem;
|
|
69
|
+
outline: none;
|
|
70
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
71
|
+
}
|
|
72
|
+
.bazi-input:focus, .bazi-select:focus {
|
|
73
|
+
border-color: #6366f1;
|
|
74
|
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.25);
|
|
75
|
+
}
|
|
76
|
+
.bazi-btn-submit {
|
|
77
|
+
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
|
|
78
|
+
color: white;
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
font-size: 0.95rem;
|
|
81
|
+
border: none;
|
|
82
|
+
border-radius: 8px;
|
|
83
|
+
padding: 12px;
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
margin-top: 6px;
|
|
86
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
87
|
+
}
|
|
88
|
+
.bazi-btn-submit:hover {
|
|
89
|
+
opacity: 0.92;
|
|
90
|
+
}
|
|
91
|
+
.bazi-btn-submit:active {
|
|
92
|
+
transform: scale(0.99);
|
|
93
|
+
}
|
|
94
|
+
.bazi-btn-submit:disabled {
|
|
95
|
+
opacity: 0.5;
|
|
96
|
+
cursor: not-allowed;
|
|
97
|
+
}
|
|
98
|
+
.bazi-widget-error {
|
|
99
|
+
background: rgba(239, 68, 68, 0.15);
|
|
100
|
+
border: 1px solid #ef4444;
|
|
101
|
+
color: #fca5a5;
|
|
102
|
+
padding: 10px;
|
|
103
|
+
border-radius: 8px;
|
|
104
|
+
font-size: 0.85rem;
|
|
105
|
+
margin-top: 12px;
|
|
106
|
+
}
|
|
107
|
+
.bazi-result-card {
|
|
108
|
+
margin-top: 20px;
|
|
109
|
+
padding-top: 20px;
|
|
110
|
+
border-top: 1px solid #374151;
|
|
111
|
+
animation: baziFadeIn 0.3s ease;
|
|
112
|
+
}
|
|
113
|
+
@keyframes baziFadeIn {
|
|
114
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
115
|
+
to { opacity: 1; transform: translateY(0); }
|
|
116
|
+
}
|
|
117
|
+
.bazi-pillars-grid {
|
|
118
|
+
display: grid;
|
|
119
|
+
grid-template-columns: repeat(4, 1fr);
|
|
120
|
+
gap: 8px;
|
|
121
|
+
text-align: center;
|
|
122
|
+
margin-bottom: 16px;
|
|
123
|
+
}
|
|
124
|
+
.bazi-pillar-col {
|
|
125
|
+
background: #111827;
|
|
126
|
+
border: 1px solid #374151;
|
|
127
|
+
border-radius: 8px;
|
|
128
|
+
padding: 8px 4px;
|
|
129
|
+
}
|
|
130
|
+
.bazi-pillar-header {
|
|
131
|
+
font-size: 0.75rem;
|
|
132
|
+
color: #9ca3af;
|
|
133
|
+
font-weight: 600;
|
|
134
|
+
margin-bottom: 4px;
|
|
135
|
+
}
|
|
136
|
+
.bazi-pillar-stem {
|
|
137
|
+
font-size: 1.1rem;
|
|
138
|
+
font-weight: 700;
|
|
139
|
+
color: #60a5fa;
|
|
140
|
+
}
|
|
141
|
+
.bazi-pillar-branch {
|
|
142
|
+
font-size: 1.1rem;
|
|
143
|
+
font-weight: 700;
|
|
144
|
+
color: #34d399;
|
|
145
|
+
}
|
|
146
|
+
.bazi-day-master-badge {
|
|
147
|
+
display: inline-block;
|
|
148
|
+
background: #4338ca;
|
|
149
|
+
color: #e0e7ff;
|
|
150
|
+
padding: 4px 10px;
|
|
151
|
+
border-radius: 9999px;
|
|
152
|
+
font-size: 0.8rem;
|
|
153
|
+
font-weight: 600;
|
|
154
|
+
margin-bottom: 12px;
|
|
155
|
+
}
|
|
156
|
+
.bazi-element-stats {
|
|
157
|
+
background: #111827;
|
|
158
|
+
border-radius: 8px;
|
|
159
|
+
padding: 12px;
|
|
160
|
+
border: 1px solid #374151;
|
|
161
|
+
}
|
|
162
|
+
.bazi-element-title {
|
|
163
|
+
font-size: 0.8rem;
|
|
164
|
+
font-weight: 600;
|
|
165
|
+
color: #9ca3af;
|
|
166
|
+
margin-bottom: 8px;
|
|
167
|
+
}
|
|
168
|
+
.bazi-element-bars {
|
|
169
|
+
display: flex;
|
|
170
|
+
gap: 6px;
|
|
171
|
+
align-items: center;
|
|
172
|
+
}
|
|
173
|
+
.bazi-element-tag {
|
|
174
|
+
flex: 1;
|
|
175
|
+
text-align: center;
|
|
176
|
+
font-size: 0.75rem;
|
|
177
|
+
padding: 4px;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
}
|
|
181
|
+
.bazi-el-wood { background: #064e3b; color: #6ee7b7; }
|
|
182
|
+
.bazi-el-fire { background: #7f1d1d; color: #fca5a5; }
|
|
183
|
+
.bazi-el-earth { background: #78350f; color: #fde68a; }
|
|
184
|
+
.bazi-el-metal { background: #374151; color: #e5e7eb; }
|
|
185
|
+
.bazi-el-water { background: #1e3a8a; color: #93c5fd; }
|
|
186
|
+
`;
|
|
187
|
+
function injectStyles() {
|
|
188
|
+
const styleEl = document.createElement("style");
|
|
189
|
+
styleEl.textContent = STYLES;
|
|
190
|
+
document.head.appendChild(styleEl);
|
|
191
|
+
}
|
|
192
|
+
function initWidget() {
|
|
193
|
+
const container = document.getElementById(WIDGET_CONTAINER_ID);
|
|
194
|
+
if (!container) return;
|
|
195
|
+
const apiKey = container.getAttribute("data-api-key") || "";
|
|
196
|
+
const baseUrl = (container.getAttribute("data-base-url") || "https://api.bazi.dev").replace(
|
|
197
|
+
/\/$/,
|
|
198
|
+
""
|
|
199
|
+
);
|
|
200
|
+
injectStyles();
|
|
201
|
+
container.innerHTML = `
|
|
202
|
+
<div class="bazi-widget-container">
|
|
203
|
+
<div class="bazi-widget-header">
|
|
204
|
+
<h3 class="bazi-widget-title">\u262F\uFE0F BaZi Four Pillars Calculator</h3>
|
|
205
|
+
<p class="bazi-widget-subtitle">Discover your Day Master & Element Balance</p>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<form class="bazi-widget-form" id="bazi-form">
|
|
209
|
+
<div class="bazi-form-row">
|
|
210
|
+
<div class="bazi-form-group">
|
|
211
|
+
<label class="bazi-label">Birth Date</label>
|
|
212
|
+
<input type="date" id="bazi-birth-date" class="bazi-input" required value="1998-08-12" />
|
|
213
|
+
</div>
|
|
214
|
+
<div class="bazi-form-group">
|
|
215
|
+
<label class="bazi-label">Birth Time</label>
|
|
216
|
+
<input type="time" id="bazi-birth-time" class="bazi-input" required value="10:30" />
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div class="bazi-form-row">
|
|
221
|
+
<div class="bazi-form-group">
|
|
222
|
+
<label class="bazi-label">Gender</label>
|
|
223
|
+
<select id="bazi-gender" class="bazi-select">
|
|
224
|
+
<option value="male">Male</option>
|
|
225
|
+
<option value="female">Female</option>
|
|
226
|
+
</select>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="bazi-form-group">
|
|
229
|
+
<label class="bazi-label">Timezone</label>
|
|
230
|
+
<input type="text" id="bazi-timezone" class="bazi-input" value="Asia/Shanghai" />
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<button type="submit" class="bazi-btn-submit" id="bazi-submit-btn">Calculate Four Pillars</button>
|
|
235
|
+
</form>
|
|
236
|
+
|
|
237
|
+
<div id="bazi-error-container" style="display: none;"></div>
|
|
238
|
+
<div id="bazi-result-container" style="display: none;"></div>
|
|
239
|
+
</div>
|
|
240
|
+
`;
|
|
241
|
+
const form = document.getElementById("bazi-form");
|
|
242
|
+
const submitBtn = document.getElementById("bazi-submit-btn");
|
|
243
|
+
const errorContainer = document.getElementById("bazi-error-container");
|
|
244
|
+
const resultContainer = document.getElementById("bazi-result-container");
|
|
245
|
+
form.addEventListener("submit", async (e) => {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
errorContainer.style.display = "none";
|
|
248
|
+
resultContainer.style.display = "none";
|
|
249
|
+
submitBtn.disabled = true;
|
|
250
|
+
submitBtn.innerText = "Calculating chart...";
|
|
251
|
+
const birthDate = document.getElementById("bazi-birth-date").value;
|
|
252
|
+
const birthTime = document.getElementById("bazi-birth-time").value;
|
|
253
|
+
const gender = document.getElementById("bazi-gender").value;
|
|
254
|
+
const timezone = document.getElementById("bazi-timezone").value;
|
|
255
|
+
try {
|
|
256
|
+
const response = await fetch(`${baseUrl}/api/v1/bazi/calculate`, {
|
|
257
|
+
method: "POST",
|
|
258
|
+
headers: {
|
|
259
|
+
"Content-Type": "application/json",
|
|
260
|
+
"x-api-key": apiKey,
|
|
261
|
+
"User-Agent": "bazi-widget/1.0.0"
|
|
262
|
+
},
|
|
263
|
+
body: JSON.stringify({
|
|
264
|
+
birthDate,
|
|
265
|
+
birthTime,
|
|
266
|
+
gender,
|
|
267
|
+
timezone,
|
|
268
|
+
language: "en"
|
|
269
|
+
})
|
|
270
|
+
});
|
|
271
|
+
const json = await response.json();
|
|
272
|
+
if (!response.ok) {
|
|
273
|
+
throw new Error(json.message || "Calculation request failed");
|
|
274
|
+
}
|
|
275
|
+
const data = json.data || json;
|
|
276
|
+
renderResult(data, resultContainer);
|
|
277
|
+
} catch (err) {
|
|
278
|
+
errorContainer.textContent = err.message || "An error occurred while calculating.";
|
|
279
|
+
errorContainer.className = "bazi-widget-error";
|
|
280
|
+
errorContainer.style.display = "block";
|
|
281
|
+
} finally {
|
|
282
|
+
submitBtn.disabled = false;
|
|
283
|
+
submitBtn.innerText = "Calculate Four Pillars";
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function renderResult(data, container) {
|
|
288
|
+
data.pillars || {};
|
|
289
|
+
const stems = data.heavenlyStems || {};
|
|
290
|
+
const branches = data.earthlyBranches || {};
|
|
291
|
+
const analysis = data.analysis || {};
|
|
292
|
+
container.className = "bazi-result-card";
|
|
293
|
+
container.innerHTML = `
|
|
294
|
+
<div style="text-align: center;">
|
|
295
|
+
<span class="bazi-day-master-badge">\u2728 Day Master: ${stems.dayStem || "N/A"}</span>
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
<div class="bazi-pillars-grid">
|
|
299
|
+
<div class="bazi-pillar-col">
|
|
300
|
+
<div class="bazi-pillar-header">HOUR</div>
|
|
301
|
+
<div class="bazi-pillar-stem">${stems.hourStem || "-"}</div>
|
|
302
|
+
<div class="bazi-pillar-branch">${branches.hourBranch || "-"}</div>
|
|
303
|
+
</div>
|
|
304
|
+
<div class="bazi-pillar-col">
|
|
305
|
+
<div class="bazi-pillar-header">DAY</div>
|
|
306
|
+
<div class="bazi-pillar-stem">${stems.dayStem || "-"}</div>
|
|
307
|
+
<div class="bazi-pillar-branch">${branches.dayBranch || "-"}</div>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="bazi-pillar-col">
|
|
310
|
+
<div class="bazi-pillar-header">MONTH</div>
|
|
311
|
+
<div class="bazi-pillar-stem">${stems.monthStem || "-"}</div>
|
|
312
|
+
<div class="bazi-pillar-branch">${branches.monthBranch || "-"}</div>
|
|
313
|
+
</div>
|
|
314
|
+
<div class="bazi-pillar-col">
|
|
315
|
+
<div class="bazi-pillar-header">YEAR</div>
|
|
316
|
+
<div class="bazi-pillar-stem">${stems.yearStem || "-"}</div>
|
|
317
|
+
<div class="bazi-pillar-branch">${branches.yearBranch || "-"}</div>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
<div class="bazi-element-stats">
|
|
322
|
+
<div class="bazi-element-title">Dominant Element: <strong style="color: #f3f4f6;">${analysis.strongestElement || "Balanced"}</strong></div>
|
|
323
|
+
<div class="bazi-element-bars">
|
|
324
|
+
<div class="bazi-element-tag bazi-el-wood">Wood</div>
|
|
325
|
+
<div class="bazi-element-tag bazi-el-fire">Fire</div>
|
|
326
|
+
<div class="bazi-element-tag bazi-el-earth">Earth</div>
|
|
327
|
+
<div class="bazi-element-tag bazi-el-metal">Metal</div>
|
|
328
|
+
<div class="bazi-element-tag bazi-el-water">Water</div>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
`;
|
|
332
|
+
container.style.display = "block";
|
|
333
|
+
}
|
|
334
|
+
if (document.readyState === "loading") {
|
|
335
|
+
document.addEventListener("DOMContentLoaded", initWidget);
|
|
336
|
+
} else {
|
|
337
|
+
initWidget();
|
|
338
|
+
}
|
|
339
|
+
})();
|
package/dist/widget.d.ts
ADDED
package/dist/widget.mjs
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
const WIDGET_CONTAINER_ID = "bazi-widget";
|
|
3
|
+
const STYLES = `
|
|
4
|
+
.bazi-widget-container {
|
|
5
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
6
|
+
max-width: 520px;
|
|
7
|
+
margin: 0 auto;
|
|
8
|
+
background: linear-gradient(135deg, #111827 0%, #1f2937 100%);
|
|
9
|
+
color: #f9fafb;
|
|
10
|
+
border-radius: 16px;
|
|
11
|
+
padding: 24px;
|
|
12
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
13
|
+
border: 1px solid #374151;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
.bazi-widget-container * {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
.bazi-widget-header {
|
|
20
|
+
text-align: center;
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
.bazi-widget-title {
|
|
24
|
+
font-size: 1.35rem;
|
|
25
|
+
font-weight: 700;
|
|
26
|
+
color: #f3f4f6;
|
|
27
|
+
margin: 0 0 6px 0;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
gap: 8px;
|
|
32
|
+
}
|
|
33
|
+
.bazi-widget-subtitle {
|
|
34
|
+
font-size: 0.85rem;
|
|
35
|
+
color: #9ca3af;
|
|
36
|
+
margin: 0;
|
|
37
|
+
}
|
|
38
|
+
.bazi-widget-form {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
gap: 14px;
|
|
42
|
+
}
|
|
43
|
+
.bazi-form-row {
|
|
44
|
+
display: flex;
|
|
45
|
+
gap: 12px;
|
|
46
|
+
}
|
|
47
|
+
.bazi-form-group {
|
|
48
|
+
flex: 1;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: 6px;
|
|
52
|
+
}
|
|
53
|
+
.bazi-label {
|
|
54
|
+
font-size: 0.8rem;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
color: #d1d5db;
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
letter-spacing: 0.05em;
|
|
59
|
+
}
|
|
60
|
+
.bazi-input, .bazi-select {
|
|
61
|
+
background: #111827;
|
|
62
|
+
border: 1px solid #4b5563;
|
|
63
|
+
color: #f9fafb;
|
|
64
|
+
border-radius: 8px;
|
|
65
|
+
padding: 10px 12px;
|
|
66
|
+
font-size: 0.95rem;
|
|
67
|
+
outline: none;
|
|
68
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
69
|
+
}
|
|
70
|
+
.bazi-input:focus, .bazi-select:focus {
|
|
71
|
+
border-color: #6366f1;
|
|
72
|
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.25);
|
|
73
|
+
}
|
|
74
|
+
.bazi-btn-submit {
|
|
75
|
+
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
|
|
76
|
+
color: white;
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
font-size: 0.95rem;
|
|
79
|
+
border: none;
|
|
80
|
+
border-radius: 8px;
|
|
81
|
+
padding: 12px;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
margin-top: 6px;
|
|
84
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
85
|
+
}
|
|
86
|
+
.bazi-btn-submit:hover {
|
|
87
|
+
opacity: 0.92;
|
|
88
|
+
}
|
|
89
|
+
.bazi-btn-submit:active {
|
|
90
|
+
transform: scale(0.99);
|
|
91
|
+
}
|
|
92
|
+
.bazi-btn-submit:disabled {
|
|
93
|
+
opacity: 0.5;
|
|
94
|
+
cursor: not-allowed;
|
|
95
|
+
}
|
|
96
|
+
.bazi-widget-error {
|
|
97
|
+
background: rgba(239, 68, 68, 0.15);
|
|
98
|
+
border: 1px solid #ef4444;
|
|
99
|
+
color: #fca5a5;
|
|
100
|
+
padding: 10px;
|
|
101
|
+
border-radius: 8px;
|
|
102
|
+
font-size: 0.85rem;
|
|
103
|
+
margin-top: 12px;
|
|
104
|
+
}
|
|
105
|
+
.bazi-result-card {
|
|
106
|
+
margin-top: 20px;
|
|
107
|
+
padding-top: 20px;
|
|
108
|
+
border-top: 1px solid #374151;
|
|
109
|
+
animation: baziFadeIn 0.3s ease;
|
|
110
|
+
}
|
|
111
|
+
@keyframes baziFadeIn {
|
|
112
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
113
|
+
to { opacity: 1; transform: translateY(0); }
|
|
114
|
+
}
|
|
115
|
+
.bazi-pillars-grid {
|
|
116
|
+
display: grid;
|
|
117
|
+
grid-template-columns: repeat(4, 1fr);
|
|
118
|
+
gap: 8px;
|
|
119
|
+
text-align: center;
|
|
120
|
+
margin-bottom: 16px;
|
|
121
|
+
}
|
|
122
|
+
.bazi-pillar-col {
|
|
123
|
+
background: #111827;
|
|
124
|
+
border: 1px solid #374151;
|
|
125
|
+
border-radius: 8px;
|
|
126
|
+
padding: 8px 4px;
|
|
127
|
+
}
|
|
128
|
+
.bazi-pillar-header {
|
|
129
|
+
font-size: 0.75rem;
|
|
130
|
+
color: #9ca3af;
|
|
131
|
+
font-weight: 600;
|
|
132
|
+
margin-bottom: 4px;
|
|
133
|
+
}
|
|
134
|
+
.bazi-pillar-stem {
|
|
135
|
+
font-size: 1.1rem;
|
|
136
|
+
font-weight: 700;
|
|
137
|
+
color: #60a5fa;
|
|
138
|
+
}
|
|
139
|
+
.bazi-pillar-branch {
|
|
140
|
+
font-size: 1.1rem;
|
|
141
|
+
font-weight: 700;
|
|
142
|
+
color: #34d399;
|
|
143
|
+
}
|
|
144
|
+
.bazi-day-master-badge {
|
|
145
|
+
display: inline-block;
|
|
146
|
+
background: #4338ca;
|
|
147
|
+
color: #e0e7ff;
|
|
148
|
+
padding: 4px 10px;
|
|
149
|
+
border-radius: 9999px;
|
|
150
|
+
font-size: 0.8rem;
|
|
151
|
+
font-weight: 600;
|
|
152
|
+
margin-bottom: 12px;
|
|
153
|
+
}
|
|
154
|
+
.bazi-element-stats {
|
|
155
|
+
background: #111827;
|
|
156
|
+
border-radius: 8px;
|
|
157
|
+
padding: 12px;
|
|
158
|
+
border: 1px solid #374151;
|
|
159
|
+
}
|
|
160
|
+
.bazi-element-title {
|
|
161
|
+
font-size: 0.8rem;
|
|
162
|
+
font-weight: 600;
|
|
163
|
+
color: #9ca3af;
|
|
164
|
+
margin-bottom: 8px;
|
|
165
|
+
}
|
|
166
|
+
.bazi-element-bars {
|
|
167
|
+
display: flex;
|
|
168
|
+
gap: 6px;
|
|
169
|
+
align-items: center;
|
|
170
|
+
}
|
|
171
|
+
.bazi-element-tag {
|
|
172
|
+
flex: 1;
|
|
173
|
+
text-align: center;
|
|
174
|
+
font-size: 0.75rem;
|
|
175
|
+
padding: 4px;
|
|
176
|
+
border-radius: 4px;
|
|
177
|
+
font-weight: 600;
|
|
178
|
+
}
|
|
179
|
+
.bazi-el-wood { background: #064e3b; color: #6ee7b7; }
|
|
180
|
+
.bazi-el-fire { background: #7f1d1d; color: #fca5a5; }
|
|
181
|
+
.bazi-el-earth { background: #78350f; color: #fde68a; }
|
|
182
|
+
.bazi-el-metal { background: #374151; color: #e5e7eb; }
|
|
183
|
+
.bazi-el-water { background: #1e3a8a; color: #93c5fd; }
|
|
184
|
+
`;
|
|
185
|
+
function injectStyles() {
|
|
186
|
+
const styleEl = document.createElement("style");
|
|
187
|
+
styleEl.textContent = STYLES;
|
|
188
|
+
document.head.appendChild(styleEl);
|
|
189
|
+
}
|
|
190
|
+
function initWidget() {
|
|
191
|
+
const container = document.getElementById(WIDGET_CONTAINER_ID);
|
|
192
|
+
if (!container) return;
|
|
193
|
+
const apiKey = container.getAttribute("data-api-key") || "";
|
|
194
|
+
const baseUrl = (container.getAttribute("data-base-url") || "https://api.bazi.dev").replace(
|
|
195
|
+
/\/$/,
|
|
196
|
+
""
|
|
197
|
+
);
|
|
198
|
+
injectStyles();
|
|
199
|
+
container.innerHTML = `
|
|
200
|
+
<div class="bazi-widget-container">
|
|
201
|
+
<div class="bazi-widget-header">
|
|
202
|
+
<h3 class="bazi-widget-title">\u262F\uFE0F BaZi Four Pillars Calculator</h3>
|
|
203
|
+
<p class="bazi-widget-subtitle">Discover your Day Master & Element Balance</p>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<form class="bazi-widget-form" id="bazi-form">
|
|
207
|
+
<div class="bazi-form-row">
|
|
208
|
+
<div class="bazi-form-group">
|
|
209
|
+
<label class="bazi-label">Birth Date</label>
|
|
210
|
+
<input type="date" id="bazi-birth-date" class="bazi-input" required value="1998-08-12" />
|
|
211
|
+
</div>
|
|
212
|
+
<div class="bazi-form-group">
|
|
213
|
+
<label class="bazi-label">Birth Time</label>
|
|
214
|
+
<input type="time" id="bazi-birth-time" class="bazi-input" required value="10:30" />
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="bazi-form-row">
|
|
219
|
+
<div class="bazi-form-group">
|
|
220
|
+
<label class="bazi-label">Gender</label>
|
|
221
|
+
<select id="bazi-gender" class="bazi-select">
|
|
222
|
+
<option value="male">Male</option>
|
|
223
|
+
<option value="female">Female</option>
|
|
224
|
+
</select>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="bazi-form-group">
|
|
227
|
+
<label class="bazi-label">Timezone</label>
|
|
228
|
+
<input type="text" id="bazi-timezone" class="bazi-input" value="Asia/Shanghai" />
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<button type="submit" class="bazi-btn-submit" id="bazi-submit-btn">Calculate Four Pillars</button>
|
|
233
|
+
</form>
|
|
234
|
+
|
|
235
|
+
<div id="bazi-error-container" style="display: none;"></div>
|
|
236
|
+
<div id="bazi-result-container" style="display: none;"></div>
|
|
237
|
+
</div>
|
|
238
|
+
`;
|
|
239
|
+
const form = document.getElementById("bazi-form");
|
|
240
|
+
const submitBtn = document.getElementById("bazi-submit-btn");
|
|
241
|
+
const errorContainer = document.getElementById("bazi-error-container");
|
|
242
|
+
const resultContainer = document.getElementById("bazi-result-container");
|
|
243
|
+
form.addEventListener("submit", async (e) => {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
errorContainer.style.display = "none";
|
|
246
|
+
resultContainer.style.display = "none";
|
|
247
|
+
submitBtn.disabled = true;
|
|
248
|
+
submitBtn.innerText = "Calculating chart...";
|
|
249
|
+
const birthDate = document.getElementById("bazi-birth-date").value;
|
|
250
|
+
const birthTime = document.getElementById("bazi-birth-time").value;
|
|
251
|
+
const gender = document.getElementById("bazi-gender").value;
|
|
252
|
+
const timezone = document.getElementById("bazi-timezone").value;
|
|
253
|
+
try {
|
|
254
|
+
const response = await fetch(`${baseUrl}/api/v1/bazi/calculate`, {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers: {
|
|
257
|
+
"Content-Type": "application/json",
|
|
258
|
+
"x-api-key": apiKey,
|
|
259
|
+
"User-Agent": "bazi-widget/1.0.0"
|
|
260
|
+
},
|
|
261
|
+
body: JSON.stringify({
|
|
262
|
+
birthDate,
|
|
263
|
+
birthTime,
|
|
264
|
+
gender,
|
|
265
|
+
timezone,
|
|
266
|
+
language: "en"
|
|
267
|
+
})
|
|
268
|
+
});
|
|
269
|
+
const json = await response.json();
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
throw new Error(json.message || "Calculation request failed");
|
|
272
|
+
}
|
|
273
|
+
const data = json.data || json;
|
|
274
|
+
renderResult(data, resultContainer);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
errorContainer.textContent = err.message || "An error occurred while calculating.";
|
|
277
|
+
errorContainer.className = "bazi-widget-error";
|
|
278
|
+
errorContainer.style.display = "block";
|
|
279
|
+
} finally {
|
|
280
|
+
submitBtn.disabled = false;
|
|
281
|
+
submitBtn.innerText = "Calculate Four Pillars";
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function renderResult(data, container) {
|
|
286
|
+
data.pillars || {};
|
|
287
|
+
const stems = data.heavenlyStems || {};
|
|
288
|
+
const branches = data.earthlyBranches || {};
|
|
289
|
+
const analysis = data.analysis || {};
|
|
290
|
+
container.className = "bazi-result-card";
|
|
291
|
+
container.innerHTML = `
|
|
292
|
+
<div style="text-align: center;">
|
|
293
|
+
<span class="bazi-day-master-badge">\u2728 Day Master: ${stems.dayStem || "N/A"}</span>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<div class="bazi-pillars-grid">
|
|
297
|
+
<div class="bazi-pillar-col">
|
|
298
|
+
<div class="bazi-pillar-header">HOUR</div>
|
|
299
|
+
<div class="bazi-pillar-stem">${stems.hourStem || "-"}</div>
|
|
300
|
+
<div class="bazi-pillar-branch">${branches.hourBranch || "-"}</div>
|
|
301
|
+
</div>
|
|
302
|
+
<div class="bazi-pillar-col">
|
|
303
|
+
<div class="bazi-pillar-header">DAY</div>
|
|
304
|
+
<div class="bazi-pillar-stem">${stems.dayStem || "-"}</div>
|
|
305
|
+
<div class="bazi-pillar-branch">${branches.dayBranch || "-"}</div>
|
|
306
|
+
</div>
|
|
307
|
+
<div class="bazi-pillar-col">
|
|
308
|
+
<div class="bazi-pillar-header">MONTH</div>
|
|
309
|
+
<div class="bazi-pillar-stem">${stems.monthStem || "-"}</div>
|
|
310
|
+
<div class="bazi-pillar-branch">${branches.monthBranch || "-"}</div>
|
|
311
|
+
</div>
|
|
312
|
+
<div class="bazi-pillar-col">
|
|
313
|
+
<div class="bazi-pillar-header">YEAR</div>
|
|
314
|
+
<div class="bazi-pillar-stem">${stems.yearStem || "-"}</div>
|
|
315
|
+
<div class="bazi-pillar-branch">${branches.yearBranch || "-"}</div>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div class="bazi-element-stats">
|
|
320
|
+
<div class="bazi-element-title">Dominant Element: <strong style="color: #f3f4f6;">${analysis.strongestElement || "Balanced"}</strong></div>
|
|
321
|
+
<div class="bazi-element-bars">
|
|
322
|
+
<div class="bazi-element-tag bazi-el-wood">Wood</div>
|
|
323
|
+
<div class="bazi-element-tag bazi-el-fire">Fire</div>
|
|
324
|
+
<div class="bazi-element-tag bazi-el-earth">Earth</div>
|
|
325
|
+
<div class="bazi-element-tag bazi-el-metal">Metal</div>
|
|
326
|
+
<div class="bazi-element-tag bazi-el-water">Water</div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
`;
|
|
330
|
+
container.style.display = "block";
|
|
331
|
+
}
|
|
332
|
+
if (document.readyState === "loading") {
|
|
333
|
+
document.addEventListener("DOMContentLoaded", initWidget);
|
|
334
|
+
} else {
|
|
335
|
+
initWidget();
|
|
336
|
+
}
|
|
337
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@baziapi/widget",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Embeddable interactive Web Widget for BaZi Four Pillars calculator",
|
|
6
|
+
"author": "Md. Nasir Uddin Shoyas",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/widget.cjs",
|
|
12
|
+
"module": "./dist/widget.mjs",
|
|
13
|
+
"types": "./dist/widget.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.6.3",
|
|
19
|
+
"unbuild": "^3.0.0"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "unbuild",
|
|
23
|
+
"dev": "unbuild --stub",
|
|
24
|
+
"lint": "eslint src"
|
|
25
|
+
}
|
|
26
|
+
}
|