apptify 0.5.0 → 0.5.4
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/README.md +39 -308
- package/dist/apptify.css +1 -1
- package/dist/apptify.js +2298 -2140
- package/dist/components/AppleCard.vue.d.ts +76 -0
- package/dist/components/button.d.ts +3 -3
- package/dist/components/content.d.ts +0 -90
- package/dist/components/foundation.d.ts +201 -129
- package/dist/components/link.d.ts +31 -0
- package/dist/components/overlays.d.ts +8 -2
- package/dist/core/context.d.ts +11 -0
- package/dist/core/overlay-surface.d.ts +6 -0
- package/dist/core/popup-motion.d.ts +5 -5
- package/dist/core/popup-placement.d.ts +3 -2
- package/dist/index.d.ts +144 -79
- package/docs/COMPONENTS.md +24 -10
- package/docs/INPUT-WORKSHOP.md +59 -0
- package/docs/PLAYGROUND-TEMPLATE.md +32 -55
- package/docs/VALIDATION.md +1 -1
- package/package.json +14 -1
- package/templates/playground/README.md +14 -10
- package/templates/playground/index.html +1 -1
- package/templates/playground/package.json +6 -2
- package/templates/playground/source-snapshot.json +139 -54
- package/templates/playground/{playground → src}/App.vue +5 -4
- package/templates/playground/{playground → src}/ComponentDemo.vue +8 -9
- package/templates/playground/{playground → src}/catalog.ts +2 -3
- package/templates/playground/src/components/ComponentIndex.vue +43 -0
- package/templates/playground/src/components/DirectoryDialog.vue +20 -0
- package/templates/playground/src/components/PageFooter.vue +7 -0
- package/templates/playground/{playground → src}/components/UserMenu.vue +11 -11
- package/templates/playground/src/editor/AppleInputExample.vue +78 -0
- package/templates/playground/src/editor/AppleInputPreview.vue +82 -0
- package/templates/playground/src/editor/ComponentDocumentLink.vue +19 -0
- package/templates/playground/src/editor/ComponentWorkshop.vue +81 -0
- package/templates/playground/src/editor/ConfigurableEditor.vue +35 -0
- package/templates/playground/src/editor/LiveVueEditor.vue +133 -0
- package/templates/playground/src/editor/apple-input-source.ts +2 -0
- package/templates/playground/src/editor/apple-input.ts +48 -0
- package/templates/playground/src/editor/contract.ts +14 -0
- package/templates/playground/src/editor/documents.ts +20 -0
- package/templates/playground/src/editor/input-playground.ts +59 -0
- package/templates/playground/src/editor/runtime.ts +5 -0
- package/templates/playground/src/editor/sections.ts +10 -0
- package/templates/playground/{playground → src}/style.css +40 -39
- package/templates/playground/{playground → src}/views/[...all].vue +2 -2
- package/templates/playground/src/views/component-docs/[component].vue +162 -0
- package/templates/playground/src/views/components.vue +148 -0
- package/templates/playground/src/views/index.vue +73 -0
- package/templates/playground/src/views/settings.vue +225 -0
- package/templates/playground/tooling/playground-editor.mjs +114 -0
- package/templates/playground/tooling/prepare-input-source.mjs +38 -0
- package/templates/playground/tsconfig.json +2 -2
- package/templates/playground/vite.config.ts +3 -1
- package/tooling/playground-editor.mjs +114 -0
- package/tooling/prepare-input-source.mjs +38 -0
- package/tooling/prepare-playground.mjs +45 -19
- package/tooling/test-create-apptify.mjs +86 -0
- package/tooling/test-playground-package.mjs +13 -7
- package/templates/playground/playground/components/ComponentIndex.vue +0 -62
- package/templates/playground/playground/components/PageFooter.vue +0 -3
- package/templates/playground/playground/views/components.vue +0 -126
- package/templates/playground/playground/views/index.vue +0 -75
- package/templates/playground/playground/views/settings.vue +0 -98
- /package/templates/playground/{playground → src}/components/not-found-paper-scene.vue +0 -0
- /package/templates/playground/{playground → src}/components/not-found-paper-story.ts +0 -0
- /package/templates/playground/{playground → src}/env.d.ts +0 -0
- /package/templates/playground/{playground → src}/main.ts +0 -0
- /package/templates/playground/{playground → src}/router/index.ts +0 -0
package/README.md
CHANGED
|
@@ -1,49 +1,18 @@
|
|
|
1
1
|
# Apptify
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
面向桌面与移动端的 Vue 3 组件库,采用 Apple 风格设计,统一使用 `<apple-*>` 标签。支持主题切换、减少动效、表单、图片预览与多层弹窗;支持 JavaScript、TypeScript 和 Options API。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[npm](https://www.npmjs.com/package/apptify) · [组件 API](docs/COMPONENTS.md) · [应用模板](docs/PLAYGROUND-TEMPLATE.md)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 本地运行与安装
|
|
10
|
-
|
|
11
|
-
项目尚未发布到 npm。不要把 `npm install apptify` 当成已发布包的安装方式。
|
|
12
|
-
|
|
13
|
-
建议使用 Node.js 22 LTS 或 24 LTS;测试工具不支持奇数版本的 Node.js。
|
|
14
|
-
|
|
15
|
-
在本仓库执行:
|
|
7
|
+
## 安装
|
|
16
8
|
|
|
17
9
|
```sh
|
|
18
|
-
npm
|
|
19
|
-
npm run dev
|
|
10
|
+
npm install apptify vue@^3.5 vuetify@^3.9
|
|
20
11
|
```
|
|
21
12
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
在另一个项目中使用本地包:
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
# 在本仓库构建并生成 apptify-0.4.0.tgz
|
|
28
|
-
npm run build
|
|
29
|
-
npm pack
|
|
30
|
-
|
|
31
|
-
# 在消费项目执行,将路径替换为实际包路径
|
|
32
|
-
npm install /absolute/path/apptify/apptify-0.4.0.tgz
|
|
33
|
-
npm install vue@^3.5 vuetify@^3.9
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Vue 与 Vuetify 是 peer dependencies。图标使用 `lucide-vue-next`,桌面图片预览的缩放与手势使用 `@panzoom/panzoom`,手机端使用图片边界约束的 Pointer Events 手势。本库没有要求安装 Vuetify 插件或导入其完整样式,也不需要 `<v-app>`。
|
|
37
|
-
|
|
38
|
-
## 复制完整应用模板
|
|
39
|
-
|
|
40
|
-
安装本地 tgz 后执行 `npx --no-install apptify-playground ../my-app`,再在新目录执行 `npm install`、`npm run dev`。复制项目携带本地库归档与完整源码/资源,能独立安装、类型检查与构建。目标目录必须为空。
|
|
41
|
-
|
|
42
|
-
完整步骤、删除示例页面后的导航与路由行为,以及本地打包验收见[模板交付说明](docs/PLAYGROUND-TEMPLATE.md)。组件库的常规接入方式保持可用。
|
|
13
|
+
Vue 与 Vuetify 是 peer dependencies。Vuetify 仅用于 Ripple,无需安装其插件、导入完整样式或使用 `<v-app>`。
|
|
43
14
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
JavaScript 和 TypeScript 项目都可直接使用。消费项目不需要 TypeScript、`tsconfig.json` 或 `<script setup>`;普通 `<script>` 与 Options API 是完整支持的用法。随包提供的类型声明也可以为 JavaScript 编辑器提供补全。
|
|
15
|
+
## 快速接入
|
|
47
16
|
|
|
48
17
|
```js
|
|
49
18
|
// src/main.js
|
|
@@ -52,30 +21,23 @@ import { createAppleUI } from 'apptify'
|
|
|
52
21
|
import 'apptify/style.css'
|
|
53
22
|
import App from './App.vue'
|
|
54
23
|
|
|
55
|
-
|
|
56
|
-
theme: 'system',
|
|
57
|
-
|
|
58
|
-
persist: true,
|
|
59
|
-
storageKey: 'my-app:appearance',
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
createApp(App).use(apple).mount('#app')
|
|
24
|
+
createApp(App)
|
|
25
|
+
.use(createAppleUI({ theme: 'system', motion: 'auto', persist: true }))
|
|
26
|
+
.mount('#app')
|
|
63
27
|
```
|
|
64
28
|
|
|
65
29
|
```vue
|
|
66
30
|
<!-- App.vue -->
|
|
67
31
|
<template>
|
|
68
32
|
<apple-provider>
|
|
69
|
-
<
|
|
70
|
-
<apple-
|
|
71
|
-
<apple-
|
|
72
|
-
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
</apple-container>
|
|
78
|
-
</main>
|
|
33
|
+
<apple-container>
|
|
34
|
+
<apple-card title="个人资料">
|
|
35
|
+
<apple-input v-model="name" label="姓名" />
|
|
36
|
+
<template #actions>
|
|
37
|
+
<apple-button @click="save">保存</apple-button>
|
|
38
|
+
</template>
|
|
39
|
+
</apple-card>
|
|
40
|
+
</apple-container>
|
|
79
41
|
</apple-provider>
|
|
80
42
|
</template>
|
|
81
43
|
|
|
@@ -91,277 +53,46 @@ export default {
|
|
|
91
53
|
</script>
|
|
92
54
|
```
|
|
93
55
|
|
|
94
|
-
|
|
56
|
+
`AppleProvider` 提供主题与弹层宿主,无需额外添加 `AppleOverlayHost`。插件全局注册组件,也支持命名导入并局部注册。嵌套 Provider 内可用 `appleKey` 注入局部上下文,或在 `setup()` 中使用 `useApple()`。
|
|
95
57
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`this.$apple` 始终指向插件级上下文。局部 Provider 内的组件如需使用局部主题、通知或弹层,使用 Options API 注入:
|
|
99
|
-
|
|
100
|
-
```js
|
|
101
|
-
import { appleKey } from 'apptify'
|
|
102
|
-
|
|
103
|
-
export default {
|
|
104
|
-
inject: { apple: { from: appleKey } },
|
|
105
|
-
methods: {
|
|
106
|
-
showMessage() {
|
|
107
|
-
this.apple.notify('使用当前 Provider 的通知')
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
也导出 `useApple()` 供 Composition API 的 `setup()` 使用,但不需要为接入组件库重写现有 Options API 页面。
|
|
114
|
-
|
|
115
|
-
## 自动路由(与 Vuetify 项目相同)
|
|
116
|
-
|
|
117
|
-
采用 `vite-plugin-pages` + Vue Router 4,默认扫描 `src/views`。新页面自动生成路由,不需要维护 routes 数组;普通 JavaScript 和 Options API 页面同样适用。
|
|
118
|
-
|
|
119
|
-
```sh
|
|
120
|
-
npm install vue-router@^4.5
|
|
121
|
-
npm install -D vite-plugin-pages@^0.32.4
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
```js
|
|
125
|
-
// vite.config.js
|
|
126
|
-
import { defineConfig } from 'vite'
|
|
127
|
-
import vue from '@vitejs/plugin-vue'
|
|
128
|
-
import apptifyRoutes from 'apptify/vite'
|
|
129
|
-
|
|
130
|
-
export default defineConfig({
|
|
131
|
-
plugins: [apptifyRoutes(), vue()],
|
|
132
|
-
})
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
```js
|
|
136
|
-
// src/router/index.js
|
|
137
|
-
import { createRouter, createWebHistory } from 'vue-router'
|
|
138
|
-
import routes from 'virtual:generated-pages'
|
|
139
|
-
|
|
140
|
-
export default createRouter({
|
|
141
|
-
history: createWebHistory(import.meta.env.BASE_URL),
|
|
142
|
-
routes,
|
|
143
|
-
})
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
```js
|
|
147
|
-
// src/main.js
|
|
148
|
-
import { createApp } from 'vue'
|
|
149
|
-
import { createAppleUI } from 'apptify'
|
|
150
|
-
import 'apptify/style.css'
|
|
151
|
-
import App from './App.vue'
|
|
152
|
-
import router from './router'
|
|
153
|
-
|
|
154
|
-
createApp(App).use(createAppleUI()).use(router).mount('#app')
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
```vue
|
|
158
|
-
<!-- src/App.vue:全局主题和弹层跨页面保留 -->
|
|
159
|
-
<template>
|
|
160
|
-
<apple-provider>
|
|
161
|
-
<router-view />
|
|
162
|
-
</apple-provider>
|
|
163
|
-
</template>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
| 页面文件 | 路由 |
|
|
167
|
-
| --- | --- |
|
|
168
|
-
| `src/views/index.vue` | `/` |
|
|
169
|
-
| `src/views/about.vue` | `/about` |
|
|
170
|
-
| `src/views/users/[id].vue` | `/users/:id` |
|
|
171
|
-
| `src/views/[...all].vue` | 未匹配地址(404 页面) |
|
|
172
|
-
|
|
173
|
-
页面内使用 `<router-link to="/about">关于</router-link>`,Options API 可通过 `this.$router.push('/about')` 跳转、通过 `this.$route.params.id` 读取参数。页面无需再包根 `apple-provider`。
|
|
174
|
-
|
|
175
|
-
TypeScript 项目在 `src/vite-env.d.ts` 增加 `/// <reference types="vite-plugin-pages/client" />`。需要改扫描目录时传入 `apptifyRoutes({ dirs: [{ dir: 'src/pages', baseRoute: '' }] })`;支持其余 Pages 选项,包括排除文件和扩展路由。
|
|
176
|
-
|
|
177
|
-
已经接入 `Pages()` 的项目继续使用现有配置即可,避免重复添加生成插件。`apptify/vite` 只负责构建时生成路由,浏览器组件入口不加载此插件。
|
|
178
|
-
|
|
179
|
-
本仓库演示也使用同一套机制:`playground/App.vue` 放 Provider 与 RouterView,`playground/router/index.ts` 创建 Router,工作台页面位于 `playground/views/index.vue`。演示扫描目录设为 `playground/views`。
|
|
180
|
-
|
|
181
|
-
使用 history 模式部署时,服务器需要将页面 URL 回退到 `index.html`,并保留 `/api` 和静态资源自己的处理规则;你的 Spring Boot 项目同样需要配置该回退。无法配置回退时,可改用 `createWebHashHistory(import.meta.env.BASE_URL)`。
|
|
182
|
-
|
|
183
|
-
## 主题与动效
|
|
184
|
-
|
|
185
|
-
共享响应式状态统一使用 `ref`:`theme`、`motion`、`overlays.entries` 和 `portalTarget`。在 JavaScript 中通过 `.value` 访问;嵌套访问(如 `$apple.theme.value.name`)也需显式使用 `.value`。
|
|
186
|
-
|
|
187
|
-
内置主题为 `light`、`dark`、`graphite`、`rose`;`system` 表示跟随系统浅深色。主题即时生效,不需要刷新页面。设置 `persist: true` 才会保存主题名称、动效等级并同步其他标签页的同名存储设置;自定义主题定义应通过初始化 `themes` 配置或启动时的 `register()` 再次提供。
|
|
58
|
+
## 常用 API
|
|
188
59
|
|
|
189
60
|
```js
|
|
190
61
|
this.$apple.theme.value.set('dark')
|
|
191
|
-
this.$apple.theme.value.register('forest', {
|
|
192
|
-
accent: '#237047',
|
|
193
|
-
'accent-text': '#ffffff',
|
|
194
|
-
bg: '#f4f7f5',
|
|
195
|
-
surface: '#ffffff',
|
|
196
|
-
}, 'light')
|
|
197
|
-
this.$apple.theme.value.set('forest')
|
|
198
62
|
this.$apple.motion.value.set('reduced')
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
`register(name, tokens, scheme)` 自动补齐对应浅色或深色主题的默认 token。可覆盖 `bg`、`surface`、`surface-alt`、`text`、`secondary`、`border`、`accent`、`accent-text`、`danger`、`success`、`warning`、`shadow`、`radius`,对应 `--apple-*` CSS 变量。注册后先调用 `set()` 才会切换;`system` 是保留名称。
|
|
202
|
-
|
|
203
|
-
| 动效值 | 行为 |
|
|
204
|
-
| --- | --- |
|
|
205
|
-
| `auto` | 自动遵循系统减少动态效果偏好。 |
|
|
206
|
-
| `full` | 在全局策略与系统偏好允许时使用完整动效。 |
|
|
207
|
-
| `reduced` | 减少位移、缩放和持续动态,保留必要状态反馈。 |
|
|
208
|
-
| `none` | 关闭动效,包括按钮 Ripple。 |
|
|
209
|
-
| `inherit` | 组件默认值,继承当前 Provider 的策略;不是全局配置值。 |
|
|
210
|
-
|
|
211
|
-
全局 `none` / `reduced` 是动效上限,安全优先。组件可以再降低动效,但 `motion="full"` 不能越过全局限制或系统的减少动态效果偏好。支持 `motion` 的组件以 [API 表](docs/COMPONENTS.md) 为准;静态布局组件不需要动效属性。
|
|
212
|
-
|
|
213
|
-
```vue
|
|
214
|
-
<apple-card motion="none" zoom="none" title="静态内容" />
|
|
215
|
-
<apple-button :ripple="false">仅关闭这个按钮的波纹</apple-button>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Dialog 与反向通道
|
|
219
|
-
|
|
220
|
-
```js
|
|
221
|
-
const dialog = this.$apple.dialog({
|
|
222
|
-
title: '删除文件?',
|
|
223
|
-
message: '此操作不能撤销。',
|
|
224
|
-
confirmText: '删除',
|
|
225
|
-
cancelText: '取消',
|
|
226
|
-
tone: 'danger',
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
const confirmed = await dialog.result
|
|
230
|
-
// 默认确认返回 true,取消返回 false,关闭按钮 / Escape 返回 undefined。
|
|
231
|
-
if (confirmed === true) this.$apple.notify('文件已删除', { tone: 'success' })
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
每次调用创建独立层。`dialog` 句柄含 `id`、`close(value?)`、`update(patch)` 与 `result` Promise。`this.$apple.overlays.closeTop()` 只关闭最上面的非通知弹层;已有层不会被新层覆盖。声明式 `<apple-dialog v-model="opened">` 与命令式弹层共享焦点栈和滚动锁。
|
|
235
|
-
|
|
236
|
-
自定义弹层组件接收 `close`、`sendMessage` 两个 prop。下面的编辑组件通过反向通道请求父调用方保存,父调用方再打开第二层确认。
|
|
237
|
-
|
|
238
|
-
```vue
|
|
239
|
-
<!-- ProfileEditor.vue -->
|
|
240
|
-
<template>
|
|
241
|
-
<apple-input v-model="name" label="姓名" />
|
|
242
|
-
<apple-button :loading="saving" @click="save">保存资料</apple-button>
|
|
243
|
-
</template>
|
|
244
|
-
|
|
245
|
-
<script>
|
|
246
|
-
export default {
|
|
247
|
-
props: {
|
|
248
|
-
initialName: { type: String, default: '' },
|
|
249
|
-
close: { type: Function, required: true },
|
|
250
|
-
sendMessage: { type: Function, required: true },
|
|
251
|
-
},
|
|
252
|
-
data() { return { name: this.initialName, saving: false } },
|
|
253
|
-
methods: {
|
|
254
|
-
async save() {
|
|
255
|
-
this.saving = true
|
|
256
|
-
try {
|
|
257
|
-
const result = await this.sendMessage('profile:save', { name: this.name })
|
|
258
|
-
if (result?.saved) this.close(result)
|
|
259
|
-
} finally {
|
|
260
|
-
this.saving = false
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
}
|
|
265
|
-
</script>
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
```js
|
|
269
|
-
import ProfileEditor from './ProfileEditor.vue'
|
|
63
|
+
this.$apple.ripple.value.set(false) // 全局关闭点击波纹
|
|
64
|
+
this.$apple.notify('保存成功', { tone: 'success' })
|
|
270
65
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
async editProfile() {
|
|
274
|
-
const editor = this.$apple.dialog({
|
|
275
|
-
title: '编辑资料',
|
|
276
|
-
component: ProfileEditor,
|
|
277
|
-
props: { initialName: '小明' },
|
|
278
|
-
confirmText: '',
|
|
279
|
-
cancelText: '取消',
|
|
280
|
-
onMessage: async (channel, payload) => {
|
|
281
|
-
if (channel !== 'profile:save') return
|
|
282
|
-
const confirmation = this.$apple.dialog({
|
|
283
|
-
title: '保存修改?',
|
|
284
|
-
message: `将姓名更新为 ${payload.name}。`,
|
|
285
|
-
})
|
|
286
|
-
if (await confirmation.result !== true) return { saved: false }
|
|
287
|
-
// 在这里执行实际业务请求;该示例只返回结果。
|
|
288
|
-
return { saved: true, name: payload.name }
|
|
289
|
-
},
|
|
290
|
-
})
|
|
291
|
-
const result = await editor.result
|
|
292
|
-
if (result?.saved) this.$apple.notify('资料已保存', { tone: 'success' })
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
}
|
|
66
|
+
const dialog = this.$apple.dialog({ title: '保存修改?', cancelText: '取消' })
|
|
67
|
+
const confirmed = await dialog.result // 确认 true,取消 false,关闭 undefined
|
|
296
68
|
```
|
|
297
69
|
|
|
298
|
-
|
|
70
|
+
内置主题:`light`、`dark`、`graphite`、`rose`;`system` 跟随系统。全局动效:`auto`、`full`、`reduced`、`none`。共享状态使用 ref,在 JavaScript 中通过 `.value` 访问。
|
|
299
71
|
|
|
300
|
-
|
|
301
|
-
const unsubscribe = this.$apple.onMessage('profile:read', () => ({ name: '小明' }))
|
|
302
|
-
const responses = this.$apple.sendMessage('profile:read')
|
|
303
|
-
console.log(responses[0].name)
|
|
304
|
-
unsubscribe()
|
|
305
|
-
```
|
|
72
|
+
可通过 `createAppleUI({ ripple: false })` 或 `apple.ripple.value.set(false)` 全局禁用点击波纹。切换到 `reduced` 或系统开启减少动态效果时,波纹自动关闭,但可手动开启;只有 `none` 模式禁止开启。`persist: true` 会同时保存该偏好。
|
|
306
73
|
|
|
307
|
-
|
|
74
|
+
Props、事件、插槽、自定义主题与弹层消息回传见[组件 API](docs/COMPONENTS.md)。
|
|
308
75
|
|
|
309
|
-
##
|
|
310
|
-
|
|
311
|
-
```js
|
|
312
|
-
const notice = this.$apple.notify('正在同步', { duration: 0 })
|
|
313
|
-
notice.update({ message: '同步完成', tone: 'success', duration: 2500 })
|
|
314
|
-
// 或 notice.close()
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
通知独立堆叠,默认 4 秒,`duration: 0` 常驻,悬停或键盘焦点进入时暂停倒计时。需要动作按钮时直接使用 `<apple-snackbar action="撤销" @action="undo" />`;命令式 `notify()` 当前没有 action 配置。
|
|
318
|
-
|
|
319
|
-
```vue
|
|
320
|
-
<apple-image
|
|
321
|
-
:gallery="[{ src: '/images/workspace.webp', alt: '桌面工作区' }, { src: '/images/detail.webp', alt: '工作区细节' }]"
|
|
322
|
-
v-model:index="imageIndex"
|
|
323
|
-
gallery-layout="compact"
|
|
324
|
-
/>
|
|
76
|
+
## 创建完整应用
|
|
325
77
|
|
|
78
|
+
```sh
|
|
79
|
+
npm create apptify@latest ./my-app
|
|
80
|
+
cd my-app
|
|
81
|
+
npm install
|
|
82
|
+
npm run dev
|
|
326
83
|
```
|
|
327
84
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
## 移动端与边界
|
|
331
|
-
|
|
332
|
-
- 弹层、抽屉、底部面板和通知考虑安全区;布局基于可用宽度,而不是把屏幕横竖方向等同于设备类型。
|
|
333
|
-
- 提供下拉刷新、无限加载、侧滑操作、验证码、级联选择、ActionSheet 等组件,保留桌面按钮或键盘入口。
|
|
334
|
-
- 日期、时间、颜色和基础 Select 使用浏览器原生选择能力;弹出界面随操作系统变化,不宣称它们在所有平台都长得完全一样。
|
|
335
|
-
- Upload 负责本地文件选择、拖放与限制校验,不自动上传文件;Table 支持客户端排序、分页、固定行高虚拟滚动与列宽拖拽,不含服务端分页协议。
|
|
336
|
-
- 导入阶段避免直接访问浏览器全局;这不等于已完成 SSR 全部组件的服务端渲染、hydration、跨请求隔离和主题首屏验证。SSR 接入时每个请求创建独立实例,并自行验证水合行为。
|
|
337
|
-
- 本项目不是浏览器、屏幕阅读器和实体设备兼容矩阵认证。即使桌面/移动视口检查通过,也不代表已覆盖 iOS Safari、Android WebView、触控笔、软键盘与所有真机组合。
|
|
338
|
-
|
|
339
|
-
## 从旧项目迁移
|
|
85
|
+
也可运行 `npx --package=apptify apptify-playground ./my-app`。
|
|
340
86
|
|
|
341
|
-
|
|
342
|
-
| --- | --- |
|
|
343
|
-
| `<apple-card title subtitle text icon icon-color>` | 保留这些属性与默认 slot,并增加 `media`、`title`、`icon`、`actions` slots。 |
|
|
344
|
-
| `zoom="big/small/none"`、`shadow="normal/static/focused/none"` | 继续支持;新默认 `zoom="small"`,不保证旧尺寸和缩放数值完全一致。 |
|
|
345
|
-
| `icon="mdi-home"` | 不再识别 MDI 字符串。导入 Lucide 组件并通过 `:icon="Home"` 传入;Card 的字符串 icon 被当作图片 URL。 |
|
|
346
|
-
| `globalTheme` / `fancyAnimation` 模块常量 | 改用响应式 `theme.value.set()` / `motion.value.set()`;不需要刷新,也不要再直接读写旧 localStorage 键。 |
|
|
347
|
-
| `sendMessage('showSnackbar', { type, text })` | 在 `this.$apple.sendMessage()` 或当前注入上下文上兼容;`showSnackBar`、`showMessage` 别名也保留。 |
|
|
348
|
-
| `sendMessage('showDiag', { title, message })` | 仍可通过当前上下文发送;推荐使用返回独立句柄与 Promise 的 `dialog()`。 |
|
|
349
|
-
| `btn: [{ bgColor, text, clickEvent }]` | **不直接兼容**。简单对话框用 `confirmText` / `cancelText`,复杂交互用声明式 `#footer` 或动态组件。 |
|
|
350
|
-
| `sendMessage('closeDiag')` | 关闭当前上下文最上面的非通知弹层;不会一次关闭全部层。 |
|
|
351
|
-
| `<e-img src squared gallery index>` | 改为 `<apple-image :gallery="{ src, alt }">`,描述放在图片对象内;不注册旧 `e-img` 名称。 |
|
|
87
|
+
目标目录需为空。模板含导航、设置、账号表单、404 和组件示例,可直接编辑;账号功能需接入自己的后端。复制项目携带库归档,可独立安装。页面开发与部署见[应用模板](docs/PLAYGROUND-TEMPLATE.md)。
|
|
352
88
|
|
|
353
|
-
##
|
|
89
|
+
## 本地开发
|
|
354
90
|
|
|
355
91
|
```sh
|
|
356
|
-
npm
|
|
357
|
-
npm
|
|
358
|
-
npm run build
|
|
359
|
-
npm run test:e2e
|
|
360
|
-
npm run test:package
|
|
92
|
+
npm ci
|
|
93
|
+
npm run dev
|
|
361
94
|
```
|
|
362
95
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
### 图片轮播
|
|
96
|
+
建议 Node.js 22 或 24 LTS。检查使用 `npm run typecheck`、`npm test`、`npm run build`、`npm run test:e2e` 和 `npm run test:package`;`npm pack` 自动构建并准备模板。生成器位于 [`packages/create-apptify`](packages/create-apptify/README.md),使用 `npm run test:create` 验证。历史验证记录见[验证文档](docs/VALIDATION.md)。
|
|
366
97
|
|
|
367
|
-
|
|
98
|
+
MIT 许可。Apptify 不是 Apple 官方产品。
|