apptify 0.6.1 → 0.7.0
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 +1 -1
- package/THIRD_PARTY_LICENSES.txt +23 -0
- package/dist/apptify.css +1 -1
- package/dist/apptify.js +2395 -2451
- package/dist/components/AppleCard.vue.d.ts +1 -1
- package/dist/components/content.d.ts +81 -20
- package/dist/components/forms.d.ts +2 -2
- package/dist/components/foundation.d.ts +133 -11
- package/dist/components/mobile-image-viewer.d.ts +35 -12
- package/dist/components/navibar.d.ts +2 -2
- package/dist/components/overlays.d.ts +10 -59
- package/dist/components/scrollbar.d.ts +88 -0
- package/dist/components/speed-dial.d.ts +157 -0
- package/dist/core/context.d.ts +11 -0
- package/dist/core/device.d.ts +2 -0
- package/dist/core/image-gallery-motion.d.ts +2 -1
- package/dist/core/image-motion.d.ts +1 -1
- package/dist/core/layers.d.ts +1 -0
- package/dist/core/motion-driver.d.ts +40 -0
- package/dist/core/motion.d.ts +1 -1
- package/dist/core/ripple.d.ts +16 -0
- package/dist/core/scroll-motion.d.ts +6 -0
- package/dist/core/scrollbar.d.ts +14 -0
- package/dist/core/speed-dial.d.ts +21 -0
- package/dist/index.d.ts +237 -26
- package/docs/COMPONENTS.md +10 -6
- package/package.json +5 -7
- package/templates/playground/README.md +1 -1
- package/templates/playground/package.json +1 -2
- package/templates/playground/source-snapshot.json +299 -66
- package/templates/playground/src/App.vue +1 -0
- package/templates/playground/src/ComponentDemo.vue +30 -21
- package/templates/playground/src/catalog.ts +70 -65
- package/templates/playground/src/components/ComponentIndex.vue +10 -14
- package/templates/playground/src/components/MasonryFeed.vue +52 -0
- package/templates/playground/src/components/UserMenu.vue +1 -1
- package/templates/playground/src/components/forbidden-paper-scene.vue +367 -0
- package/templates/playground/src/components/forbidden-paper-story.ts +233 -0
- package/templates/playground/src/editor/ComponentPlayground.vue +89 -0
- package/templates/playground/src/editor/ConfigurableEditor.vue +1 -1
- package/templates/playground/src/editor/apple-input-source.ts +1 -1
- package/templates/playground/src/editor/component-metadata.ts +72 -0
- package/templates/playground/src/editor/component-playground.ts +162 -0
- package/templates/playground/src/editor/contract.ts +1 -1
- package/templates/playground/src/editor/documents.ts +11 -2
- package/templates/playground/src/editor/handbook.ts +22 -0
- package/templates/playground/src/editor/handbooks/apple-accordion.ts +66 -0
- package/templates/playground/src/editor/handbooks/apple-action-sheet.ts +72 -0
- package/templates/playground/src/editor/handbooks/apple-alert.ts +67 -0
- package/templates/playground/src/editor/handbooks/apple-aside.ts +32 -0
- package/templates/playground/src/editor/handbooks/apple-auto-size.ts +32 -0
- package/templates/playground/src/editor/handbooks/apple-autocomplete.ts +114 -0
- package/templates/playground/src/editor/handbooks/apple-avatar-group.ts +50 -0
- package/templates/playground/src/editor/handbooks/apple-avatar.ts +56 -0
- package/templates/playground/src/editor/handbooks/apple-back-top.ts +62 -0
- package/templates/playground/src/editor/handbooks/apple-badge.ts +62 -0
- package/templates/playground/src/editor/handbooks/apple-breadcrumbs.ts +38 -0
- package/templates/playground/src/editor/handbooks/apple-button.ts +92 -0
- package/templates/playground/src/editor/handbooks/apple-card.ts +112 -0
- package/templates/playground/src/editor/handbooks/apple-cascader.ts +102 -0
- package/templates/playground/src/editor/handbooks/apple-checkbox.ts +85 -0
- package/templates/playground/src/editor/handbooks/apple-color-picker.ts +79 -0
- package/templates/playground/src/editor/handbooks/apple-container.ts +26 -0
- package/templates/playground/src/editor/handbooks/apple-date-picker.ts +104 -0
- package/templates/playground/src/editor/handbooks/apple-dialog.ts +151 -0
- package/templates/playground/src/editor/handbooks/apple-divider.ts +38 -0
- package/templates/playground/src/editor/handbooks/apple-drawer.ts +151 -0
- package/templates/playground/src/editor/handbooks/apple-empty.ts +43 -0
- package/templates/playground/src/editor/handbooks/apple-floating-group.ts +51 -0
- package/templates/playground/src/editor/handbooks/apple-form-field.ts +69 -0
- package/templates/playground/src/editor/handbooks/apple-form.ts +76 -0
- package/templates/playground/src/editor/handbooks/apple-grid.ts +32 -0
- package/templates/playground/src/editor/handbooks/apple-image.ts +122 -0
- package/templates/playground/src/editor/handbooks/apple-infinite-scroll.ts +73 -0
- package/templates/playground/src/editor/handbooks/apple-link.ts +68 -0
- package/templates/playground/src/editor/handbooks/apple-list.ts +67 -0
- package/templates/playground/src/editor/handbooks/apple-menu.ts +72 -0
- package/templates/playground/src/editor/handbooks/apple-navibar.ts +100 -0
- package/templates/playground/src/editor/handbooks/apple-otp-input.ts +108 -0
- package/templates/playground/src/editor/handbooks/apple-overlay-host.ts +13 -0
- package/templates/playground/src/editor/handbooks/apple-pagination.ts +61 -0
- package/templates/playground/src/editor/handbooks/apple-popover.ts +112 -0
- package/templates/playground/src/editor/handbooks/apple-progress.ts +56 -0
- package/templates/playground/src/editor/handbooks/apple-provider.ts +32 -0
- package/templates/playground/src/editor/handbooks/apple-pull-refresh.ts +61 -0
- package/templates/playground/src/editor/handbooks/apple-radio-group.ts +91 -0
- package/templates/playground/src/editor/handbooks/apple-rate.ts +97 -0
- package/templates/playground/src/editor/handbooks/apple-scroll-bar.ts +15 -0
- package/templates/playground/src/editor/handbooks/apple-search.ts +49 -0
- package/templates/playground/src/editor/handbooks/apple-segmented-control.ts +85 -0
- package/templates/playground/src/editor/handbooks/apple-select.ts +91 -0
- package/templates/playground/src/editor/handbooks/apple-sheet.ts +151 -0
- package/templates/playground/src/editor/handbooks/apple-skeleton.ts +74 -0
- package/templates/playground/src/editor/handbooks/apple-slider.ts +103 -0
- package/templates/playground/src/editor/handbooks/apple-snackbar.ts +89 -0
- package/templates/playground/src/editor/handbooks/apple-speed-dial-item.ts +16 -0
- package/templates/playground/src/editor/handbooks/apple-speed-dial.ts +13 -0
- package/templates/playground/src/editor/handbooks/apple-spinner.ts +38 -0
- package/templates/playground/src/editor/handbooks/apple-stack.ts +44 -0
- package/templates/playground/src/editor/handbooks/apple-statistic.ts +69 -0
- package/templates/playground/src/editor/handbooks/apple-stepper.ts +91 -0
- package/templates/playground/src/editor/handbooks/apple-steps.ts +61 -0
- package/templates/playground/src/editor/handbooks/apple-switch.ts +79 -0
- package/templates/playground/src/editor/handbooks/apple-tab-bar.ts +66 -0
- package/templates/playground/src/editor/handbooks/apple-table.ts +176 -0
- package/templates/playground/src/editor/handbooks/apple-tabs.ts +72 -0
- package/templates/playground/src/editor/handbooks/apple-tag.ts +56 -0
- package/templates/playground/src/editor/handbooks/apple-textarea.ts +109 -0
- package/templates/playground/src/editor/handbooks/apple-timeline.ts +44 -0
- package/templates/playground/src/editor/handbooks/apple-tooltip.ts +45 -0
- package/templates/playground/src/editor/handbooks/apple-transition.ts +44 -0
- package/templates/playground/src/editor/handbooks/apple-tree.ts +84 -0
- package/templates/playground/src/editor/handbooks/apple-upload.ts +126 -0
- package/templates/playground/src/editor/playground-examples.ts +105 -0
- package/templates/playground/src/images.ts +3 -0
- package/templates/playground/src/router/index.ts +19 -2
- package/templates/playground/src/style.css +4 -4
- package/templates/playground/src/views/403.vue +65 -0
- package/templates/playground/src/views/component-docs/[component].vue +11 -14
- package/templates/playground/src/views/components.vue +11 -41
- package/templates/playground/src/views/index.vue +3 -1
- package/templates/playground/src/views/settings.vue +5 -2
- package/tooling/create-playground.mjs +2 -2
- package/tooling/prepare-playground.mjs +3 -3
- package/tooling/test-create-apptify.mjs +3 -1
- package/tooling/test-playground-package.mjs +10 -0
- package/dist/components/gallery-scrollbar.d.ts +0 -46
- package/dist/core/desktop-image-enter.d.ts +0 -6
- package/dist/core/desktop-image-return.d.ts +0 -1
- package/templates/playground/src/components/DirectoryDialog.vue +0 -20
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
<aside class="directory-index sidebar" aria-label="组件目录">
|
|
7
7
|
<header class="directory-header">
|
|
8
8
|
<span>组件目录</span>
|
|
9
|
-
<div class="directory-search"><apple-search v-model="directorySearch" label="搜索组件目录" placeholder="名称、标签或描述" /></div>
|
|
10
9
|
</header>
|
|
11
|
-
<div class="directory-tree"><ComponentIndex v-model:expanded="expandedGroups" :active-group="activeGroup" :active-id="activeId"
|
|
10
|
+
<div class="directory-tree"><ComponentIndex v-model:expanded="expandedGroups" :active-group="activeGroup" :active-id="activeId" /></div>
|
|
12
11
|
</aside>
|
|
13
12
|
<div class="components-content">
|
|
14
13
|
<div class="feed-toolbar">
|
|
@@ -21,54 +20,40 @@
|
|
|
21
20
|
<div ref="feed" class="component-feed">
|
|
22
21
|
<section v-for="(section, index) in sections" :id="section.id" :key="section.id" class="feed-group feed-anchor" :data-group="section.id" :aria-labelledby="`${section.id}-heading`">
|
|
23
22
|
<header class="feed-group-heading"><span>0{{ index + 1 }}</span><h2 :id="`${section.id}-heading`">{{ section.label }}</h2><small>{{ section.items.length }} 个组件</small></header>
|
|
24
|
-
<
|
|
23
|
+
<MasonryFeed class="feed-cards" @layout="schedulePosition">
|
|
25
24
|
<apple-card v-for="item in section.items" :id="componentId(item.name)" :key="item.name" class="component-card feed-anchor" :data-group="section.id" :aria-labelledby="`${componentId(item.name)}-heading`">
|
|
26
25
|
<header class="component-card-heading"><div><h3 :id="`${componentId(item.name)}-heading`"><router-link :to="`#${componentId(item.name)}`">{{ item.label }}<Hash :size="14" /></router-link></h3><p>{{ item.description }}</p></div><code>{{ componentId(item.name) }}</code></header>
|
|
27
26
|
<section class="detail-preview" :class="{ 'mobile-preview': previewMode === 'mobile' }" :aria-label="`${item.label}预览`"><ComponentDemo :name="item.name" @navigate="navigateGroup" /></section>
|
|
28
|
-
<ComponentDocumentLink
|
|
29
|
-
<apple-accordion v-else class="component-source" :items="sourceSections">
|
|
30
|
-
<template #item>
|
|
31
|
-
<div class="code-view"><div class="code-toolbar"><span>使用示例</span><apple-link @click="copy(item.code)">复制代码</apple-link></div><pre><code>{{ item.code }}</code></pre><h4>接口</h4><p class="api-line">{{ item.api }}</p></div>
|
|
32
|
-
</template>
|
|
33
|
-
</apple-accordion>
|
|
27
|
+
<ComponentDocumentLink :href="documentPaths[item.name]" label="代码与 API" />
|
|
34
28
|
</apple-card>
|
|
35
|
-
</
|
|
29
|
+
</MasonryFeed>
|
|
36
30
|
</section>
|
|
37
31
|
</div>
|
|
38
32
|
</div>
|
|
39
33
|
</div>
|
|
40
34
|
</apple-container>
|
|
41
35
|
</main>
|
|
42
|
-
<DirectoryDialog v-model="mobileIndex" title="组件目录">
|
|
43
|
-
<div class="directory-search"><apple-search v-model="directorySearch" label="搜索组件目录" placeholder="名称、标签或描述" /></div>
|
|
44
|
-
<ComponentIndex v-model:expanded="expandedGroups" :active-group="activeGroup" :active-id="activeId" :search="directorySearch" @navigate="mobileIndex = false" />
|
|
45
|
-
</DirectoryDialog>
|
|
46
36
|
</template>
|
|
47
37
|
|
|
48
38
|
<script setup lang="ts">
|
|
49
39
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
50
40
|
import { useRoute, useRouter } from 'vue-router'
|
|
51
41
|
import { Hash, Monitor, Smartphone } from 'lucide-vue-next'
|
|
52
|
-
import { useApple } from 'apptify'
|
|
53
42
|
import { catalog, sections, componentId } from '../catalog'
|
|
54
43
|
import ComponentDemo from '../ComponentDemo.vue'
|
|
55
44
|
import ComponentIndex from '../components/ComponentIndex.vue'
|
|
56
|
-
import
|
|
45
|
+
import MasonryFeed from '../components/MasonryFeed.vue'
|
|
57
46
|
import ComponentDocumentLink from '../editor/ComponentDocumentLink.vue'
|
|
58
47
|
import { componentDocuments, componentDocumentPath } from '../editor/documents'
|
|
59
48
|
|
|
60
49
|
const documentPaths = Object.fromEntries(Object.entries(componentDocuments).map(([slug, document]) => [document.name, componentDocumentPath(slug)]))
|
|
61
50
|
const route = useRoute()
|
|
62
51
|
const router = useRouter()
|
|
63
|
-
const apple = useApple()
|
|
64
52
|
const feed = ref<HTMLElement>()
|
|
65
53
|
const activeGroup = ref(sections[0].id)
|
|
66
54
|
const activeId = ref('')
|
|
67
55
|
const previewMode = ref('desktop')
|
|
68
|
-
const mobileIndex = ref(false)
|
|
69
|
-
const directorySearch = ref('')
|
|
70
56
|
const expandedGroups = ref(sections.map(section => section.id))
|
|
71
|
-
const sourceSections = [{ label: '代码与 API', value: 'source' }]
|
|
72
57
|
let anchors: HTMLElement[] = []
|
|
73
58
|
let frame = 0
|
|
74
59
|
let observer: ResizeObserver | undefined
|
|
@@ -92,14 +77,10 @@ function navigateGroup(label: string) {
|
|
|
92
77
|
const section = sections.find(section => section.label === label)
|
|
93
78
|
void router.push(section ? `/components#${section.id}` : '/components')
|
|
94
79
|
}
|
|
95
|
-
|
|
96
|
-
try { await navigator.clipboard.writeText(value); apple.notify('已复制', { tone: 'success' }) }
|
|
97
|
-
catch { apple.notify('无法访问剪贴板,请手动选择代码复制', { tone: 'warning' }) }
|
|
98
|
-
}
|
|
99
|
-
watch(() => route.hash, () => { mobileIndex.value = false; schedulePosition() })
|
|
80
|
+
watch(() => route.hash, schedulePosition)
|
|
100
81
|
watch(activeId, async () => {
|
|
101
82
|
await nextTick()
|
|
102
|
-
const sidebar = document.querySelector<HTMLElement>('.directory-tree')
|
|
83
|
+
const sidebar = document.querySelector<HTMLElement>('.directory-tree .apple-tree-scroll')
|
|
103
84
|
const current = sidebar?.querySelector<HTMLElement>('.apple-tree__row.is-selected')
|
|
104
85
|
if (!sidebar || !current) return
|
|
105
86
|
const item = current.getBoundingClientRect(), bounds = sidebar.getBoundingClientRect()
|
|
@@ -126,23 +107,12 @@ onBeforeUnmount(() => {
|
|
|
126
107
|
.directory-index { display: flex; flex-direction: column; overflow: hidden; }
|
|
127
108
|
.directory-header { flex-shrink: 0; }
|
|
128
109
|
.directory-header > span { color: var(--apple-secondary); font-size: 12px; display: block; margin: 0 0 12px 8px; }
|
|
129
|
-
.directory-tree {
|
|
110
|
+
.directory-tree { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
|
130
111
|
@media (max-width: 900px) { .directory-index { display: none; } }
|
|
131
|
-
.directory-search { min-width: 0; margin: 0 4px 16px; }
|
|
132
|
-
.directory-search :deep(.apple-field__label) { font-size: 11px; }
|
|
133
|
-
.directory-search :deep(input) { min-width: 0; font-size: 12px; }
|
|
134
112
|
.components-page > * { max-width: none; }
|
|
135
|
-
.feed-
|
|
113
|
+
.feed-anchor { scroll-margin-top: 96px; }
|
|
136
114
|
.feed-group-heading { padding-bottom: 20px; }
|
|
137
|
-
.component-card {
|
|
115
|
+
.component-card { width: 100%; padding: 0; }
|
|
138
116
|
.component-card :deep(> .apple-card__body) { padding: 0; border-radius: inherit; }
|
|
139
|
-
.component-card :deep(> .apple-card__body > .documentation-entry)
|
|
140
|
-
.component-card :deep(> .apple-card__body > .component-source) { border-radius: 0 0 18px 18px; overflow: hidden; }
|
|
141
|
-
.component-source :deep(.apple-accordion__item) { border: 0; }
|
|
142
|
-
.component-source :deep(.apple-accordion__item > h3) { font-size: 11px; font-weight: 400; }
|
|
143
|
-
.component-source :deep(.apple-accordion__item > h3 > button) { min-height: 44px; gap: 8px; padding: 13px 28px; color: var(--apple-secondary); }
|
|
144
|
-
.component-source :deep(.apple-accordion__content) { padding: 0; }
|
|
145
|
-
@media (max-width: 800px) {
|
|
146
|
-
.component-source :deep(.apple-accordion__item > h3 > button) { padding-inline: 18px; }
|
|
147
|
-
}
|
|
117
|
+
.component-card :deep(> .apple-card__body > .documentation-entry) { border-radius: 0 0 18px 18px; overflow: hidden; }
|
|
148
118
|
</style>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<apple-card class="specimen"><div class="specimen-caption"><span>02 / 控制</span></div><h2>点到,即止。</h2><div class="button-specimens"><apple-button :icon="arrowIcon" @click="$apple.notify('操作已完成',{tone:'success'})">继续探索</apple-button><apple-button variant="secondary" @click="$apple.notify('已加入收藏')">加入收藏</apple-button><apple-button variant="outline" @click="$router.push('/components#apple-button')">了解更多</apple-button><div class="icon-button-row"><apple-button variant="secondary" :icon="plusIcon" icon-only label="添加" @click="$apple.notify('已添加')" /><apple-button :variant="liked?'primary':'secondary'" :icon="heartIcon" icon-only :label="liked ? '取消收藏' : '收藏'" :aria-pressed="liked" @click="liked=!liked" /><apple-button variant="secondary" :icon="downloadIcon" icon-only label="浏览组件示例" @click="$router.push('/components')" /></div></div><div class="specimen-foot"><code>apple-button</code><span>5 种样式</span></div></apple-card>
|
|
21
21
|
<apple-card class="specimen"><div class="specimen-caption"><span>03 / 偏好</span></div><h2>恰好,是你的。</h2><div class="preference-demo"><apple-segmented-control v-model="period" :items="periods" label="统计周期" /><div class="setting-line"><div><strong>消息通知</strong><small>不错过重要的事</small></div><apple-switch v-model="notices" aria-label="消息通知" /></div><div class="setting-line"><div><strong>自动同步</strong><small>在所有设备上保持一致</small></div><apple-switch v-model="sync" aria-label="自动同步" /></div><apple-slider v-model="volume" label="音量" /><div class="check-row"><apple-checkbox v-model="agreed" label="记住我的偏好" /></div></div></apple-card>
|
|
22
22
|
<apple-card class="specimen form-specimen"><div class="specimen-caption"><span>04 / 输入</span></div><h2>开始一段对话。</h2><apple-form @submit="$apple.notify(`你好,${name || '新朋友'}!`,{tone:'success'})"><apple-input v-model="name" label="你的名字" placeholder="怎么称呼你" autocomplete="name" clearable required /><apple-input v-model="email" label="电子邮箱" type="email" placeholder="name@example.com" autocomplete="email" required /><apple-button type="submit">加入我们<ArrowRight :size="15" /></apple-button></apple-form></apple-card>
|
|
23
|
-
<apple-card class="specimen media-specimen"><div class="specimen-caption"><span>05 / 媒体</span></div><h2>靠近一点,再一点。</h2><apple-image :gallery="[{ src: '
|
|
23
|
+
<apple-card class="specimen media-specimen"><div class="specimen-caption"><span>05 / 媒体</span></div><h2>靠近一点,再一点。</h2><apple-image :gallery="[{ src: imageUrl('lake.jpg'), alt: '山间湖泊和木屋' }, { src: imageUrl('airpods-max-orange.jpg'), alt: '橙色耳机' }]" aspect-ratio="4/3" /><div class="specimen-foot"><code>apple-image</code><span>山间的一刻</span></div></apple-card>
|
|
24
24
|
<apple-card class="specimen feedback-specimen"><div class="specimen-caption"><span>06 / 反馈</span></div><h2>每一步,都有回应。</h2><apple-alert title="所有更改已保存" tone="success" /><div class="progress-demo"><div><span>正在同步</span><span>{{progress}}%</span></div><apple-progress :model-value="progress" label="正在同步" /></div><apple-avatar-group :items="[{name:'林初'},{name:'Alex'},{name:'Taylor'},{name:'Quinn'}]" /><div class="feedback-actions"><apple-button variant="secondary" size="small" @click="openDemoDialog">打开对话框</apple-button><apple-link as="button" @click="$apple.notify('所有更改已保存',{tone:'success'});progress=Math.min(100,progress+10)">显示提示</apple-link></div></apple-card>
|
|
25
25
|
</div>
|
|
26
26
|
</section>
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
36
|
<script lang="ts">
|
|
37
|
+
import { imageUrl } from '../images'
|
|
37
38
|
import { defineComponent, markRaw } from 'vue'
|
|
38
39
|
import { ArrowRight, ArrowUpRight, Download, Heart, Plus } from 'lucide-vue-next'
|
|
39
40
|
import { catalog } from '../catalog'
|
|
@@ -57,6 +58,7 @@ export default defineComponent({
|
|
|
57
58
|
},
|
|
58
59
|
},
|
|
59
60
|
methods: {
|
|
61
|
+
imageUrl,
|
|
60
62
|
openDemoDialog() { this.$apple.dialog({title:'一切,就从这里开始。',message:'试试这些组件,找到适合你的交互。',confirmText:'好的',cancelText:'稍后'}) },
|
|
61
63
|
},
|
|
62
64
|
})
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<div class="settings-section-heading"><div><h2 id="ripple-heading">点击波纹</h2><p>让每一次轻点,都有细微的回应。</p></div></div>
|
|
39
39
|
<apple-switch :model-value="rippleAllowed && apple.ripple.value.enabled" :disabled="!rippleAllowed" label="点击波纹" :hint="rippleAllowed ? '减弱动效时自动关闭,可手动开启;偏好保存在这台设备上。' : '关闭动效时,无法开启点击波纹。'" @update:model-value="apple.ripple.value.set" />
|
|
40
40
|
<div ref="rippleDemo" class="effect-demo ripple-sample" aria-label="波纹自动演示" @pointerenter="ripplePaused = true" @pointerleave="ripplePaused = false" @focusin="ripplePaused = true" @focusout="ripplePaused = false">
|
|
41
|
-
<apple-
|
|
41
|
+
<apple-list :items="rippleDemoItems" selectable label="点击波纹演示" @select="rippleDemoClicks++" />
|
|
42
42
|
<span class="ripple-click-count">已点击 {{ rippleDemoClicks }} 次</span>
|
|
43
43
|
</div>
|
|
44
44
|
<div class="settings-card-foot">{{ rippleAllowed && apple.ripple.value.enabled ? '自动点击 · 也可以手动试一试' : '点击波纹已关闭 · 静态展示' }}</div>
|
|
@@ -93,6 +93,7 @@ const rippleDemo = ref<HTMLElement>()
|
|
|
93
93
|
const motionDemoOpened = ref<string[]>([])
|
|
94
94
|
const motionDemoItems = [{ label: '预览效果', value: 'preview', content: '折叠面板与所有组件的动画速度、数量都会跟随你选择的动效强度。' }]
|
|
95
95
|
const rippleDemoClicks = ref(0)
|
|
96
|
+
const rippleDemoItems = [{ label: '试试点击波纹', value: 'ripple-preview' }]
|
|
96
97
|
const motionPaused = ref(false)
|
|
97
98
|
const ripplePaused = ref(false)
|
|
98
99
|
let demoTimer: number | undefined
|
|
@@ -193,13 +194,15 @@ function reset() {
|
|
|
193
194
|
.motion-sample :deep(.apple-accordion h3) { font-size: 14px; }
|
|
194
195
|
.motion-sample :deep(.apple-accordion__content) { font-size: 12px; }
|
|
195
196
|
.ripple-sample { flex: 1; max-height: 180px; margin-block: auto; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 16px; padding: 20px; }
|
|
197
|
+
.ripple-sample :deep(.apple-list-size) { width: 100%; border-radius: 12px; background: var(--apple-surface); }
|
|
198
|
+
.ripple-sample :deep(.apple-list__item) { padding-inline: 16px; }
|
|
196
199
|
.ripple-click-count { color: var(--apple-secondary); font-size: 11px; }
|
|
197
200
|
.glass-sample { min-height: 156px; display: grid; place-items: center; margin: 0 0 20px; isolation: isolate; }
|
|
198
201
|
.glass-sample-colors { position: absolute; inset: -40px; display: flex; align-items: center; justify-content: center; gap: 20px; animation: sample-glass 6s ease-in-out infinite; }
|
|
199
202
|
.glass-sample-colors span { width: 95px; height: 95px; flex-shrink: 0; border-radius: 28px; background: #82b6ef; transform: rotate(-20deg); }
|
|
200
203
|
.glass-sample-colors span:nth-child(2) { background: #e9aa99; width: 72px; height: 120px; transform: rotate(25deg); }
|
|
201
204
|
.glass-sample-colors span:nth-child(3) { background: #ada1e2; border-radius: 50%; }
|
|
202
|
-
.glass-sample-panel { position: relative; display: grid; grid-template-columns: 20px 1fr; gap: 12px; width: 168px; padding: 18px; border: 1px solid var(--apple-border); border-radius: 12px; background: rgb(var(--apple-glass-rgb, 255 255 255) / var(--apple-glass-opacity, .
|
|
205
|
+
.glass-sample-panel { position: relative; display: grid; grid-template-columns: 20px 1fr; gap: 12px; width: 168px; padding: 18px; border: 1px solid var(--apple-border); border-radius: 12px; background: rgb(var(--apple-glass-rgb, 255 255 255) / var(--apple-glass-opacity, .5)); backdrop-filter: blur(var(--apple-glass-blur, 12px)) saturate(2); -webkit-backdrop-filter: blur(var(--apple-glass-blur, 12px)) saturate(2); font-size: 12px; }
|
|
203
206
|
.glass-sample-panel i { grid-column: 1 / -1; height: 5px; width: 100%; border-radius: 4px; background: currentColor; opacity: .15; }
|
|
204
207
|
.glass-sample-panel i:last-child { width: 65%; }
|
|
205
208
|
@keyframes sample-glass { 0%, 100% { transform: translateX(-32px) rotate(-8deg); } 50% { transform: translateX(32px) rotate(8deg); } }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { cp, mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { cp, mkdir, readFile, readdir, realpath, rename, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { resolve, join, sep } from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { execFileSync } from 'node:child_process'
|
|
@@ -13,7 +13,7 @@ if (!destination || ['--help', '-h'].includes(destination)) {
|
|
|
13
13
|
}
|
|
14
14
|
try {
|
|
15
15
|
const target = resolve(destination)
|
|
16
|
-
const packageRoot =
|
|
16
|
+
const packageRoot = await realpath(root)
|
|
17
17
|
if (target === packageRoot || target.startsWith(packageRoot + sep)) throw new Error('Destination must be outside the installed apptify package')
|
|
18
18
|
const existing = await readdir(target).catch(error => { if (error.code === 'ENOENT') return []; throw error })
|
|
19
19
|
if (existing.length) throw new Error('Destination must be empty: ' + target)
|
|
@@ -50,7 +50,7 @@ async function adapt(directory) {
|
|
|
50
50
|
source = source.replace('to="/" aria-label="Apptify 首页"', ':to="homePath" aria-label="Apptify 首页"')
|
|
51
51
|
source = source.replace(navigationEnd, "].filter(item => router.getRoutes().some(page => page.path === item.href))\nconst homePath = navigation[0]?.href ?? '/'\n\nfunction navigate")
|
|
52
52
|
}
|
|
53
|
-
if (path === join(output, 'src/views
|
|
53
|
+
if (['[...all].vue', '403.vue'].some(view => path === join(output, 'src/views', view))) {
|
|
54
54
|
source = source.replace('to="/" custom', ':to="homePath" custom')
|
|
55
55
|
source = source.replace('const router = useRouter()', "const router = useRouter()\nconst homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'")
|
|
56
56
|
source = source.replace("else void router.push('/')", 'else void router.push(homePath)')
|
|
@@ -65,7 +65,7 @@ const manifest = {
|
|
|
65
65
|
scripts: { dev: 'vite', typecheck: 'vue-tsc --noEmit', build: 'vue-tsc --noEmit && vite build', preview: 'vite preview --host 127.0.0.1' },
|
|
66
66
|
dependencies: {
|
|
67
67
|
apptify: '^' + library.version, vue: library.peerDependencies.vue,
|
|
68
|
-
'vue-router': library.devDependencies['vue-router'],
|
|
68
|
+
'vue-router': library.devDependencies['vue-router'],
|
|
69
69
|
'lucide-vue-next': library.dependencies['lucide-vue-next'],
|
|
70
70
|
},
|
|
71
71
|
devDependencies: Object.fromEntries(['@vitejs/plugin-vue', 'typescript', 'vite', 'vite-plugin-pages', 'vue-tsc', '@vue/repl', 'es-module-shims', 'esbuild', 'postcss'].map(name => [name, library.devDependencies[name]])),
|
|
@@ -92,7 +92,7 @@ await writeFile(join(output, 'gitignore'), 'node_modules/\ndist/\n.env.local\n')
|
|
|
92
92
|
await writeFile(join(output, 'README.md'), [
|
|
93
93
|
"# Apptify 应用模板",
|
|
94
94
|
"",
|
|
95
|
-
"可编辑的 Vue 应用,包含导航、账号表单、外观设置、404 与组件示例。建议 Node.js 22 或 24 LTS。",
|
|
95
|
+
"可编辑的 Vue 应用,包含导航、账号表单、外观设置、403、404 与组件示例。建议 Node.js 22 或 24 LTS。",
|
|
96
96
|
"",
|
|
97
97
|
"```sh",
|
|
98
98
|
"npm install",
|
|
@@ -67,7 +67,9 @@ try {
|
|
|
67
67
|
assert.equal(refused.status, 1)
|
|
68
68
|
assert.match(refused.stderr, /Destination must be empty/)
|
|
69
69
|
assert.equal(await readFile(join(app, 'package.json'), 'utf8'), before)
|
|
70
|
-
|
|
70
|
+
const unsafe = run([join(library, 'unsafe')])
|
|
71
|
+
assert.equal(unsafe.status, 1, unsafe.stdout + unsafe.stderr)
|
|
72
|
+
assert.match(unsafe.stderr, /outside the installed apptify package/)
|
|
71
73
|
const alias = join(scratch, 'library-alias')
|
|
72
74
|
await symlink(library, alias, process.platform === 'win32' ? 'junction' : 'dir')
|
|
73
75
|
assert.equal(run([join(alias, 'unsafe')]).status, 1)
|
|
@@ -114,6 +114,14 @@ async function checkPage(baseURL, path, check) {
|
|
|
114
114
|
assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), 'Page overflow: ' + path)
|
|
115
115
|
await page.close()
|
|
116
116
|
}
|
|
117
|
+
async function checkTableHandbook(page) {
|
|
118
|
+
await expect(page.getByTestId('component-playground')).toHaveAttribute('data-component', 'AppleTable')
|
|
119
|
+
const frame = page.frameLocator('.vue-repl iframe')
|
|
120
|
+
await frame.getByRole('button', { name: '评分', exact: true }).click()
|
|
121
|
+
await expect(frame.locator('tbody tr').first()).toContainText('Alex')
|
|
122
|
+
await expect(frame.getByRole('textbox', { name: '事件记录内容' })).toHaveValue(/update:sortBy "score"/)
|
|
123
|
+
await expect(page.getByTestId('component-document').locator('iframe')).toHaveCount(0)
|
|
124
|
+
}
|
|
117
125
|
let server
|
|
118
126
|
try {
|
|
119
127
|
server = await serve()
|
|
@@ -138,6 +146,7 @@ try {
|
|
|
138
146
|
await frame.locator('.apple-input-wrap input').first().fill('Template src preview')
|
|
139
147
|
await expect(frame.locator('.apple-input-wrap input').first()).toHaveValue('Template src preview')
|
|
140
148
|
})
|
|
149
|
+
await checkPage(server.url, '/component-docs/apple-table', checkTableHandbook)
|
|
141
150
|
await checkPage(server.url, '/settings', async page => {
|
|
142
151
|
await page.setViewportSize({ width: 320, height: 900 })
|
|
143
152
|
await page.getByRole('button', { name: '深色', exact: true }).click()
|
|
@@ -174,6 +183,7 @@ try {
|
|
|
174
183
|
run(['run', 'typecheck'], app)
|
|
175
184
|
run(['run', 'build'], app)
|
|
176
185
|
server = await serve()
|
|
186
|
+
await checkPage(server.url, '/component-docs/apple-table', checkTableHandbook)
|
|
177
187
|
await checkPage(server.url, '/settings', async page => {
|
|
178
188
|
assert.equal(await page.locator('.site-nav a.apple-navibar__item').count(), 1)
|
|
179
189
|
assert.equal(await page.locator('.site-nav .brand').getAttribute('href'), '/settings')
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { type PropType } from 'vue';
|
|
2
|
-
export declare const GalleryScrollbar: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
|
-
target: {
|
|
4
|
-
type: PropType<() => HTMLElement | undefined>;
|
|
5
|
-
required: true;
|
|
6
|
-
};
|
|
7
|
-
controls: {
|
|
8
|
-
type: StringConstructor;
|
|
9
|
-
required: true;
|
|
10
|
-
};
|
|
11
|
-
}>, {}, {
|
|
12
|
-
box: HTMLElement | null;
|
|
13
|
-
width: number;
|
|
14
|
-
total: number;
|
|
15
|
-
left: number;
|
|
16
|
-
observer: ResizeObserver | null;
|
|
17
|
-
mutations: MutationObserver | null;
|
|
18
|
-
drag: {
|
|
19
|
-
id: number;
|
|
20
|
-
x: number;
|
|
21
|
-
left: number;
|
|
22
|
-
snap: string;
|
|
23
|
-
} | null;
|
|
24
|
-
}, {
|
|
25
|
-
maximum(): number;
|
|
26
|
-
progress(): number;
|
|
27
|
-
}, {
|
|
28
|
-
observe(): void;
|
|
29
|
-
measure(): void;
|
|
30
|
-
scroll(left: number): void;
|
|
31
|
-
start(event: PointerEvent): void;
|
|
32
|
-
move(event: PointerEvent): void;
|
|
33
|
-
end(event?: PointerEvent): void;
|
|
34
|
-
key(event: KeyboardEvent): void;
|
|
35
|
-
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "interaction"[], "interaction", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
36
|
-
target: {
|
|
37
|
-
type: PropType<() => HTMLElement | undefined>;
|
|
38
|
-
required: true;
|
|
39
|
-
};
|
|
40
|
-
controls: {
|
|
41
|
-
type: StringConstructor;
|
|
42
|
-
required: true;
|
|
43
|
-
};
|
|
44
|
-
}>> & Readonly<{
|
|
45
|
-
onInteraction?: ((...args: any[]) => any) | undefined;
|
|
46
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type PhotoGeometry } from './image-geometry';
|
|
2
|
-
export declare const interruptedPhotoEnter: WeakMap<HTMLElement, {
|
|
3
|
-
geometry: PhotoGeometry;
|
|
4
|
-
background: string;
|
|
5
|
-
}>;
|
|
6
|
-
export declare function enterDesktopPhoto(panel: HTMLElement, thumbnail: HTMLImageElement | null, motion: string, signal: AbortSignal): Promise<void>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function returnDesktopPhoto(panel: HTMLElement, thumbnail: HTMLImageElement | null, motion: string, signal: AbortSignal): Promise<void>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<apple-floating-group label="页面导航">
|
|
3
|
-
<apple-button class="directory-toggle" variant="secondary" icon-only :icon="Menu" :label="`展开${title}`" aria-haspopup="dialog" :aria-expanded="modelValue" @click="modelValue = true" />
|
|
4
|
-
</apple-floating-group>
|
|
5
|
-
<apple-dialog v-model="modelValue" :title="title" :show-footer="false" width="480px">
|
|
6
|
-
<div class="directory-dialog-content"><slot /></div>
|
|
7
|
-
</apple-dialog>
|
|
8
|
-
</template>
|
|
9
|
-
|
|
10
|
-
<script setup lang="ts">
|
|
11
|
-
import { Menu } from 'lucide-vue-next'
|
|
12
|
-
defineProps<{ title: string }>()
|
|
13
|
-
const modelValue = defineModel<boolean>({ default: false })
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<style scoped>
|
|
17
|
-
.directory-toggle { display: none; order: 1001; width: 44px; height: 44px; padding: 0; border-radius: 50%; box-shadow: var(--apple-shadow); }
|
|
18
|
-
.directory-dialog-content { min-width: 0; }
|
|
19
|
-
@media (max-width: 900px) { .directory-toggle { display: inline-flex; } }
|
|
20
|
-
</style>
|