@lobehub/lobehub 2.0.0-next.210 → 2.0.0-next.211

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 2.0.0-next.211](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.210...v2.0.0-next.211)
6
+
7
+ <sup>Released on **2026-01-05**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Add lost like button in discover detail page.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Add lost like button in discover detail page, closes [#11182](https://github.com/lobehub/lobe-chat/issues/11182) ([41215d4](https://github.com/lobehub/lobe-chat/commit/41215d4))
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 2.0.0-next.210](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.209...v2.0.0-next.210)
6
31
 
7
32
  <sup>Released on **2026-01-04**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Add lost like button in discover detail page."
6
+ ]
7
+ },
8
+ "date": "2026-01-05",
9
+ "version": "2.0.0-next.211"
10
+ },
2
11
  {
3
12
  "children": {},
4
13
  "date": "2026-01-04",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.210",
3
+ "version": "2.0.0-next.211",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent 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",
@@ -158,7 +158,7 @@ export const GET = async (req: NextRequest, context: RouteContext) => {
158
158
  // Follow queries
159
159
  case 'follow-status': {
160
160
  const targetUserId = Number(segments[1]);
161
- if (!accessToken) {
161
+ if (!accessToken && !trustedClientToken) {
162
162
  return NextResponse.json({ isFollowing: false, isMutual: false });
163
163
  }
164
164
  const result = await market.follows.checkFollowStatus(targetUserId);
@@ -193,7 +193,7 @@ export const GET = async (req: NextRequest, context: RouteContext) => {
193
193
  case 'favorite-status': {
194
194
  const targetType = segments[1] as 'agent' | 'plugin';
195
195
  const targetIdOrIdentifier = segments[2];
196
- if (!accessToken) {
196
+ if (!accessToken && !trustedClientToken) {
197
197
  return NextResponse.json({ isFavorited: false });
198
198
  }
199
199
  // SDK accepts both number (targetId) and string (identifier)
@@ -236,7 +236,7 @@ export const GET = async (req: NextRequest, context: RouteContext) => {
236
236
  case 'like-status': {
237
237
  const targetType = segments[1] as 'agent' | 'plugin';
238
238
  const targetIdOrIdentifier = segments[2];
239
- if (!accessToken) {
239
+ if (!accessToken && !trustedClientToken) {
240
240
  return NextResponse.json({ isLiked: false });
241
241
  }
242
242
  const isNumeric = /^\d+$/.test(targetIdOrIdentifier);
@@ -13,7 +13,14 @@ import {
13
13
  } from '@lobehub/ui';
14
14
  import { App } from 'antd';
15
15
  import { createStaticStyles, cssVar, useResponsive } from 'antd-style';
16
- import { BookTextIcon, BookmarkCheckIcon, BookmarkIcon, CoinsIcon, DotIcon } from 'lucide-react';
16
+ import {
17
+ BookTextIcon,
18
+ BookmarkCheckIcon,
19
+ BookmarkIcon,
20
+ CoinsIcon,
21
+ DotIcon,
22
+ HeartIcon,
23
+ } from 'lucide-react';
17
24
  import qs from 'query-string';
18
25
  import { memo, useState } from 'react';
19
26
  import { useTranslation } from 'react-i18next';
@@ -54,8 +61,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
54
61
  const { mobile = isMobile } = useResponsive();
55
62
  const { isAuthenticated, signIn, session } = useMarketAuth();
56
63
  const [favoriteLoading, setFavoriteLoading] = useState(false);
57
- // TODO: enable like feature
58
- // const [likeLoading, setLikeLoading] = useState(false);
64
+ const [likeLoading, setLikeLoading] = useState(false);
59
65
 
60
66
  // Set access token for social service
61
67
  if (session?.accessToken) {
@@ -71,13 +77,13 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
71
77
 
72
78
  const isFavorited = favoriteStatus?.isFavorited ?? false;
73
79
 
74
- // TODO: enable like feature
75
- // const { data: likeStatus, mutate: mutateLike } = useSWR(
76
- // identifier && isAuthenticated ? ['like-status', 'agent', identifier] : null,
77
- // () => socialService.checkLikeStatus('agent', identifier!),
78
- // { revalidateOnFocus: false },
79
- // );
80
- // const isLiked = likeStatus?.isLiked ?? false;
80
+ // Fetch like status
81
+ const { data: likeStatus, mutate: mutateLike } = useSWR(
82
+ identifier && isAuthenticated ? ['like-status', 'agent', identifier] : null,
83
+ () => socialService.checkLikeStatus('agent', identifier!),
84
+ { revalidateOnFocus: false },
85
+ );
86
+ const isLiked = likeStatus?.isLiked ?? false;
81
87
 
82
88
  const handleFavoriteClick = async () => {
83
89
  if (!isAuthenticated) {
@@ -105,30 +111,29 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
105
111
  }
106
112
  };
107
113
 
108
- // TODO: enable like feature
109
- // const handleLikeClick = async () => {
110
- // if (!isAuthenticated) {
111
- // await signIn();
112
- // return;
113
- // }
114
- // if (!identifier) return;
115
- // setLikeLoading(true);
116
- // try {
117
- // if (isLiked) {
118
- // await socialService.unlike('agent', identifier);
119
- // message.success(t('assistant.unlikeSuccess'));
120
- // } else {
121
- // await socialService.like('agent', identifier);
122
- // message.success(t('assistant.likeSuccess'));
123
- // }
124
- // await mutateLike();
125
- // } catch (error) {
126
- // console.error('Like action failed:', error);
127
- // message.error(t('assistant.likeFailed'));
128
- // } finally {
129
- // setLikeLoading(false);
130
- // }
131
- // };
114
+ const handleLikeClick = async () => {
115
+ if (!isAuthenticated) {
116
+ await signIn();
117
+ return;
118
+ }
119
+ if (!identifier) return;
120
+ setLikeLoading(true);
121
+ try {
122
+ if (isLiked) {
123
+ await socialService.unlike('agent', identifier);
124
+ message.success(t('assistant.unlikeSuccess'));
125
+ } else {
126
+ await socialService.like('agent', identifier);
127
+ message.success(t('assistant.likeSuccess'));
128
+ }
129
+ await mutateLike();
130
+ } catch (error) {
131
+ console.error('Like action failed:', error);
132
+ message.error(t('assistant.likeFailed'));
133
+ } finally {
134
+ setLikeLoading(false);
135
+ }
136
+ };
132
137
 
133
138
  const categories = useCategory();
134
139
  const cate = categories.find((c) => c.key === category);
@@ -186,6 +191,14 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
186
191
  {title}
187
192
  </Text>
188
193
  </Flexbox>
194
+ <Tooltip title={isLiked ? t('assistant.unlike') : t('assistant.like')}>
195
+ <ActionIcon
196
+ icon={HeartIcon}
197
+ loading={likeLoading}
198
+ onClick={handleLikeClick}
199
+ style={isLiked ? { color: '#ff4d4f' } : undefined}
200
+ />
201
+ </Tooltip>
189
202
  <Tooltip title={isFavorited ? t('assistant.unfavorite') : t('assistant.favorite')}>
190
203
  <ActionIcon
191
204
  icon={isFavorited ? BookmarkCheckIcon : BookmarkIcon}