weifuwu 0.27.10 → 0.27.11

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.
@@ -0,0 +1,23 @@
1
+ import { Router, layout, view, theme, i18n, cssContext, cssRouter, assetRouter } from 'weifuwu'
2
+
3
+ export const app = new Router()
4
+
5
+ // Middleware
6
+ app.use(theme())
7
+ app.use(i18n({ dir: './locales' }))
8
+ app.use(cssContext('./ui'))
9
+
10
+ // Layout — wraps all pages
11
+ app.use(layout('./ui/app/layout.ts'))
12
+
13
+ // Static assets (HTMX, Alpine)
14
+ app.use('/', assetRouter())
15
+
16
+ // CSS serving
17
+ app.use('/', cssRouter('./ui'))
18
+
19
+ // Pages
20
+ app.get('/', view('./ui/app/page.ts'))
21
+
22
+ // API route
23
+ app.get('/api/ping', () => Response.json({ pong: true, time: new Date().toISOString() }))
@@ -0,0 +1,6 @@
1
+ import { loadEnv, serve } from 'weifuwu'
2
+ import { app } from './app.ts'
3
+
4
+ loadEnv()
5
+ const port = Number(process.env.PORT) || 3000
6
+ serve(app.handler(), { port })
@@ -0,0 +1,6 @@
1
+ {
2
+ "title": "Build APIs & UI, Zero Build Step",
3
+ "cta": "Try Alpine",
4
+ "docs": "Documentation",
5
+ "demo": "This is Alpine.js in action — click-toggled content, zero JavaScript written."
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "title": "零编译构建 API 和 UI",
3
+ "cta": "体验 Alpine",
4
+ "docs": "文档",
5
+ "demo": "这是 Alpine.js 的演示——点击切换内容,不需要写 JavaScript。"
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "type": "module",
4
+ "scripts": {
5
+ "dev": "node --watch index.ts",
6
+ "start": "node index.ts"
7
+ },
8
+ "dependencies": {
9
+ "weifuwu": "^__VERSION__"
10
+ }
11
+ }
@@ -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,8 @@
1
+ @import "tailwindcss";
2
+ @custom-variant dark (&:is([data-theme="dark"] *));
3
+
4
+ /* Fallback for browsers without CSS Nesting support */
5
+ [data-theme="dark"] body {
6
+ background-color: var(--color-gray-950);
7
+ color: var(--color-gray-100);
8
+ }
@@ -0,0 +1,44 @@
1
+ import { html, raw, assetScripts } from 'weifuwu'
2
+
3
+ export default function(body: string, ctx: any) {
4
+ // Theme: resolve at server from cookie, override 'system' on client
5
+ const themeVal = ctx.theme?.value || 'system'
6
+ const resolvedTheme = themeVal === 'dark' ? 'dark' : 'light'
7
+
8
+ const themeScript = raw(`<script>
9
+ !function(){
10
+ var t=(document.cookie.match(/(?:^|;\s*)theme=([^;]+)/)||[])[1]||'system';
11
+ if(t==='system')t=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';
12
+ document.documentElement.setAttribute('data-theme',t);
13
+ }()
14
+ </script>`)
15
+
16
+ // i18n: set lang attribute
17
+ const lang = ctx.i18n?.locale || 'en'
18
+
19
+ // CSS: include compiled stylesheet
20
+ const cssLink = ctx.css?.url
21
+ ? raw(`<link rel="stylesheet" href="${ctx.css.url}">`)
22
+ : ''
23
+
24
+ return html`<!DOCTYPE html>
25
+ <html lang="${lang}" data-theme="${resolvedTheme}">
26
+ <head>
27
+ <meta charset="utf-8" />
28
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
29
+ ${themeScript}
30
+ <style>
31
+ /* Force dark mode when data-theme is set */
32
+ [data-theme="dark"] body {
33
+ background-color: #030712 !important;
34
+ color: #f3f4f6 !important;
35
+ }
36
+ </style>
37
+ ${assetScripts()}
38
+ ${cssLink}
39
+ </head>
40
+ <body class="min-h-screen bg-white text-gray-900 dark:bg-gray-950 dark:text-gray-100">
41
+ ${raw(body)}
42
+ </body>
43
+ </html>`
44
+ }
@@ -0,0 +1,57 @@
1
+ import { html } from 'weifuwu'
2
+
3
+ export default function(ctx: any) {
4
+ const t = ctx.i18n?.t || ((k: string) => k)
5
+ const theme = ctx.theme?.value || 'system'
6
+ const locale = ctx.i18n?.locale || 'en'
7
+
8
+ return html`<div x-data="{ open: false }" class="min-h-screen">
9
+ <!-- Navbar -->
10
+ <nav class="border-b border-gray-200 dark:border-gray-800">
11
+ <div class="max-w-5xl mx-auto flex items-center justify-between h-14 px-4">
12
+ <span class="font-bold text-lg">weifuwu</span>
13
+ <div class="flex items-center gap-3 text-sm">
14
+ <!-- Locale toggle -->
15
+ <a href="/__lang/${locale === 'en' ? 'zh-CN' : 'en'}"
16
+ class="px-2 py-1 rounded border border-gray-300 dark:border-gray-600
17
+ hover:bg-gray-100 dark:hover:bg-gray-800 transition">
18
+ ${locale === 'en' ? '中文' : 'EN'}
19
+ </a>
20
+ <!-- Theme toggle -->
21
+ <a href="/__theme/${theme === 'dark' ? 'light' : 'dark'}"
22
+ class="px-2 py-1 rounded border border-gray-300 dark:border-gray-600
23
+ hover:bg-gray-100 dark:hover:bg-gray-800 transition">
24
+ ${theme === 'dark' ? '☀️' : '🌙'}
25
+ </a>
26
+ </div>
27
+ </div>
28
+ </nav>
29
+
30
+ <!-- Hero -->
31
+ <section class="max-w-3xl mx-auto px-4 py-16 text-center">
32
+ <h1 class="text-4xl font-bold tracking-tight mb-3">${t('title')}</h1>
33
+ <p class="text-gray-500 dark:text-gray-400 text-lg mb-8">
34
+ Pure Node.js, no build step
35
+ </p>
36
+
37
+ <div class="flex justify-center gap-3">
38
+ <button @click="open = !open"
39
+ class="rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white
40
+ hover:bg-gray-700 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-300">
41
+ ${t('cta')}
42
+ </button>
43
+ <a href="/docs"
44
+ class="rounded-md border border-gray-300 px-4 py-2 text-sm font-medium
45
+ hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-800">
46
+ ${t('docs')}
47
+ </a>
48
+ </div>
49
+
50
+ <!-- Alpine demo: click to reveal -->
51
+ <div x-show="open" x-cloak
52
+ class="mt-6 p-4 bg-gray-100 dark:bg-gray-800 rounded-lg text-sm text-left">
53
+ ${t('demo')}
54
+ </div>
55
+ </section>
56
+ </div>`
57
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * cn() — Merge class names, handling conditional and array inputs.
3
+ * Lightweight alternative to clsx + tailwind-merge.
4
+ */
5
+ export function cn(...classes: (string | false | null | undefined)[]): string {
6
+ return classes.filter(Boolean).join(' ')
7
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.27.10",
4
+ "version": "0.27.11",
5
5
  "description": "Web-standard HTTP microframework for Node.js — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": "./dist/index.js"