@lobehub/lobehub 2.0.0-next.276 → 2.0.0-next.278

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 (98) hide show
  1. package/.cursor/rules/db-migrations.mdc +1 -1
  2. package/.cursor/rules/debug-usage.mdc +7 -5
  3. package/.cursor/rules/desktop-controller-tests.mdc +2 -1
  4. package/.cursor/rules/desktop-feature-implementation.mdc +9 -5
  5. package/.cursor/rules/desktop-local-tools-implement.mdc +67 -66
  6. package/.cursor/rules/desktop-menu-configuration.mdc +21 -9
  7. package/.cursor/rules/desktop-window-management.mdc +17 -2
  8. package/.cursor/rules/drizzle-schema-style-guide.mdc +6 -6
  9. package/.cursor/rules/hotkey.mdc +1 -0
  10. package/.cursor/rules/i18n.mdc +1 -0
  11. package/.cursor/rules/project-structure.mdc +16 -3
  12. package/.cursor/rules/react.mdc +17 -5
  13. package/.cursor/rules/recent-data-usage.mdc +2 -1
  14. package/.cursor/rules/testing-guide/testing-guide.mdc +262 -238
  15. package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +1 -1
  16. package/.cursor/rules/zustand-action-patterns.mdc +1 -1
  17. package/.cursor/rules/zustand-slice-organization.mdc +4 -4
  18. package/CHANGELOG.md +51 -0
  19. package/CLAUDE.md +1 -1
  20. package/GEMINI.md +1 -1
  21. package/changelog/v1.json +14 -0
  22. package/docs/development/database-schema.dbml +16 -0
  23. package/locales/en-US/chat.json +24 -0
  24. package/locales/en-US/setting.json +11 -0
  25. package/locales/zh-CN/chat.json +24 -0
  26. package/locales/zh-CN/setting.json +11 -0
  27. package/package.json +1 -1
  28. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/BatchCreateAgents/index.tsx +2 -2
  29. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/UpdateGroup/index.tsx +56 -56
  30. package/packages/builtin-tool-group-agent-builder/src/client/Render/BatchCreateAgents.tsx +3 -2
  31. package/packages/builtin-tool-group-agent-builder/src/executor.ts +2 -1
  32. package/packages/business/const/src/index.ts +3 -0
  33. package/packages/database/migrations/0069_add_topic_shares_table.sql +22 -0
  34. package/packages/database/migrations/meta/0069_snapshot.json +9704 -0
  35. package/packages/database/migrations/meta/_journal.json +7 -0
  36. package/packages/database/src/models/__tests__/topicShare.test.ts +318 -0
  37. package/packages/database/src/models/topicShare.ts +177 -0
  38. package/packages/database/src/schemas/topic.ts +44 -2
  39. package/packages/types/src/agentCronJob/index.ts +19 -23
  40. package/packages/types/src/conversation.ts +5 -0
  41. package/packages/types/src/serverConfig.ts +1 -0
  42. package/packages/types/src/topic/topic.ts +46 -0
  43. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/Actions.tsx +31 -0
  44. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/CronTopicGroup.tsx +10 -6
  45. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/index.tsx +7 -11
  46. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/useDropdownMenu.tsx +102 -0
  47. package/src/app/[variants]/(main)/agent/cron/[cronId]/CronConfig.ts +179 -0
  48. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobContentEditor.tsx +111 -0
  49. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobHeader.tsx +45 -0
  50. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobSaveButton.tsx +31 -0
  51. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +213 -0
  52. package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +186 -344
  53. package/src/app/[variants]/(main)/agent/features/Conversation/Header/ShareButton/index.tsx +24 -9
  54. package/src/app/[variants]/(main)/agent/profile/features/AgentCronJobs/index.tsx +42 -97
  55. package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/index.tsx +4 -20
  56. package/src/app/[variants]/(main)/community/features/UserAvatar/index.tsx +15 -5
  57. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/AgentProfilePopup.tsx +1 -6
  58. package/src/app/[variants]/(main)/group/features/Conversation/Header/ShareButton/index.tsx +26 -9
  59. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/AspectRatioSelect/index.tsx +1 -2
  60. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ImageNum.tsx +54 -173
  61. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ResolutionSelect.tsx +22 -67
  62. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +18 -0
  63. package/src/app/[variants]/router/desktopRouter.config.tsx +18 -0
  64. package/src/app/[variants]/share/t/[id]/SharedMessageList.tsx +54 -0
  65. package/src/app/[variants]/share/t/[id]/_layout/index.tsx +170 -0
  66. package/src/app/[variants]/share/t/[id]/features/Portal/index.tsx +66 -0
  67. package/src/app/[variants]/share/t/[id]/index.tsx +112 -0
  68. package/src/app/robots.tsx +1 -1
  69. package/src/business/client/BusinessMobileRoutes.tsx +1 -1
  70. package/src/features/Conversation/ChatList/index.tsx +12 -5
  71. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/index.tsx +8 -4
  72. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +15 -10
  73. package/src/features/Conversation/Messages/AssistantGroup/Tools.tsx +3 -1
  74. package/src/features/Conversation/Messages/AssistantGroup/components/ContentBlock.tsx +3 -2
  75. package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +2 -2
  76. package/src/features/Conversation/Messages/Supervisor/components/ContentBlock.tsx +25 -26
  77. package/src/features/Conversation/Messages/Supervisor/components/Group.tsx +4 -2
  78. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +16 -12
  79. package/src/features/Conversation/Messages/Tool/index.tsx +20 -11
  80. package/src/features/Conversation/Messages/index.tsx +1 -1
  81. package/src/features/Conversation/store/slices/data/action.ts +2 -1
  82. package/src/features/SharePopover/index.tsx +215 -0
  83. package/src/features/SharePopover/style.ts +10 -0
  84. package/src/libs/next/proxy/define-config.ts +4 -1
  85. package/src/locales/default/chat.ts +26 -0
  86. package/src/proxy.ts +1 -0
  87. package/src/server/globalConfig/index.ts +1 -0
  88. package/src/server/routers/lambda/__tests__/message.test.ts +152 -0
  89. package/src/server/routers/lambda/__tests__/share.test.ts +227 -0
  90. package/src/server/routers/lambda/__tests__/topic.test.ts +174 -0
  91. package/src/server/routers/lambda/index.ts +2 -0
  92. package/src/server/routers/lambda/message.ts +37 -4
  93. package/src/server/routers/lambda/share.ts +55 -0
  94. package/src/server/routers/lambda/topic.ts +45 -0
  95. package/src/services/chatGroup/index.ts +1 -4
  96. package/src/services/message/index.ts +1 -0
  97. package/src/services/topic/index.ts +16 -0
  98. package/src/store/serverConfig/selectors.ts +1 -0
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
3
4
  import { ActionIcon } from '@lobehub/ui';
4
5
  import { Share2 } from 'lucide-react';
5
6
  import dynamic from 'next/dynamic';
@@ -8,8 +9,10 @@ import { useTranslation } from 'react-i18next';
8
9
 
9
10
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
10
11
  import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
12
+ import { useChatStore } from '@/store/chat';
11
13
 
12
14
  const ShareModal = dynamic(() => import('@/features/ShareModal'));
15
+ const SharePopover = dynamic(() => import('@/features/SharePopover'));
13
16
 
14
17
  interface ShareButtonProps {
15
18
  mobile?: boolean;
@@ -20,18 +23,30 @@ interface ShareButtonProps {
20
23
  const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
21
24
  const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
22
25
  const { t } = useTranslation('common');
26
+ const activeTopicId = useChatStore((s) => s.activeTopicId);
27
+
28
+ // Hide share button when no topic exists (no messages sent yet)
29
+ if (!activeTopicId) return null;
30
+
31
+ const iconButton = (
32
+ <ActionIcon
33
+ icon={Share2}
34
+ onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
35
+ size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
36
+ title={t('share')}
37
+ tooltipProps={{
38
+ placement: 'bottom',
39
+ }}
40
+ />
41
+ );
23
42
 
24
43
  return (
25
44
  <>
26
- <ActionIcon
27
- icon={Share2}
28
- onClick={() => setIsModalOpen(true)}
29
- size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
30
- title={t('share')}
31
- tooltipProps={{
32
- placement: 'bottom',
33
- }}
34
- />
45
+ {ENABLE_TOPIC_LINK_SHARE ? (
46
+ <SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
47
+ ) : (
48
+ iconButton
49
+ )}
35
50
  <ShareModal onCancel={() => setIsModalOpen(false)} open={isModalOpen} />
36
51
  </>
37
52
  );
@@ -2,38 +2,43 @@
2
2
 
3
3
  import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
4
4
  import { Flexbox } from '@lobehub/ui';
5
- import { Modal, Typography } from 'antd';
5
+ import { Typography } from 'antd';
6
6
  import { Clock } from 'lucide-react';
7
- import { memo, useRef, useState } from 'react';
7
+ import { memo, useCallback } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
+ import urlJoin from 'url-join';
9
10
 
11
+ import { useQueryRoute } from '@/hooks/useQueryRoute';
10
12
  import { useAgentStore } from '@/store/agent';
11
13
 
12
14
  import CronJobCards from './CronJobCards';
13
- import CronJobForm from './CronJobForm';
14
15
  import { useAgentCronJobs } from './hooks/useAgentCronJobs';
15
16
 
16
17
  const { Title } = Typography;
17
18
 
18
- interface AgentCronJobsProps {
19
- onFormModalChange?: (show: boolean) => void;
20
- showFormModal?: boolean;
21
- }
22
-
23
- const AgentCronJobs = memo<AgentCronJobsProps>(({ showFormModal, onFormModalChange }) => {
19
+ const AgentCronJobs = memo(() => {
24
20
  const { t } = useTranslation('setting');
25
21
  const agentId = useAgentStore((s) => s.activeAgentId);
26
- const [internalShowForm, setInternalShowForm] = useState(false);
27
- const [editingJob, setEditingJob] = useState<string | null>(null);
28
- const [submitting, setSubmitting] = useState(false);
29
- const formRef = useRef<any>(null);
22
+ const router = useQueryRoute();
23
+
24
+ const { cronJobs, loading, deleteCronJob } = useAgentCronJobs(agentId);
30
25
 
31
- // Use external control if provided, otherwise use internal state
32
- const showForm = showFormModal ?? internalShowForm;
33
- const setShowForm = onFormModalChange ?? setInternalShowForm;
26
+ // Edit: Navigate to cron job detail page
27
+ const handleEdit = useCallback(
28
+ (jobId: string) => {
29
+ if (!agentId) return;
30
+ router.push(urlJoin('/agent', agentId, 'cron', jobId));
31
+ },
32
+ [agentId, router],
33
+ );
34
34
 
35
- const { cronJobs, loading, createCronJob, updateCronJob, deleteCronJob } =
36
- useAgentCronJobs(agentId);
35
+ // Delete: Keep the existing delete logic
36
+ const handleDelete = useCallback(
37
+ async (jobId: string) => {
38
+ await deleteCronJob(jobId);
39
+ },
40
+ [deleteCronJob],
41
+ );
37
42
 
38
43
  if (!ENABLE_BUSINESS_FEATURES) return null;
39
44
 
@@ -41,89 +46,29 @@ const AgentCronJobs = memo<AgentCronJobsProps>(({ showFormModal, onFormModalChan
41
46
  return null;
42
47
  }
43
48
 
44
- const handleCreate = async (data: any) => {
45
- setSubmitting(true);
46
- try {
47
- await createCronJob(data);
48
- setShowForm(false);
49
- } finally {
50
- setSubmitting(false);
51
- }
52
- };
53
-
54
- const handleEdit = (jobId: string) => {
55
- setEditingJob(jobId);
56
- setShowForm(true);
57
- };
58
-
59
- const handleUpdate = async (data: any) => {
60
- if (editingJob) {
61
- setSubmitting(true);
62
- try {
63
- await updateCronJob(editingJob, data);
64
- setShowForm(false);
65
- setEditingJob(null);
66
- } finally {
67
- setSubmitting(false);
68
- }
69
- }
70
- };
71
-
72
- const handleCancel = () => {
73
- setShowForm(false);
74
- setEditingJob(null);
75
- formRef.current?.resetFields();
76
- };
77
-
78
- const handleModalOk = () => {
79
- formRef.current?.submit();
80
- };
81
-
82
- const handleDelete = async (jobId: string) => {
83
- await deleteCronJob(jobId);
84
- };
85
-
86
49
  const hasCronJobs = cronJobs && cronJobs.length > 0;
87
50
 
88
- return (
89
- <>
90
- {/* Show cards section only if there are jobs */}
91
- {hasCronJobs && (
92
- <Flexbox gap={12} style={{ marginBottom: 16, marginTop: 16 }}>
93
- <Title level={5} style={{ margin: 0 }}>
94
- <Flexbox align="center" gap={8} horizontal>
95
- <Clock size={16} />
96
- {t('agentCronJobs.title')}
97
- </Flexbox>
98
- </Title>
51
+ // Only show if there are jobs
52
+ if (!hasCronJobs) {
53
+ return null;
54
+ }
99
55
 
100
- <CronJobCards
101
- cronJobs={cronJobs}
102
- loading={loading}
103
- onDelete={handleDelete}
104
- onEdit={handleEdit}
105
- />
56
+ return (
57
+ <Flexbox gap={12} style={{ marginBottom: 16, marginTop: 16 }}>
58
+ <Title level={5} style={{ margin: 0 }}>
59
+ <Flexbox align="center" gap={8} horizontal>
60
+ <Clock size={16} />
61
+ {t('agentCronJobs.title')}
106
62
  </Flexbox>
107
- )}
108
-
109
- {/* Form Modal */}
110
- <Modal
111
- confirmLoading={submitting}
112
- okText={editingJob ? t('agentCronJobs.save' as any) : t('agentCronJobs.create' as any)}
113
- onCancel={handleCancel}
114
- onOk={handleModalOk}
115
- open={showForm}
116
- title={editingJob ? t('agentCronJobs.editJob') : t('agentCronJobs.addJob')}
117
- width={640}
118
- >
119
- <CronJobForm
120
- editingJob={editingJob ? cronJobs?.find((job) => job.id === editingJob) : undefined}
121
- formRef={formRef}
122
- onCancel={handleCancel}
123
- onSubmit={editingJob ? handleUpdate : handleCreate}
124
- />
125
- </Modal>
126
- </>
63
+ </Title>
64
+
65
+ <CronJobCards
66
+ cronJobs={cronJobs}
67
+ loading={loading}
68
+ onDelete={handleDelete}
69
+ onEdit={handleEdit}
70
+ />
71
+ </Flexbox>
127
72
  );
128
73
  });
129
74
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
4
4
  import { Button, Flexbox } from '@lobehub/ui';
5
- import { Divider, message } from 'antd';
5
+ import { Divider } from 'antd';
6
6
  import isEqual from 'fast-deep-equal';
7
7
  import { Clock, PlayIcon } from 'lucide-react';
8
8
  import React, { memo, useCallback } from 'react';
@@ -11,7 +11,6 @@ import urlJoin from 'url-join';
11
11
 
12
12
  import ModelSelect from '@/features/ModelSelect';
13
13
  import { useQueryRoute } from '@/hooks/useQueryRoute';
14
- import { agentCronJobService } from '@/services/agentCronJob';
15
14
  import { useAgentStore } from '@/store/agent';
16
15
  import { agentSelectors } from '@/store/agent/selectors';
17
16
  import { useChatStore } from '@/store/chat';
@@ -29,25 +28,10 @@ const ProfileEditor = memo(() => {
29
28
  const switchTopic = useChatStore((s) => s.switchTopic);
30
29
  const router = useQueryRoute();
31
30
 
32
- const handleCreateCronJob = useCallback(async () => {
31
+ const handleCreateCronJob = useCallback(() => {
33
32
  if (!agentId) return;
34
- try {
35
- const result = await agentCronJobService.create({
36
- agentId,
37
- content: t('agentCronJobs.form.content.placeholder') || 'This is a cron job',
38
- cronPattern: '*/30 * * * *',
39
- enabled: true,
40
- name: t('agentCronJobs.addJob') || 'Cron Job Task',
41
- });
42
-
43
- if (result.success) {
44
- router.push(urlJoin('/agent', agentId, 'cron', result.data.id));
45
- }
46
- } catch (error) {
47
- console.error('Failed to create cron job:', error);
48
- message.error('Failed to create scheduled task');
49
- }
50
- }, [agentId, router, t]);
33
+ router.push(urlJoin('/agent', agentId, 'cron', 'new'));
34
+ }, [agentId, router]);
51
35
 
52
36
  return (
53
37
  <>
@@ -16,7 +16,14 @@ import { serverConfigSelectors } from '@/store/serverConfig/selectors';
16
16
  */
17
17
  const checkNeedsProfileSetup = (
18
18
  enableMarketTrustedClient: boolean,
19
- userProfile: { avatarUrl: string | null; bannerUrl: string | null; socialLinks: { github?: string; twitter?: string; website?: string } | null } | null | undefined,
19
+ userProfile:
20
+ | {
21
+ avatarUrl: string | null;
22
+ bannerUrl: string | null;
23
+ socialLinks: { github?: string; twitter?: string; website?: string } | null;
24
+ }
25
+ | null
26
+ | undefined,
20
27
  ): boolean => {
21
28
  if (!enableMarketTrustedClient) return false;
22
29
  if (!userProfile) return true;
@@ -33,7 +40,9 @@ const UserAvatar = memo(() => {
33
40
  const [loading, setLoading] = useState(false);
34
41
  const { isAuthenticated, isLoading, getCurrentUserInfo, signIn } = useMarketAuth();
35
42
 
36
- const enableMarketTrustedClient = useServerConfigStore(serverConfigSelectors.enableMarketTrustedClient);
43
+ const enableMarketTrustedClient = useServerConfigStore(
44
+ serverConfigSelectors.enableMarketTrustedClient,
45
+ );
37
46
 
38
47
  const userInfo = getCurrentUserInfo();
39
48
  const username = userInfo?.sub;
@@ -70,8 +79,9 @@ const UserAvatar = memo(() => {
70
79
  return <Skeleton.Avatar active shape={'square'} size={28} style={{ borderRadius: 6 }} />;
71
80
  }
72
81
 
73
- // 未认证,或者是 trustedClient 模式但需要完善资料时,显示登录按钮
74
- if (!isAuthenticated || needsProfileSetup) {
82
+ // 如果启用了 trustedClient,不显示"成为创作者"按钮,直接显示头像
83
+ // 否则,未认证或需要完善资料时,显示登录按钮
84
+ if (!enableMarketTrustedClient && (!isAuthenticated || needsProfileSetup)) {
75
85
  return (
76
86
  <Button
77
87
  icon={UserCircleIcon}
@@ -92,7 +102,7 @@ const UserAvatar = memo(() => {
92
102
 
93
103
  return (
94
104
  <Avatar
95
- avatar={avatarUrl || userProfile?.userName}
105
+ avatar={avatarUrl || userProfile?.userName || username}
96
106
  onClick={handleAvatarClick}
97
107
  shape={'square'}
98
108
  size={28}
@@ -136,12 +136,7 @@ const AgentProfilePopup = memo<AgentProfilePopupProps>(({ agent, groupId, childr
136
136
  </Text>
137
137
 
138
138
  {/* Settings Button */}
139
- <Flexbox
140
- align="center"
141
- horizontal
142
- justify="flex-end"
143
- style={{ paddingBlockStart: 0 }}
144
- >
139
+ <Flexbox align="center" horizontal justify="flex-end" style={{ paddingBlockStart: 0 }}>
145
140
  <ActionIcon
146
141
  icon={Settings}
147
142
  onClick={handleSettings}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
3
4
  import { ActionIcon } from '@lobehub/ui';
4
5
  import { Share2 } from 'lucide-react';
5
6
  import dynamic from 'next/dynamic';
@@ -8,8 +9,12 @@ import { useTranslation } from 'react-i18next';
8
9
 
9
10
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
10
11
  import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
12
+ import { useChatStore } from '@/store/chat';
13
+
14
+ console.log('ENABLE_TOPIC_LINK_SHARE', ENABLE_TOPIC_LINK_SHARE);
11
15
 
12
16
  const ShareModal = dynamic(() => import('@/features/ShareModal'));
17
+ const SharePopover = dynamic(() => import('@/features/SharePopover'));
13
18
 
14
19
  interface ShareButtonProps {
15
20
  mobile?: boolean;
@@ -20,18 +25,30 @@ interface ShareButtonProps {
20
25
  const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
21
26
  const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
22
27
  const { t } = useTranslation('common');
28
+ const activeTopicId = useChatStore((s) => s.activeTopicId);
29
+
30
+ // Hide share button when no topic exists (no messages sent yet)
31
+ if (!activeTopicId) return null;
32
+
33
+ const iconButton = (
34
+ <ActionIcon
35
+ icon={Share2}
36
+ onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
37
+ size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
38
+ title={t('share')}
39
+ tooltipProps={{
40
+ placement: 'bottom',
41
+ }}
42
+ />
43
+ );
23
44
 
24
45
  return (
25
46
  <>
26
- <ActionIcon
27
- icon={Share2}
28
- onClick={() => setIsModalOpen(true)}
29
- size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
30
- title={t('share')}
31
- tooltipProps={{
32
- placement: 'bottom',
33
- }}
34
- />
47
+ {ENABLE_TOPIC_LINK_SHARE ? (
48
+ <SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
49
+ ) : (
50
+ iconButton
51
+ )}
35
52
  <ShareModal onCancel={() => setIsModalOpen(false)} open={isModalOpen} />
36
53
  </>
37
54
  );
@@ -29,8 +29,7 @@ const AspectRatioSelect = memo<AspectRatioSelectProps>(
29
29
  {options?.map((item) => {
30
30
  const [width, height] = item.value.split(':').map(Number);
31
31
  const isWidthGreater = width > height;
32
- const isEqual = width === height;
33
- const isActive = isEqual ? item.value === '1:1' : active === item.value;
32
+ const isActive = active === item.value;
34
33
  return (
35
34
  <Block
36
35
  align={'center'}