apptify 0.8.0 → 0.8.5
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/dist/apptify.css +1 -1
- package/dist/apptify.js +1503 -1721
- package/dist/components/button.d.ts +1 -1
- package/dist/components/foundation.d.ts +2 -4
- package/dist/components/link.d.ts +1 -1
- package/dist/core/image-gallery-motion.d.ts +1 -1
- package/dist/core/layers.d.ts +0 -1
- package/dist/index.d.ts +2 -46
- package/docs/COMPONENTS.md +7 -4
- package/package.json +1 -1
- package/templates/playground/README.md +1 -1
- package/templates/playground/package.json +1 -1
- package/templates/playground/source-snapshot.json +80 -40
- package/templates/playground/src/ComponentDemo.vue +2 -5
- package/templates/playground/src/catalog.ts +0 -1
- package/templates/playground/src/components/ErrorPagePreviews.vue +86 -0
- package/templates/playground/src/components/bad-request-paper-scene.vue +280 -0
- package/templates/playground/src/components/bad-request-paper-story.ts +169 -0
- package/templates/playground/src/components/gateway-paper-scene.vue +336 -0
- package/templates/playground/src/components/gateway-paper-story.ts +197 -0
- package/templates/playground/src/components/hamster-429-scene.vue +1045 -0
- package/templates/playground/src/components/server-fire-paper-scene.vue +249 -0
- package/templates/playground/src/components/server-fire-paper-story.ts +272 -0
- package/templates/playground/src/components/unavailable-paper-scene.vue +488 -0
- package/templates/playground/src/editor/component-metadata.ts +0 -1
- package/templates/playground/src/editor/handbooks/apple-dialog.ts +1 -1
- package/templates/playground/src/editor/playground-examples.ts +0 -1
- package/templates/playground/src/error-pages.ts +9 -0
- package/templates/playground/src/style.css +0 -2
- package/templates/playground/src/views/400.vue +74 -0
- package/templates/playground/src/views/403.vue +5 -2
- package/templates/playground/src/views/429.vue +74 -0
- package/templates/playground/src/views/500.vue +67 -0
- package/templates/playground/src/views/502.vue +68 -0
- package/templates/playground/src/views/503.vue +79 -0
- package/templates/playground/src/views/[...all].vue +5 -2
- package/templates/playground/src/views/components.vue +8 -8
- package/tooling/prepare-playground.mjs +2 -2
- package/dist/components/scrollbar.d.ts +0 -88
- package/dist/core/scrollbar.d.ts +0 -14
- package/templates/playground/src/editor/handbooks/apple-scroll-bar.ts +0 -15
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="main-content paper-400-page">
|
|
3
|
+
<apple-card class="paper-400-card" shadow="none" zoom="none">
|
|
4
|
+
<template #title>
|
|
5
|
+
<div class="paper-400-heading">
|
|
6
|
+
<p class="paper-400-number" aria-hidden="true">400</p>
|
|
7
|
+
<h1><span class="paper-400-sr-only">400 · </span>{{ page.title }}</h1>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<p class="paper-400-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
|
+
<div class="paper-400-actions">
|
|
12
|
+
<router-link v-slot="{ href, navigate }" to="/" custom>
|
|
13
|
+
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
14
|
+
</router-link>
|
|
15
|
+
<apple-link as="button" @click="goBack"><ArrowLeft :size="16" aria-hidden="true" /> 返回上一页</apple-link>
|
|
16
|
+
</div>
|
|
17
|
+
</apple-card>
|
|
18
|
+
<BadRequestPaperScene class="paper-400-illustration" :theme="scheme" :reduced-motion="reducedMotion" />
|
|
19
|
+
</main>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<route lang="json">
|
|
23
|
+
{ "alias": "/error/400", "meta": { "title": "请求有误" } }
|
|
24
|
+
</route>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { computed } from 'vue'
|
|
28
|
+
import { ArrowLeft } from 'lucide-vue-next'
|
|
29
|
+
import { useRouter } from 'vue-router'
|
|
30
|
+
import { useApple } from 'apptify'
|
|
31
|
+
import { resolveMotion } from 'apptify'
|
|
32
|
+
import BadRequestPaperScene from '../components/bad-request-paper-scene.vue'
|
|
33
|
+
|
|
34
|
+
import { errorPages } from '../error-pages'
|
|
35
|
+
|
|
36
|
+
const page = errorPages[400]
|
|
37
|
+
const router = useRouter()
|
|
38
|
+
const apple = useApple()
|
|
39
|
+
const scheme = computed(() => apple.theme.value.current.scheme)
|
|
40
|
+
const reducedMotion = computed(() => resolveMotion('inherit', apple.motion.value.mode, apple.motion.value.reduced) !== 'full')
|
|
41
|
+
function goBack() {
|
|
42
|
+
if (typeof router.options.history.state.back === 'string') router.back()
|
|
43
|
+
else void router.push('/')
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<style scoped>
|
|
48
|
+
.paper-400-page { max-width:1360px; display:grid; grid-template-columns:minmax(260px,.78fr) minmax(0,1.65fr); align-content:center; align-items:center; column-gap:16px; padding-top:38px; padding-bottom:calc(38px + 64px); }
|
|
49
|
+
.paper-400-card { background:transparent; border:0; overflow:visible; }
|
|
50
|
+
.paper-400-card :deep(.apple-card__body) { padding:0 0 0 8px; }
|
|
51
|
+
.paper-400-card :deep(.apple-card__heading) { margin:0; }
|
|
52
|
+
.paper-400-heading { width:100%; }
|
|
53
|
+
.paper-400-number { color:var(--apple-text); font-family:Georgia,'Times New Roman',serif; font-size:clamp(78px,8.2vw,118px); line-height:.9; letter-spacing:-.075em; margin:0 0 28px; font-weight:400; }
|
|
54
|
+
.paper-400-heading h1 { font-size:clamp(26px,2.7vw,35px); line-height:1.35; letter-spacing:-.035em; font-weight:600; margin:0 0 17px; }
|
|
55
|
+
.paper-400-copy { font-size:13px; line-height:1.95; color:var(--apple-secondary); margin:0; text-wrap:pretty; }
|
|
56
|
+
.paper-400-actions { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:27px; }
|
|
57
|
+
.paper-400-actions .apple-link { font-size:12px; padding-inline:8px; color:var(--apple-secondary); }
|
|
58
|
+
.paper-400-illustration { min-width:0; }
|
|
59
|
+
.paper-400-sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
|
|
60
|
+
@media(max-width:880px) {
|
|
61
|
+
.paper-400-page { grid-template-columns:minmax(0,1fr); max-width:680px; padding-top:18px; }
|
|
62
|
+
.paper-400-illustration { grid-row:1; }
|
|
63
|
+
.paper-400-card { margin-top:36px; }
|
|
64
|
+
.paper-400-card :deep(.apple-card__body) { padding:0; text-align:center; }
|
|
65
|
+
.paper-400-number { font-size:70px; margin-bottom:18px; }
|
|
66
|
+
.paper-400-heading h1 { font-size:26px; margin-bottom:12px; }
|
|
67
|
+
.paper-400-actions { justify-content:center; margin-top:18px; }
|
|
68
|
+
}
|
|
69
|
+
@media(max-width:420px) {
|
|
70
|
+
.paper-400-page { padding-inline:18px; padding-top:12px; }
|
|
71
|
+
.paper-400-copy { font-size:12px; }
|
|
72
|
+
.paper-400-card { margin-top:30px; }
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<template #title>
|
|
5
5
|
<div class="paper-403-heading">
|
|
6
6
|
<p class="paper-403-number" aria-hidden="true">403</p>
|
|
7
|
-
<h1
|
|
7
|
+
<h1>{{ page.title }}</h1>
|
|
8
8
|
</div>
|
|
9
9
|
</template>
|
|
10
|
-
<p class="paper-403-copy"
|
|
10
|
+
<p class="paper-403-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
11
|
<div class="paper-403-actions">
|
|
12
12
|
<router-link v-slot="{ href, navigate }" :to="homePath" custom>
|
|
13
13
|
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
@@ -28,6 +28,9 @@ import { ArrowLeft } from 'lucide-vue-next'
|
|
|
28
28
|
import { useRouter } from 'vue-router'
|
|
29
29
|
import ForbiddenPaperScene from '../components/forbidden-paper-scene.vue'
|
|
30
30
|
|
|
31
|
+
import { errorPages } from '../error-pages'
|
|
32
|
+
|
|
33
|
+
const page = errorPages[403]
|
|
31
34
|
const router = useRouter()
|
|
32
35
|
const homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'
|
|
33
36
|
function goBack() {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="main-content paper-429-page">
|
|
3
|
+
<apple-card class="paper-429-card" shadow="none" zoom="none">
|
|
4
|
+
<template #title>
|
|
5
|
+
<div class="paper-429-heading">
|
|
6
|
+
<p class="paper-429-number" aria-hidden="true">429</p>
|
|
7
|
+
<h1><span class="paper-429-sr-only">429 · </span>{{ page.title }}</h1>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<p class="paper-429-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
|
+
<div class="paper-429-actions">
|
|
12
|
+
<router-link v-slot="{ href, navigate }" to="/" custom>
|
|
13
|
+
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
14
|
+
</router-link>
|
|
15
|
+
<apple-link as="button" @click="goBack"><ArrowLeft :size="16" aria-hidden="true" /> 返回上一页</apple-link>
|
|
16
|
+
</div>
|
|
17
|
+
</apple-card>
|
|
18
|
+
<Hamster429Scene class="paper-429-illustration" :theme="scheme" :reduced-motion="reducedMotion" />
|
|
19
|
+
</main>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<route lang="json">
|
|
23
|
+
{ "alias": "/error/429", "meta": { "title": "请求过于频繁" } }
|
|
24
|
+
</route>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { computed } from 'vue'
|
|
28
|
+
import { ArrowLeft } from 'lucide-vue-next'
|
|
29
|
+
import { useRouter } from 'vue-router'
|
|
30
|
+
import { useApple } from 'apptify'
|
|
31
|
+
import { resolveMotion } from 'apptify'
|
|
32
|
+
import Hamster429Scene from '../components/hamster-429-scene.vue'
|
|
33
|
+
|
|
34
|
+
import { errorPages } from '../error-pages'
|
|
35
|
+
|
|
36
|
+
const page = errorPages[429]
|
|
37
|
+
const router = useRouter()
|
|
38
|
+
const apple = useApple()
|
|
39
|
+
const scheme = computed(() => apple.theme.value.current.scheme)
|
|
40
|
+
const reducedMotion = computed(() => resolveMotion('inherit', apple.motion.value.mode, apple.motion.value.reduced) !== 'full')
|
|
41
|
+
function goBack() {
|
|
42
|
+
if (typeof router.options.history.state.back === 'string') router.back()
|
|
43
|
+
else void router.push('/')
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<style scoped>
|
|
48
|
+
.paper-429-page { max-width:1360px; display:grid; grid-template-columns:minmax(260px,.78fr) minmax(0,1.65fr); align-content:center; align-items:center; column-gap:16px; padding-top:38px; padding-bottom:calc(38px + 64px); }
|
|
49
|
+
.paper-429-card { background:transparent; border:0; overflow:visible; }
|
|
50
|
+
.paper-429-card :deep(.apple-card__body) { padding:0 0 0 8px; }
|
|
51
|
+
.paper-429-card :deep(.apple-card__heading) { margin:0; }
|
|
52
|
+
.paper-429-heading { width:100%; }
|
|
53
|
+
.paper-429-number { color:var(--apple-text); font-family:Georgia,'Times New Roman',serif; font-size:clamp(78px,8.2vw,118px); line-height:.9; letter-spacing:-.075em; margin:0 0 28px; font-weight:429; }
|
|
54
|
+
.paper-429-heading h1 { font-size:clamp(26px,2.7vw,35px); line-height:1.35; letter-spacing:-.035em; font-weight:600; margin:0 0 17px; }
|
|
55
|
+
.paper-429-copy { font-size:13px; line-height:1.95; color:var(--apple-secondary); margin:0; text-wrap:pretty; }
|
|
56
|
+
.paper-429-actions { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:27px; }
|
|
57
|
+
.paper-429-actions .apple-link { font-size:12px; padding-inline:8px; color:var(--apple-secondary); }
|
|
58
|
+
.paper-429-illustration { min-width:0; }
|
|
59
|
+
.paper-429-sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
|
|
60
|
+
@media(max-width:880px) {
|
|
61
|
+
.paper-429-page { grid-template-columns:minmax(0,1fr); max-width:680px; padding-top:18px; }
|
|
62
|
+
.paper-429-illustration { grid-row:1; }
|
|
63
|
+
.paper-429-card { margin-top:36px; }
|
|
64
|
+
.paper-429-card :deep(.apple-card__body) { padding:0; text-align:center; }
|
|
65
|
+
.paper-429-number { font-size:70px; margin-bottom:18px; }
|
|
66
|
+
.paper-429-heading h1 { font-size:26px; margin-bottom:12px; }
|
|
67
|
+
.paper-429-actions { justify-content:center; margin-top:18px; }
|
|
68
|
+
}
|
|
69
|
+
@media(max-width:420px) {
|
|
70
|
+
.paper-429-page { padding-inline:18px; padding-top:12px; }
|
|
71
|
+
.paper-429-copy { font-size:12px; }
|
|
72
|
+
.paper-429-card { margin-top:30px; }
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="main-content paper-500-page">
|
|
3
|
+
<apple-card class="paper-500-card" shadow="none" zoom="none">
|
|
4
|
+
<template #title>
|
|
5
|
+
<div class="paper-500-heading">
|
|
6
|
+
<p class="paper-500-number" aria-hidden="true">500</p>
|
|
7
|
+
<h1>{{ page.title }}</h1>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<p class="paper-500-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
|
+
<div class="paper-500-actions">
|
|
12
|
+
<router-link v-slot="{ href, navigate }" :to="homePath" custom>
|
|
13
|
+
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
14
|
+
</router-link>
|
|
15
|
+
<apple-link as="button" @click="goBack"><ArrowLeft :size="16" aria-hidden="true" /> 返回上一页</apple-link>
|
|
16
|
+
</div>
|
|
17
|
+
</apple-card>
|
|
18
|
+
<ServerFirePaperScene class="paper-500-illustration" />
|
|
19
|
+
</main>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<route lang="json">
|
|
23
|
+
{ "alias": "/error/500", "meta": { "title": "服务器内部错误" } }
|
|
24
|
+
</route>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ArrowLeft } from 'lucide-vue-next'
|
|
28
|
+
import { useRouter } from 'vue-router'
|
|
29
|
+
import { errorPages } from '../error-pages'
|
|
30
|
+
import ServerFirePaperScene from '../components/server-fire-paper-scene.vue'
|
|
31
|
+
|
|
32
|
+
const page = errorPages[500]
|
|
33
|
+
const router = useRouter()
|
|
34
|
+
const homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'
|
|
35
|
+
function goBack() {
|
|
36
|
+
if (typeof router.options.history.state.back === 'string') router.back()
|
|
37
|
+
else void router.push(homePath)
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<style scoped>
|
|
42
|
+
.paper-500-page { max-width: 1360px; display: grid; grid-template-columns: minmax(260px, .78fr) minmax(0, 1.65fr); align-content: center; align-items: center; column-gap: 16px; padding-top: 38px; padding-bottom: calc(38px + 64px); }
|
|
43
|
+
.paper-500-card { background: transparent; border: 0; overflow: visible; }
|
|
44
|
+
.paper-500-card :deep(.apple-card__body) { padding: 0 0 0 8px; }
|
|
45
|
+
.paper-500-card :deep(.apple-card__heading) { margin: 0; }
|
|
46
|
+
.paper-500-heading { width: 100%; }
|
|
47
|
+
.paper-500-number { color: var(--apple-text); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(78px, 8.2vw, 118px); line-height: .9; letter-spacing: -.075em; margin: 0 0 28px; font-weight: 400; }
|
|
48
|
+
.paper-500-heading h1 { font-size: clamp(26px, 2.7vw, 35px); line-height: 1.35; letter-spacing: -.035em; font-weight: 600; margin: 0 0 17px; }
|
|
49
|
+
.paper-500-copy { font-size: 13px; line-height: 1.95; color: var(--apple-secondary); margin: 0; text-wrap: pretty; }
|
|
50
|
+
.paper-500-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 27px; }
|
|
51
|
+
.paper-500-actions .apple-link { font-size: 12px; padding-inline: 8px; color: var(--apple-secondary); }
|
|
52
|
+
.paper-500-illustration { min-width: 0; }
|
|
53
|
+
@media (max-width: 880px) {
|
|
54
|
+
.paper-500-page { grid-template-columns: minmax(0, 1fr); max-width: 680px; padding-top: 18px; }
|
|
55
|
+
.paper-500-illustration { grid-row: 1; }
|
|
56
|
+
.paper-500-card { margin-top: 26px; }
|
|
57
|
+
.paper-500-card :deep(.apple-card__body) { padding: 0; text-align: center; }
|
|
58
|
+
.paper-500-number { font-size: 70px; margin-bottom: 18px; }
|
|
59
|
+
.paper-500-heading h1 { font-size: 26px; margin-bottom: 12px; }
|
|
60
|
+
.paper-500-actions { justify-content: center; margin-top: 18px; }
|
|
61
|
+
}
|
|
62
|
+
@media (max-width: 420px) {
|
|
63
|
+
.paper-500-page { padding-inline: 18px; padding-top: 12px; }
|
|
64
|
+
.paper-500-copy { font-size: 12px; }
|
|
65
|
+
.paper-500-card { margin-top: 22px; }
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="main-content paper-502-page">
|
|
3
|
+
<apple-card class="paper-502-card" shadow="none" zoom="none">
|
|
4
|
+
<template #title>
|
|
5
|
+
<div class="paper-502-heading">
|
|
6
|
+
<p class="paper-502-number" aria-hidden="true">502</p>
|
|
7
|
+
<h1>{{ page.title }}</h1>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<p class="paper-502-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
|
+
<div class="paper-502-actions">
|
|
12
|
+
<router-link v-slot="{ href, navigate }" :to="homePath" custom>
|
|
13
|
+
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
14
|
+
</router-link>
|
|
15
|
+
<apple-link as="button" @click="goBack"><ArrowLeft :size="16" aria-hidden="true" /> 返回上一页</apple-link>
|
|
16
|
+
</div>
|
|
17
|
+
</apple-card>
|
|
18
|
+
<GatewayPaperScene class="paper-502-illustration" />
|
|
19
|
+
</main>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<route lang="json">
|
|
23
|
+
{ "alias": "/error/502", "meta": { "title": "网关错误" } }
|
|
24
|
+
</route>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ArrowLeft } from 'lucide-vue-next'
|
|
28
|
+
import { useRouter } from 'vue-router'
|
|
29
|
+
import GatewayPaperScene from '../components/gateway-paper-scene.vue'
|
|
30
|
+
|
|
31
|
+
import { errorPages } from '../error-pages'
|
|
32
|
+
|
|
33
|
+
const page = errorPages[502]
|
|
34
|
+
const router = useRouter()
|
|
35
|
+
const homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'
|
|
36
|
+
function goBack() {
|
|
37
|
+
if (typeof router.options.history.state.back === 'string') router.back()
|
|
38
|
+
else void router.push(homePath)
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style scoped>
|
|
43
|
+
.paper-502-page { max-width: 1360px; display: grid; grid-template-columns: minmax(260px, .78fr) minmax(0, 1.65fr); align-content: center; align-items: center; column-gap: 16px; padding-top: 38px; padding-bottom: calc(38px + 64px); }
|
|
44
|
+
.paper-502-card { background: transparent; border: 0; overflow: visible; }
|
|
45
|
+
.paper-502-card :deep(.apple-card__body) { padding: 0 0 0 8px; }
|
|
46
|
+
.paper-502-card :deep(.apple-card__heading) { margin: 0; }
|
|
47
|
+
.paper-502-heading { width: 100%; }
|
|
48
|
+
.paper-502-number { color: var(--apple-text); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(78px, 8.2vw, 118px); line-height: .9; letter-spacing: -.075em; margin: 0 0 28px; font-weight: 400; }
|
|
49
|
+
.paper-502-heading h1 { font-size: clamp(26px, 2.7vw, 35px); line-height: 1.35; letter-spacing: -.035em; font-weight: 600; margin: 0 0 17px; }
|
|
50
|
+
.paper-502-copy { font-size: 13px; line-height: 1.95; color: var(--apple-secondary); margin: 0; text-wrap: pretty; }
|
|
51
|
+
.paper-502-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 27px; }
|
|
52
|
+
.paper-502-actions .apple-link { font-size: 12px; padding-inline: 8px; color: var(--apple-secondary); }
|
|
53
|
+
.paper-502-illustration { min-width: 0; }
|
|
54
|
+
@media (max-width: 880px) {
|
|
55
|
+
.paper-502-page { grid-template-columns: minmax(0, 1fr); max-width: 680px; padding-top: 18px; }
|
|
56
|
+
.paper-502-illustration { grid-row: 1; }
|
|
57
|
+
.paper-502-card { margin-top: 26px; }
|
|
58
|
+
.paper-502-card :deep(.apple-card__body) { padding: 0; text-align: center; }
|
|
59
|
+
.paper-502-number { font-size: 70px; margin-bottom: 18px; }
|
|
60
|
+
.paper-502-heading h1 { font-size: 26px; margin-bottom: 12px; }
|
|
61
|
+
.paper-502-actions { justify-content: center; margin-top: 18px; }
|
|
62
|
+
}
|
|
63
|
+
@media (max-width: 420px) {
|
|
64
|
+
.paper-502-page { padding-inline: 18px; padding-top: 12px; }
|
|
65
|
+
.paper-502-copy { font-size: 12px; }
|
|
66
|
+
.paper-502-card { margin-top: 22px; }
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main class="main-content paper-503-page">
|
|
3
|
+
<apple-card class="paper-503-card" shadow="none" zoom="none">
|
|
4
|
+
<template #title>
|
|
5
|
+
<div class="paper-503-heading">
|
|
6
|
+
<p class="paper-503-number" aria-hidden="true">503</p>
|
|
7
|
+
<h1><span class="paper-503-sr-only">503 · </span>{{ page.title }}</h1>
|
|
8
|
+
<p class="paper-503-english" lang="en">Service temporarily unavailable</p>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
<p class="paper-503-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
12
|
+
<div class="paper-503-actions">
|
|
13
|
+
<router-link v-slot="{ href, navigate }" :to="homePath" custom>
|
|
14
|
+
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
15
|
+
</router-link>
|
|
16
|
+
<apple-link as="button" @click="goBack"><ArrowLeft :size="16" aria-hidden="true" /> 返回上一页</apple-link>
|
|
17
|
+
</div>
|
|
18
|
+
</apple-card>
|
|
19
|
+
<UnavailablePaperScene class="paper-503-illustration" :theme="scheme" :reduced-motion="reducedMotion" />
|
|
20
|
+
</main>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<route lang="json">
|
|
24
|
+
{ "alias": "/error/503", "meta": { "title": "服务暂时不可用" } }
|
|
25
|
+
</route>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { computed } from 'vue'
|
|
29
|
+
import { ArrowLeft } from 'lucide-vue-next'
|
|
30
|
+
import { useRouter } from 'vue-router'
|
|
31
|
+
import { useApple } from 'apptify'
|
|
32
|
+
import { resolveMotion } from 'apptify'
|
|
33
|
+
import UnavailablePaperScene from '../components/unavailable-paper-scene.vue'
|
|
34
|
+
|
|
35
|
+
import { errorPages } from '../error-pages'
|
|
36
|
+
|
|
37
|
+
const page = errorPages[503]
|
|
38
|
+
const router = useRouter()
|
|
39
|
+
const homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'
|
|
40
|
+
const apple = useApple()
|
|
41
|
+
const scheme = computed(() => apple.theme.value.current.scheme)
|
|
42
|
+
const reducedMotion = computed(() => resolveMotion('inherit', apple.motion.value.mode, apple.motion.value.reduced) !== 'full')
|
|
43
|
+
|
|
44
|
+
function goBack() {
|
|
45
|
+
if (typeof router.options.history.state.back === 'string') router.back()
|
|
46
|
+
else void router.push(homePath)
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<style scoped>
|
|
51
|
+
.paper-503-page { max-width: 1360px; display: grid; grid-template-columns: minmax(260px, .78fr) minmax(0, 1.65fr); align-content: center; align-items: center; column-gap: 16px; padding-top: 38px; padding-bottom: calc(38px + 64px); }
|
|
52
|
+
.paper-503-card { background: transparent; border: 0; overflow: visible; }
|
|
53
|
+
.paper-503-card :deep(.apple-card__body) { padding: 0 0 0 8px; }
|
|
54
|
+
.paper-503-card :deep(.apple-card__heading) { margin: 0; }
|
|
55
|
+
.paper-503-heading { width: 100%; }
|
|
56
|
+
.paper-503-number { color: var(--apple-text); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(78px, 8.2vw, 118px); line-height: .9; letter-spacing: -.075em; margin: 0 0 28px; font-weight: 400; }
|
|
57
|
+
.paper-503-heading h1 { font-size: clamp(26px, 2.7vw, 35px); line-height: 1.35; letter-spacing: -.035em; font-weight: 600; margin: 0 0 9px; }
|
|
58
|
+
.paper-503-english { font-size: 11px; line-height: 1.6; letter-spacing: .015em; color: var(--apple-secondary); margin: 0 0 20px; font-weight: 400; }
|
|
59
|
+
.paper-503-copy { font-size: 13px; line-height: 1.95; color: var(--apple-secondary); margin: 0; text-wrap: pretty; }
|
|
60
|
+
.paper-503-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 27px; }
|
|
61
|
+
.paper-503-actions .apple-link { font-size: 12px; padding-inline: 8px; color: var(--apple-secondary); }
|
|
62
|
+
.paper-503-illustration { min-width: 0; }
|
|
63
|
+
.paper-503-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
64
|
+
@media (max-width: 880px) {
|
|
65
|
+
.paper-503-page { grid-template-columns: minmax(0, 1fr); max-width: 680px; padding-top: 18px; }
|
|
66
|
+
.paper-503-illustration { grid-row: 1; }
|
|
67
|
+
.paper-503-card { margin-top: 26px; }
|
|
68
|
+
.paper-503-card :deep(.apple-card__body) { padding: 0; text-align: center; }
|
|
69
|
+
.paper-503-number { font-size: 70px; margin-bottom: 18px; }
|
|
70
|
+
.paper-503-heading h1 { font-size: 26px; margin-bottom: 8px; }
|
|
71
|
+
.paper-503-english { margin-bottom: 15px; }
|
|
72
|
+
.paper-503-actions { justify-content: center; margin-top: 18px; }
|
|
73
|
+
}
|
|
74
|
+
@media (max-width: 420px) {
|
|
75
|
+
.paper-503-page { padding-inline: 18px; padding-top: 12px; }
|
|
76
|
+
.paper-503-copy { font-size: 12px; }
|
|
77
|
+
.paper-503-card { margin-top: 22px; }
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<template #title>
|
|
5
5
|
<div class="paper-404-heading">
|
|
6
6
|
<p class="paper-404-number" aria-hidden="true">404</p>
|
|
7
|
-
<h1
|
|
7
|
+
<h1>{{ page.title }}</h1>
|
|
8
8
|
</div>
|
|
9
9
|
</template>
|
|
10
|
-
<p class="paper-404-copy"
|
|
10
|
+
<p class="paper-404-copy">{{ page.copy[0] }}<br />{{ page.copy[1] }}</p>
|
|
11
11
|
<div class="paper-404-actions">
|
|
12
12
|
<router-link v-slot="{ href, navigate }" :to="homePath" custom>
|
|
13
13
|
<apple-button :href="href" @click="navigate">返回首页</apple-button>
|
|
@@ -24,6 +24,9 @@ import { ArrowLeft } from 'lucide-vue-next'
|
|
|
24
24
|
import { useRouter } from 'vue-router'
|
|
25
25
|
import NotFoundPaperScene from '../components/not-found-paper-scene.vue'
|
|
26
26
|
|
|
27
|
+
import { errorPages } from '../error-pages'
|
|
28
|
+
|
|
29
|
+
const page = errorPages[404]
|
|
27
30
|
const router = useRouter()
|
|
28
31
|
const homePath = router.getRoutes().some(page => page.path === '/') ? '/' : '/settings'
|
|
29
32
|
function goBack() {
|
|
@@ -12,10 +12,9 @@
|
|
|
12
12
|
<div class="components-content">
|
|
13
13
|
<div class="feed-toolbar">
|
|
14
14
|
<span class="feed-count">全部组件 <small>{{ catalog.length }}</small></span>
|
|
15
|
-
<
|
|
16
|
-
<apple-link
|
|
17
|
-
|
|
18
|
-
</div>
|
|
15
|
+
<router-link v-slot="{ href, navigate }" to="#error-pages" custom>
|
|
16
|
+
<apple-link :href="href" @click="navigate">错误页面 <ArrowDown :size="14" aria-hidden="true" /></apple-link>
|
|
17
|
+
</router-link>
|
|
19
18
|
</div>
|
|
20
19
|
<div ref="feed" class="component-feed">
|
|
21
20
|
<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,12 +22,13 @@
|
|
|
23
22
|
<MasonryFeed class="feed-cards" @layout="schedulePosition">
|
|
24
23
|
<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`">
|
|
25
24
|
<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>
|
|
26
|
-
<section class="detail-preview" :
|
|
25
|
+
<section class="detail-preview" :aria-label="`${item.label}预览`"><ComponentDemo :name="item.name" @navigate="navigateGroup" /></section>
|
|
27
26
|
<ComponentDocumentLink :href="documentPaths[item.name]" label="代码与 API" />
|
|
28
27
|
</apple-card>
|
|
29
28
|
</MasonryFeed>
|
|
30
29
|
</section>
|
|
31
30
|
</div>
|
|
31
|
+
<ErrorPagePreviews id="error-pages" class="feed-anchor" />
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
</apple-container>
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
<script setup lang="ts">
|
|
39
39
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
40
40
|
import { useRoute, useRouter } from 'vue-router'
|
|
41
|
-
import {
|
|
41
|
+
import { ArrowDown, Hash } from 'lucide-vue-next'
|
|
42
42
|
import { catalog, sections, componentId } from '../catalog'
|
|
43
43
|
import ComponentDemo from '../ComponentDemo.vue'
|
|
44
44
|
import ComponentIndex from '../components/ComponentIndex.vue'
|
|
45
|
+
import ErrorPagePreviews from '../components/ErrorPagePreviews.vue'
|
|
45
46
|
import MasonryFeed from '../components/MasonryFeed.vue'
|
|
46
47
|
import ComponentDocumentLink from '../editor/ComponentDocumentLink.vue'
|
|
47
48
|
import { componentDocuments, componentDocumentPath } from '../editor/documents'
|
|
@@ -52,7 +53,6 @@ const router = useRouter()
|
|
|
52
53
|
const feed = ref<HTMLElement>()
|
|
53
54
|
const activeGroup = ref(sections[0].id)
|
|
54
55
|
const activeId = ref('')
|
|
55
|
-
const previewMode = ref('desktop')
|
|
56
56
|
const expandedGroups = ref(sections.map(section => section.id))
|
|
57
57
|
let anchors: HTMLElement[] = []
|
|
58
58
|
let frame = 0
|
|
@@ -107,7 +107,7 @@ onBeforeUnmount(() => {
|
|
|
107
107
|
.directory-index { display: flex; flex-direction: column; overflow: hidden; }
|
|
108
108
|
.directory-header { flex-shrink: 0; }
|
|
109
109
|
.directory-header > span { color: var(--apple-secondary); font-size: 12px; display: block; margin: 0 0 12px 8px; }
|
|
110
|
-
.directory-tree { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
|
110
|
+
.directory-tree { display: flex; flex-direction: column; min-height: 0; overflow: hidden; padding-inline: var(--apple-focus-clearance, 6px); padding-block-start: var(--apple-focus-clearance, 6px); }
|
|
111
111
|
@media (max-width: 900px) { .directory-index { display: none; } }
|
|
112
112
|
.components-page > * { max-width: none; }
|
|
113
113
|
.feed-anchor { scroll-margin-top: 96px; }
|
|
@@ -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 (['[...all].vue', '403.vue'].some(view => path === join(output, 'src/views', view))) {
|
|
53
|
+
if (['[...all].vue', '403.vue', '500.vue', '502.vue', '503.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)')
|
|
@@ -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 应用,包含导航、账号表单、外观设置、403、404 与组件示例。建议 Node.js 22 或 24 LTS。",
|
|
95
|
+
"可编辑的 Vue 应用,包含导航、账号表单、外观设置、403、404、502、503 与组件示例。建议 Node.js 22 或 24 LTS。",
|
|
96
96
|
"",
|
|
97
97
|
"```sh",
|
|
98
98
|
"npm install",
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { type PropType } from 'vue';
|
|
2
|
-
import { type ScrollBarAxis } from '../core/scrollbar';
|
|
3
|
-
export declare const AppleScrollBar: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
4
|
-
target: {
|
|
5
|
-
type: PropType<string | HTMLElement | (() => HTMLElement | undefined)>;
|
|
6
|
-
default: string;
|
|
7
|
-
};
|
|
8
|
-
axis: {
|
|
9
|
-
type: PropType<ScrollBarAxis>;
|
|
10
|
-
default: string;
|
|
11
|
-
};
|
|
12
|
-
label: {
|
|
13
|
-
type: StringConstructor;
|
|
14
|
-
default: string;
|
|
15
|
-
};
|
|
16
|
-
controls: {
|
|
17
|
-
type: StringConstructor;
|
|
18
|
-
default: string;
|
|
19
|
-
};
|
|
20
|
-
}>, () => null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "interaction"[], "interaction", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
21
|
-
target: {
|
|
22
|
-
type: PropType<string | HTMLElement | (() => HTMLElement | undefined)>;
|
|
23
|
-
default: string;
|
|
24
|
-
};
|
|
25
|
-
axis: {
|
|
26
|
-
type: PropType<ScrollBarAxis>;
|
|
27
|
-
default: string;
|
|
28
|
-
};
|
|
29
|
-
label: {
|
|
30
|
-
type: StringConstructor;
|
|
31
|
-
default: string;
|
|
32
|
-
};
|
|
33
|
-
controls: {
|
|
34
|
-
type: StringConstructor;
|
|
35
|
-
default: string;
|
|
36
|
-
};
|
|
37
|
-
}>> & Readonly<{
|
|
38
|
-
onInteraction?: ((...args: any[]) => any) | undefined;
|
|
39
|
-
}>, {
|
|
40
|
-
label: string;
|
|
41
|
-
target: string | HTMLElement | (() => HTMLElement | undefined);
|
|
42
|
-
axis: ScrollBarAxis;
|
|
43
|
-
controls: string;
|
|
44
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
45
|
-
export declare const scrollBarComponents: {
|
|
46
|
-
AppleScrollBar: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
47
|
-
target: {
|
|
48
|
-
type: PropType<string | HTMLElement | (() => HTMLElement | undefined)>;
|
|
49
|
-
default: string;
|
|
50
|
-
};
|
|
51
|
-
axis: {
|
|
52
|
-
type: PropType<ScrollBarAxis>;
|
|
53
|
-
default: string;
|
|
54
|
-
};
|
|
55
|
-
label: {
|
|
56
|
-
type: StringConstructor;
|
|
57
|
-
default: string;
|
|
58
|
-
};
|
|
59
|
-
controls: {
|
|
60
|
-
type: StringConstructor;
|
|
61
|
-
default: string;
|
|
62
|
-
};
|
|
63
|
-
}>, () => null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "interaction"[], "interaction", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
64
|
-
target: {
|
|
65
|
-
type: PropType<string | HTMLElement | (() => HTMLElement | undefined)>;
|
|
66
|
-
default: string;
|
|
67
|
-
};
|
|
68
|
-
axis: {
|
|
69
|
-
type: PropType<ScrollBarAxis>;
|
|
70
|
-
default: string;
|
|
71
|
-
};
|
|
72
|
-
label: {
|
|
73
|
-
type: StringConstructor;
|
|
74
|
-
default: string;
|
|
75
|
-
};
|
|
76
|
-
controls: {
|
|
77
|
-
type: StringConstructor;
|
|
78
|
-
default: string;
|
|
79
|
-
};
|
|
80
|
-
}>> & Readonly<{
|
|
81
|
-
onInteraction?: ((...args: any[]) => any) | undefined;
|
|
82
|
-
}>, {
|
|
83
|
-
label: string;
|
|
84
|
-
target: string | HTMLElement | (() => HTMLElement | undefined);
|
|
85
|
-
axis: ScrollBarAxis;
|
|
86
|
-
controls: string;
|
|
87
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
88
|
-
};
|
package/dist/core/scrollbar.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type ScrollBarAxis = 'both' | 'horizontal' | 'vertical';
|
|
2
|
-
interface ScrollBarOptions {
|
|
3
|
-
axis?: ScrollBarAxis;
|
|
4
|
-
label?: string;
|
|
5
|
-
controls?: string;
|
|
6
|
-
host?: HTMLElement;
|
|
7
|
-
interaction?: () => void;
|
|
8
|
-
}
|
|
9
|
-
export declare function attachScrollBar(target: HTMLElement, options?: ScrollBarOptions): {
|
|
10
|
-
refresh: () => void;
|
|
11
|
-
dispose(): void;
|
|
12
|
-
};
|
|
13
|
-
export declare function installScrollBars(host: HTMLElement): () => void;
|
|
14
|
-
export {};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { defineHandbook } from '../handbook'
|
|
2
|
-
|
|
3
|
-
export default defineHandbook({
|
|
4
|
-
name: 'AppleScrollBar', source: 'src/components/scrollbar.ts',
|
|
5
|
-
props: [
|
|
6
|
-
{ name: 'target', type: 'string | HTMLElement | (() => HTMLElement | undefined)', default: '""', description: 'CSS 选择器、元素或返回元素的函数;空值自动接管当前文档的滚动容器。' },
|
|
7
|
-
{ name: 'axis', type: "'both' | 'horizontal' | 'vertical'", default: '"both"', description: '指定目标时显示的滚动方向。' },
|
|
8
|
-
{ name: 'label', type: 'string', default: '""', description: '滚动条的可访问名称,默认从目标名称生成。' },
|
|
9
|
-
{ name: 'controls', type: 'string', default: '""', description: '目标元素 ID;未提供时使用或生成目标 ID。' },
|
|
10
|
-
],
|
|
11
|
-
events: [{ name: 'interaction', type: '() => void', description: '拖动、点击轨道、键盘或滚轮操作时触发。' }],
|
|
12
|
-
slots: [],
|
|
13
|
-
methods: [{ name: 'refresh()', type: '() => void', description: '重新测量目标及滚动位置。尺寸、内容和滚动变化默认自动同步。' }],
|
|
14
|
-
notes: ['AppleProvider 默认启用全局接管,无需逐个包裹内容。滚动条使用 fixed,不占布局空间;z-index 跟随目标及祖先层级,默认为 0,弹窗内留在所属弹层上下文。', '原本主动隐藏滚动条的轮播、标签栏与日期滚轮保持原有交互;data-apple-scrollbar-ignore 可排除指定容器。'],
|
|
15
|
-
})
|