@creativault/powerdata-cli 0.0.1

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.
Files changed (69) hide show
  1. package/dist/index.js +240 -0
  2. package/dist/index.js.map +1 -0
  3. package/package.json +55 -0
  4. package/template/nextjs_template/.dockerignore +12 -0
  5. package/template/nextjs_template/.editorconfig +15 -0
  6. package/template/nextjs_template/.env.example +43 -0
  7. package/template/nextjs_template/Dockerfile +57 -0
  8. package/template/nextjs_template/README.md +83 -0
  9. package/template/nextjs_template/_gitignore +55 -0
  10. package/template/nextjs_template/biome.json +58 -0
  11. package/template/nextjs_template/components.json +21 -0
  12. package/template/nextjs_template/eslint.config.mjs +16 -0
  13. package/template/nextjs_template/next.config.ts +31 -0
  14. package/template/nextjs_template/package.json +57 -0
  15. package/template/nextjs_template/postcss.config.mjs +8 -0
  16. package/template/nextjs_template/public/.gitkeep +0 -0
  17. package/template/nextjs_template/src/app/demo/page.tsx +258 -0
  18. package/template/nextjs_template/src/app/layout.tsx +46 -0
  19. package/template/nextjs_template/src/app/page.tsx +101 -0
  20. package/template/nextjs_template/src/components/layout/footer.tsx +11 -0
  21. package/template/nextjs_template/src/components/layout/header.tsx +25 -0
  22. package/template/nextjs_template/src/components/theme-provider.tsx +17 -0
  23. package/template/nextjs_template/src/components/theme-toggle.tsx +21 -0
  24. package/template/nextjs_template/src/components/ui/badge.tsx +35 -0
  25. package/template/nextjs_template/src/components/ui/button.tsx +56 -0
  26. package/template/nextjs_template/src/components/ui/card.tsx +82 -0
  27. package/template/nextjs_template/src/config/index.ts +1 -0
  28. package/template/nextjs_template/src/config/website.ts +9 -0
  29. package/template/nextjs_template/src/env.js +22 -0
  30. package/template/nextjs_template/src/hooks/index.ts +1 -0
  31. package/template/nextjs_template/src/lib/constants.ts +15 -0
  32. package/template/nextjs_template/src/lib/urls.ts +22 -0
  33. package/template/nextjs_template/src/lib/utils.ts +6 -0
  34. package/template/nextjs_template/src/middleware.ts +53 -0
  35. package/template/nextjs_template/src/routes.ts +47 -0
  36. package/template/nextjs_template/src/styles/globals.css +157 -0
  37. package/template/nextjs_template/src/test/setup.ts +1 -0
  38. package/template/nextjs_template/src/types/index.ts +25 -0
  39. package/template/nextjs_template/tsconfig.json +34 -0
  40. package/template/nextjs_template/vitest.config.mts +34 -0
  41. package/template/nextjs_template_monorepo/.dockerignore +11 -0
  42. package/template/nextjs_template_monorepo/.env.example +43 -0
  43. package/template/nextjs_template_monorepo/Dockerfile +65 -0
  44. package/template/nextjs_template_monorepo/README.md +55 -0
  45. package/template/nextjs_template_monorepo/components.json +21 -0
  46. package/template/nextjs_template_monorepo/eslint.config.mjs +16 -0
  47. package/template/nextjs_template_monorepo/next.config.ts +38 -0
  48. package/template/nextjs_template_monorepo/package.json +44 -0
  49. package/template/nextjs_template_monorepo/postcss.config.mjs +8 -0
  50. package/template/nextjs_template_monorepo/public/.gitkeep +0 -0
  51. package/template/nextjs_template_monorepo/src/app/demo/page.tsx +255 -0
  52. package/template/nextjs_template_monorepo/src/app/layout.tsx +46 -0
  53. package/template/nextjs_template_monorepo/src/app/page.tsx +102 -0
  54. package/template/nextjs_template_monorepo/src/components/layout/footer.tsx +11 -0
  55. package/template/nextjs_template_monorepo/src/components/layout/header.tsx +25 -0
  56. package/template/nextjs_template_monorepo/src/components/theme-provider.tsx +17 -0
  57. package/template/nextjs_template_monorepo/src/components/theme-toggle.tsx +21 -0
  58. package/template/nextjs_template_monorepo/src/config/index.ts +1 -0
  59. package/template/nextjs_template_monorepo/src/config/website.ts +13 -0
  60. package/template/nextjs_template_monorepo/src/env.js +22 -0
  61. package/template/nextjs_template_monorepo/src/hooks/index.ts +6 -0
  62. package/template/nextjs_template_monorepo/src/lib/utils.ts +2 -0
  63. package/template/nextjs_template_monorepo/src/middleware.ts +53 -0
  64. package/template/nextjs_template_monorepo/src/routes.ts +47 -0
  65. package/template/nextjs_template_monorepo/src/styles/globals.css +157 -0
  66. package/template/nextjs_template_monorepo/src/test/setup.ts +1 -0
  67. package/template/nextjs_template_monorepo/src/types/index.ts +30 -0
  68. package/template/nextjs_template_monorepo/tsconfig.json +34 -0
  69. package/template/nextjs_template_monorepo/vitest.config.mts +34 -0
@@ -0,0 +1,25 @@
1
+ import { ThemeToggle } from '@/components/theme-toggle';
2
+ import Link from 'next/link';
3
+
4
+ export function Header() {
5
+ return (
6
+ <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
7
+ <div className="container flex h-14 max-w-screen-2xl items-center px-4 md:px-8">
8
+ <Link href="/" className="mr-6 flex items-center space-x-2">
9
+ <span className="text-lg font-bold">MyApp</span>
10
+ </Link>
11
+ <nav className="flex flex-1 items-center space-x-6 text-sm font-medium">
12
+ <Link
13
+ href="/demo"
14
+ className="transition-colors hover:text-foreground/80 text-foreground/60"
15
+ >
16
+ Demo
17
+ </Link>
18
+ </nav>
19
+ <div className="flex items-center space-x-2">
20
+ <ThemeToggle />
21
+ </div>
22
+ </div>
23
+ </header>
24
+ );
25
+ }
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+
3
+ import { ThemeProvider as NextThemesProvider } from 'next-themes';
4
+ import type { ReactNode } from 'react';
5
+
6
+ export function ThemeProvider({ children }: { children: ReactNode }) {
7
+ return (
8
+ <NextThemesProvider
9
+ attribute="class"
10
+ defaultTheme="system"
11
+ enableSystem
12
+ disableTransitionOnChange
13
+ >
14
+ {children}
15
+ </NextThemesProvider>
16
+ );
17
+ }
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+
3
+ import { Button } from '@repo/ui';
4
+ import { Moon, Sun } from 'lucide-react';
5
+ import { useTheme } from 'next-themes';
6
+
7
+ export function ThemeToggle() {
8
+ const { theme, setTheme } = useTheme();
9
+
10
+ return (
11
+ <Button
12
+ variant="ghost"
13
+ size="icon"
14
+ onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
15
+ aria-label="Toggle theme"
16
+ >
17
+ <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
18
+ <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
19
+ </Button>
20
+ );
21
+ }
@@ -0,0 +1 @@
1
+ export { siteConfig } from './website';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 网站全局配置
3
+ */
4
+ export const siteConfig = {
5
+ name: 'MyApp',
6
+ description: 'A modern Next.js application',
7
+ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
8
+ ogImage: '/og.png',
9
+ links: {
10
+ github: '',
11
+ docs: '',
12
+ },
13
+ } as const;
@@ -0,0 +1,22 @@
1
+ import { createEnv } from '@t3-oss/env-nextjs';
2
+ import { z } from 'zod';
3
+
4
+ export const env = createEnv({
5
+ server: {
6
+ NODE_ENV: z.enum(['development', 'test', 'production']),
7
+ DATABASE_URL: z.string().optional(),
8
+ // 后端服务 URL
9
+ API_URL: z.string().optional(),
10
+ },
11
+ client: {
12
+ NEXT_PUBLIC_APP_URL: z.string().optional(),
13
+ },
14
+ runtimeEnv: {
15
+ NODE_ENV: process.env.NODE_ENV,
16
+ DATABASE_URL: process.env.DATABASE_URL,
17
+ API_URL: process.env.API_URL,
18
+ NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
19
+ },
20
+ skipValidation: !!process.env.SKIP_ENV_VALIDATION,
21
+ emptyStringAsUndefined: true,
22
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 自定义 Hooks
3
+ *
4
+ * 在此文件中导出所有自定义 hooks
5
+ * 示例: export { useDebounce } from './use-debounce';
6
+ */
@@ -0,0 +1,2 @@
1
+ // Re-export from shared utils package
2
+ export { cn } from '@repo/utils';
@@ -0,0 +1,53 @@
1
+ import { type NextRequest, NextResponse } from 'next/server';
2
+ import {
3
+ DEFAULT_LOGIN_REDIRECT,
4
+ protectedRoutePrefixes,
5
+ protectedRoutes,
6
+ routesNotAllowedByLoggedInUsers,
7
+ } from './routes';
8
+
9
+ /**
10
+ * Next.js Middleware
11
+ * https://nextjs.org/docs/app/building-your-application/routing/middleware
12
+ *
13
+ * 处理路由保护、认证重定向等逻辑
14
+ * 注意:middleware 中避免进行 API 或数据库调用,仅检查 cookie 存在性
15
+ */
16
+ export default async function middleware(req: NextRequest) {
17
+ const { nextUrl } = req;
18
+ const pathname = nextUrl.pathname;
19
+
20
+ // TODO: 替换为实际的 session 检查逻辑
21
+ // 示例:检查 session cookie 是否存在
22
+ const sessionCookie = req.cookies.get('session_token');
23
+ const isLoggedIn = !!sessionCookie;
24
+
25
+ // 检查是否为受保护路由
26
+ const isProtectedRoute =
27
+ protectedRoutes.some((route) => pathname === route) ||
28
+ protectedRoutePrefixes.some((prefix) => pathname.startsWith(prefix));
29
+
30
+ // 未登录用户访问受保护路由 → 重定向到登录页
31
+ if (isProtectedRoute && !isLoggedIn) {
32
+ const loginUrl = new URL('/auth/login', nextUrl);
33
+ loginUrl.searchParams.set('callbackUrl', pathname);
34
+ return NextResponse.redirect(loginUrl);
35
+ }
36
+
37
+ // 已登录用户访问登录/注册页 → 重定向到 Dashboard
38
+ const isAuthRoute = routesNotAllowedByLoggedInUsers.some(
39
+ (route) => pathname === route
40
+ );
41
+ if (isAuthRoute && isLoggedIn) {
42
+ return NextResponse.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl));
43
+ }
44
+
45
+ return NextResponse.next();
46
+ }
47
+
48
+ export const config = {
49
+ matcher: [
50
+ // 匹配所有路由,排除静态资源和 API
51
+ '/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
52
+ ],
53
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 应用路由配置
3
+ */
4
+ export enum Routes {
5
+ Root = '/',
6
+
7
+ // 营销页面
8
+ Features = '/features',
9
+ Pricing = '/pricing',
10
+ Blog = '/blog',
11
+ About = '/about',
12
+ Contact = '/contact',
13
+ PrivacyPolicy = '/privacy',
14
+ TermsOfService = '/terms',
15
+
16
+ // 认证路由
17
+ Login = '/auth/login',
18
+ Register = '/auth/register',
19
+ ForgotPassword = '/auth/forgot-password',
20
+
21
+ // 业务路由
22
+ Dashboard = '/dashboard',
23
+ Settings = '/settings',
24
+ }
25
+
26
+ /**
27
+ * 需要登录才能访问的路由
28
+ */
29
+ export const protectedRoutes: string[] = [Routes.Dashboard, Routes.Settings];
30
+
31
+ /**
32
+ * 需要登录才能访问的路由前缀
33
+ */
34
+ export const protectedRoutePrefixes: string[] = ['/dashboard', '/settings'];
35
+
36
+ /**
37
+ * 登录后默认跳转路由
38
+ */
39
+ export const DEFAULT_LOGIN_REDIRECT = Routes.Dashboard;
40
+
41
+ /**
42
+ * 已登录用户不允许访问的路由
43
+ */
44
+ export const routesNotAllowedByLoggedInUsers: string[] = [
45
+ Routes.Login,
46
+ Routes.Register,
47
+ ];
@@ -0,0 +1,157 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @plugin '@tailwindcss/typography';
4
+
5
+ @custom-variant dark (&:is(.dark *));
6
+
7
+ @theme inline {
8
+ --color-background: var(--background);
9
+ --color-foreground: var(--foreground);
10
+ --color-card: var(--card);
11
+ --color-card-foreground: var(--card-foreground);
12
+ --color-popover: var(--popover);
13
+ --color-popover-foreground: var(--popover-foreground);
14
+ --color-primary: var(--primary);
15
+ --color-primary-foreground: var(--primary-foreground);
16
+ --color-secondary: var(--secondary);
17
+ --color-secondary-foreground: var(--secondary-foreground);
18
+ --color-muted: var(--muted);
19
+ --color-muted-foreground: var(--muted-foreground);
20
+ --color-accent: var(--accent);
21
+ --color-accent-foreground: var(--accent-foreground);
22
+ --color-destructive: var(--destructive);
23
+ --color-destructive-foreground: var(--destructive-foreground);
24
+ --color-border: var(--border);
25
+ --color-input: var(--input);
26
+ --color-ring: var(--ring);
27
+ --color-chart-1: var(--chart-1);
28
+ --color-chart-2: var(--chart-2);
29
+ --color-chart-3: var(--chart-3);
30
+ --color-chart-4: var(--chart-4);
31
+ --color-chart-5: var(--chart-5);
32
+ --color-sidebar: var(--sidebar);
33
+ --color-sidebar-foreground: var(--sidebar-foreground);
34
+ --color-sidebar-primary: var(--sidebar-primary);
35
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
36
+ --color-sidebar-accent: var(--sidebar-accent);
37
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
38
+ --color-sidebar-border: var(--sidebar-border);
39
+ --color-sidebar-ring: var(--sidebar-ring);
40
+
41
+ --radius-sm: calc(var(--radius) - 4px);
42
+ --radius-md: calc(var(--radius) - 2px);
43
+ --radius-lg: var(--radius);
44
+ --radius-xl: calc(var(--radius) + 4px);
45
+
46
+ --animate-accordion-down: accordion-down 0.2s ease-out;
47
+ --animate-accordion-up: accordion-up 0.2s ease-out;
48
+
49
+ @keyframes accordion-down {
50
+ from {
51
+ height: 0;
52
+ }
53
+ to {
54
+ height: var(--radix-accordion-content-height);
55
+ }
56
+ }
57
+
58
+ @keyframes accordion-up {
59
+ from {
60
+ height: var(--radix-accordion-content-height);
61
+ }
62
+ to {
63
+ height: 0;
64
+ }
65
+ }
66
+ }
67
+
68
+ :root {
69
+ --background: oklch(1.0 0 0);
70
+ --foreground: oklch(0.1448 0 0);
71
+ --card: oklch(1.0 0 0);
72
+ --card-foreground: oklch(0.1448 0 0);
73
+ --popover: oklch(1.0 0 0);
74
+ --popover-foreground: oklch(0.1448 0 0);
75
+ --primary: oklch(0.623 0.214 259.815);
76
+ --primary-foreground: oklch(0.9851 0 0);
77
+ --secondary: oklch(0.9702 0 0);
78
+ --secondary-foreground: oklch(0.2046 0 0);
79
+ --muted: oklch(0.9702 0 0);
80
+ --muted-foreground: oklch(0.5555 0 0);
81
+ --accent: oklch(0.9702 0 0);
82
+ --accent-foreground: oklch(0.2046 0 0);
83
+ --destructive: oklch(0.6368 0.2078 25.3313);
84
+ --destructive-foreground: oklch(0.9851 0 0);
85
+ --border: oklch(0.9219 0 0);
86
+ --input: oklch(0.9219 0 0);
87
+ --ring: oklch(0.1448 0 0);
88
+ --chart-1: oklch(0.6231 0.188 259.8145);
89
+ --chart-2: oklch(0.6056 0.2189 292.7172);
90
+ --chart-3: oklch(0.7686 0.1647 70.0804);
91
+ --chart-4: oklch(0.6959 0.1491 162.4796);
92
+ --chart-5: oklch(0.551 0.0234 264.3637);
93
+ --sidebar: oklch(1.0 0 0);
94
+ --sidebar-foreground: oklch(0.446 0.03 256.802);
95
+ --sidebar-primary: oklch(0.325 0 0);
96
+ --sidebar-primary-foreground: oklch(0.9881 0 0);
97
+ --sidebar-accent: oklch(0.9761 0 0);
98
+ --sidebar-accent-foreground: oklch(0.325 0 0);
99
+ --sidebar-border: oklch(0.9401 0 0);
100
+ --sidebar-ring: oklch(0.7731 0 0);
101
+ --radius: 0.5rem;
102
+ --spacing: 0.25rem;
103
+ }
104
+
105
+ .dark {
106
+ --background: oklch(0.1448 0 0);
107
+ --foreground: oklch(0.9851 0 0);
108
+ --card: oklch(0.1448 0 0);
109
+ --card-foreground: oklch(0.9851 0 0);
110
+ --popover: oklch(0.1448 0 0);
111
+ --popover-foreground: oklch(0.9851 0 0);
112
+ --primary: oklch(0.9851 0 0);
113
+ --primary-foreground: oklch(0.2046 0 0);
114
+ --secondary: oklch(0.2686 0 0);
115
+ --secondary-foreground: oklch(0.9851 0 0);
116
+ --muted: oklch(0.2686 0 0);
117
+ --muted-foreground: oklch(0.7155 0 0);
118
+ --accent: oklch(0.2686 0 0);
119
+ --accent-foreground: oklch(0.9851 0 0);
120
+ --destructive: oklch(0.3958 0.1331 25.723);
121
+ --destructive-foreground: oklch(0.9851 0 0);
122
+ --border: oklch(0.2686 0 0);
123
+ --input: oklch(0.2686 0 0);
124
+ --ring: oklch(0.8699 0 0);
125
+ --chart-1: oklch(0.5298 0.1932 262.0493);
126
+ --chart-2: oklch(0.6994 0.1339 165.4606);
127
+ --chart-3: oklch(0.7227 0.1502 60.5799);
128
+ --chart-4: oklch(0.6193 0.2029 312.7422);
129
+ --chart-5: oklch(0.6118 0.2093 6.1387);
130
+ --sidebar: oklch(0.2103 0.0059 285.8852);
131
+ --sidebar-foreground: oklch(0.9674 0.0013 286.3752);
132
+ --sidebar-primary: oklch(0.4882 0.2172 264.3763);
133
+ --sidebar-primary-foreground: oklch(1.0 0 0);
134
+ --sidebar-accent: oklch(0.2739 0.0055 286.0326);
135
+ --sidebar-accent-foreground: oklch(0.9674 0.0013 286.3752);
136
+ --sidebar-border: oklch(0.2739 0.0055 286.0326);
137
+ --sidebar-ring: oklch(0.8711 0.0055 286.286);
138
+ }
139
+
140
+ @layer base {
141
+ *,
142
+ ::after,
143
+ ::before,
144
+ ::backdrop,
145
+ ::file-selector-button {
146
+ border-color: var(--color-gray-200, currentColor);
147
+ }
148
+
149
+ * {
150
+ @apply border-border outline-ring/50;
151
+ }
152
+
153
+ body {
154
+ @apply bg-background text-foreground overscroll-none;
155
+ font-feature-settings: "rlig" 1, "calt" 1;
156
+ }
157
+ }
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 通用 API 响应类型
3
+ */
4
+ export interface ApiResponse<T = unknown> {
5
+ success: boolean;
6
+ data?: T;
7
+ error?: string;
8
+ message?: string;
9
+ }
10
+
11
+ /**
12
+ * 分页响应类型
13
+ */
14
+ export interface PaginatedResponse<T> {
15
+ items: T[];
16
+ total: number;
17
+ page: number;
18
+ pageSize: number;
19
+ totalPages: number;
20
+ }
21
+
22
+ /**
23
+ * 分页请求参数
24
+ */
25
+ export interface PaginationParams {
26
+ page?: number;
27
+ pageSize?: number;
28
+ sortBy?: string;
29
+ sortOrder?: 'asc' | 'desc';
30
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"],
23
+ "@/public/*": ["./public/*"]
24
+ }
25
+ },
26
+ "include": [
27
+ "next-env.d.ts",
28
+ "**/*.ts",
29
+ "**/*.tsx",
30
+ ".next/types/**/*.ts",
31
+ ".next/dev/types/**/*.ts"
32
+ ],
33
+ "exclude": ["node_modules", "vitest.config.mts"]
34
+ }
@@ -0,0 +1,34 @@
1
+ import path from 'path';
2
+ import react from '@vitejs/plugin-react';
3
+ import { defineConfig } from 'vitest/config';
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ test: {
8
+ environment: 'happy-dom',
9
+ globals: true,
10
+ setupFiles: ['./src/test/setup.ts'],
11
+ include: ['src/**/*.{test,spec}.{ts,tsx}'],
12
+ exclude: ['node_modules', '.next', 'dist'],
13
+ coverage: {
14
+ provider: 'v8',
15
+ reporter: ['text', 'json', 'html'],
16
+ reportsDirectory: './coverage',
17
+ exclude: [
18
+ 'node_modules/',
19
+ 'src/test/',
20
+ '**/*.d.ts',
21
+ '**/*.config.*',
22
+ '**/types/**',
23
+ ],
24
+ },
25
+ passWithNoTests: true,
26
+ testTimeout: 10000,
27
+ hookTimeout: 10000,
28
+ },
29
+ resolve: {
30
+ alias: {
31
+ '@': path.resolve(__dirname, './src'),
32
+ },
33
+ },
34
+ });