create-wenuts-cli 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.
Files changed (51) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +168 -0
  3. package/package.json +35 -0
  4. package/template/default/.env.development +19 -0
  5. package/template/default/README.md +36 -0
  6. package/template/default/envConfig/.env.development +26 -0
  7. package/template/default/envConfig/.env.production +23 -0
  8. package/template/default/eslint.config.mjs +15 -0
  9. package/template/default/next.config.ts +10 -0
  10. package/template/default/package.json +40 -0
  11. package/template/default/postcss.config.mjs +17 -0
  12. package/template/default/public/file.svg +1 -0
  13. package/template/default/public/globe.svg +1 -0
  14. package/template/default/public/next.svg +1 -0
  15. package/template/default/public/vercel.svg +1 -0
  16. package/template/default/public/window.svg +1 -0
  17. package/template/default/src/api/user.ts +149 -0
  18. package/template/default/src/app/[local]/(default-layout)/layout.tsx +5 -0
  19. package/template/default/src/app/[local]/(default-layout)/page.tsx +5 -0
  20. package/template/default/src/app/[local]/(no-layout)/home/page.tsx +16 -0
  21. package/template/default/src/app/[local]/(no-layout)/login/components/LoginHandle/index.tsx +55 -0
  22. package/template/default/src/app/[local]/(no-layout)/login/page.tsx +41 -0
  23. package/template/default/src/app/[local]/(no-layout)/login/style.module.css +4 -0
  24. package/template/default/src/app/[local]/layout.tsx +54 -0
  25. package/template/default/src/app/api/auth/[...nextauth]/route.ts +54 -0
  26. package/template/default/src/app/favicon.ico +0 -0
  27. package/template/default/src/app/globals.css +27 -0
  28. package/template/default/src/app/layout.tsx +26 -0
  29. package/template/default/src/appConfig.ts +37 -0
  30. package/template/default/src/components/System/ClientLayout/index.tsx +69 -0
  31. package/template/default/src/components/System/LoginModal/index.tsx +61 -0
  32. package/template/default/src/components/System/ThemeProvider/index.tsx +55 -0
  33. package/template/default/src/config/CookieMap.ts +3 -0
  34. package/template/default/src/config/LocalStorageMap.ts +11 -0
  35. package/template/default/src/i18n/request.ts +17 -0
  36. package/template/default/src/i18n/routing.ts +15 -0
  37. package/template/default/src/lang/en.json +6 -0
  38. package/template/default/src/libs/casdoor_provider.ts +39 -0
  39. package/template/default/src/libs/dataAnalytics.ts +176 -0
  40. package/template/default/src/libs/fetch.ts +176 -0
  41. package/template/default/src/libs/fetchCookie/clientCookies.ts +5 -0
  42. package/template/default/src/libs/fetchCookie/getCookie.ts +15 -0
  43. package/template/default/src/libs/fetchCookie/serverCookies.ts +10 -0
  44. package/template/default/src/libs/localCache.ts +28 -0
  45. package/template/default/src/libs/nextauth.ts +49 -0
  46. package/template/default/src/libs/seo.ts +89 -0
  47. package/template/default/src/middleware.ts +11 -0
  48. package/template/default/src/store/useUserStore.ts +42 -0
  49. package/template/default/src/types/payment.ts +163 -0
  50. package/template/default/src/types/user.ts +137 -0
  51. package/template/default/tsconfig.json +27 -0
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ import LoginHandle from "./components/LoginHandle";
3
+ import { ScrollArea } from "@mantine/core";
4
+ import { cookies } from "next/headers";
5
+ import CookieMap from "@/config/CookieMap";
6
+
7
+ import style from "./style.module.css";
8
+
9
+ interface IProps {
10
+ searchParams: { redirect: string };
11
+ }
12
+
13
+ const LoginPage: React.FC<IProps> = async ({ searchParams }) => {
14
+ const cookieStore = await cookies();
15
+
16
+ const userState = cookieStore.get(CookieMap.UserState);
17
+
18
+ let isLogin = false;
19
+
20
+ if (userState) {
21
+ isLogin = true;
22
+ }
23
+
24
+ return (
25
+ <ScrollArea
26
+ className="h-screen w-screen"
27
+ type="never"
28
+ classNames={{
29
+ viewport: `${style.custom_scroll}`,
30
+ }}
31
+ >
32
+ <div className="w-full h-full p-3 md:p-6 bg-white">
33
+ <div className="flex md:h-full md:grid gap-6 md:gap-12 items-center flex-col-reverse">
34
+ <LoginHandle isLogin={isLogin} />
35
+ </div>
36
+ </div>
37
+ </ScrollArea>
38
+ );
39
+ };
40
+
41
+ export default LoginPage;
@@ -0,0 +1,4 @@
1
+ .custom_scroll>div:first-child {
2
+ height: 100%;
3
+ position: relative;
4
+ }
@@ -0,0 +1,54 @@
1
+ import UserApi from "@/api/user";
2
+ import CookieMap from "@/config/CookieMap";
3
+ import { IUserProfile } from "@/types/user";
4
+ import { NextIntlClientProvider } from "next-intl";
5
+ import { getMessages } from "next-intl/server";
6
+ import { pathname } from "next-extra/pathname";
7
+ import { cookies } from "next/headers";
8
+ import React from "react";
9
+ import ClientLayout from "@/components/System/ClientLayout";
10
+ import { initLangTags } from "@/libs/seo";
11
+ import appConfig from "@/appConfig";
12
+
13
+ interface IProps {
14
+ children: React.ReactNode;
15
+ params: Promise<{ locale: string }>;
16
+ }
17
+
18
+ const LocaleLayout: React.FC<IProps> = async ({ children }) => {
19
+ const messages = await getMessages();
20
+ let profile: null | IUserProfile = null;
21
+ const cookieStore = await cookies();
22
+
23
+ const userState = cookieStore.get(CookieMap.UserState);
24
+
25
+ if (userState) {
26
+ const res = await UserApi.userProfile();
27
+
28
+ if (res.code === 0 && res.data) {
29
+ profile = res.data;
30
+ } else {
31
+ console.warn("login-error:111", res.info);
32
+ }
33
+ }
34
+
35
+ return (
36
+ <NextIntlClientProvider messages={messages}>
37
+ <ClientLayout profile={profile}>{children}</ClientLayout>
38
+ </NextIntlClientProvider>
39
+ );
40
+ };
41
+
42
+ export default LocaleLayout;
43
+
44
+ export const generateMetadata: (props: IProps) => void = async () => {
45
+ const path = await pathname(); // url 地址
46
+ const lang = path.split("/")[1];
47
+ let seoPath = path;
48
+ let seoLang = "";
49
+ if (appConfig.locales.includes(lang)) {
50
+ seoPath = path.replace(`/${lang}`, "") || "/";
51
+ seoLang = lang;
52
+ }
53
+ return initLangTags(seoPath, seoLang);
54
+ };
@@ -0,0 +1,54 @@
1
+ import NextAuth from "next-auth";
2
+ import { authOptions } from "@/libs/nextauth";
3
+ import { NextRequest, NextResponse } from "next/server";
4
+ import { cookies } from "next/headers";
5
+ import UserApi from "@/api/user";
6
+ import CookieMap from "@/config/CookieMap";
7
+ const handler = NextAuth(authOptions);
8
+
9
+ // 自定义 GET 处理程序
10
+ export async function GET(request: any, response: any) {
11
+ const cookieStore = await cookies();
12
+ const baseurl = process.env.NEXT_PUBLIC_DOMAIN;
13
+ const pathname = request.nextUrl.pathname;
14
+ const searchParams = request.nextUrl.searchParams;
15
+ const backurl = cookieStore.get("login_back_url")?.value || "/";
16
+
17
+ // 如果路径包含callback/casdoor 说明是casdoor登录 且有code参数
18
+ if (pathname.includes("/callback/casdoor") && searchParams.has("code")) {
19
+ try {
20
+ const { searchParams } = new URL(request.url);
21
+ const code = searchParams.get("code");
22
+ if (code) {
23
+ const res = await UserApi.userLogin({
24
+ code,
25
+ srcType: "casdoor",
26
+ });
27
+
28
+ if (res.code === 0 && res.data) {
29
+ cookieStore.set(
30
+ CookieMap.UserState,
31
+ encodeURIComponent(JSON.stringify(res.data))
32
+ );
33
+ return NextResponse.redirect(new URL("/login", baseurl));
34
+ } else {
35
+ console.warn("res.info", res.info);
36
+ return NextResponse.redirect(new URL(backurl, baseurl));
37
+ }
38
+ } else {
39
+ console.warn("没有 code, 直接返回首页");
40
+ return NextResponse.redirect(new URL(backurl, baseurl));
41
+ }
42
+ } catch (error) {
43
+ console.warn("error", error);
44
+ return NextResponse.redirect(new URL(backurl, baseurl));
45
+ }
46
+ }
47
+
48
+ // 其他登录方式使用默认的 NextAuth 处理
49
+ const authHandler = await NextAuth(authOptions);
50
+ return authHandler(request, response);
51
+ }
52
+
53
+ // POST 请求使用默认处理
54
+ export { handler as POST };
@@ -0,0 +1,27 @@
1
+ @import "tailwindcss";
2
+
3
+
4
+ :root {
5
+ --background: #ffffff;
6
+ --foreground: #171717;
7
+ }
8
+
9
+ @theme inline {
10
+ --color-background: var(--background);
11
+ --color-foreground: var(--foreground);
12
+ --font-sans: var(--font-geist-sans);
13
+ --font-mono: var(--font-geist-mono);
14
+ }
15
+
16
+ @media (prefers-color-scheme: dark) {
17
+ :root {
18
+ --background: #0a0a0a;
19
+ --foreground: #ededed;
20
+ }
21
+ }
22
+
23
+ body {
24
+ background: var(--background);
25
+ color: var(--foreground);
26
+ font-family: Arial, Helvetica, sans-serif;
27
+ }
@@ -0,0 +1,26 @@
1
+ import type { Metadata } from "next";
2
+ import "./globals.css";
3
+ import "@mantine/core/styles.css";
4
+ import { Toaster } from "sonner";
5
+ import ThemeProvider from "@/components/System/ThemeProvider";
6
+
7
+ export const metadata: Metadata = {
8
+ title: "Create Next App",
9
+ description: "Generated by create next app",
10
+ };
11
+
12
+ export default function RootLayout({
13
+ children,
14
+ }: Readonly<{
15
+ children: React.ReactNode;
16
+ }>) {
17
+ return (
18
+ <html lang="en">
19
+ <body>
20
+ <Toaster position="top-center" richColors />
21
+
22
+ <ThemeProvider>{children}</ThemeProvider>
23
+ </body>
24
+ </html>
25
+ );
26
+ }
@@ -0,0 +1,37 @@
1
+ export const mediaMap = {
2
+ ph: 450,
3
+ sm: 576,
4
+ md: 768,
5
+ xg: 896,
6
+ lg: 1024,
7
+ xl: 1280,
8
+ xl2: 1536,
9
+ xl3: 1792,
10
+ xl4: 2048,
11
+ xl5: 2304,
12
+ xl6: 2560,
13
+ xl7: 2816,
14
+ xl8: 3072,
15
+ };
16
+
17
+ interface IConfig {
18
+ appName: string;
19
+ baseDomain: string;
20
+ ossDomain: string;
21
+ locales: string[];
22
+ defaultLocale: string;
23
+ colorScheme: 'light' | 'dark';
24
+ subjectColor: string;
25
+ }
26
+
27
+ const appConfig: IConfig = {
28
+ appName: 'Aitubo',
29
+ baseDomain: process.env.NEXT_PUBLIC_DOMAIN!,
30
+ ossDomain: process.env.NEXT_PUBLIC_OSS_DOMAIN!,
31
+ locales: ['en'],
32
+ defaultLocale: 'en',
33
+ colorScheme: 'dark',
34
+ subjectColor: '#693EE4',
35
+ };
36
+
37
+ export default appConfig;
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import React, { useEffect } from "react";
3
+ import Cookies from "js-cookie";
4
+ import { SessionProvider } from "next-auth/react";
5
+ // import { usePathname } from "@/i18n/routing";
6
+ import CookieMap from "@/config/CookieMap";
7
+ // import { dataInit, dataPush } from "@/libs/dataAnalytics";
8
+ import useUserStore from "@/store/useUserStore";
9
+ import { IUserProfile } from "@/types/user";
10
+ import LoginModal from "../LoginModal";
11
+
12
+ // import InitGoogleOneTap from "../InitGoogleOneTap";
13
+ // import LoginModal from "../LoginModal";
14
+ // import PaymentModal from "@/components/Modals/PaymentModal";
15
+ // import UpdateModal from "@/components/Modals/UpdateModal";
16
+
17
+ interface IProps {
18
+ children: React.ReactNode;
19
+ profile: null | IUserProfile;
20
+ }
21
+
22
+ const ClientLayout: React.FC<IProps> = ({ children, profile }) => {
23
+ // const pathname = usePathname();
24
+
25
+ useEffect(() => {
26
+ // dataInit({ profile }); // 初始化数据上报相关信息
27
+
28
+ // 初始化用户相关信息
29
+ useUserStore.setState({
30
+ userInfo: profile,
31
+ });
32
+
33
+ console.log(profile, "profile???");
34
+
35
+ // 如果没有用户信息,还存在用户登录的缓存就清除用户状态
36
+ if (!profile) {
37
+ const userState = Cookies.get(CookieMap.UserState);
38
+
39
+ if (userState) {
40
+ Cookies.remove(CookieMap.UserState);
41
+ }
42
+ }
43
+ }, []);
44
+
45
+ // useEffect(() => {
46
+ // dataPush("page_show", { url: location.href });
47
+ // }, [pathname]);
48
+
49
+ return (
50
+ <SessionProvider>
51
+ {children}
52
+
53
+ {/* 初始化 google one tap 登录 ---登录页面不展示 */}
54
+ {/* {process.env.NEXT_PUBLIC_NODE_ENV !== "dev" &&
55
+ !pathname.includes("/login") && <InitGoogleOneTap />} */}
56
+
57
+ {/* 登录弹框 */}
58
+ <LoginModal />
59
+
60
+ {/* 订阅、加油包弹框 */}
61
+ {/* <PaymentModal /> */}
62
+
63
+ {/* 更新弹窗 */}
64
+ {/* {useUserStore.getState().isShowUpdateModal && <UpdateModal />} */}
65
+ </SessionProvider>
66
+ );
67
+ };
68
+
69
+ export default ClientLayout;
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import UserApi from "@/api/user";
3
+ import useUserStore from "@/store/useUserStore";
4
+ import { Button, Modal } from "@mantine/core";
5
+ import { useDisclosure } from "@mantine/hooks";
6
+ import { signIn } from "next-auth/react";
7
+ import { useEffect } from "react";
8
+
9
+ const LoginModal = () => {
10
+ const setOpenLoginModal = useUserStore((state) => state.setOpenLoginModal);
11
+
12
+ const userInfo = useUserStore((state) => state.userInfo);
13
+
14
+ const [loginModalOpened, { open: loginModalOpen, close: loginModalClose }] =
15
+ useDisclosure(false);
16
+
17
+ const handleLogin = () => {
18
+ const width = 500;
19
+ const height = 600;
20
+ const left = window.screenX + (window.outerWidth - width) / 2;
21
+ const top = window.screenY + (window.outerHeight - height) / 2;
22
+ window.open(
23
+ `${process.env.NEXT_PUBLIC_DOMAIN}/login`,
24
+ "ThirdPartyLogin",
25
+ `width=${width},height=${height},left=${left},top=${top}`
26
+ );
27
+ };
28
+
29
+ useEffect(() => {
30
+ const handleMessage = async (event: MessageEvent) => {
31
+ const { data } = event;
32
+ if (data === "login_success") {
33
+ loginModalClose();
34
+ // 需要在主窗口再次请求一次个人详情信息
35
+ const res = await UserApi.userProfile();
36
+ if (res.code === 0 && res.data) {
37
+ useUserStore.setState({
38
+ userInfo: res.data,
39
+ });
40
+ }
41
+ }
42
+ };
43
+ window.addEventListener("message", handleMessage);
44
+
45
+ return () => {
46
+ window.removeEventListener("message", handleMessage);
47
+ };
48
+ }, []);
49
+
50
+ useEffect(() => {
51
+ setOpenLoginModal(loginModalOpen);
52
+ }, [loginModalOpened]);
53
+
54
+ return (
55
+ <Modal opened={loginModalOpened} onClose={loginModalClose}>
56
+ <Button onClick={handleLogin}>Login</Button>
57
+ </Modal>
58
+ );
59
+ };
60
+
61
+ export default LoginModal;
@@ -0,0 +1,55 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { createTheme, MantineProvider } from "@mantine/core";
4
+ import appConfig from "@/appConfig";
5
+
6
+ interface Props {
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ const theme = createTheme({
11
+ colors: {
12
+ primaryColors: [
13
+ "#f7f0ff",
14
+ "#e0c9ff",
15
+ "#c5a1ff",
16
+ "#a778ff",
17
+ "#8850ff",
18
+ "#6638d9",
19
+ "#4925b3",
20
+ "#30168c",
21
+ "#1f0f66",
22
+ "#1C0C63",
23
+ ],
24
+ },
25
+ primaryColor: "primaryColors",
26
+ primaryShade: 4, // 默认使用第5个颜色
27
+ defaultRadius: "sm",
28
+ cursorType: "pointer",
29
+ autoContrast: true,
30
+ luminanceThreshold: 0.5,
31
+ defaultGradient: {
32
+ from: "#D77E80",
33
+ to: "#693EE4",
34
+ deg: 142,
35
+ },
36
+ breakpoints: {
37
+ sm: "30em",
38
+ md: "48em",
39
+ lg: "64em",
40
+ xl: "90em",
41
+ xl2: "120em",
42
+ xl3: "160em",
43
+ xl4: "240em",
44
+ },
45
+ });
46
+
47
+ const ThemeProvider: React.FC<Props> = ({ children }) => {
48
+ return (
49
+ <MantineProvider defaultColorScheme={appConfig.colorScheme} theme={theme}>
50
+ {children}
51
+ </MantineProvider>
52
+ );
53
+ };
54
+
55
+ export default ThemeProvider;
@@ -0,0 +1,3 @@
1
+ export default {
2
+ UserState: "next_source_state",
3
+ };
@@ -0,0 +1,11 @@
1
+ export default {
2
+ UnreportedList: 'unreported_list', // 未上报的数据列表
3
+ PushedDataList: 'pushed_list', // 上报过的支付订单
4
+ ThinkingDataJSSDK_cross: 'ThinkingDataJSSDK_cross', // 数数会默认存储
5
+ ISFIRSTGENERATE: 'isFirstGenerate', // 是否是第一次制作 null就是第一次制作
6
+ UpdateInfoReadIdList: 'update_info_read_id_list', // 更新信息已读列表id
7
+ SELECTEDLORAS: 'selectedLoras', // 选择的Lora模型
8
+ everShowNewVersionModal: 'everShowNewVersionModal', // 曾经 出现过新版本弹框
9
+ everUseFlux: 'everUseFlux', // 曾经使用过 Flux
10
+ CHECKIN_RESET_TIME: 'checkInResetTime', // 签到重置时间
11
+ };
@@ -0,0 +1,17 @@
1
+ import { getRequestConfig } from 'next-intl/server';
2
+ import { routing } from './routing';
3
+
4
+ export default getRequestConfig(async ({ requestLocale }) => {
5
+ // This typically corresponds to the `[locale]` segment
6
+ let locale = await requestLocale;
7
+
8
+ // Ensure that a valid locale is used
9
+ if (!locale || !routing.locales.includes(locale as any)) {
10
+ locale = routing.defaultLocale;
11
+ }
12
+
13
+ return {
14
+ locale,
15
+ messages: (await import(`../lang/${locale}.json`)).default,
16
+ };
17
+ });
@@ -0,0 +1,15 @@
1
+ import { defineRouting } from "next-intl/routing";
2
+ import { createNavigation } from "next-intl/navigation";
3
+ import appConfig from "@/appConfig";
4
+
5
+ export const routing = defineRouting({
6
+ locales: appConfig.locales,
7
+ defaultLocale: appConfig.defaultLocale,
8
+ localePrefix: "as-needed", // 本地语言不需要 语言路径
9
+ localeDetection: false, // 使用默认语言
10
+ });
11
+
12
+ // Lightweight wrappers around Next.js' navigation APIs
13
+ // that will consider the routing configuration
14
+ export const { Link, redirect, usePathname, useRouter } =
15
+ createNavigation(routing);
@@ -0,0 +1,6 @@
1
+ {
2
+ "HomePage": {
3
+ "title": "Hello world!",
4
+ "about": "Go to the about page"
5
+ }
6
+ }
@@ -0,0 +1,39 @@
1
+ // src/libs/auth/casdoor-provider.ts
2
+ import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers/index";
3
+
4
+ export interface CasdoorProfile {
5
+ name: string;
6
+ email: string;
7
+ avatar: string;
8
+ }
9
+
10
+ export default function CasdoorProvider<P extends CasdoorProfile>(
11
+ options: OAuthUserConfig<P>
12
+ ): OAuthConfig<P> {
13
+ return {
14
+ id: "casdoor",
15
+ name: "Casdoor",
16
+ type: "oauth",
17
+ authorization: {
18
+ url: `${options.issuer}/login/oauth/authorize`,
19
+ params: {
20
+ scope: "read",
21
+ response_type: "code",
22
+ client_id: options.clientId,
23
+ // 自定义casdoor官网中配置的回调url,不配置默认为next-auth的/api/auth/callback/casdoor
24
+ // redirect_uri: `${process.env.NEXT_PUBLIC_DOMAIN}/auth/callback/casdoor`,
25
+ },
26
+ },
27
+ // 定义casdoor中使用code换取token的地址
28
+ token: `${options.issuer}/login/oauth/token`,
29
+ clientId: options.clientId,
30
+ profile(profile: CasdoorProfile) {
31
+ return {
32
+ id: profile.name,
33
+ name: profile.name,
34
+ email: profile.email,
35
+ image: profile.avatar,
36
+ };
37
+ },
38
+ };
39
+ }