@lobehub/chat 1.69.2 → 1.69.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.69.3](https://github.com/lobehub/lobe-chat/compare/v1.69.2...v1.69.3)
6
+
7
+ <sup>Released on **2025-03-08**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Add login ui for next-auth.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Add login ui for next-auth, closes [#6434](https://github.com/lobehub/lobe-chat/issues/6434) ([541f275](https://github.com/lobehub/lobe-chat/commit/541f275))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.69.2](https://github.com/lobehub/lobe-chat/compare/v1.69.1...v1.69.2)
6
31
 
7
32
  <sup>Released on **2025-03-07**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Add login ui for next-auth."
6
+ ]
7
+ },
8
+ "date": "2025-03-08",
9
+ "version": "1.69.3"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "improvements": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.69.2",
3
+ "version": "1.69.3",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -165,7 +165,7 @@
165
165
  "epub2": "^3.0.2",
166
166
  "fast-deep-equal": "^3.1.3",
167
167
  "file-type": "^20.0.0",
168
- "framer-motion": "^11.16.0",
168
+ "framer-motion": "^12.0.0",
169
169
  "gpt-tokenizer": "^2.8.1",
170
170
  "html-to-text": "^9.0.5",
171
171
  "i18next": "^24.2.1",
@@ -0,0 +1,161 @@
1
+ 'use client';
2
+
3
+ import { LobeChat } from '@lobehub/ui/brand';
4
+ import { Button, Col, Flex, Row, Skeleton, Typography } from 'antd';
5
+ import { createStyles } from 'antd-style';
6
+ import { AuthError } from 'next-auth';
7
+ import { signIn } from 'next-auth/react';
8
+ import { useRouter, useSearchParams } from 'next/navigation';
9
+ import { memo } from 'react';
10
+ import { useTranslation } from 'react-i18next';
11
+
12
+ import BrandWatermark from '@/components/BrandWatermark';
13
+ import AuthIcons from '@/components/NextAuth/AuthIcons';
14
+ import { DOCUMENTS_REFER_URL, PRIVACY_URL, TERMS_URL } from '@/const/url';
15
+ import { useUserStore } from '@/store/user';
16
+
17
+ const { Title, Paragraph } = Typography;
18
+
19
+ const useStyles = createStyles(({ css, token }) => ({
20
+ button: css`
21
+ text-transform: capitalize;
22
+ `,
23
+ container: css`
24
+ min-width: 360px;
25
+ border: 1px solid ${token.colorBorder};
26
+ border-radius: ${token.borderRadiusLG}px;
27
+ background: ${token.colorBgContainer};
28
+ `,
29
+ contentCard: css`
30
+ padding-block: 2.5rem;
31
+ padding-inline: 2rem;
32
+ `,
33
+ description: css`
34
+ margin: 0;
35
+ color: ${token.colorTextSecondary};
36
+ `,
37
+ footer: css`
38
+ padding: 1rem;
39
+ border-block-start: 1px solid ${token.colorBorder};
40
+ border-radius: 0 0 8px 8px;
41
+
42
+ color: ${token.colorTextDescription};
43
+
44
+ background: ${token.colorBgElevated};
45
+ `,
46
+ text: css`
47
+ text-align: center;
48
+ `,
49
+ title: css`
50
+ margin: 0;
51
+ color: ${token.colorTextHeading};
52
+ `,
53
+ }));
54
+
55
+ const BtnListLoading = memo(() => {
56
+ return (
57
+ <Flex gap={'small'} vertical>
58
+ <Skeleton.Button active style={{ minWidth: 300 }} />
59
+ <Skeleton.Button active style={{ minWidth: 300 }} />
60
+ <Skeleton.Button active style={{ minWidth: 300 }} />
61
+ </Flex>
62
+ );
63
+ });
64
+
65
+ /**
66
+ * Follow the implementation from AuthJS official documentation,
67
+ * but using client components.
68
+ * ref: https://authjs.dev/guides/pages/signin
69
+ */
70
+ export default memo(() => {
71
+ const { styles } = useStyles();
72
+ const { t } = useTranslation('clerk');
73
+ const router = useRouter();
74
+
75
+ const oAuthSSOProviders = useUserStore((s) => s.oAuthSSOProviders);
76
+
77
+ const searchParams = useSearchParams();
78
+
79
+ // Redirect back to the page url
80
+ const callbackUrl = searchParams.get('callbackUrl') ?? '';
81
+
82
+ const handleSignIn = async (provider: string) => {
83
+ try {
84
+ await signIn(provider, { redirectTo: callbackUrl });
85
+ } catch (error) {
86
+ // Signin can fail for a number of reasons, such as the user
87
+ // not existing, or the user not having the correct role.
88
+ // In some cases, you may want to redirect to a custom error
89
+ if (error instanceof AuthError) {
90
+ return router.push(`/next-auth/?error=${error.type}`);
91
+ }
92
+
93
+ // Otherwise if a redirects happens Next.js can handle it
94
+ // so you can just re-thrown the error and let Next.js handle it.
95
+ // Docs: https://nextjs.org/docs/app/api-reference/functions/redirect#server-component
96
+ throw error;
97
+ }
98
+ };
99
+
100
+ const footerBtns = [
101
+ { href: DOCUMENTS_REFER_URL, id: 0, label: t('footerPageLink__help') },
102
+ { href: PRIVACY_URL, id: 1, label: t('footerPageLink__privacy') },
103
+ { href: TERMS_URL, id: 2, label: t('footerPageLink__terms') },
104
+ ];
105
+
106
+ return (
107
+ <div className={styles.container}>
108
+ <div className={styles.contentCard}>
109
+ {/* Card Body */}
110
+ <Flex gap="large" vertical>
111
+ {/* Header */}
112
+ <div className={styles.text}>
113
+ <Title className={styles.title} level={4}>
114
+ <div>
115
+ <LobeChat size={48} />
116
+ </div>
117
+ {t('signIn.start.title', { applicationName: 'LobeChat' })}
118
+ </Title>
119
+ <Paragraph className={styles.description}>{t('signIn.start.subtitle')}</Paragraph>
120
+ </div>
121
+ {/* Content */}
122
+ <Flex gap="small" vertical>
123
+ {oAuthSSOProviders ? (
124
+ oAuthSSOProviders.map((provider) => (
125
+ <Button
126
+ className={styles.button}
127
+ icon={AuthIcons(provider, 16)}
128
+ key={provider}
129
+ onClick={() => handleSignIn(provider)}
130
+ >
131
+ {provider}
132
+ </Button>
133
+ ))
134
+ ) : (
135
+ <BtnListLoading />
136
+ )}
137
+ </Flex>
138
+ </Flex>
139
+ </div>
140
+ <div className={styles.footer}>
141
+ {/* Footer */}
142
+ <Row>
143
+ <Col span={12}>
144
+ <Flex justify="left" style={{ height: '100%' }}>
145
+ <BrandWatermark />
146
+ </Flex>
147
+ </Col>
148
+ <Col offset={4} span={8}>
149
+ <Flex justify="right">
150
+ {footerBtns.map((btn) => (
151
+ <Button key={btn.id} onClick={() => router.push(btn.href)} size="small" type="text">
152
+ {btn.label}
153
+ </Button>
154
+ ))}
155
+ </Flex>
156
+ </Col>
157
+ </Row>
158
+ </div>
159
+ </div>
160
+ );
161
+ });
@@ -0,0 +1,11 @@
1
+ import { Suspense } from 'react';
2
+
3
+ import Loading from '@/components/Loading/BrandTextLoading';
4
+
5
+ import AuthSignInBox from './AuthSignInBox';
6
+
7
+ export default () => (
8
+ <Suspense fallback={<Loading />}>
9
+ <AuthSignInBox />
10
+ </Suspense>
11
+ );
@@ -10,7 +10,7 @@ import { userService } from '@/services/user';
10
10
  import { useUserStore } from '@/store/user';
11
11
  import { userProfileSelectors } from '@/store/user/selectors';
12
12
 
13
- import AuthIcons from './AuthIcons';
13
+ import AuthIcons from '@/components/NextAuth/AuthIcons';
14
14
 
15
15
  const { Item } = List;
16
16
 
@@ -12,10 +12,6 @@ import {
12
12
  } from '@lobehub/ui/icons';
13
13
  import React from 'react';
14
14
 
15
- const iconProps = {
16
- size: 32,
17
- };
18
-
19
15
  const iconComponents: { [key: string]: React.ElementType } = {
20
16
  'auth0': Auth0,
21
17
  'authelia': Authelia.Color,
@@ -29,9 +25,15 @@ const iconComponents: { [key: string]: React.ElementType } = {
29
25
  'zitadel': Zitadel.Color,
30
26
  };
31
27
 
32
- const AuthIcons = (id: string) => {
28
+ /**
29
+ * Get the auth icons component for the given id
30
+ * @param id
31
+ * @param size default is 36
32
+ * @returns
33
+ */
34
+ const AuthIcons = (id: string, size = 36) => {
33
35
  const IconComponent = iconComponents[id] || iconComponents.default;
34
- return <IconComponent {...iconProps} />;
36
+ return <IconComponent size={size}/>;
35
37
  };
36
38
 
37
39
  export default AuthIcons;
@@ -42,6 +42,7 @@ export default {
42
42
  debug: authEnv.NEXT_AUTH_DEBUG,
43
43
  pages: {
44
44
  error: '/next-auth/error',
45
+ signIn: '/next-auth/signin',
45
46
  },
46
47
  providers: initSSOProviders(),
47
48
  secret: authEnv.NEXT_AUTH_SECRET,
package/src/middleware.ts CHANGED
@@ -36,7 +36,7 @@ export const config = {
36
36
 
37
37
  '/login(.*)',
38
38
  '/signup(.*)',
39
- '/next-auth/error',
39
+ '/next-auth/(.*)',
40
40
  // ↓ cloud ↓
41
41
  ],
42
42
  };