@liujitcn/kratos-taro-app-core 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 (45) hide show
  1. package/dist/build.mjs +4 -2
  2. package/package.json +1 -1
  3. package/src/components/BootstrapStatus.scss +3 -3
  4. package/src/components/BootstrapStatus.tsx +3 -1
  5. package/src/components/KratosTabBar.scss +32 -13
  6. package/src/components/KratosTabBar.tsx +34 -3
  7. package/src/components/MfaRecoveryCodesDialog.scss +11 -10
  8. package/src/components/MfaSetupPanel.scss +4 -4
  9. package/src/components/PasswordVerifyDialog.scss +21 -21
  10. package/src/navigation.ts +6 -3
  11. package/src/pages.ts +4 -2
  12. package/src/rpc/base/v1/config.ts +1 -1
  13. package/src/rpc/base/v1/file.ts +1 -1
  14. package/src/rpc/base/v1/language.ts +1 -1
  15. package/src/rpc/base/v1/login.ts +1 -1
  16. package/src/rpc/base/v1/mcp.ts +1 -1
  17. package/src/rpc/base/v1/mfa.ts +1 -1
  18. package/src/rpc/base/v1/oauth.ts +1 -1
  19. package/src/rpc/base/v1/secret_crypto.ts +1 -1
  20. package/src/rpc/base/v1/sse.ts +1 -1
  21. package/src/rpc/common/v1/common.ts +1 -1
  22. package/src/rpc/common/v1/types.ts +1 -1
  23. package/src/rpc/google/protobuf/empty.ts +1 -1
  24. package/src/rpc/google/protobuf/struct.ts +2 -2
  25. package/src/rpc/google/protobuf/wrappers.ts +1 -1
  26. package/src/rpc/system/app/v1/auth.ts +1 -1
  27. package/src/rpc/system/app/v1/base_area.ts +1 -1
  28. package/src/rpc/system/app/v1/base_dict.ts +1 -1
  29. package/src/rpc/system/app/v1/base_menu.ts +1 -1
  30. package/src/rpc/system/common/v1/common.ts +1 -1
  31. package/src/stores/index.ts +1 -0
  32. package/src/stores/theme.ts +108 -0
  33. package/src/styles/base.scss +90 -5
  34. package/src/styles/components.scss +765 -0
  35. package/src/utils/http.ts +3 -0
  36. package/src/utils/index.ts +19 -0
  37. package/src/utils/navigation.ts +12 -0
  38. package/src/views/pages/index/index.scss +69 -73
  39. package/src/views/pages/index/index.tsx +50 -34
  40. package/src/views/pages/login/login.scss +109 -142
  41. package/src/views/pages/login/login.tsx +142 -82
  42. package/src/views/pages/login/protocal.scss +14 -14
  43. package/src/views/pages/login/protocal.tsx +16 -3
  44. package/src/views/pages/webview/webview.scss +6 -5
  45. package/src/views/pages/webview/webview.tsx +3 -1
package/src/utils/http.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  } from './auth'
12
12
  import { saveCurrentRoute } from './navigation'
13
13
  import { getLocaleRequestHeaders, t } from '../locales'
14
+ import { useThemeStore } from '../stores/theme'
14
15
 
15
16
  const apiBasePath = process.env.VITE_APP_BASE_API || '/api'
16
17
  const apiTargetUrl = process.env.VITE_APP_API_URL || ''
@@ -265,11 +266,13 @@ async function promptRelogin(): Promise<void> {
265
266
  if (isPromptingRelogin) return
266
267
  isPromptingRelogin = true
267
268
  try {
269
+ const theme = useThemeStore.getState().theme
268
270
  const modal = await Taro.showModal({
269
271
  title: t('common.title.notice'),
270
272
  content: t('core.auth.session_expired'),
271
273
  showCancel: false,
272
274
  confirmText: t('core.auth.login_again'),
275
+ confirmColor: theme === 'light' ? '#039e8c' : '#28f0d4',
273
276
  })
274
277
  if (!modal.confirm) return
275
278
  await new Promise((resolve) => setTimeout(resolve, 80))
@@ -1,3 +1,5 @@
1
+ import Taro from '@tarojs/taro'
2
+
1
3
  const configuredStaticUrl =
2
4
  process.env.VITE_APP_STATIC_URL || process.env.VITE_APP_API_URL || ''
3
5
 
@@ -44,3 +46,20 @@ export function formatSrc(src: string): string {
44
46
  ? `${staticOrigin}${src}`
45
47
  : `${staticOrigin}/${src.replace(/^\/+/, '')}`
46
48
  }
49
+
50
+ /**
51
+ * 微信小程序原生胶囊按钮(右上角 ⋯ / ◯)右侧避让宽度(px)。
52
+ * 自定义导航栏(navigationStyle: 'custom')在 weapp 下仍会显示原生胶囊,
53
+ * 页头右侧若放置可交互图标/按钮需预留该宽度,避免与胶囊重叠;
54
+ * 非 weapp 平台返回 0,无需特殊处理。
55
+ */
56
+ export function getMpCapsuleRightGap(): number {
57
+ if (process.env.TARO_ENV !== 'weapp') return 0
58
+ try {
59
+ const menu = Taro.getMenuButtonBoundingClientRect()
60
+ const { windowWidth } = Taro.getSystemInfoSync()
61
+ return Math.max(0, Math.round(windowWidth - menu.left + 12))
62
+ } catch {
63
+ return 0
64
+ }
65
+ }
@@ -80,6 +80,18 @@ export function navigateToLogin(redirectUrl?: string): void {
80
80
  })
81
81
  }
82
82
 
83
+ /** 跳转登录页并替换当前页面:路由守卫使用,避免反复拦截时在页面栈堆积登录页。 */
84
+ export function redirectToLogin(redirectUrl?: string): void {
85
+ if (typeof redirectUrl === 'string' && redirectUrl) saveLoginRedirectUrl(redirectUrl)
86
+ else saveCurrentRoute()
87
+ void Taro.redirectTo({
88
+ url: LOGIN_PAGE,
89
+ fail: () => {
90
+ void Taro.reLaunch({ url: LOGIN_PAGE })
91
+ },
92
+ })
93
+ }
94
+
83
95
  /** 返回首页。 */
84
96
  export function switchTabToHome(): Promise<TaroGeneral.CallbackResult> {
85
97
  return Taro.reLaunch({ url: homeTabPage })
@@ -1,122 +1,118 @@
1
+ page {
2
+ background-color: #eef3f8;
3
+ }
4
+
1
5
  .home-page {
6
+ position: relative;
2
7
  min-height: 100vh;
3
- padding: 44px 28px 56px;
4
- box-sizing: border-box;
5
- background-color: #f7f7f8;
8
+ overflow: hidden;
9
+ background: var(--kratos-bg-gradient);
10
+ }
11
+
12
+ .home-page--weapp .home-content {
13
+ /* 44PX 是系统导航栏高度,88px 按设计稿转换为 44 物理像素。 */
14
+ padding-top: calc(44PX + 88px);
6
15
  }
7
16
 
8
- .home-page--weapp {
9
- padding-top: calc(44px + 44PX);
17
+ .home-content {
18
+ position: relative;
19
+ z-index: 1;
20
+ padding: calc(env(safe-area-inset-top) + 20px) 32px 220px;
21
+ }
22
+
23
+ .home-top {
24
+ padding: 8px 4px 24px;
25
+ }
26
+
27
+ /* 页面大标题 */
28
+ .home-top__title {
29
+ margin-top: 14px;
30
+ color: var(--kratos-color-text);
31
+ font-size: 44px;
32
+ font-weight: 800;
33
+ letter-spacing: -0.5px;
10
34
  }
11
35
 
12
36
  .home-hero {
37
+ padding: 40px 36px;
38
+ }
39
+
40
+ .home-hero__main {
13
41
  display: flex;
14
42
  align-items: center;
15
- padding: 34px 28px;
16
- border-radius: 12px;
17
- background-color: #27ba9b;
18
- box-shadow: 0 8px 18px rgba(39, 186, 155, 0.18);
19
43
  }
20
44
 
45
+ /* 简洁 Logo:圆角方块 + 细描边 */
21
46
  .home-logo {
22
47
  flex: 0 0 auto;
23
- width: 92px;
24
- height: 92px;
25
- border-radius: 20px;
26
- background-color: #fff;
48
+ width: 104px;
49
+ height: 104px;
50
+ border-radius: 26px;
51
+ border: 1PX solid var(--kratos-color-border-accent);
52
+ background: var(--kratos-color-surface-2);
27
53
  }
28
54
 
29
55
  .home-hero__copy {
30
56
  min-width: 0;
31
- margin-left: 22px;
57
+ margin-left: 26px;
32
58
  }
33
59
 
34
- .home-title,
35
60
  .home-subtitle {
36
61
  display: block;
37
- }
38
-
39
- .home-title {
40
- margin-top: 8px;
41
- color: #fff;
42
- font-size: 40px;
43
- font-weight: 600;
44
- }
45
-
46
- .home-subtitle {
47
- margin-top: 10px;
48
- color: rgba(255, 255, 255, 0.86);
49
- font-size: 24px;
62
+ color: var(--kratos-color-text-muted);
63
+ font-size: 26px;
64
+ line-height: 1.6;
50
65
  }
51
66
 
52
67
  .home-section {
53
- margin-top: 24px;
68
+ margin-top: 36px;
54
69
  }
55
70
 
56
71
  .home-section__title {
57
72
  display: block;
58
- margin: 0 8px 14px;
59
- color: #26332f;
60
- font-size: 28px;
61
- font-weight: 600;
62
- }
63
-
64
- .home-info-list,
65
- .home-demo-list {
66
- overflow: hidden;
67
- border-radius: 10px;
68
- background-color: #fff;
69
- }
70
-
71
- .home-info-row {
72
- display: flex;
73
- align-items: center;
74
- justify-content: space-between;
75
- padding: 26px 24px;
76
- border-bottom: 1px solid #edf1ef;
77
-
78
- &:last-child {
79
- border-bottom: 0;
80
- }
73
+ margin: 0 4px 16px;
74
+ color: var(--kratos-color-text-muted);
75
+ font-size: 26px;
76
+ font-weight: 700;
81
77
  }
82
78
 
83
- .home-info-label {
84
- color: #66736f;
85
- font-size: 26px;
79
+ .home-info-list {
80
+ padding: 8px 28px;
86
81
  }
87
82
 
88
- .home-info-value {
89
- color: #26332f;
90
- font-size: 26px;
91
- font-weight: 500;
83
+ .home-demo-list {
84
+ padding: 10px 28px;
92
85
  }
93
86
 
94
87
  .home-demo-item {
95
88
  display: flex;
96
89
  align-items: flex-start;
97
- padding: 26px 24px;
98
- border-bottom: 1px solid #edf1ef;
90
+ padding: 28px 0;
91
+ border-top: 1PX solid var(--kratos-color-border);
99
92
 
100
- &:last-child {
101
- border-bottom: 0;
93
+ &:first-child {
94
+ border-top: 0;
102
95
  }
103
96
  }
104
97
 
105
98
  .home-demo-dot {
106
99
  flex: 0 0 auto;
107
- width: 42px;
108
- height: 42px;
109
- border-radius: 50%;
110
- background-color: #e8f8f4;
111
- color: #16806d;
100
+ width: 48px;
101
+ height: 48px;
102
+ border-radius: 14px;
103
+ background: var(--kratos-color-primary-soft);
104
+ border: 1PX solid var(--kratos-color-primary-edge);
105
+ color: var(--kratos-color-primary);
112
106
  font-size: 24px;
113
- line-height: 42px;
107
+ font-family: var(--kratos-font-mono);
108
+ font-weight: 700;
109
+ line-height: 46px;
114
110
  text-align: center;
115
111
  }
116
112
 
117
113
  .home-demo-copy {
118
114
  min-width: 0;
119
- margin-left: 18px;
115
+ margin-left: 22px;
120
116
  }
121
117
 
122
118
  .home-demo-title,
@@ -125,14 +121,14 @@
125
121
  }
126
122
 
127
123
  .home-demo-title {
128
- color: #26332f;
124
+ color: var(--kratos-color-text);
129
125
  font-size: 28px;
130
- font-weight: 500;
126
+ font-weight: 600;
131
127
  }
132
128
 
133
129
  .home-demo-desc {
134
130
  margin-top: 8px;
135
- color: #8a9691;
131
+ color: var(--kratos-color-text-muted);
136
132
  font-size: 24px;
137
133
  line-height: 1.5;
138
134
  }
@@ -2,7 +2,7 @@ import { Image, Text, View } from '@tarojs/components'
2
2
  import { useLoad } from '@tarojs/taro'
3
3
  import { useEffect, useState } from 'react'
4
4
  import defaultLogo from '@liujitcn/kratos-taro-app-core/static/images/logo_icon.png'
5
- import { useSettingStore } from '../../../stores'
5
+ import { useSettingStore, useThemeStore } from '../../../stores'
6
6
  import { formatSrc } from '../../../utils'
7
7
  import './index.scss'
8
8
  import { useI18n } from '../../../locales'
@@ -10,6 +10,7 @@ import { useI18n } from '../../../locales'
10
10
  /** 应用首页。 */
11
11
  export default function HomePage() {
12
12
  const { t } = useI18n()
13
+ const themeStore = useThemeStore()
13
14
  const settings = useSettingStore((state) => state.data)
14
15
  const loadData = useSettingStore((state) => state.loadData)
15
16
  const mainTitle = settings?.get('mainTitle') || t('core.home.main_title')
@@ -37,46 +38,61 @@ export default function HomePage() {
37
38
  [t('core.home.account_capability'), t('core.home.account_capability_description')],
38
39
  [t('core.home.static_home'), t('core.home.static_home_description')],
39
40
  ]
40
-
41
41
  return (
42
- <View className={`home-page${process.env.TARO_ENV === 'weapp' ? ' home-page--weapp' : ''}`}>
43
- <View className='home-hero'>
44
- <Image
45
- className='home-logo'
46
- src={appLogo}
47
- mode='aspectFit'
48
- onError={() => setAppLogo(defaultLogo)}
49
- />
50
- <View className='home-hero__copy'>
51
- <Text className='home-title'>{mainTitle}</Text>
52
- <Text className='home-subtitle'>{subTitle}</Text>
42
+ <View
43
+ className={`home-page${process.env.TARO_ENV === 'weapp' ? ' home-page--weapp' : ''} ${
44
+ themeStore.theme === 'light' ? 'theme-light' : 'theme-dark'
45
+ }`}
46
+ >
47
+ <View className='k-grid-bg' aria-hidden />
48
+ <View className='home-content'>
49
+ <View className='home-top'>
50
+ <View className='home-top__title'>{mainTitle}</View>
53
51
  </View>
54
- </View>
55
52
 
56
- <View className='home-section'>
57
- <Text className='home-section__title'>{t('core.home.tech_stack')}</Text>
58
- <View className='home-info-list'>
59
- {stack.map(([label, value]) => (
60
- <View className='home-info-row' key={label}>
61
- <Text className='home-info-label'>{label}</Text>
62
- <Text className='home-info-value'>{value}</Text>
53
+ <View className='k-glass k-glass--lit home-hero'>
54
+ <View className='k-cnr k-cnr--tl' aria-hidden />
55
+ <View className='k-cnr k-cnr--tr' aria-hidden />
56
+ <View className='k-cnr k-cnr--bl' aria-hidden />
57
+ <View className='k-cnr k-cnr--br' aria-hidden />
58
+ <View className='home-hero__main'>
59
+ <Image
60
+ className='home-logo'
61
+ src={appLogo}
62
+ mode='aspectFit'
63
+ onError={() => setAppLogo(defaultLogo)}
64
+ />
65
+ <View className='home-hero__copy'>
66
+ <Text className='home-subtitle'>{subTitle}</Text>
63
67
  </View>
64
- ))}
68
+ </View>
65
69
  </View>
66
- </View>
67
70
 
68
- <View className='home-section'>
69
- <Text className='home-section__title'>{t('core.home.demo_scope')}</Text>
70
- <View className='home-demo-list'>
71
- {demos.map(([title, description], index) => (
72
- <View className='home-demo-item' key={title}>
73
- <View className='home-demo-dot'>{index + 1}</View>
74
- <View className='home-demo-copy'>
75
- <Text className='home-demo-title'>{title}</Text>
76
- <Text className='home-demo-desc'>{description}</Text>
71
+ <View className='home-section'>
72
+ <Text className='home-section__title'>{t('core.home.tech_stack')}</Text>
73
+ <View className='k-glass home-info-list'>
74
+ {stack.map(([label, value]) => (
75
+ <View className='k-field' key={label}>
76
+ <Text className='k-field__k'>{label}</Text>
77
+ <Text className='k-field__v'>{value}</Text>
77
78
  </View>
78
- </View>
79
- ))}
79
+ ))}
80
+ </View>
81
+ </View>
82
+
83
+ <View className='home-section'>
84
+ <Text className='home-section__title'>{t('core.home.demo_scope')}</Text>
85
+ <View className='k-glass home-demo-list'>
86
+ {demos.map(([title, description], index) => (
87
+ <View className='home-demo-item' key={title}>
88
+ <View className='home-demo-dot'>{index + 1}</View>
89
+ <View className='home-demo-copy'>
90
+ <Text className='home-demo-title'>{title}</Text>
91
+ <Text className='home-demo-desc'>{description}</Text>
92
+ </View>
93
+ </View>
94
+ ))}
95
+ </View>
80
96
  </View>
81
97
  </View>
82
98
  </View>