@liujitcn/kratos-taro-app-system 0.0.78 → 0.0.80

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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/build.mjs +2 -2
  3. package/dist/module.mjs +54 -6
  4. package/package.json +3 -3
  5. package/src/api/base/v1/ai_knowledge.ts +25 -0
  6. package/src/locales/en-US.json +13 -1
  7. package/src/locales/ja-JP.json +13 -1
  8. package/src/locales/zh-CN.json +13 -1
  9. package/src/locales/zh-TW.json +13 -1
  10. package/src/pages.ts +2 -2
  11. package/src/rpc/base/v1/ai_knowledge.ts +33 -0
  12. package/src/rpc/base/v1/ai_message.ts +1 -1
  13. package/src/rpc/base/v1/ai_provider.ts +1 -1
  14. package/src/rpc/base/v1/ai_search.ts +1 -1
  15. package/src/rpc/base/v1/ai_session.ts +1 -1
  16. package/src/rpc/base/v1/ai_tool.ts +1 -1
  17. package/src/rpc/base/v1/notification.ts +1 -1
  18. package/src/rpc/google/protobuf/empty.ts +1 -1
  19. package/src/rpc/google/protobuf/timestamp.ts +1 -1
  20. package/src/views/pages/my/my.scss +28 -109
  21. package/src/views/pages/my/my.tsx +62 -49
  22. package/src/views/pagesMember/ai/components/Composer.tsx +52 -3
  23. package/src/views/pagesMember/ai/components/KnowledgePicker.tsx +58 -0
  24. package/src/views/pagesMember/ai/components/SessionDrawer.tsx +8 -5
  25. package/src/views/pagesMember/ai/components/WelcomePanel.tsx +7 -4
  26. package/src/views/pagesMember/ai/components/composer.scss +28 -23
  27. package/src/views/pagesMember/ai/components/knowledge-picker.scss +139 -0
  28. package/src/views/pagesMember/ai/components/model-picker.scss +24 -18
  29. package/src/views/pagesMember/ai/components/session-drawer.scss +44 -22
  30. package/src/views/pagesMember/ai/components/welcome-panel.scss +28 -17
  31. package/src/views/pagesMember/ai/index.scss +35 -72
  32. package/src/views/pagesMember/ai/index.tsx +47 -14
  33. package/src/views/pagesMember/message/detail.tsx +43 -25
  34. package/src/views/pagesMember/message/index.tsx +107 -98
  35. package/src/views/pagesMember/message/message.scss +78 -179
  36. package/src/views/pagesMember/profile/profile.scss +43 -99
  37. package/src/views/pagesMember/profile/profile.tsx +68 -48
  38. package/src/views/pagesMember/settings/components/PasswordVerifyDialog.scss +14 -13
  39. package/src/views/pagesMember/settings/settings.scss +27 -68
  40. package/src/views/pagesMember/settings/settings.tsx +161 -36
@@ -1,7 +1,7 @@
1
- import { useLoad } from '@tarojs/taro'
1
+ import Taro, { useLoad } from '@tarojs/taro'
2
2
  import { Button, RichText, Text, View } from '@tarojs/components'
3
3
  import { useState } from 'react'
4
- import { navigateAppView, t } from '@liujitcn/kratos-taro-app-core'
4
+ import { homeTabPage, navigateAppView, t, useThemeStore } from '@liujitcn/kratos-taro-app-core'
5
5
  import { UniIcon } from '@liujitcn/kratos-taro-app-ui'
6
6
  import { defNotificationService } from '../../../api/base/v1/notification'
7
7
  import type { Notification } from '../../../rpc/base/v1/notification'
@@ -11,6 +11,7 @@ import './message.scss'
11
11
 
12
12
  /** Taro 站内信详情页面。 */
13
13
  export default function MessageDetailPage() {
14
+ const themeStore = useThemeStore()
14
15
  const [detail, setDetail] = useState<Notification>()
15
16
 
16
17
  useLoad((options) => {
@@ -53,32 +54,49 @@ export default function MessageDetailPage() {
53
54
  navigateAppView(detail.action_target, params)
54
55
  }
55
56
 
56
- if (!detail) return <View className='empty'>{t('core.status.loading')}</View>
57
+ /** 返回消息列表,页面栈为空时回到首页。 */
58
+ function onBack() {
59
+ void Taro.navigateBack({ fail: () => void Taro.reLaunch({ url: homeTabPage }) })
60
+ }
61
+
57
62
  return (
58
- <View className='detail-page'>
59
- <Text className='detail-title'>{detail.title}</Text>
60
- <View className='detail-meta'>
61
- <View className='detail-category' style={{ color: detail.category_color || undefined }}>
62
- <UniIcon
63
- className='detail-category__icon'
64
- type={resolveMessageCategoryIcon(detail.category_icon)}
65
- size={18}
66
- color={detail.category_color || '#64748b'}
67
- />
68
- <Text>{detail.category_name}</Text>
69
- </View>
70
- <Text>{resolveSenderName(detail.sender_name)}</Text>
71
- <Text>{detail.received_at}</Text>
63
+ <View
64
+ className={`detail-page ${themeStore.theme === 'light' ? 'theme-light' : 'theme-dark'}`}
65
+ >
66
+ <View className={`k-page-nav ${process.env.TARO_ENV === 'weapp' ? 'k-page-nav--weapp' : ''}`}>
67
+ <View className='k-page-nav__back' aria-label={t('common.action.back')} onClick={onBack} />
68
+ <View className='k-page-nav__title'>{t('system.notification.title')}</View>
69
+ <View className='k-page-nav__side' aria-hidden />
72
70
  </View>
73
- {detail.content_format === MessageContentFormat.MESSAGE_CONTENT_FORMAT_RICH_TEXT ? (
74
- <RichText className='detail-content-rich' nodes={detail.content} />
71
+ {detail ? (
72
+ <>
73
+ <Text className='detail-title'>{detail.title}</Text>
74
+ <View className='detail-meta'>
75
+ <View className='detail-category' style={{ color: detail.category_color || undefined }}>
76
+ <UniIcon
77
+ className='detail-category__icon'
78
+ type={resolveMessageCategoryIcon(detail.category_icon)}
79
+ size={18}
80
+ color={detail.category_color || '#64748b'}
81
+ />
82
+ <Text>{detail.category_name}</Text>
83
+ </View>
84
+ <Text>{resolveSenderName(detail.sender_name)}</Text>
85
+ <Text>{detail.received_at}</Text>
86
+ </View>
87
+ {detail.content_format === MessageContentFormat.MESSAGE_CONTENT_FORMAT_RICH_TEXT ? (
88
+ <RichText className='detail-content-rich' nodes={detail.content} />
89
+ ) : (
90
+ <Text className='detail-content'>{detail.content}</Text>
91
+ )}
92
+ {detail.action_type === MessageActionType.MESSAGE_ACTION_TYPE_VIEW_KEY && (
93
+ <Button className='detail-action' onClick={openAction}>
94
+ {t('common.action.view')}
95
+ </Button>
96
+ )}
97
+ </>
75
98
  ) : (
76
- <Text className='detail-content'>{detail.content}</Text>
77
- )}
78
- {detail.action_type === MessageActionType.MESSAGE_ACTION_TYPE_VIEW_KEY && (
79
- <Button className='detail-action' onClick={openAction}>
80
- {t('common.action.view')}
81
- </Button>
99
+ <View className='detail-loading'>{t('core.status.loading')}</View>
82
100
  )}
83
101
  </View>
84
102
  )
@@ -1,7 +1,8 @@
1
+ import type { CSSProperties } from 'react'
1
2
  import { useDidShow } from '@tarojs/taro'
2
- import { Button, ScrollView, Text, View } from '@tarojs/components'
3
+ import { Button, Text, View } from '@tarojs/components'
3
4
  import { useRef, useState } from 'react'
4
- import { navigateAppView, t } from '@liujitcn/kratos-taro-app-core'
5
+ import { getMpCapsuleRightGap, navigateAppView, t, useThemeStore } from '@liujitcn/kratos-taro-app-core'
5
6
  import { UniIcon } from '@liujitcn/kratos-taro-app-ui'
6
7
  import { defNotificationService } from '../../../api/base/v1/notification'
7
8
  import type { Notification, NotificationCategory } from '../../../rpc/base/v1/notification'
@@ -12,6 +13,10 @@ import './message.scss'
12
13
 
13
14
  /** Taro 站内信收件箱页面。 */
14
15
  export default function MessageInboxPage() {
16
+ const themeStore = useThemeStore()
17
+ /** MP-WEIXIN 原生胶囊按钮右侧避让宽度,写入 --mp-capsule-gap 供 .k-top 预留空间。 */
18
+ const capsuleGap = getMpCapsuleRightGap()
19
+ const topNavStyle = { '--mp-capsule-gap': `${capsuleGap}px` } as CSSProperties
15
20
  const [items, setItems] = useState<Notification[]>([])
16
21
  const [cursorId, setCursorId] = useState(0)
17
22
  const [loading, setLoading] = useState(false)
@@ -151,119 +156,123 @@ export default function MessageInboxPage() {
151
156
  }
152
157
 
153
158
  return (
154
- <View className='message-page'>
155
- <View className='message-header'>
159
+ <View
160
+ className={`message-page ${
161
+ themeStore.theme === 'light' ? 'theme-light' : 'theme-dark'
162
+ }`}
163
+ >
164
+ <View className='k-top message-header' style={topNavStyle}>
156
165
  <View className='message-header__title'>
157
- <Text className='message-title'>{t('system.notification.title')}</Text>
166
+ <Text className='k-top__t2'>{t('system.notification.title')}</Text>
158
167
  {unreadTotal > 0 && <View className='message-unread-dot' aria-hidden='true' />}
159
168
  </View>
160
169
  {selectedView !== NotificationView.NOTIFICATION_VIEW_ARCHIVED && unreadTotal > 0 && (
161
- <Button
162
- className='message-action message-action--read message-header__action'
170
+ <View
171
+ className='k-ch k-ch--pri'
163
172
  onClick={() => void markAllRead().catch(() => undefined)}
164
173
  >
165
174
  {t('system.notification.mark_all_read')}
166
- </Button>
167
- )}
168
- </View>
169
- <View className='message-controls'>
170
- <ScrollView className='message-category-scroll' scrollX showScrollbar={false}>
171
- <View className='message-category-list'>
172
- <Button
173
- className={categoryId === undefined ? 'message-category active' : 'message-category'}
174
- onClick={() => changeCategory()}
175
- >
176
- {t('system.notification.view.inbox')}
177
- </Button>
178
- {categoryOptions.map((category) => (
179
- <Button
180
- key={category.id}
181
- className={
182
- categoryId === category.id ? 'message-category active' : 'message-category'
183
- }
184
- onClick={() => changeCategory(category.id)}
185
- >
186
- <UniIcon
187
- className='message-category__icon'
188
- type={resolveMessageCategoryIcon(category.icon)}
189
- size={16}
190
- color={categoryId === category.id ? '#fff' : category.color || '#64748b'}
191
- />
192
- {category.name}
193
- </Button>
194
- ))}
195
175
  </View>
196
- </ScrollView>
197
- <View className='message-tabs'>
198
- {viewOptions.map((option) => (
199
- <Button
200
- key={option.value}
201
- className={selectedView === option.value ? 'message-tab active' : 'message-tab'}
202
- onClick={() => changeView(option.value)}
203
- >
204
- {t(option.key)}
205
- </Button>
206
- ))}
207
- </View>
176
+ )}
208
177
  </View>
209
- {items.map((item) => (
178
+ <View className='k-chips'>
210
179
  <View
211
- className='message-item'
212
- key={item.id}
213
- onClick={() => void openDetail(item).catch(() => undefined)}
180
+ className={`k-ch${categoryId === undefined ? ' k-ch--pri' : ''}`}
181
+ onClick={() => changeCategory()}
214
182
  >
215
- <View className='message-item__main'>
216
- <Text className={`message-item__title ${item.read_at ? '' : 'unread'}`}>
217
- {item.title}
218
- </Text>
219
- <Text className='message-item__time'>{item.received_at}</Text>
220
- </View>
221
- <View className='message-item__category'>
183
+ {t('system.notification.view.inbox')}
184
+ </View>
185
+ {categoryOptions.map((category) => (
186
+ <View
187
+ key={category.id}
188
+ className={`k-ch${categoryId === category.id ? ' k-ch--pri' : ''}`}
189
+ onClick={() => changeCategory(category.id)}
190
+ >
222
191
  <UniIcon
223
- className='message-item__category-icon'
224
- type={resolveMessageCategoryIcon(item.category_icon)}
192
+ type={resolveMessageCategoryIcon(category.icon)}
225
193
  size={16}
226
- color={item.category_color || '#64748b'}
194
+ color={category.color || '#64748b'}
227
195
  />
228
- <Text>{item.category_name}</Text>
196
+ {category.name}
229
197
  </View>
230
- <View className='message-item__actions'>
231
- {selectedView !== NotificationView.NOTIFICATION_VIEW_ARCHIVED && item.allow_archive && (
232
- <Button
233
- size='mini'
234
- onClick={(event) => {
235
- event.stopPropagation()
236
- void toggleArchive(item).catch(() => undefined)
237
- }}
238
- >
239
- {t('system.notification.action.archive')}
240
- </Button>
241
- )}
242
- {selectedView === NotificationView.NOTIFICATION_VIEW_ARCHIVED && (
243
- <Button
244
- size='mini'
245
- onClick={(event) => {
246
- event.stopPropagation()
247
- void toggleArchive(item).catch(() => undefined)
248
- }}
249
- >
250
- {t('system.notification.action.restore')}
251
- </Button>
252
- )}
253
- {item.allow_delete && (
254
- <Button
255
- size='mini'
256
- onClick={(event) => {
257
- event.stopPropagation()
258
- void deleteItem(item).catch(() => undefined)
259
- }}
260
- >
261
- {t('system.notification.action.delete')}
262
- </Button>
198
+ ))}
199
+ </View>
200
+ <View className='k-pills message-tabs'>
201
+ {viewOptions.map((option) => (
202
+ <View
203
+ key={option.value}
204
+ className={`k-pills__item message-tab${
205
+ selectedView === option.value ? ' k-pills__item--on' : ''
206
+ }`}
207
+ onClick={() => changeView(option.value)}
208
+ >
209
+ {t(option.key)}
210
+ </View>
211
+ ))}
212
+ </View>
213
+ <View className='k-msg-list'>
214
+ {items.map((item) => (
215
+ <View
216
+ className={`k-msg-item${item.read_at ? '' : ' k-msg-item--unread'}`}
217
+ key={item.id}
218
+ onClick={() => void openDetail(item).catch(() => undefined)}
219
+ >
220
+ <View className='k-msg-item__head'>
221
+ <View className='k-msg-item__icon'>
222
+ <UniIcon
223
+ type={resolveMessageCategoryIcon(item.category_icon)}
224
+ size={18}
225
+ color={item.category_color || '#64748b'}
226
+ />
227
+ </View>
228
+ <View className='message-item__body'>
229
+ <Text className='k-msg-item__title'>{item.title}</Text>
230
+ <Text className='k-msg-item__meta'>{item.category_name}</Text>
231
+ </View>
232
+ <Text className='k-msg-item__time'>{item.received_at}</Text>
233
+ </View>
234
+ {(selectedView === NotificationView.NOTIFICATION_VIEW_ARCHIVED ||
235
+ item.allow_archive ||
236
+ item.allow_delete) && (
237
+ <View className='k-msg-item__actions'>
238
+ {selectedView !== NotificationView.NOTIFICATION_VIEW_ARCHIVED && item.allow_archive && (
239
+ <Text
240
+ className='k-msg-item__action'
241
+ onClick={(event) => {
242
+ event.stopPropagation()
243
+ void toggleArchive(item).catch(() => undefined)
244
+ }}
245
+ >
246
+ {t('system.notification.action.archive')}
247
+ </Text>
248
+ )}
249
+ {selectedView === NotificationView.NOTIFICATION_VIEW_ARCHIVED && (
250
+ <Text
251
+ className='k-msg-item__action'
252
+ onClick={(event) => {
253
+ event.stopPropagation()
254
+ void toggleArchive(item).catch(() => undefined)
255
+ }}
256
+ >
257
+ {t('system.notification.action.restore')}
258
+ </Text>
259
+ )}
260
+ {item.allow_delete && (
261
+ <Text
262
+ className='k-msg-item__action'
263
+ onClick={(event) => {
264
+ event.stopPropagation()
265
+ void deleteItem(item).catch(() => undefined)
266
+ }}
267
+ >
268
+ {t('system.notification.action.delete')}
269
+ </Text>
270
+ )}
271
+ </View>
263
272
  )}
264
273
  </View>
265
- </View>
266
- ))}
274
+ ))}
275
+ </View>
267
276
  {!finished && (
268
277
  <Button
269
278
  className='load-more'
@@ -1,245 +1,144 @@
1
1
  .message-page {
2
2
  box-sizing: border-box;
3
3
  min-height: 100vh;
4
- padding: 16px 24px calc(120px + env(safe-area-inset-bottom));
5
- background: var(--kratos-color-background, #f7f8fa);
6
- color: var(--kratos-color-text, #1f2937);
4
+ padding: 16px 24px calc(200px + env(safe-area-inset-bottom));
5
+ background: var(--kratos-bg-gradient);
6
+ color: var(--kratos-color-text);
7
7
  }
8
8
 
9
9
  .message-header {
10
- display: flex;
11
- align-items: center;
12
- justify-content: space-between;
13
- gap: 20px;
14
10
  padding: 20px 4px 24px;
15
11
  }
12
+
16
13
  .message-header__title {
17
14
  display: flex;
18
15
  align-items: center;
19
16
  min-width: 0;
20
17
  }
21
- .message-title {
22
- display: block;
23
- color: var(--kratos-color-text, #1f2937);
24
- font-size: 40px;
25
- font-weight: 700;
26
- line-height: 1.35;
27
- }
18
+
28
19
  .message-unread-dot {
29
20
  width: 12px;
30
21
  height: 12px;
31
- margin-left: 8px;
22
+ margin-left: 12px;
32
23
  border-radius: 50%;
33
- background: #e5484d;
34
- }
35
- .message-controls {
36
- margin-bottom: 24px;
37
- }
38
- .message-category-scroll {
39
- width: 100%;
40
- white-space: nowrap;
41
- }
42
- .message-category-list {
43
- display: flex;
44
- gap: 12px;
45
- width: max-content;
46
- padding-bottom: 4px;
47
- }
48
- .message-category,
49
- .message-tabs,
50
- .message-item__actions {
51
- display: flex;
52
- align-items: center;
53
- }
54
- .message-category {
55
- flex-shrink: 0;
56
- width: auto;
57
- height: 64px;
58
- margin: 0;
59
- padding: 0 22px;
60
- border: 1px solid var(--kratos-color-border, #e2e8f0);
61
- border-radius: 32px;
62
- background: #fff;
63
- color: var(--kratos-color-text-muted, #6b7280);
64
- font-size: 24px;
65
- line-height: 64px;
66
- white-space: nowrap;
67
- }
68
- .message-category__icon,
69
- .message-item__category-icon {
70
- flex: 0 0 auto;
71
- margin-right: 8px;
72
- }
73
- .message-category.active {
74
- border-color: var(--kratos-color-primary, #27ba9b);
75
- background: var(--kratos-color-primary, #27ba9b);
76
- color: #fff;
24
+ background: var(--kratos-color-danger);
25
+ box-shadow: 0 0 16px var(--kratos-color-danger);
77
26
  }
27
+
78
28
  .message-tabs {
79
- gap: 12px;
80
- margin-top: 18px;
81
- padding: 6px;
82
- border-radius: 12px;
83
- background: #eef1f3;
84
- }
85
- .message-tab::after,
86
- .message-category::after,
87
- .message-action::after,
88
- .message-item__actions button::after,
89
- .load-more::after {
90
- border: 0;
91
- }
92
- .message-item__actions {
93
- flex-wrap: wrap;
94
- justify-content: flex-end;
95
- gap: 12px;
29
+ display: flex;
30
+ margin-top: 4px;
96
31
  }
32
+
97
33
  .message-tab {
98
- box-sizing: border-box;
99
34
  flex: 1;
100
- min-width: 0;
101
- height: 68px;
102
- margin: 0;
103
- padding: 0 12px;
104
- border: 0;
105
- border-radius: 8px;
106
- background: transparent;
107
- color: var(--kratos-color-text-muted, #6b7280);
108
- font-size: 26px;
109
- line-height: 68px;
110
- white-space: nowrap;
111
- }
112
- .message-tab.active {
113
- background: var(--kratos-color-primary, #27ba9b);
114
- color: #fff;
115
- }
116
- .message-action,
117
- .message-item__actions button {
118
- box-sizing: border-box;
119
- flex-shrink: 0;
120
- width: auto;
121
- height: 68px;
122
- margin: 0;
123
- padding: 0 20px;
124
- border: 0;
125
- border-radius: 8px;
126
- background: #eef1f3;
127
- color: var(--kratos-color-text, #1f2937);
128
- font-size: 24px;
129
- line-height: 68px;
130
- white-space: nowrap;
131
- }
132
- .message-action--read {
133
- background: #e8f8f4;
134
- color: var(--kratos-color-primary, #16806d);
135
- }
136
- .message-header__action {
137
- height: 56px;
138
- padding: 0 18px;
139
- line-height: 56px;
140
- }
141
- .message-item__actions button {
142
- height: 56px;
143
- padding: 0 16px;
144
- font-size: 22px;
145
- line-height: 56px;
146
- }
147
- .message-item {
148
- margin-bottom: 16px;
149
- padding: 28px;
150
- border-radius: 12px;
151
- background: #fff;
152
- box-shadow: 0 4px 16px rgba(31, 41, 55, 0.05);
153
35
  }
154
- .message-item__main {
155
- display: flex;
156
- align-items: center;
157
- justify-content: space-between;
158
- gap: 20px;
159
- }
160
- .message-item__title {
161
- display: block;
162
- min-width: 0;
36
+
37
+ .message-item__body {
163
38
  flex: 1;
164
- overflow: hidden;
165
- color: var(--kratos-color-text, #1f2937);
166
- text-overflow: ellipsis;
167
- white-space: nowrap;
168
- }
169
- .message-item__title.unread {
170
- color: var(--kratos-color-text, #1f2937);
171
- font-weight: 700;
172
- }
173
- .message-item__time,
174
- .message-item__category {
175
- color: var(--kratos-color-text-muted, #6b7280);
176
- font-size: 24px;
177
- }
178
- .message-item__time {
179
- flex-shrink: 0;
39
+ min-width: 0;
180
40
  }
181
- .message-item__category {
182
- display: flex;
183
- align-items: center;
184
- margin-top: 14px;
41
+
42
+ .message-item__body .k-msg-item__meta {
43
+ display: block;
185
44
  }
45
+
186
46
  .load-more {
187
47
  box-sizing: border-box;
188
48
  width: 100%;
189
- height: 72px;
49
+ height: 76px;
190
50
  margin-top: 24px;
191
51
  padding: 0 24px;
52
+ border: 1PX solid var(--kratos-color-border);
53
+ border-radius: 16px;
54
+ background: var(--kratos-color-surface-2);
55
+ color: var(--kratos-color-text);
56
+ font-size: 26px;
57
+ line-height: 74px;
58
+ }
59
+
60
+ .load-more::after {
192
61
  border: 0;
193
- border-radius: 8px;
194
- background: #eef1f3;
195
- color: var(--kratos-color-text, #1f2937);
196
- font-size: 28px;
197
- line-height: 72px;
198
62
  }
63
+
199
64
  .empty {
200
65
  padding: 120px 0;
201
- color: var(--kratos-color-text-muted, #6b7280);
66
+ color: var(--kratos-color-text-dim);
67
+ font-family: var(--kratos-font-mono);
202
68
  text-align: center;
203
69
  }
70
+
204
71
  .detail-page {
205
72
  box-sizing: border-box;
206
73
  min-height: 100vh;
207
74
  padding: 24px 30px calc(96px + env(safe-area-inset-bottom));
208
- background: var(--kratos-color-background, #f7f8fa);
75
+ background: var(--kratos-bg-gradient);
76
+ color: var(--kratos-color-text);
209
77
  }
78
+
79
+ .detail-loading {
80
+ padding: 120px 0;
81
+ color: var(--kratos-color-text-dim);
82
+ font-family: var(--kratos-font-mono);
83
+ text-align: center;
84
+ }
85
+
210
86
  .detail-title {
211
87
  display: block;
212
- color: var(--kratos-color-text, #1f2937);
88
+ padding-top: 16px;
89
+ color: var(--kratos-color-text);
213
90
  font-size: 42px;
214
- font-weight: 700;
91
+ font-weight: 800;
215
92
  line-height: 1.35;
216
93
  }
94
+
217
95
  .detail-meta {
218
96
  display: flex;
219
97
  flex-wrap: wrap;
220
98
  gap: 18px;
221
99
  margin: 24px 0 36px;
222
- color: var(--kratos-color-text-muted, #6b7280);
223
- font-size: 24px;
100
+ padding-bottom: 28px;
101
+ border-bottom: 1PX solid var(--kratos-color-border);
102
+ color: var(--kratos-color-text-muted);
103
+ font-size: 22px;
104
+ font-family: var(--kratos-font-mono);
224
105
  }
106
+
225
107
  .detail-category {
226
108
  display: inline-flex;
227
109
  align-items: center;
228
110
  }
111
+
229
112
  .detail-category__icon {
230
113
  margin-right: 8px;
231
114
  }
232
- .detail-content {
233
- color: var(--kratos-color-text, #1f2937);
234
- font-size: 30px;
235
- line-height: 1.8;
236
- white-space: pre-wrap;
237
- overflow-wrap: anywhere;
238
- }
115
+
116
+ .detail-content,
239
117
  .detail-content-rich {
240
118
  display: block;
241
- color: var(--kratos-color-text, #1f2937);
119
+ padding: 28px;
120
+ border: 1PX solid var(--kratos-color-border);
121
+ border-radius: 20px;
122
+ background: var(--kratos-color-surface);
123
+ color: var(--kratos-color-text);
242
124
  font-size: 30px;
243
125
  line-height: 1.8;
244
126
  overflow-wrap: anywhere;
245
127
  }
128
+
129
+ .detail-content {
130
+ white-space: pre-wrap;
131
+ }
132
+
133
+ .detail-action {
134
+ width: 100%;
135
+ height: 88px;
136
+ margin-top: 36px;
137
+ border: 1PX solid var(--kratos-color-border-accent);
138
+ border-radius: 20px;
139
+ background: var(--kratos-color-primary-soft);
140
+ color: var(--kratos-color-primary);
141
+ font-size: 28px;
142
+ font-weight: 700;
143
+ line-height: 86px;
144
+ }