@liujitcn/kratos-uni-app-core 0.0.79 → 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.
@@ -0,0 +1,66 @@
1
+ /* ============================================================
2
+ * Kratos 移动端主题令牌(暗黑 / 明亮双主题)
3
+ * 变量挂在页面根类 .theme-dark / .theme-light 上,页面样式只消费变量。
4
+ * ============================================================ */
5
+
6
+ /* 暗黑主题:深色数据驾驶舱 */
7
+ .theme-dark {
8
+ --kratos-color-background: #060a12;
9
+ --kratos-bg-gradient: linear-gradient(180deg, #081120 0%, #060a12 40%);
10
+ --kratos-color-surface: rgba(255, 255, 255, 0.035);
11
+ --kratos-color-surface-2: rgba(255, 255, 255, 0.06);
12
+ --kratos-color-surface-solid: #070d18;
13
+ --kratos-color-border: rgba(255, 255, 255, 0.08);
14
+ --kratos-color-border-accent: rgba(120, 230, 215, 0.16);
15
+ --kratos-color-primary: #28f0d4;
16
+ --kratos-color-primary-deep: #13c7b4;
17
+ --kratos-color-on-primary: #031513;
18
+ --kratos-color-primary-soft: rgba(40, 240, 212, 0.08);
19
+ --kratos-color-primary-soft-2: rgba(40, 240, 212, 0.1);
20
+ --kratos-color-primary-edge: rgba(40, 240, 212, 0.3);
21
+ --kratos-color-info: #45c2ff;
22
+ --kratos-color-warning: #ffb648;
23
+ --kratos-color-danger: #ff4d6d;
24
+ --kratos-color-danger-soft: rgba(255, 77, 109, 0.1);
25
+ --kratos-color-violet: #9b8cff;
26
+ --kratos-color-text: #e9f4f6;
27
+ --kratos-color-text-muted: #8aa0b4;
28
+ --kratos-color-text-dim: #4e6378;
29
+ --kratos-color-track: rgba(255, 255, 255, 0.06);
30
+ --kratos-color-mask: rgba(2, 6, 12, 0.55);
31
+ --kratos-dock-bg: rgba(10, 18, 30, 0.72);
32
+ --kratos-glow: 0 0 24px rgba(40, 240, 212, 0.35);
33
+ --kratos-glow-soft: 0 0 40px rgba(40, 240, 212, 0.06);
34
+ --kratos-font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
35
+ }
36
+
37
+ /* 明亮主题 */
38
+ .theme-light {
39
+ --kratos-color-background: #eef3f8;
40
+ --kratos-bg-gradient: linear-gradient(180deg, #f4f9fd 0%, #e9f1f8 60%);
41
+ --kratos-color-surface: #ffffff;
42
+ --kratos-color-surface-2: #eef4fa;
43
+ --kratos-color-surface-solid: #ffffff;
44
+ --kratos-color-border: #e3eaf2;
45
+ --kratos-color-border-accent: rgba(0, 150, 134, 0.28);
46
+ --kratos-color-primary: #039e8c;
47
+ --kratos-color-primary-deep: #00b3a0;
48
+ --kratos-color-on-primary: #ffffff;
49
+ --kratos-color-primary-soft: rgba(3, 158, 140, 0.08);
50
+ --kratos-color-primary-soft-2: rgba(3, 158, 140, 0.1);
51
+ --kratos-color-primary-edge: rgba(3, 158, 140, 0.3);
52
+ --kratos-color-info: #1a93d8;
53
+ --kratos-color-warning: #d9880f;
54
+ --kratos-color-danger: #e0324f;
55
+ --kratos-color-danger-soft: rgba(224, 50, 79, 0.1);
56
+ --kratos-color-violet: #5f4fe0;
57
+ --kratos-color-text: #102232;
58
+ --kratos-color-text-muted: #5a7083;
59
+ --kratos-color-text-dim: #9aabbb;
60
+ --kratos-color-track: #e8eef5;
61
+ --kratos-color-mask: rgba(16, 34, 50, 0.45);
62
+ --kratos-dock-bg: rgba(255, 255, 255, 0.82);
63
+ --kratos-glow: 0 10px 26px rgba(0, 120, 110, 0.14);
64
+ --kratos-glow-soft: none;
65
+ --kratos-font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
66
+ }
@@ -83,3 +83,24 @@ export const formatSrc = (src: string) => {
83
83
 
84
84
  return `${staticOrigin}/${src.replace(/^\/+/, '')}`
85
85
  }
86
+
87
+ /**
88
+ * 微信小程序原生胶囊按钮(右上角 ⋯ / ◯)右侧避让宽度(px)。
89
+ * 自定义导航栏(navigationStyle: 'custom')在 MP-WEIXIN 下仍会显示原生胶囊,
90
+ * 页头右侧若放置可交互图标/按钮需预留该宽度,避免与胶囊重叠;
91
+ * 非 MP-WEIXIN 平台返回 0,无需特殊处理。
92
+ */
93
+ export const getMpCapsuleRightGap = (): number => {
94
+ // #ifdef MP-WEIXIN
95
+ try {
96
+ const menu = uni.getMenuButtonBoundingClientRect()
97
+ const { windowWidth } = uni.getSystemInfoSync()
98
+ return Math.max(0, Math.round(windowWidth - menu.left + 12))
99
+ } catch {
100
+ return 0
101
+ }
102
+ // #endif
103
+ // #ifndef MP-WEIXIN
104
+ return 0
105
+ // #endif
106
+ }
@@ -77,5 +77,21 @@ export const navigateToLogin = (redirectUrl?: string) => {
77
77
  })
78
78
  }
79
79
 
80
+ /** 跳转登录页并替换当前页面:路由守卫使用,避免反复拦截时在页面栈堆积登录页。 */
81
+ export const redirectToLogin = (redirectUrl?: string) => {
82
+ // 模板直接绑定时会传入点击事件对象,只有字符串才是明确的回跳地址。
83
+ if (typeof redirectUrl === 'string' && redirectUrl) {
84
+ saveLoginRedirectUrl(redirectUrl)
85
+ } else {
86
+ saveCurrentRoute()
87
+ }
88
+ uni.redirectTo({
89
+ url: LOGIN_PAGE,
90
+ fail: () => {
91
+ uni.reLaunch({ url: LOGIN_PAGE })
92
+ },
93
+ })
94
+ }
95
+
80
96
  /** 返回首页。 */
81
97
  export const switchTabToHome = () => uni.reLaunch({ url: homeTabPage })
@@ -1,12 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import { onLoad } from '@dcloudio/uni-app'
3
3
  import { computed, ref, watch } from 'vue'
4
- import { useSettingStore } from '../../../stores'
4
+ import { useSettingStore, useThemeStore } from '../../../stores'
5
5
  import defaultLogo from '../../../static/images/logo_icon.png'
6
6
  import { formatSrc } from '../../../utils'
7
7
  import { useI18n } from '../../../locales'
8
8
 
9
9
  const settingStore = useSettingStore()
10
+ const themeStore = useThemeStore()
10
11
  const { t } = useI18n()
11
12
  const mainTitle = computed(() => settingStore.getData('mainTitle') || t('core.home.main_title'))
12
13
  const subTitle = computed(() => settingStore.getData('subTitle') || t('core.home.sub_title'))
@@ -37,59 +38,73 @@ onLoad(() => {
37
38
  </script>
38
39
 
39
40
  <template>
40
- <view class="page">
41
- <view class="hero">
42
- <image class="logo" :src="appLogo" mode="aspectFit" @error="handleLogoError" />
43
- <view class="hero-copy">
44
- <text class="title">{{ mainTitle }}</text>
45
- <text class="subtitle">{{ subTitle }}</text>
41
+ <view class="home-page" :class="themeStore.themeClass">
42
+ <view class="k-grid-bg" aria-hidden="true"></view>
43
+ <view class="home-content">
44
+ <view class="home-top">
45
+ <view class="home-top__title">{{ mainTitle }}</view>
46
46
  </view>
47
- </view>
48
47
 
49
- <view class="section">
50
- <text class="section-title">{{ t('core.home.tech_stack') }}</text>
51
- <view class="info-list">
52
- <view class="info-row">
53
- <text class="info-label">{{ t('core.home.framework') }}</text>
54
- <text class="info-value">uni-app + Vue 3</text>
55
- </view>
56
- <view class="info-row">
57
- <text class="info-label">{{ t('core.home.language') }}</text>
58
- <text class="info-value">TypeScript</text>
59
- </view>
60
- <view class="info-row">
61
- <text class="info-label">{{ t('core.home.state_management') }}</text>
62
- <text class="info-value">Pinia</text>
63
- </view>
64
- <view class="info-row">
65
- <text class="info-label">{{ t('core.home.style_solution') }}</text>
66
- <text class="info-value">Sass + rpx</text>
48
+ <view class="k-glass k-glass--lit home-hero">
49
+ <view class="k-cnr k-cnr--tl" aria-hidden="true"></view>
50
+ <view class="k-cnr k-cnr--tr" aria-hidden="true"></view>
51
+ <view class="k-cnr k-cnr--bl" aria-hidden="true"></view>
52
+ <view class="k-cnr k-cnr--br" aria-hidden="true"></view>
53
+ <view class="home-hero__main">
54
+ <image class="home-logo" :src="appLogo" mode="aspectFit" @error="handleLogoError" />
55
+ <view class="home-hero__copy">
56
+ <text class="home-subtitle">{{ subTitle }}</text>
57
+ </view>
67
58
  </view>
68
59
  </view>
69
- </view>
70
60
 
71
- <view class="section">
72
- <text class="section-title">{{ t('core.home.demo_scope') }}</text>
73
- <view class="demo-list">
74
- <view class="demo-item">
75
- <view class="demo-dot">1</view>
76
- <view class="demo-copy">
77
- <text class="demo-title">{{ t('core.home.cross_platform') }}</text>
78
- <text class="demo-desc">{{ t('core.home.cross_platform_description') }}</text>
61
+ <view class="home-section">
62
+ <text class="home-section__title">{{ t('core.home.tech_stack') }}</text>
63
+ <view class="k-glass home-info-list">
64
+ <view class="k-field">
65
+ <text class="k-field__k">{{ t('core.home.framework') }}</text>
66
+ <text class="k-field__v">uni-app + Vue 3</text>
79
67
  </view>
80
- </view>
81
- <view class="demo-item">
82
- <view class="demo-dot">2</view>
83
- <view class="demo-copy">
84
- <text class="demo-title">{{ t('core.home.account_capability') }}</text>
85
- <text class="demo-desc">{{ t('core.home.account_capability_description') }}</text>
68
+ <view class="k-field">
69
+ <text class="k-field__k">{{ t('core.home.language') }}</text>
70
+ <text class="k-field__v">TypeScript</text>
71
+ </view>
72
+ <view class="k-field">
73
+ <text class="k-field__k">{{ t('core.home.state_management') }}</text>
74
+ <text class="k-field__v">Pinia</text>
75
+ </view>
76
+ <view class="k-field">
77
+ <text class="k-field__k">{{ t('core.home.style_solution') }}</text>
78
+ <text class="k-field__v">Sass + rpx</text>
86
79
  </view>
87
80
  </view>
88
- <view class="demo-item">
89
- <view class="demo-dot">3</view>
90
- <view class="demo-copy">
91
- <text class="demo-title">{{ t('core.home.static_home') }}</text>
92
- <text class="demo-desc">{{ t('core.home.static_home_description') }}</text>
81
+ </view>
82
+
83
+ <view class="home-section">
84
+ <text class="home-section__title">{{ t('core.home.demo_scope') }}</text>
85
+ <view class="k-glass home-demo-list">
86
+ <view class="home-demo-item">
87
+ <view class="home-demo-dot">1</view>
88
+ <view class="home-demo-copy">
89
+ <text class="home-demo-title">{{ t('core.home.cross_platform') }}</text>
90
+ <text class="home-demo-desc">{{ t('core.home.cross_platform_description') }}</text>
91
+ </view>
92
+ </view>
93
+ <view class="home-demo-item">
94
+ <view class="home-demo-dot">2</view>
95
+ <view class="home-demo-copy">
96
+ <text class="home-demo-title">{{ t('core.home.account_capability') }}</text>
97
+ <text class="home-demo-desc">{{
98
+ t('core.home.account_capability_description')
99
+ }}</text>
100
+ </view>
101
+ </view>
102
+ <view class="home-demo-item">
103
+ <view class="home-demo-dot">3</view>
104
+ <view class="home-demo-copy">
105
+ <text class="home-demo-title">{{ t('core.home.static_home') }}</text>
106
+ <text class="home-demo-desc">{{ t('core.home.static_home_description') }}</text>
107
+ </view>
93
108
  </view>
94
109
  </view>
95
110
  </view>
@@ -98,151 +113,132 @@ onLoad(() => {
98
113
  </template>
99
114
 
100
115
  <style lang="scss">
101
- page {
102
- background-color: #f7f7f8;
116
+ .home-page {
117
+ position: relative;
118
+ min-height: 100vh;
119
+ overflow: hidden;
120
+ background: var(--kratos-bg-gradient);
103
121
  }
104
122
 
105
- .page {
106
- min-height: 100vh;
107
- padding: 44rpx 28rpx 56rpx;
108
- box-sizing: border-box;
123
+ .home-content {
124
+ position: relative;
125
+ z-index: 1;
126
+ padding: calc(env(safe-area-inset-top) + 20rpx) 32rpx 220rpx;
109
127
 
110
128
  /* #ifdef MP-WEIXIN */
111
- padding-top: calc(44rpx + 44px);
129
+ padding-top: calc(44px + 24rpx);
112
130
  /* #endif */
113
131
  }
114
132
 
115
- .hero {
116
- display: flex;
117
- align-items: center;
118
- padding: 34rpx 28rpx;
119
- border-radius: 12rpx;
120
- background-color: #27ba9b;
121
- box-shadow: 0 8rpx 18rpx rgba(39, 186, 155, 0.18);
122
- }
123
-
124
- .logo {
125
- flex: 0 0 auto;
126
- width: 92rpx;
127
- height: 92rpx;
128
- border-radius: 20rpx;
129
- background-color: #fff;
133
+ .home-top {
134
+ padding: 8rpx 4rpx 24rpx;
130
135
  }
131
136
 
132
- .hero-copy {
133
- min-width: 0;
134
- margin-left: 22rpx;
137
+ /* 页面大标题 */
138
+ .home-top__title {
139
+ margin-top: 14rpx;
140
+ color: var(--kratos-color-text);
141
+ font-size: 44rpx;
142
+ font-weight: 800;
143
+ letter-spacing: -0.5rpx;
135
144
  }
136
145
 
137
- .eyebrow,
138
- .title,
139
- .subtitle {
140
- display: block;
146
+ .home-hero {
147
+ padding: 40rpx 36rpx;
141
148
  }
142
149
 
143
- .eyebrow {
144
- color: rgba(255, 255, 255, 0.8);
145
- font-size: 20rpx;
146
- letter-spacing: 2rpx;
147
- }
148
-
149
- .title {
150
- margin-top: 8rpx;
151
- color: #fff;
152
- font-size: 40rpx;
153
- font-weight: 600;
150
+ .home-hero__main {
151
+ display: flex;
152
+ align-items: center;
154
153
  }
155
154
 
156
- .subtitle {
157
- margin-top: 10rpx;
158
- color: rgba(255, 255, 255, 0.86);
159
- font-size: 24rpx;
155
+ /* 简洁 Logo:圆角方块 + 细描边 */
156
+ .home-logo {
157
+ flex: 0 0 auto;
158
+ width: 104rpx;
159
+ height: 104rpx;
160
+ border-radius: 26rpx;
161
+ border: 1rpx solid var(--kratos-color-border-accent);
162
+ background: var(--kratos-color-surface-2);
160
163
  }
161
164
 
162
- .section {
163
- margin-top: 24rpx;
165
+ .home-hero__copy {
166
+ min-width: 0;
167
+ margin-left: 26rpx;
164
168
  }
165
169
 
166
- .section-title {
170
+ .home-subtitle {
167
171
  display: block;
168
- margin: 0 8rpx 14rpx;
169
- color: #26332f;
170
- font-size: 28rpx;
171
- font-weight: 600;
172
- }
173
-
174
- .info-list,
175
- .demo-list {
176
- overflow: hidden;
177
- border-radius: 10rpx;
178
- background-color: #fff;
172
+ color: var(--kratos-color-text-muted);
173
+ font-size: 26rpx;
174
+ line-height: 1.6;
179
175
  }
180
176
 
181
- .info-row {
182
- display: flex;
183
- align-items: center;
184
- justify-content: space-between;
185
- padding: 26rpx 24rpx;
186
- border-bottom: 1rpx solid #edf1ef;
177
+ .home-section {
178
+ margin-top: 36rpx;
187
179
  }
188
180
 
189
- .info-row:last-child {
190
- border-bottom: 0;
181
+ .home-section__title {
182
+ display: block;
183
+ margin: 0 4rpx 16rpx;
184
+ color: var(--kratos-color-text-muted);
185
+ font-size: 26rpx;
186
+ font-weight: 700;
191
187
  }
192
188
 
193
- .info-label {
194
- color: #66736f;
195
- font-size: 26rpx;
189
+ .home-info-list {
190
+ padding: 8rpx 28rpx;
196
191
  }
197
192
 
198
- .info-value {
199
- color: #26332f;
200
- font-size: 26rpx;
201
- font-weight: 500;
193
+ .home-demo-list {
194
+ padding: 10rpx 28rpx;
202
195
  }
203
196
 
204
- .demo-item {
197
+ .home-demo-item {
205
198
  display: flex;
206
199
  align-items: flex-start;
207
- padding: 26rpx 24rpx;
208
- border-bottom: 1rpx solid #edf1ef;
209
- }
200
+ padding: 28rpx 0;
201
+ border-top: 1rpx solid var(--kratos-color-border);
210
202
 
211
- .demo-item:last-child {
212
- border-bottom: 0;
203
+ &:first-child {
204
+ border-top: 0;
205
+ }
213
206
  }
214
207
 
215
- .demo-dot {
208
+ .home-demo-dot {
216
209
  flex: 0 0 auto;
217
- width: 42rpx;
218
- height: 42rpx;
219
- border-radius: 50%;
220
- background-color: #e8f8f4;
221
- color: #16806d;
210
+ width: 48rpx;
211
+ height: 48rpx;
212
+ border-radius: 14rpx;
213
+ background: var(--kratos-color-primary-soft);
214
+ border: 1rpx solid var(--kratos-color-primary-edge);
215
+ color: var(--kratos-color-primary);
222
216
  font-size: 24rpx;
223
- line-height: 42rpx;
217
+ font-family: var(--kratos-font-mono);
218
+ font-weight: 700;
219
+ line-height: 46rpx;
224
220
  text-align: center;
225
221
  }
226
222
 
227
- .demo-copy {
223
+ .home-demo-copy {
228
224
  min-width: 0;
229
- margin-left: 18rpx;
225
+ margin-left: 22rpx;
230
226
  }
231
227
 
232
- .demo-title,
233
- .demo-desc {
228
+ .home-demo-title,
229
+ .home-demo-desc {
234
230
  display: block;
235
231
  }
236
232
 
237
- .demo-title {
238
- color: #26332f;
233
+ .home-demo-title {
234
+ color: var(--kratos-color-text);
239
235
  font-size: 28rpx;
240
- font-weight: 500;
236
+ font-weight: 600;
241
237
  }
242
238
 
243
- .demo-desc {
239
+ .home-demo-desc {
244
240
  margin-top: 8rpx;
245
- color: #8a9691;
241
+ color: var(--kratos-color-text-muted);
246
242
  font-size: 24rpx;
247
243
  line-height: 1.5;
248
244
  }