weifuwu 0.27.10 → 0.27.12
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 +44 -60
- package/dist/index.d.ts +1 -0
- package/dist/index.js +40 -29
- package/dist/ssr/assets.d.ts +3 -18
- package/dist/ssr/ui/assets.d.ts +2 -0
- package/dist/template/app.ts +20 -0
- package/dist/template/index.ts +6 -0
- package/dist/template/locales/en.json +6 -0
- package/dist/template/locales/zh-CN.json +6 -0
- package/dist/template/package.json +11 -0
- package/dist/template/tsconfig.json +15 -0
- package/dist/template/ui/app/globals.css +2 -0
- package/dist/template/ui/app/layout.ts +39 -0
- package/dist/template/ui/app/page.ts +41 -0
- package/dist/template/ui/lib/utils.ts +7 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -66,36 +66,27 @@ app.use(rateLimit({ window: 60 }))
|
|
|
66
66
|
## Full-stack SSR
|
|
67
67
|
|
|
68
68
|
Server-rendered HTML with zero frontend build tools. Uses `html()` tagged templates
|
|
69
|
-
for safe HTML rendering,
|
|
69
|
+
for safe HTML rendering, and `weifuwu-ui.js` for client-side interactions.
|
|
70
70
|
|
|
71
71
|
```ts
|
|
72
|
-
import { Router, serve, html, raw, layout, view,
|
|
72
|
+
import { Router, serve, html, raw, layout, view, wfuwAssets, theme, i18n, flash } from 'weifuwu'
|
|
73
73
|
|
|
74
74
|
const app = new Router()
|
|
75
75
|
|
|
76
76
|
// Middleware
|
|
77
77
|
app.use(theme())
|
|
78
78
|
app.use(i18n({ dir: './locales' }))
|
|
79
|
-
app.use(
|
|
79
|
+
app.use(flash())
|
|
80
|
+
|
|
81
|
+
// weifuwu-ui frontend runtime
|
|
82
|
+
app.use('/', wfuwAssets())
|
|
80
83
|
|
|
81
84
|
// Layout (wraps all pages)
|
|
82
85
|
app.use(layout('./ui/app/layout.ts'))
|
|
83
86
|
|
|
84
|
-
// Static assets (HTMX, Alpine — served locally, no CDN)
|
|
85
|
-
app.use(assetRouter())
|
|
86
|
-
|
|
87
|
-
// CSS serving
|
|
88
|
-
app.use('/', cssRouter('./ui'))
|
|
89
|
-
|
|
90
87
|
// Page
|
|
91
88
|
app.get('/', view('./ui/app/page.ts'))
|
|
92
89
|
|
|
93
|
-
// HTMX fragment handler
|
|
94
|
-
app.get('/users/table', async (req, ctx) => {
|
|
95
|
-
const users = await ctx.sql`SELECT * FROM users`
|
|
96
|
-
return html`${users.map((u) => html`<div>${u.name}</div>`)}`
|
|
97
|
-
})
|
|
98
|
-
|
|
99
90
|
// API
|
|
100
91
|
app.get('/api/ping', () => Response.json({ pong: true }))
|
|
101
92
|
|
|
@@ -139,15 +130,17 @@ import { html, raw } from 'weifuwu'
|
|
|
139
130
|
// ui/app/layout.ts
|
|
140
131
|
export default function (body: string, ctx: any) {
|
|
141
132
|
return html`<!DOCTYPE html>
|
|
142
|
-
<html>
|
|
133
|
+
<html data-theme="${ctx.theme?.value || 'light'}">
|
|
143
134
|
<head>
|
|
144
135
|
<meta charset="utf-8" />
|
|
145
|
-
<
|
|
146
|
-
<script
|
|
136
|
+
<link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css" />
|
|
137
|
+
<script src="/__wfw/js/weifuwu-ui.js"></script>
|
|
138
|
+
<script id="__wfw-i18n" type="application/json">
|
|
139
|
+
${raw(JSON.stringify(ctx.i18n?.messages || {}))}
|
|
140
|
+
</script>
|
|
147
141
|
</head>
|
|
148
|
-
<body
|
|
142
|
+
<body data-locale="${ctx.i18n?.locale || 'en'}">
|
|
149
143
|
${raw(body)}
|
|
150
|
-
<!-- ← use raw() for page content -->
|
|
151
144
|
</body>
|
|
152
145
|
</html>`
|
|
153
146
|
}
|
|
@@ -167,29 +160,23 @@ export default function (ctx: any) {
|
|
|
167
160
|
}
|
|
168
161
|
```
|
|
169
162
|
|
|
170
|
-
###
|
|
163
|
+
### UI frontend runtime (weifuwu-ui)
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/* ui/app/globals.css */
|
|
176
|
-
@import 'tailwindcss';
|
|
177
|
-
@custom-variant dark (&:is(.dark *));
|
|
178
|
-
```
|
|
165
|
+
weifuwu-ui is a zero-dependency frontend runtime (~5KB) that ships with weifuwu.
|
|
166
|
+
One `<script>` + `<link>` covers AJAX loading, state binding, SSE streaming,
|
|
167
|
+
WebSocket, theme/i18n/flash integration, and UI components.
|
|
179
168
|
|
|
180
169
|
```ts
|
|
181
|
-
|
|
182
|
-
app.use(cssRouter('./ui')) // serve /__wfw/style/:hash.css
|
|
183
|
-
```
|
|
170
|
+
import { wfuwAssets } from 'weifuwu'
|
|
184
171
|
|
|
185
|
-
|
|
172
|
+
app.use(wfuwAssets()) // serve /__wfw/js/weifuwu-ui.js + /__wfw/css/weifuwu-ui.css
|
|
173
|
+
```
|
|
186
174
|
|
|
187
|
-
|
|
188
|
-
No external network requests.
|
|
175
|
+
In your layout:
|
|
189
176
|
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
177
|
+
```html
|
|
178
|
+
<script src="/__wfw/js/weifuwu-ui.js"></script>
|
|
179
|
+
<link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css" />
|
|
193
180
|
```
|
|
194
181
|
|
|
195
182
|
---
|
|
@@ -567,24 +554,20 @@ import { view } from 'weifuwu'
|
|
|
567
554
|
app.get('/', view('./ui/app/page.ts'))
|
|
568
555
|
```
|
|
569
556
|
|
|
570
|
-
####
|
|
557
|
+
#### wfuwAssets()
|
|
571
558
|
|
|
572
|
-
|
|
559
|
+
Serve weifuwu-ui.js and weifuwu-ui.css — zero-dependency frontend runtime (~5KB total).
|
|
560
|
+
Covers: AJAX loading, state binding, SSE streaming, WebSocket, theme/i18n/flash,
|
|
561
|
+
modal/collapse/tabs/dropdown/toast components.
|
|
573
562
|
|
|
574
563
|
```ts
|
|
575
|
-
import {
|
|
576
|
-
app.use(
|
|
577
|
-
app.use(cssRouter('./ui')) // serve /__wfw/style/:hash.css
|
|
564
|
+
import { wfuwAssets } from 'weifuwu'
|
|
565
|
+
app.use(wfuwAssets())
|
|
578
566
|
```
|
|
579
567
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
```ts
|
|
585
|
-
import { assetRouter, assetScripts } from 'weifuwu'
|
|
586
|
-
app.use(assetRouter())
|
|
587
|
-
// In layout: ${assetScripts()}
|
|
568
|
+
```html
|
|
569
|
+
<script src="/__wfw/js/weifuwu-ui.js"></script>
|
|
570
|
+
<link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css" />
|
|
588
571
|
```
|
|
589
572
|
|
|
590
573
|
### Standalone utilities
|
|
@@ -666,15 +649,15 @@ throw new HttpError('Not found', 404) // caught by serve(), returns 404
|
|
|
666
649
|
## CLI
|
|
667
650
|
|
|
668
651
|
```bash
|
|
669
|
-
npx weifuwu init my-app # Full-stack project (SSR +
|
|
652
|
+
npx weifuwu init my-app # Full-stack project (SSR + weifuwu-ui)
|
|
670
653
|
npx weifuwu init my-app --minimal # Minimal API-only project
|
|
671
654
|
npx weifuwu version # Print version
|
|
672
655
|
```
|
|
673
656
|
|
|
674
657
|
### Full-stack template (`init`)
|
|
675
658
|
|
|
676
|
-
Generates a complete project with SSR
|
|
677
|
-
|
|
659
|
+
Generates a complete project with SSR via `html()` tagged templates, weifuwu-ui frontend
|
|
660
|
+
runtime (zero external deps, ~5KB), theme switching, i18n, and flash messages.
|
|
678
661
|
|
|
679
662
|
```
|
|
680
663
|
my-app/
|
|
@@ -682,9 +665,9 @@ my-app/
|
|
|
682
665
|
app.ts — Router setup
|
|
683
666
|
ui/
|
|
684
667
|
app/
|
|
685
|
-
globals.css —
|
|
686
|
-
layout.ts — root layout (
|
|
687
|
-
page.ts — home page (theme/
|
|
668
|
+
globals.css — custom styles
|
|
669
|
+
layout.ts — root layout (weifuwu-ui + theme/i18n/flash)
|
|
670
|
+
page.ts — home page (wu-data/wu-theme/wu-lang demo)
|
|
688
671
|
locales/
|
|
689
672
|
en.json
|
|
690
673
|
zh-CN.json
|
|
@@ -709,10 +692,11 @@ Creates a minimal API project with `app.ts`, `index.ts`, and TypeScript config.
|
|
|
709
692
|
- `ws` — WebSocket
|
|
710
693
|
- `zod` — Schema validation
|
|
711
694
|
|
|
712
|
-
### Frontend
|
|
695
|
+
### Frontend
|
|
696
|
+
|
|
697
|
+
- weifuwu-ui.js (~5KB) — built-in, zero external dependencies
|
|
713
698
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
- `alpinejs` — Lightweight client interactivity
|
|
699
|
+
Covers: AJAX loading, state binding, SSE streaming, WebSocket, theme/i18n/flash,
|
|
700
|
+
modal/collapse/tabs/dropdown/toast components.
|
|
717
701
|
|
|
718
702
|
Zero build tools. Zero frontend framework compilation.
|
package/dist/index.d.ts
CHANGED
|
@@ -66,3 +66,4 @@ export { loadModule, clearModuleCache } from './ssr/compile.ts';
|
|
|
66
66
|
export { cssContext, cssRouter, clearCSSCache } from './ssr/css.ts';
|
|
67
67
|
export type { CssAsset } from './ssr/css.ts';
|
|
68
68
|
export { assetRouter, assetScripts } from './ssr/assets.ts';
|
|
69
|
+
export { wfuwAssets } from './ssr/ui/assets.ts';
|
package/dist/index.js
CHANGED
|
@@ -3594,6 +3594,7 @@ import { createHash } from "node:crypto";
|
|
|
3594
3594
|
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
3595
3595
|
import { join as join3, resolve as resolve6, sep as sep2 } from "node:path";
|
|
3596
3596
|
import tailwindPlugin from "@tailwindcss/postcss";
|
|
3597
|
+
import postcssNesting from "postcss-nesting";
|
|
3597
3598
|
import postcss from "postcss";
|
|
3598
3599
|
var cssCache = /* @__PURE__ */ new Map();
|
|
3599
3600
|
function findTailwindDir() {
|
|
@@ -3625,7 +3626,7 @@ async function compileCSS(cssPath, sourceDir) {
|
|
|
3625
3626
|
}
|
|
3626
3627
|
const src = `@source "${sourceDir}";
|
|
3627
3628
|
${raw2}`;
|
|
3628
|
-
const result = await postcss([tailwindPlugin()]).process(src, { from: cssPath });
|
|
3629
|
+
const result = await postcss([tailwindPlugin(), postcssNesting()]).process(src, { from: cssPath });
|
|
3629
3630
|
const hash = createHash("md5").update(result.css).digest("hex").slice(0, 8);
|
|
3630
3631
|
const asset = { css: result.css, hash, url: `/__wfw/style/${hash}.css` };
|
|
3631
3632
|
cssCache.set(cssPath, asset);
|
|
@@ -3658,51 +3659,60 @@ function clearCSSCache() {
|
|
|
3658
3659
|
cssCache.clear();
|
|
3659
3660
|
}
|
|
3660
3661
|
|
|
3661
|
-
// ssr/assets.ts
|
|
3662
|
+
// ssr/ui/assets.ts
|
|
3662
3663
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
3663
|
-
import { resolve as resolve7 } from "node:path";
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
var HTMX_PATH = resolvePackage("htmx.org", "dist/htmx.min.js");
|
|
3668
|
-
var ALPINE_PATH = resolvePackage("alpinejs", "dist/cdn.min.js");
|
|
3669
|
-
var htmxContent = null;
|
|
3670
|
-
var alpineContent = null;
|
|
3671
|
-
function loadAsset(path) {
|
|
3672
|
-
try {
|
|
3673
|
-
return readFileSync3(path, "utf-8");
|
|
3674
|
-
} catch {
|
|
3675
|
-
return null;
|
|
3676
|
-
}
|
|
3677
|
-
}
|
|
3678
|
-
function assetRouter() {
|
|
3664
|
+
import { resolve as resolve7, dirname } from "node:path";
|
|
3665
|
+
import { fileURLToPath } from "node:url";
|
|
3666
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3667
|
+
function wfuwAssets() {
|
|
3679
3668
|
const router = new Router();
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3669
|
+
const jsPath = resolve7(__dirname, "weifuwu-ui.js");
|
|
3670
|
+
const cssPath = resolve7(__dirname, "weifuwu-ui.css");
|
|
3671
|
+
let jsContent = null;
|
|
3672
|
+
let cssContent = null;
|
|
3673
|
+
router.get("/__wfw/js/weifuwu-ui.js", () => {
|
|
3674
|
+
if (!jsContent) {
|
|
3675
|
+
try {
|
|
3676
|
+
jsContent = readFileSync3(jsPath, "utf-8");
|
|
3677
|
+
} catch {
|
|
3678
|
+
return new Response("weifuwu-ui.js not found", { status: 404 });
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
return new Response(jsContent, {
|
|
3684
3682
|
headers: {
|
|
3685
3683
|
"content-type": "application/javascript; charset=utf-8",
|
|
3686
3684
|
"cache-control": "public, max-age=31536000, immutable"
|
|
3687
3685
|
}
|
|
3688
3686
|
});
|
|
3689
3687
|
});
|
|
3690
|
-
router.get("/__wfw/
|
|
3691
|
-
if (!
|
|
3692
|
-
|
|
3693
|
-
|
|
3688
|
+
router.get("/__wfw/css/weifuwu-ui.css", () => {
|
|
3689
|
+
if (!cssContent) {
|
|
3690
|
+
try {
|
|
3691
|
+
cssContent = readFileSync3(cssPath, "utf-8");
|
|
3692
|
+
} catch {
|
|
3693
|
+
return new Response("weifuwu-ui.css not found", { status: 404 });
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
return new Response(cssContent, {
|
|
3694
3697
|
headers: {
|
|
3695
|
-
"content-type": "
|
|
3698
|
+
"content-type": "text/css; charset=utf-8",
|
|
3696
3699
|
"cache-control": "public, max-age=31536000, immutable"
|
|
3697
3700
|
}
|
|
3698
3701
|
});
|
|
3699
3702
|
});
|
|
3700
3703
|
return router;
|
|
3701
3704
|
}
|
|
3705
|
+
|
|
3706
|
+
// ssr/assets.ts
|
|
3707
|
+
function assetRouter() {
|
|
3708
|
+
console.warn("[weifuwu] assetRouter() is deprecated. Use wfuwAssets() instead.");
|
|
3709
|
+
return wfuwAssets();
|
|
3710
|
+
}
|
|
3702
3711
|
function assetScripts() {
|
|
3712
|
+
console.warn("[weifuwu] assetScripts() is deprecated. Use weifuwu-ui.js directly.");
|
|
3703
3713
|
return raw(`
|
|
3704
|
-
<script src="/__wfw/js/
|
|
3705
|
-
<
|
|
3714
|
+
<script src="/__wfw/js/weifuwu-ui.js"></script>
|
|
3715
|
+
<link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css">
|
|
3706
3716
|
`);
|
|
3707
3717
|
}
|
|
3708
3718
|
export {
|
|
@@ -3775,5 +3785,6 @@ export {
|
|
|
3775
3785
|
upload,
|
|
3776
3786
|
validate,
|
|
3777
3787
|
view,
|
|
3788
|
+
wfuwAssets,
|
|
3778
3789
|
withTestDb
|
|
3779
3790
|
};
|
package/dist/ssr/assets.d.ts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
import { Router } from '../core/router.ts';
|
|
2
1
|
import { type RawString } from './html.ts';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* ```ts
|
|
7
|
-
* app.use('/', assetRouter())
|
|
8
|
-
* ```
|
|
9
|
-
*/
|
|
10
|
-
export declare function assetRouter(): Router;
|
|
11
|
-
/**
|
|
12
|
-
* Generate `<script>` tags for HTMX and Alpine, pointing to local paths.
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* <head>
|
|
16
|
-
* ${assetScripts()}
|
|
17
|
-
* </head>
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
2
|
+
/** @deprecated Use {@link wfuwAssets} instead. */
|
|
3
|
+
export declare function assetRouter(): import("../index.ts").Router<import("../types.ts").Context>;
|
|
4
|
+
/** @deprecated Use `<script src="/__wfw/js/weifuwu-ui.js">` instead. */
|
|
20
5
|
export declare function assetScripts(): RawString;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Router, layout, view, theme, i18n, flash, wfuwAssets } from 'weifuwu'
|
|
2
|
+
|
|
3
|
+
export const app = new Router()
|
|
4
|
+
|
|
5
|
+
// Core middleware
|
|
6
|
+
app.use(theme())
|
|
7
|
+
app.use(i18n({ dir: './locales' }))
|
|
8
|
+
app.use(flash())
|
|
9
|
+
|
|
10
|
+
// weifuwu-ui static assets
|
|
11
|
+
app.use('/', wfuwAssets())
|
|
12
|
+
|
|
13
|
+
// Layout
|
|
14
|
+
app.use(layout('./ui/app/layout.ts'))
|
|
15
|
+
|
|
16
|
+
// Pages
|
|
17
|
+
app.get('/', view('./ui/app/page.ts'))
|
|
18
|
+
|
|
19
|
+
// API route
|
|
20
|
+
app.get('/api/ping', () => Response.json({ pong: true, time: new Date().toISOString() }))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"paths": {
|
|
11
|
+
"@/*": ["./ui/*"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"include": ["*.ts", "ui/**/*.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { html, raw } from 'weifuwu'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
export default function (body: string, ctx: any) {
|
|
5
|
+
// Theme
|
|
6
|
+
const themeVal = ctx.theme?.value || 'system'
|
|
7
|
+
const resolvedTheme = themeVal === 'dark' ? 'dark' : 'light'
|
|
8
|
+
|
|
9
|
+
// i18n
|
|
10
|
+
const locale = ctx.i18n?.locale || 'en'
|
|
11
|
+
const messages = ctx.i18n?.messages || {}
|
|
12
|
+
|
|
13
|
+
return html`<!DOCTYPE html>
|
|
14
|
+
<html lang="${locale}" data-theme="${resolvedTheme}">
|
|
15
|
+
<head>
|
|
16
|
+
<meta charset="utf-8" />
|
|
17
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
18
|
+
<title>weifuwu</title>
|
|
19
|
+
<link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css" />
|
|
20
|
+
<script src="/__wfw/js/weifuwu-ui.js"></script>
|
|
21
|
+
<script id="__wfw-i18n" type="application/json">
|
|
22
|
+
${raw(JSON.stringify(messages))}
|
|
23
|
+
</script>
|
|
24
|
+
${ctx.flash?.value
|
|
25
|
+
? raw(
|
|
26
|
+
`<script id="__wfw-flash" type="application/json">${JSON.stringify(ctx.flash.value)}</script>`,
|
|
27
|
+
)
|
|
28
|
+
: ''}
|
|
29
|
+
<style>
|
|
30
|
+
body {
|
|
31
|
+
margin: 0;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
</head>
|
|
35
|
+
<body data-locale="${locale}">
|
|
36
|
+
${raw(body)}
|
|
37
|
+
</body>
|
|
38
|
+
</html>`
|
|
39
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { html } from 'weifuwu'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
export default function (ctx: any) {
|
|
5
|
+
const t = ctx.i18n?.t || ((k: string) => k)
|
|
6
|
+
const theme = ctx.theme?.value || 'system'
|
|
7
|
+
const locale = ctx.i18n?.locale || 'en'
|
|
8
|
+
|
|
9
|
+
return html`<div wu-data="{ open: false }">
|
|
10
|
+
<!-- Navbar -->
|
|
11
|
+
<nav class="wu-flex wu-items-center wu-justify-between wu-p-4 wu-border-bottom">
|
|
12
|
+
<strong class="wu-text-lg">weifuwu</strong>
|
|
13
|
+
<div class="wu-flex wu-gap-sm wu-items-center">
|
|
14
|
+
<button wu-theme="${theme === 'dark' ? 'light' : 'dark'}" class="wu-btn wu-btn-sm">
|
|
15
|
+
${theme === 'dark' ? '☀️' : '🌙'}
|
|
16
|
+
</button>
|
|
17
|
+
<button wu-lang="${locale === 'en' ? 'zh-CN' : 'en'}" class="wu-btn wu-btn-sm">
|
|
18
|
+
${locale === 'en' ? '中文' : 'EN'}
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
</nav>
|
|
22
|
+
|
|
23
|
+
<!-- Hero -->
|
|
24
|
+
<section class="wu-p-4" style="max-width: 640px; margin: 80px auto; text-align: center;">
|
|
25
|
+
<h1 class="wu-text-2xl" style="margin-bottom: 8px;">${t('title')}</h1>
|
|
26
|
+
<p class="wu-text-secondary wu-text-md" style="margin-bottom: 32px;">
|
|
27
|
+
Pure Node.js, no build step
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<div class="wu-flex wu-justify-center wu-gap-md">
|
|
31
|
+
<button class="wu-btn wu-btn-primary" wu-on="click: open = !open">${t('cta')}</button>
|
|
32
|
+
<a href="https://weifuwu.dev" class="wu-btn" target="_blank"> ${t('docs')} </a>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- Demo: toggled content -->
|
|
36
|
+
<div wu-show="open" class="wu-card" style="margin-top: 24px; text-align: left;">
|
|
37
|
+
${t('demo')}
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
</div>`
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weifuwu",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.27.
|
|
4
|
+
"version": "0.27.12",
|
|
5
5
|
"description": "Web-standard HTTP microframework for Node.js — (req, ctx) => Response",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./dist/index.js"
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"htmx.org": "^2",
|
|
36
36
|
"ioredis": "^5.11.0",
|
|
37
37
|
"postcss": "^8",
|
|
38
|
+
"postcss-nesting": "^14.0.0",
|
|
38
39
|
"postgres": "^3.4.9",
|
|
39
40
|
"tailwindcss": "^4",
|
|
40
41
|
"ws": "^8",
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
"eslint": "^10.5.0",
|
|
58
59
|
"globals": "^17.6.0",
|
|
59
60
|
"husky": "^9.1.7",
|
|
61
|
+
"jsdom": "^29.1.1",
|
|
60
62
|
"lint-staged": "^17.0.7",
|
|
61
63
|
"prettier": "^3.8.4",
|
|
62
64
|
"typescript-eslint": "^8.61.0"
|