apptify 0.2.0 → 0.5.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 +95 -22
- package/dist/apptify.css +1 -1
- package/dist/apptify.js +4153 -2177
- package/dist/components/button.d.ts +1 -1
- package/dist/components/content.d.ts +73 -362
- package/dist/components/date-picker.d.ts +10 -0
- package/dist/components/forms.d.ts +77 -18
- package/dist/components/foundation.d.ts +2061 -111
- package/dist/components/gallery-scrollbar.d.ts +46 -0
- package/dist/components/mobile-image-viewer.d.ts +166 -0
- package/dist/components/navibar.d.ts +80 -0
- package/dist/components/overlays.d.ts +127 -158
- package/dist/components/tabs.d.ts +117 -0
- package/dist/core/context.d.ts +573 -9
- package/dist/core/desktop-image-enter.d.ts +6 -0
- package/dist/core/desktop-image-return.d.ts +1 -0
- package/dist/core/device.d.ts +5 -0
- package/dist/core/image-gallery-motion.d.ts +2 -0
- package/dist/core/image-geometry.d.ts +28 -0
- package/dist/core/image-motion.d.ts +18 -0
- package/dist/core/layers.d.ts +2 -0
- package/dist/core/motion.d.ts +2 -0
- package/dist/core/popup-motion.d.ts +12 -0
- package/dist/core/popup-placement.d.ts +31 -0
- package/dist/core/preview-navigation.d.ts +5 -0
- package/dist/index.d.ts +1214 -339
- package/docs/COMPONENTS.md +17 -15
- package/docs/PLAYGROUND-TEMPLATE.md +74 -0
- package/docs/VALIDATION.md +24 -0
- package/package.json +26 -7
- package/templates/playground/README.md +17 -0
- package/templates/playground/gitignore +3 -0
- package/templates/playground/index.html +26 -0
- package/templates/playground/package.json +26 -0
- package/templates/playground/playground/App.vue +73 -0
- package/templates/playground/playground/ComponentDemo.vue +234 -0
- package/templates/playground/playground/catalog.ts +80 -0
- package/templates/playground/playground/components/ComponentIndex.vue +62 -0
- package/templates/playground/playground/components/PageFooter.vue +3 -0
- package/templates/playground/playground/components/UserMenu.vue +132 -0
- package/templates/playground/playground/components/not-found-paper-scene.vue +210 -0
- package/templates/playground/playground/components/not-found-paper-story.ts +149 -0
- package/templates/playground/playground/env.d.ts +1 -0
- package/templates/playground/playground/main.ts +8 -0
- package/templates/playground/playground/router/index.ts +24 -0
- package/templates/playground/playground/style.css +228 -0
- package/templates/playground/playground/views/[...all].vue +68 -0
- package/templates/playground/playground/views/components.vue +126 -0
- package/templates/playground/playground/views/index.vue +75 -0
- package/templates/playground/playground/views/settings.vue +98 -0
- package/templates/playground/public/images/SOURCES.md +21 -0
- package/templates/playground/public/images/airpods-max-orange.jpg +0 -0
- package/templates/playground/public/images/architecture.jpg +0 -0
- package/templates/playground/public/images/city.jpg +0 -0
- package/templates/playground/public/images/coast.jpg +0 -0
- package/templates/playground/public/images/desert.jpg +0 -0
- package/templates/playground/public/images/food.jpg +0 -0
- package/templates/playground/public/images/forest.jpg +0 -0
- package/templates/playground/public/images/lake.jpg +0 -0
- package/templates/playground/public/images/mountains.jpg +0 -0
- package/templates/playground/public/images/snow.jpg +0 -0
- package/templates/playground/public/images/sunset.jpg +0 -0
- package/templates/playground/public/images/waterfall.jpg +0 -0
- package/templates/playground/source-snapshot.json +111 -0
- package/templates/playground/tsconfig.json +24 -0
- package/templates/playground/vite.config.ts +9 -0
- package/tooling/create-playground.mjs +35 -0
- package/tooling/prepare-package.mjs +35 -0
- package/tooling/prepare-playground.mjs +90 -0
- package/tooling/test-playground-package.mjs +188 -0
- package/tooling/vite.d.ts +5 -0
- package/tooling/vite.js +10 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="component-demo" :class="demoClass" :data-component="name">
|
|
3
|
+
<apple-stack v-if="name === 'AppleButton'" direction="row" align="center">
|
|
4
|
+
<apple-button @click="notify('操作已完成')">继续</apple-button>
|
|
5
|
+
<apple-button variant="secondary" @click="notify('已选择次要操作')">稍后再说</apple-button>
|
|
6
|
+
<apple-button variant="outline" @click="notify('已加入收藏')">加入收藏</apple-button>
|
|
7
|
+
<apple-button variant="ghost" :icon="icons.ArrowUpRight" @click="notify('正在查看详情')">了解更多</apple-button>
|
|
8
|
+
<apple-button :icon="icons.Plus" icon-only label="添加" @click="notify('已添加')" />
|
|
9
|
+
<apple-button loading>处理中</apple-button><apple-button disabled>暂不可用</apple-button>
|
|
10
|
+
</apple-stack>
|
|
11
|
+
<apple-stack v-else-if="name === 'AppleLink'" direction="row" align="center">
|
|
12
|
+
<apple-link href="https://www.apple.com.cn/" external>Apple 官网</apple-link>
|
|
13
|
+
<apple-link href="https://www.apple.com.cn/accessibility/" external>辅助功能</apple-link>
|
|
14
|
+
<apple-link disabled external>暂不可用</apple-link>
|
|
15
|
+
</apple-stack>
|
|
16
|
+
<apple-stack v-else-if="name === 'AppleSearch'">
|
|
17
|
+
<apple-search v-model="searchText" label="搜索设置" placeholder="搜索设置" @search="notify(searchText ? `正在搜索:${searchText}` : '显示全部设置')" />
|
|
18
|
+
<apple-list v-if="searchResults.length" v-model="setting" :items="searchResults" selectable @select="notify('已选择设置项')" />
|
|
19
|
+
<apple-empty v-else title="没有找到相关设置" />
|
|
20
|
+
</apple-stack>
|
|
21
|
+
<apple-stack v-else-if="name === 'AppleProvider'">
|
|
22
|
+
<apple-segmented-control v-model="previewTheme" :items="previewThemes" label="局部外观" />
|
|
23
|
+
<apple-provider :theme="previewTheme" motion="auto" style="padding: 24px">
|
|
24
|
+
<apple-stack>
|
|
25
|
+
<apple-input v-model="text" label="显示名称" placeholder="你的名称" />
|
|
26
|
+
<apple-switch v-model="checked" label="接收通知" />
|
|
27
|
+
<apple-button @click="notify('偏好已保存')">保存偏好</apple-button>
|
|
28
|
+
</apple-stack>
|
|
29
|
+
</apple-provider>
|
|
30
|
+
</apple-stack>
|
|
31
|
+
<apple-stack v-else-if="name === 'AppleContainer'">
|
|
32
|
+
<apple-slider v-model="containerWidth" label="内容宽度" :min="240" :max="640" :step="40" />
|
|
33
|
+
<apple-container :width="containerWidth">
|
|
34
|
+
<apple-stack><apple-button v-for="section in layoutItems" :key="section" variant="secondary" @click="notify(`已选择${section}`)">{{ section }}</apple-button></apple-stack>
|
|
35
|
+
</apple-container>
|
|
36
|
+
</apple-stack>
|
|
37
|
+
<apple-stack v-else-if="name === 'AppleStack'">
|
|
38
|
+
<apple-segmented-control v-model="stackDirection" :items="[{label:'横向',value:'row'},{label:'纵向',value:'column'}]" label="排列方向" />
|
|
39
|
+
<apple-stack :direction="stackDirection" :gap="16" align="center">
|
|
40
|
+
<apple-button v-for="section in layoutItems" :key="section" variant="secondary" @click="notify(`已选择${section}`)">{{ section }}</apple-button>
|
|
41
|
+
</apple-stack>
|
|
42
|
+
</apple-stack>
|
|
43
|
+
<apple-stack v-else-if="name === 'AppleGrid'">
|
|
44
|
+
<apple-slider v-model="gridMin" label="最小列宽" :min="120" :max="320" :step="40" />
|
|
45
|
+
<apple-grid :min="gridMin" :gap="16">
|
|
46
|
+
<div v-for="(section, index) in layoutItems" :key="section" class="demo-layout-tile"><span>0{{ index + 1 }}</span><strong>{{ section }}</strong></div>
|
|
47
|
+
</apple-grid>
|
|
48
|
+
</apple-stack>
|
|
49
|
+
<apple-card v-else-if="name === 'AppleCard'" class="demo-product" title="AirPods Max" subtitle="每个音符,都更动听。" eyebrow="声音,出类拔萃。">
|
|
50
|
+
<apple-image :gallery="{ src: '/images/airpods-max-orange.jpg', alt: '橙色 AirPods Max 耳机' }" aspect-ratio="1" fit="contain" />
|
|
51
|
+
<template #actions><apple-button @click="notify('已加入购物袋')">加入购物袋</apple-button><apple-button variant="ghost" :icon="icons.Heart" icon-only label="收藏" @click="notify('已收藏')" /></template>
|
|
52
|
+
</apple-card>
|
|
53
|
+
<apple-stack v-else-if="name === 'AppleImage'" class="demo-image">
|
|
54
|
+
<apple-segmented-control v-model="imageLayout" :items="[{label:'省空间',value:'compact'},{label:'平铺',value:'tiled'},{label:'换行平铺',value:'tiled-wrap'}]" label="图片组布局" />
|
|
55
|
+
<apple-switch v-model="imageCarousel" label="轮播模式" />
|
|
56
|
+
<apple-switch v-model="imageSquare" label="强制 1:1(裁剪)" />
|
|
57
|
+
<apple-image :carousel="imageCarousel" :gallery="imageCarousel ? slides : galleryImages" :gallery-layout="imageLayout" :gallery-shape="imageSquare ? 'square' : 'natural'" />
|
|
58
|
+
</apple-stack>
|
|
59
|
+
<apple-stack v-else-if="name === 'AppleAvatar'"><apple-slider v-model="avatarSize" label="头像尺寸" :min="24" :max="72" :step="8" /><apple-stack direction="row" align="center"><apple-avatar name="林初" :size="avatarSize" /><apple-avatar name="Alex" :size="avatarSize" /><apple-avatar name="Taylor" :size="avatarSize" square /></apple-stack></apple-stack>
|
|
60
|
+
<apple-stack v-else-if="name === 'AppleAvatarGroup'"><apple-stepper v-model="avatarMax" label="显示人数" :min="1" :max="5" /><apple-avatar-group :items="people" :max="avatarMax" :size="44" label="设计团队" /></apple-stack>
|
|
61
|
+
<apple-stack v-else-if="name === 'AppleBadge'" direction="row" align="center"><apple-badge :value="unread"><apple-button variant="secondary" :icon="icons.Bell" @click="unread++">新消息</apple-button></apple-badge><apple-button variant="ghost" :disabled="!unread" @click="unread = 0">全部已读</apple-button></apple-stack>
|
|
62
|
+
<apple-stack v-else-if="name === 'AppleTag'" class="demo-tag-row" direction="row" align="center" :gap="10"><apple-tag>默认标签</apple-tag><apple-tag tone="success">已完成</apple-tag><apple-tag tone="info">进行中</apple-tag><apple-tag tone="warning">待确认</apple-tag><apple-tag v-if="tag" label="设计系统" closable @close="tag = false">设计系统</apple-tag><apple-button v-else variant="ghost" :icon="icons.Plus" @click="tag = true">添加标签</apple-button></apple-stack>
|
|
63
|
+
<apple-stack v-else-if="name === 'AppleDivider'"><apple-switch v-model="dividerVertical" label="纵向分隔" /><apple-stack :direction="dividerVertical ? 'row' : 'column'" :gap="0" align="center"><span>配送到家</span><apple-divider :vertical="dividerVertical" :label="dividerVertical ? undefined : '更多选择'" /><span>到店取货</span></apple-stack></apple-stack>
|
|
64
|
+
<apple-input v-else-if="name === 'AppleInput'" v-model="text" label="姓名" placeholder="怎么称呼你" clearable />
|
|
65
|
+
<apple-textarea v-else-if="name === 'AppleTextarea'" v-model="bio" label="个人简介" placeholder="写下你的想法" :maxlength="160" counter />
|
|
66
|
+
<apple-select v-else-if="name === 'AppleSelect'" v-model="city" label="所在城市" :items="cities" />
|
|
67
|
+
<apple-autocomplete v-else-if="name === 'AppleAutocomplete'" v-model="device" label="搜索设备" :items="devices" />
|
|
68
|
+
<apple-checkbox v-else-if="name === 'AppleCheckbox'" v-model="checked" label="我已阅读并同意条款" />
|
|
69
|
+
<apple-radio-group v-else-if="name === 'AppleRadioGroup'" v-model="delivery" label="配送方式" :items="deliveryItems" />
|
|
70
|
+
<apple-switch v-else-if="name === 'AppleSwitch'" v-model="checked" label="接收通知" />
|
|
71
|
+
<apple-slider v-else-if="name === 'AppleSlider'" v-model="volume" label="音量" />
|
|
72
|
+
<apple-stepper v-else-if="name === 'AppleStepper'" v-model="quantity" label="数量" :min="1" :max="10" />
|
|
73
|
+
<apple-segmented-control v-else-if="name === 'AppleSegmentedControl'" v-model="period" :items="periods" label="统计周期" />
|
|
74
|
+
<apple-stack v-else-if="name === 'AppleDatePicker'"><apple-select v-model="dateFormat" :items="dateFormats" label="日期精度" @update:model-value="date=''" /><apple-date-picker :key="dateFormat" v-model="date" :format="dateFormat" label="到店日期" /></apple-stack>
|
|
75
|
+
<apple-color-picker v-else-if="name === 'AppleColorPicker'" v-model="color" label="强调色" />
|
|
76
|
+
<apple-upload v-else-if="name === 'AppleUpload'" v-model="files" label="上传图片" accept="image/*" multiple :max-files="5" :max-size="5000000" @reject="notify('文件类型、大小或数量不符合要求')" />
|
|
77
|
+
<apple-otp-input v-else-if="name === 'AppleOtpInput'" v-model="otp" label="验证码" @complete="notify('验证码已填完')" />
|
|
78
|
+
<apple-cascader v-else-if="name === 'AppleCascader'" v-model="region" label="所在地区" :items="regions" />
|
|
79
|
+
<apple-rate v-else-if="name === 'AppleRate'" v-model="rating" label="体验评分" />
|
|
80
|
+
<apple-form v-else-if="name === 'AppleForm'" :validator="validate" @submit="notify('表单提交成功')">
|
|
81
|
+
<apple-input v-model="text" label="姓名" name="name" required placeholder="请输入姓名" />
|
|
82
|
+
<apple-input v-model="email" label="邮箱" name="email" type="email" required placeholder="name@example.com" />
|
|
83
|
+
<apple-button type="submit">提交</apple-button>
|
|
84
|
+
</apple-form>
|
|
85
|
+
<apple-form-field v-else-if="name === 'AppleFormField'" label="个人网站" :error="website && !website.startsWith('https://') ? '请输入以 https:// 开头的网址' : ''" hint="你的公开主页">
|
|
86
|
+
<template #default="field"><input v-bind="field" v-model="website" class="apple-control" type="url" placeholder="https://example.com" /></template>
|
|
87
|
+
</apple-form-field>
|
|
88
|
+
<apple-navibar v-else-if="name === 'AppleNavibar'" v-model="tab" brand="Apptify" :fixed="false" :items="tabs" label="示例导航"><template #actions><apple-button variant="ghost" :icon="icons.Bell" icon-only label="通知" @click="notify('暂无新通知')" /></template></apple-navibar>
|
|
89
|
+
<apple-aside v-else-if="name === 'AppleAside'" :hide-on-preview="false" aria-label="示例侧栏"><apple-list v-model="setting" :items="settings" selectable /></apple-aside>
|
|
90
|
+
<apple-tabs v-else-if="name === 'AppleTabs'" v-model="tab" :items="tabs"><template #default="{ value }"><p class="demo-copy">{{ value === 'overview' ? '这里是产品概览。' : value === 'spec' ? '这里是技术规格。' : '你的服务与支持。' }}</p></template></apple-tabs>
|
|
91
|
+
<apple-tab-bar v-else-if="name === 'AppleTabBar'" v-model="tab" :items="tabs"><template #default="{ value }"><p class="demo-copy">{{ value === 'overview' ? '这里是产品概览。' : value === 'spec' ? '这里是技术规格。' : '你的服务与支持。' }}</p></template></apple-tab-bar>
|
|
92
|
+
<apple-breadcrumbs v-else-if="name === 'AppleBreadcrumbs'" :items="[{label:'组件',value:'home'},{label:'导航',value:'nav'},{label:'面包屑',value:'current'}]" @click="item=>$emit('navigate',item.value==='home'?'全部组件':'导航')" />
|
|
93
|
+
<apple-pagination v-else-if="name === 'ApplePagination'" v-model="page" :total="120" :page-size="10" />
|
|
94
|
+
<apple-steps v-else-if="name === 'AppleSteps'" v-model="step" :items="steps" clickable />
|
|
95
|
+
<apple-accordion v-else-if="name === 'AppleAccordion'" :items="questions" />
|
|
96
|
+
<apple-stack v-else-if="name === 'AppleTable'"><apple-switch v-model="virtualTable" label="虚拟滚动 · 5000 行" /><apple-table :columns="columns" :rows="virtualTable ? virtualRows : rows" selectable :virtual="virtualTable" :height="360" :page-size="virtualTable ? 0 : 3" /></apple-stack>
|
|
97
|
+
<apple-tree v-else-if="name === 'AppleTree'" v-model="tree" :items="folders" />
|
|
98
|
+
<apple-list v-else-if="name === 'AppleList'" v-model="setting" :items="settings" selectable @select="notify('已选择设置项')" />
|
|
99
|
+
<apple-stack v-else-if="name === 'AppleTimeline'"><apple-segmented-control v-model="timelineDirection" :items="[{label:'纵向',value:'vertical'},{label:'横向',value:'horizontal'}]" label="时间线方向" /><apple-timeline :items="events" :orientation="timelineDirection" /><apple-button variant="secondary" @click="updateDelivery">{{ delivered ? '查看配送过程' : '确认签收' }}</apple-button></apple-stack>
|
|
100
|
+
<apple-stack v-else-if="name === 'AppleStatistic'"><apple-segmented-control v-model="period" :items="periods" label="统计周期" /><apple-statistic :label="period === 'day' ? '今日访问' : period === 'week' ? '本周访问' : '本月访问'" :value="period === 'day' ? 428 : period === 'week' ? 2996 : 12840" suffix="次" description="最新访问数据" /></apple-stack>
|
|
101
|
+
<apple-stack v-else-if="name === 'AppleDialog'" direction="row"><apple-button @click="openDialog">打开对话框</apple-button><apple-button variant="secondary" @click="openStack">多层对话框</apple-button></apple-stack>
|
|
102
|
+
<template v-else-if="name === 'AppleDrawer'"><apple-button @click="drawer = true">打开抽屉</apple-button><apple-drawer v-model="drawer" title="偏好设置"><apple-stack><apple-switch v-model="checked" label="接收通知" /><apple-slider v-model="volume" label="音量" /></apple-stack></apple-drawer></template>
|
|
103
|
+
<template v-else-if="name === 'AppleSheet'"><apple-button @click="sheet = true">打开底部面板</apple-button><apple-sheet v-model="sheet" title="分享这份灵感"><apple-stack direction="row"><apple-button @click="notify('链接已准备好'); sheet = false">生成链接</apple-button><apple-button variant="secondary" @click="sheet = false">取消</apple-button></apple-stack></apple-sheet></template>
|
|
104
|
+
<apple-stack v-else-if="name === 'AppleSnackbar'" direction="row"><apple-button @click="notify('你的更改已保存')">成功提示</apple-button><apple-button variant="secondary" @click="$apple.notify('网络连接暂时中断', {tone:'warning'})">提醒</apple-button><apple-button variant="outline" @click="notify('第一条消息'); notify('第二条消息')">堆叠提示</apple-button></apple-stack>
|
|
105
|
+
<apple-stack v-else-if="name === 'AppleAlert'"><apple-alert v-model="alertVisible" title="一切已就绪" tone="success" closable>内容已同步到你的所有设备。</apple-alert><apple-button v-if="!alertVisible" variant="secondary" @click="alertVisible = true">重新同步</apple-button></apple-stack>
|
|
106
|
+
<apple-stack v-else-if="name === 'AppleProgress'"><apple-progress :model-value="volume" label="正在上传" show-value /><apple-slider v-model="volume" label="进度" /></apple-stack>
|
|
107
|
+
<apple-stack v-else-if="name === 'AppleSpinner'"><apple-switch v-model="demoLoading" label="同步内容" /><apple-spinner v-if="demoLoading" label="正在同步">正在同步</apple-spinner><apple-tag v-else tone="success">已同步</apple-tag></apple-stack>
|
|
108
|
+
<apple-stack v-else-if="name === 'AppleSkeleton'"><apple-select v-model="skeletonVariant" :items="skeletonVariants" label="骨架类型" /><apple-switch v-model="demoLoading" label="加载内容" /><apple-skeleton v-if="demoLoading" :variant="skeletonVariant" :lines="3" avatar /><apple-list v-else :items="settings" /></apple-stack>
|
|
109
|
+
<apple-empty v-else-if="name === 'AppleEmpty'" title="还没有收藏" description="喜欢的内容,会出现在这里。"><apple-button variant="secondary" @click="notify('开始浏览')">开始探索</apple-button></apple-empty>
|
|
110
|
+
<apple-popover v-else-if="name === 'ApplePopover'" label="更多选项"><template #activator><apple-button variant="secondary" :icon="icons.MoreHorizontal">更多选项</apple-button></template><p>已同步到 iCloud</p><apple-switch v-model="checked" label="自动同步" /></apple-popover>
|
|
111
|
+
<apple-tooltip v-else-if="name === 'AppleTooltip'" text="添加到收藏"><apple-button variant="secondary" :icon="icons.Heart" icon-only label="收藏" @click="notify('已收藏')" /></apple-tooltip>
|
|
112
|
+
<apple-menu v-else-if="name === 'AppleMenu'" :items="actions" label="更多操作" @select="notify('操作已完成')" />
|
|
113
|
+
<template v-else-if="name === 'AppleActionSheet'">
|
|
114
|
+
<apple-button @click="actionSheet = true">选择操作</apple-button>
|
|
115
|
+
<apple-action-sheet v-model="actionSheet" title="山间的一刻" message="收藏这份灵感,或与朋友分享。" @select="notify('操作已完成')">
|
|
116
|
+
<template #default="{ select }">
|
|
117
|
+
<div class="apple-action-sheet-items">
|
|
118
|
+
<button v-for="action in photoActions" :key="action.value" v-apple-ripple type="button" class="apple-action-sheet-item" :class="{'apple-action-sheet-item--danger':action.danger}" @click="select(action)">
|
|
119
|
+
<component :is="action.icon" :size="21" aria-hidden="true" /><span>{{ action.label }}<small>{{ action.description }}</small></span>
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
</template>
|
|
123
|
+
</apple-action-sheet>
|
|
124
|
+
</template>
|
|
125
|
+
<apple-pull-refresh v-else-if="name === 'ApplePullRefresh'" @refresh="refresh"><apple-list :items="[{label:'最新内容',value:'latest',description:refreshText},{label:'最近更新',value:'recent',description:'所有内容已同步'}]" /></apple-pull-refresh>
|
|
126
|
+
<apple-infinite-scroll v-else-if="name === 'AppleInfiniteScroll'" :finished="itemsCount >= 12" @load="loadMore"><apple-list :items="Array.from({length:itemsCount}, (_, i) => ({label:`灵感收藏 ${i+1}`, value:i, description:'刚刚更新'}))" /></apple-infinite-scroll>
|
|
127
|
+
<template v-else-if="name === 'AppleBackTop'"><apple-button :icon="icons.ArrowUp" variant="secondary" @click="toTop">回到顶部</apple-button><apple-back-top :threshold="0" :fixed="false" /></template>
|
|
128
|
+
<template v-else-if="name === 'AppleFloatingGroup'"><apple-button variant="secondary" @click="notify('快捷操作已就绪')">快捷操作</apple-button><apple-provider class="demo-floating-preview"><apple-floating-group :threshold="0"><apple-button icon-only :icon="icons.Plus" label="添加收藏" @click="notify('已加入收藏')" /><apple-button variant="secondary" icon-only :icon="icons.Bell" label="查看通知" @click="notify('暂无新通知')" /></apple-floating-group></apple-provider></template>
|
|
129
|
+
<apple-stack v-else-if="name === 'AppleAutoSize'"><apple-switch v-model="checked" label="显示详情" /><apple-auto-size><apple-list :items="checked ? settings : settings.slice(0,1)" selectable /></apple-auto-size></apple-stack>
|
|
130
|
+
<apple-stack v-else-if="name === 'AppleTransition'">
|
|
131
|
+
<apple-segmented-control v-model="period" :items="periods" label="统计周期" />
|
|
132
|
+
<div class="demo-transition-stage" :class="{ 'is-backward': transitionBackward }">
|
|
133
|
+
<apple-transition name="slide-x" mode="default" :appear="false">
|
|
134
|
+
<apple-statistic :key="period" :value="period==='day'?428:period==='week'?2996:12840" label="访问次数" />
|
|
135
|
+
</apple-transition>
|
|
136
|
+
</div>
|
|
137
|
+
</apple-stack>
|
|
138
|
+
<apple-marquee v-else-if="name === 'AppleMarquee'" text="你的新设备已准备就绪,今天就开始探索更多可能。" />
|
|
139
|
+
</div>
|
|
140
|
+
</template>
|
|
141
|
+
|
|
142
|
+
<script lang="ts">
|
|
143
|
+
import { defineComponent, h, markRaw } from 'vue'
|
|
144
|
+
import { Plus, Heart, Bell, ArrowUpRight, ArrowUp, MoreHorizontal, ZoomIn, Share2, Trash2 } from 'lucide-vue-next'
|
|
145
|
+
import { AppleButton } from 'apptify'
|
|
146
|
+
export default defineComponent({
|
|
147
|
+
name: 'ComponentDemo', props: { name: { type: String, required: true } }, emits: ['navigate'],
|
|
148
|
+
data() { return {
|
|
149
|
+
icons: markRaw({ Plus, Heart, Bell, ArrowUpRight, ArrowUp, MoreHorizontal, ZoomIn }), text: '', bio: '', email: '', city: 'beijing', device: null, checked: true, delivery: 'express', volume: 68, quantity: 1, period: 'month', date: '', time: '10:30', color: '#0071e3', files: [], otp: '', region: [], rating: 4, tab: 'overview', page: 1, step: 1, tree: '', drawer: false, sheet: false, actionSheet: false, tag: true, refreshText: '今天 09:41', itemsCount: 3,
|
|
150
|
+
searchText: '', setting: 'profile', website: '', previewTheme: 'dark', stackDirection: 'row' as 'row' | 'column', containerWidth: 480, gridMin: 160, avatarSize: 48, avatarMax: 3, unread: 8, dividerVertical: false, delivered: false, alertVisible: true, demoLoading: true, imageLayout: 'compact' as 'compact' | 'tiled' | 'tiled-wrap', imageSquare: false, imageCarousel: false,
|
|
151
|
+
virtualTable: false, transitionBackward: false,
|
|
152
|
+
timelineDirection:'vertical' as 'vertical'|'horizontal', skeletonVariant:'text' as 'text'|'avatar'|'card'|'list'|'table'|'image', skeletonVariants:[{label:'文本',value:'text'},{label:'头像',value:'avatar'},{label:'卡片',value:'card'},{label:'列表',value:'list'},{label:'表格',value:'table'},{label:'图片',value:'image'}],
|
|
153
|
+
dateFormat:'YYYY/MM/DD HH:mm', dateFormats:[{label:'年 / 月',value:'YYYY/MM'},{label:'年 / 月 / 日',value:'YYYY/MM/DD'},{label:'日期与时分',value:'YYYY/MM/DD HH:mm'},{label:'日期与时分秒',value:'YYYY/MM/DD HH:mm:ss'},{label:'时分',value:'HH:mm'},{label:'时分秒',value:'HH:mm:ss'}],
|
|
154
|
+
previewThemes: [{label:'浅色',value:'light'},{label:'深色',value:'dark'},{label:'石墨',value:'graphite'},{label:'玫瑰',value:'rose'}], layoutItems: ['概览', '设计', '支持'],
|
|
155
|
+
galleryImages: [
|
|
156
|
+
{ src: '/images/lake.jpg', alt: '山间湖泊与小屋' },
|
|
157
|
+
{ src: '/images/airpods-max-orange.jpg', alt: '橙色 AirPods Max 耳机' },
|
|
158
|
+
{ src: '/images/city.jpg', alt: '城市天际线' },
|
|
159
|
+
{ src: '/images/mountains.jpg', alt: '群山与山峰' },
|
|
160
|
+
{ src: '/images/forest.jpg', alt: '阳光下的森林' },
|
|
161
|
+
{ src: '/images/architecture.jpg', alt: '建筑细节' },
|
|
162
|
+
{ src: '/images/coast.jpg', alt: '海岸风景' },
|
|
163
|
+
{ src: '/images/food.jpg', alt: '餐桌上的美食' },
|
|
164
|
+
{ src: '/images/desert.jpg', alt: '沙漠沙丘' },
|
|
165
|
+
{ src: '/images/waterfall.jpg', alt: '山间瀑布' },
|
|
166
|
+
{ src: '/images/sunset.jpg', alt: '夕阳风景' },
|
|
167
|
+
{ src: '/images/snow.jpg', alt: '雪地风景' },
|
|
168
|
+
],
|
|
169
|
+
images: ['/images/lake.jpg', '/images/airpods-max-orange.jpg'], people: [{name:'林初'},{name:'Alex'},{name:'Taylor'},{name:'Quinn'},{name:'Sam'}],
|
|
170
|
+
cities: [{label:'北京',value:'beijing'},{label:'上海',value:'shanghai'},{label:'杭州',value:'hangzhou'}], devices: [{label:'MacBook Air',value:'mac'},{label:'iPad Pro',value:'ipad'},{label:'AirPods Max',value:'airpods'}],
|
|
171
|
+
deliveryItems: [{label:'快递送达',value:'express'},{label:'到店取货',value:'pickup'}], periods: [{label:'日',value:'day'},{label:'周',value:'week'},{label:'月',value:'month'}],
|
|
172
|
+
regions: [{label:'北京市',value:'beijing',children:[{label:'朝阳区',value:'chaoyang'},{label:'海淀区',value:'haidian'}]},{label:'浙江省',value:'zhejiang',children:[{label:'杭州市',value:'hangzhou',children:[{label:'西湖区',value:'xihu'}]}]}],
|
|
173
|
+
tabs: [{label:'概览',value:'overview'},{label:'技术规格',value:'spec'},{label:'支持',value:'support'}], steps: [{label:'选择产品',value:0},{label:'确认信息',value:1},{label:'完成',value:2}],
|
|
174
|
+
questions: [{label:'如何管理我的订阅?',value:'subscription',content:'前往账户设置,选择订阅即可查看或管理。'},{label:'可以随时取消吗?',value:'cancel',content:'可以。你可以随时在账户中取消,服务会保留至当前周期结束。'},{label:'如何获得帮助?',value:'support',content:'通过支持页面联系我们,我们很乐意提供帮助。'}],
|
|
175
|
+
columns: [{key:'name',label:'名称',sortable:true},{key:'category',label:'分类',sortable:true},{key:'status',label:'状态'},{key:'updated',label:'更新时间',sortable:true}], rows: [{id:1,name:'Apple Card',category:'基础',status:'已发布',updated:'09-24'},{id:2,name:'Apple Dialog',category:'反馈',status:'已发布',updated:'09-25'},{id:3,name:'Apple Input',category:'表单',status:'已发布',updated:'09-26'},{id:4,name:'Apple Image',category:'基础',status:'已发布',updated:'09-26'}],
|
|
176
|
+
folders: [{label:'设计资源',value:'design',children:[{label:'组件',value:'components',children:[{label:'按钮',value:'buttons'},{label:'输入框',value:'inputs'}]},{label:'图标',value:'icons'}]},{label:'项目文件',value:'project'}],
|
|
177
|
+
settings: [{label:'个人资料',value:'profile',description:'姓名、头像和联系方式'},{label:'通知',value:'notifications',description:'推送和邮件偏好'},{label:'隐私与安全',value:'security',description:'管理账户的安全设置'}],
|
|
178
|
+
events: [{label:'订单已确认',value:'confirmed',description:'我们正在准备你的订单',time:'09:41'},{label:'正在配送',value:'shipping',description:'你的包裹已出发',time:'12:00'},{label:'即将送达',value:'arrival',description:'留意配送通知',time:'预计明天'}],
|
|
179
|
+
actions: [{label:'收藏',value:'favorite'},{label:'分享',value:'share'},{label:'删除',value:'delete',danger:true}], slides: [{label:'山间清晨',value:0,src:'/images/lake.jpg'},{label:'一场聆听',value:1,src:'/images/airpods-max-orange.jpg'}],
|
|
180
|
+
photoActions: [{label:'加入收藏',value:'favorite',description:'将这张照片保存到你的灵感收藏',icon:markRaw(Heart),danger:false},{label:'分享照片',value:'share',description:'与朋友分享山间的这一刻',icon:markRaw(Share2),danger:false},{label:'删除照片',value:'delete',description:'从当前相册中移除',icon:markRaw(Trash2),danger:true}],
|
|
181
|
+
timers: [] as ReturnType<typeof setTimeout>[],
|
|
182
|
+
} },
|
|
183
|
+
computed: {
|
|
184
|
+
virtualRows() { return this.virtualTable ? Array.from({length:5000},(_,i)=>({id:i+1,name:`组件 ${String(i+1).padStart(4,'0')}`,category:i%2?'基础':'表单',status:'已发布',updated:'09-26'})) : [] },
|
|
185
|
+
demoClass(): string {
|
|
186
|
+
const compact = ['AppleSearch', 'AppleProvider', 'AppleAvatar', 'AppleAvatarGroup', 'AppleInput', 'AppleTextarea', 'AppleSelect', 'AppleAutocomplete', 'AppleCheckbox', 'AppleRadioGroup', 'AppleSwitch', 'AppleSlider', 'AppleStepper', 'AppleSegmentedControl', 'AppleDatePicker', 'AppleColorPicker', 'AppleUpload', 'AppleOtpInput', 'AppleCascader', 'AppleRate', 'AppleForm', 'AppleFormField', 'AppleProgress', 'AppleSpinner', 'AppleStatistic', 'AppleTransition']
|
|
187
|
+
const media = ['AppleImage']
|
|
188
|
+
return compact.includes(this.name) ? 'component-demo--compact' : media.includes(this.name) ? 'component-demo--media' : 'component-demo--wide'
|
|
189
|
+
},
|
|
190
|
+
searchResults() { return this.settings.filter(item => `${item.label} ${item.description}`.includes(this.searchText.trim())) },
|
|
191
|
+
},
|
|
192
|
+
watch: {
|
|
193
|
+
period(next: string, previous: string) {
|
|
194
|
+
this.transitionBackward = this.periods.findIndex(item => item.value === next) < this.periods.findIndex(item => item.value === previous)
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
beforeUnmount() { this.timers.forEach(clearTimeout) },
|
|
198
|
+
methods: {
|
|
199
|
+
notify(message: string) { this.$apple.notify(message, {tone:'success'}) },
|
|
200
|
+
validate(data: FormData) { return String(data.get('name') ?? '').trim().length > 0 || '请输入姓名' },
|
|
201
|
+
updateDelivery() { this.delivered = !this.delivered; this.events[2] = this.delivered ? { label: '已签收', value: 'arrival', description: '包裹已送达,祝你使用愉快', time: new Date().toLocaleTimeString('zh-CN') } : { label: '即将送达', value: 'arrival', description: '留意配送通知', time: '预计明天' } },
|
|
202
|
+
openDialog() { this.$apple.dialog({title:'保存更改?',message:'你的更改会同步到所有设备。',confirmText:'保存'}).result.then(result => { if (result) this.notify('你的更改已保存') }) },
|
|
203
|
+
openStack() {
|
|
204
|
+
const apple = this.$apple
|
|
205
|
+
const Inner = defineComponent({ props:['close','sendMessage'], render() { return h('div', {class:'demo-dialog-body'}, [h('p','第一层仍然保留在下面。'), h(AppleButton, {onClick:() => apple.dialog({title:'第二层对话框',message:'关闭这一层后,会回到第一层。'})}, () => '打开第二层')]) } })
|
|
206
|
+
apple.dialog({title:'第一层对话框',component:Inner})
|
|
207
|
+
},
|
|
208
|
+
refresh(done: () => void) { this.timers.push(setTimeout(() => { this.refreshText = `更新于 ${new Date().toLocaleTimeString('zh-CN')}`; done() }, 700)) },
|
|
209
|
+
loadMore(done: () => void) { this.timers.push(setTimeout(() => { this.itemsCount = Math.min(12, this.itemsCount + 3); done() }, 500)) },
|
|
210
|
+
toTop() { window.scrollTo({top:0,behavior:this.$apple.motion.value.mode === 'none' || this.$apple.motion.value.reduced ? 'instant':'smooth'}) },
|
|
211
|
+
},
|
|
212
|
+
})
|
|
213
|
+
</script>
|
|
214
|
+
|
|
215
|
+
<style scoped>
|
|
216
|
+
.demo-tag-row { width: 100%; max-width: 100%; }
|
|
217
|
+
.component-demo > .demo-tag-row > :deep(.apple-button) { min-height: 44px; padding: 7px 10px; font-size: 11px; font-weight: 500; line-height: 1.5; }
|
|
218
|
+
.demo-tag-row :deep(.apple-button__content) { gap: 4px; }
|
|
219
|
+
.demo-tag-row :deep(.apple-button__content > svg) { width: 13px; height: 13px; }
|
|
220
|
+
.component-demo > .demo-tag-row > :deep(.apple-tag),
|
|
221
|
+
.component-demo > .demo-tag-row > :deep(.apple-button) { align-self: center; max-width: 100%; }
|
|
222
|
+
|
|
223
|
+
.demo-transition-stage { display: grid; min-width: 0; overflow: hidden; --demo-slide-distance: 24px; }
|
|
224
|
+
.demo-transition-stage.is-backward { --demo-slide-distance: -24px; }
|
|
225
|
+
.demo-transition-stage :deep(.apple-statistic) { grid-area: 1 / 1; min-width: 0; }
|
|
226
|
+
.demo-transition-stage :deep(.apple-slide-x-enter-active),
|
|
227
|
+
.demo-transition-stage :deep(.apple-slide-x-leave-active) { transition: opacity var(--apple-duration) var(--apple-ease), transform var(--apple-duration) var(--apple-ease); }
|
|
228
|
+
.demo-transition-stage :deep(.apple-slide-x-enter-from) { opacity: 0; transform: translateX(var(--demo-slide-distance)); }
|
|
229
|
+
.demo-transition-stage :deep(.apple-slide-x-leave-to) { opacity: 0; transform: translateX(calc(-1 * var(--demo-slide-distance))); }
|
|
230
|
+
@media (prefers-reduced-motion: reduce) {
|
|
231
|
+
.demo-transition-stage :deep(.apple-slide-x-enter-from),
|
|
232
|
+
.demo-transition-stage :deep(.apple-slide-x-leave-to) { transform: none; }
|
|
233
|
+
}
|
|
234
|
+
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export interface CatalogItem { name: string; label: string; group: string; description: string; api: string; code: string }
|
|
2
|
+
const item = (name: string, label: string, group: string, description: string, api: string, code: string): CatalogItem => ({ name, label, group, description, api, code })
|
|
3
|
+
export const catalog: CatalogItem[] = [
|
|
4
|
+
item('AppleButton', '按钮', '基础', '清晰的操作层级。', 'variant · size · icon · iconOnly · label · loading · disabled · ripple · motion', '<apple-button variant="primary" :loading="saving" @click="save">继续</apple-button>'),
|
|
5
|
+
item('AppleLink', '链接', '基础', '让下一步清楚可见。', 'href · external · disabled | slot: default', '<apple-link href="https://www.apple.com.cn/" external>Apple 官网</apple-link>'),
|
|
6
|
+
item('AppleSearch', '搜索', '基础', '快速找到关心的内容。', 'v-model(string) · label · placeholder · disabled | search(query)', '<apple-search v-model="query" label="搜索设置" placeholder="搜索设置" @search="search" />'),
|
|
7
|
+
item('AppleProvider', '主题容器', '基础', '独立区域,也有统一的设计语言。', 'theme · motion(auto|full|reduced|none) | slot: default', '<apple-provider theme="dark" motion="auto">\n <apple-button>继续</apple-button>\n</apple-provider>'),
|
|
8
|
+
item('AppleContainer', '内容容器', '基础', '在不同屏幕上保留合适的内容宽度。', 'width(number|string) | slot: default', '<apple-container :width="960">\n <apple-stack>内容</apple-stack>\n</apple-container>'),
|
|
9
|
+
item('AppleStack', '弹性布局', '基础', '有序排列,自然换行。', 'direction(row|column) · gap · align · wrap | slot: default', '<apple-stack direction="row" :gap="16" align="center">\n <apple-button>继续</apple-button>\n <apple-button variant="secondary">取消</apple-button>\n</apple-stack>'),
|
|
10
|
+
item('AppleGrid', '网格布局', '基础', '让列数随内容空间变化。', 'min(number) · gap(number) | slot: default', '<apple-grid :min="240" :gap="20">\n <div v-for="item in items" :key="item.id">{{ item.label }}</div>\n</apple-grid>'),
|
|
11
|
+
item('AppleCard', '卡片', '基础', '来自 Apple Store 的产品表达。', 'title · subtitle · text · image · zoom · shadow · motion | slots: media, title, icon, actions', '<apple-card title="AirPods Max" subtitle="声音,出类拔萃。" motion="auto" zoom="small">\n <template #actions><apple-button>进一步了解</apple-button></template>\n</apple-card>'),
|
|
12
|
+
item('AppleImage', '图片与预览', '基础', '让值得细看的内容更近一步。', 'gallery(object|array) · index · preview · carousel · disabled · label · galleryLayout(compact|tiled|tiled-wrap) · v-model:index | item({item,index,active}) · squared · aspectRatio · fit', '<apple-image :gallery="images" gallery-layout="compact" :index="0" />'),
|
|
13
|
+
item('AppleAvatar', '头像', '基础', '为每一位用户保留位置。', 'src · name · size', '<apple-avatar name="林初" :size="48" />'),
|
|
14
|
+
item('AppleAvatarGroup', '头像组', '基础', '一起参与的人,一眼可见。', 'items[{name,src,value}] · max · size · label | slot: default', '<apple-avatar-group :items="members" :max="4" :size="40" label="项目成员" />'),
|
|
15
|
+
item('AppleBadge', '徽标', '基础', '不打扰,也不遗漏。', 'value · max · dot · tone', '<apple-badge :value="8"><apple-button>消息</apple-button></apple-badge>'),
|
|
16
|
+
item('AppleTag', '标签', '基础', '轻量的分类与状态。', 'tone · closable | close', '<apple-tag tone="success" closable @close="remove">已完成</apple-tag>'),
|
|
17
|
+
item('AppleDivider', '分隔线', '基础', '恰到好处的分界。', 'label · vertical', '<apple-divider label="更多选择" />'),
|
|
18
|
+
item('AppleInput', '输入框', '表单', '每一次输入,都自然流畅。', 'v-model · label · placeholder · type · error · hint · clearable · disabled', '<apple-input v-model="name" label="姓名" placeholder="怎么称呼你" clearable />'),
|
|
19
|
+
item('AppleTextarea', '多行输入', '表单', '为更长的想法留白。', 'v-model · label · rows · maxlength · error · hint', '<apple-textarea v-model="bio" label="个人简介" :maxlength="160" />'),
|
|
20
|
+
item('AppleSelect', '选择器', '表单', '从容找到你的选择。', 'v-model · label · items[{label,value,disabled}] · placeholder · disabled', '<apple-select v-model="city" label="所在城市" :items="cities" />'),
|
|
21
|
+
item('AppleAutocomplete', '自动补全', '表单', '想到哪里,找到哪里。', 'v-model · label · items · placeholder · disabled', '<apple-autocomplete v-model="device" label="搜索设备" :items="devices" />'),
|
|
22
|
+
item('AppleCheckbox', '复选框', '表单', '一个,或不止一个。', 'v-model · label · disabled · indeterminate', '<apple-checkbox v-model="agreed" label="我已阅读并同意条款" />'),
|
|
23
|
+
item('AppleRadioGroup', '单选框', '表单', '专注于一个明确的选择。', 'v-model · label · items · disabled', '<apple-radio-group v-model="delivery" label="配送方式" :items="methods" />'),
|
|
24
|
+
item('AppleSwitch', '开关', '表单', '简单的一开一关。', 'v-model · label · disabled', '<apple-switch v-model="notifications" label="接收通知" />'),
|
|
25
|
+
item('AppleSlider', '滑块', '表单', '把控制权交给指尖。', 'v-model · label · min · max · step · disabled', '<apple-slider v-model="volume" label="音量" :min="0" :max="100" />'),
|
|
26
|
+
item('AppleStepper', '步进器', '表单', '精确一点,也轻松一点。', 'v-model · label · min · max · step', '<apple-stepper v-model="quantity" label="数量" :min="1" :max="10" />'),
|
|
27
|
+
item('AppleSegmentedControl', '分段控制', '表单', '在相邻的视图间切换。', 'v-model · items · label · disabled', '<apple-segmented-control v-model="period" :items="periods" label="统计周期" />'),
|
|
28
|
+
item('AppleDatePicker', '日期与时间', '表单', '为值得记住的日子。', 'v-model · format · granularity · label · min · max · required · disabled | change(value)', '<apple-date-picker v-model="date" label="到店日期" format="YYYY/MM/DD HH:mm" />'),
|
|
29
|
+
item('AppleColorPicker', '颜色选择', '表单', '找到属于你的颜色。', 'v-model(#hex) · label · disabled', '<apple-color-picker v-model="color" label="强调色" />'),
|
|
30
|
+
item('AppleUpload', '文件上传', '表单', '拖入文件,继续创作。', 'v-model(File[]) · label · accept · multiple · maxSize(bytes) · maxFiles · capture | reject([{file,reason}]), remove(file)', '<apple-upload v-model="files" label="上传图片" accept="image/*" multiple :max-files="5" />'),
|
|
31
|
+
item('AppleOtpInput', '验证码', '表单', '验证步骤,也可以很顺手。', 'v-model · length · label | complete', '<apple-otp-input v-model="code" :length="6" label="验证码" />'),
|
|
32
|
+
item('AppleCascader', '级联选择', '表单', '从整体,找到细节。', 'v-model(value[]) · items[{label,value,children}] · label', '<apple-cascader v-model="region" label="所在地区" :items="regions" />'),
|
|
33
|
+
item('AppleRate', '评分', '表单', '记录真实的感受。', 'v-model · max · label · readonly · disabled', '<apple-rate v-model="rating" label="体验评分" />'),
|
|
34
|
+
item('AppleForm', '表单验证', '表单', '把完整提交做好。', 'validator(FormData) => boolean|string|Promise · loading · disabled | submit(FormData), invalid, reset | methods: validate(), submit(), reset()', '<apple-form :validator="validate" @submit="submit">\n <apple-input v-model="name" name="name" label="姓名" required />\n <apple-button type="submit">提交</apple-button>\n</apple-form>'),
|
|
35
|
+
item('AppleFormField', '表单字段', '表单', '为自定义控件补齐标签与验证信息。', 'label · for · error · hint · required · disabled | default({id,disabled,required,aria-invalid,aria-describedby})', '<apple-form-field label="个人网站" :error="error">\n <template #default="field">\n <input v-bind="field" v-model="website" class="apple-control" type="url" />\n </template>\n</apple-form-field>'),
|
|
36
|
+
item('AppleNavibar', '顶部导航栏', '导航', '随可用宽度折叠的顶部导航。', 'v-model · items · brand · brandHref · fixed · breakpoint=640 · hideOnPreview · label · motion | change(value,item), toggle(open) | slots: brand, item, actions', '<apple-navibar v-model="page" brand="Apptify" :items="pages" />'),
|
|
37
|
+
item('AppleAside', '侧栏容器', '导航', '图片归位后,导航自然恢复。', 'hideOnPreview=true · motion | slot: default | 布局由调用方提供', '<apple-aside :hide-on-preview="false">\n <apple-list :items="items" />\n</apple-aside>'),
|
|
38
|
+
item('AppleTabs', '标签页', '导航', '内容各归其位。', 'v-model · items[{label,value,disabled}] | slot: default({value})', '<apple-tabs v-model="tab" :items="tabs">\n <template #default="{ value }">{{ value }}</template>\n</apple-tabs>'),
|
|
39
|
+
item('AppleTabBar', '页签栏', '导航', '相邻页面,自然衔接。', 'v-model · items · label · disabled · motion | slot: default({value})', '<apple-tab-bar v-model="tab" :items="tabs">\n <template #default="{value}">{{ value }}</template>\n</apple-tab-bar>'),
|
|
40
|
+
item('AppleBreadcrumbs', '面包屑', '导航', '始终知道身在何处。', 'items[{label,value,href,disabled}] · label', '<apple-breadcrumbs :items="[{label:\'首页\',value:\'home\',href:\'/\'},{label:\'设置\',value:\'settings\'}]" />'),
|
|
41
|
+
item('ApplePagination', '分页', '导航', '一步步,轻松浏览。', 'v-model(page) · total · pageSize', '<apple-pagination v-model="page" :total="120" :page-size="10" />'),
|
|
42
|
+
item('AppleSteps', '步骤条', '导航', '每一步,都有进展。', 'v-model(index) · items[{label,value,description,disabled}] · clickable · disabled', '<apple-steps v-model="step" :items="steps" clickable />'),
|
|
43
|
+
item('AppleAccordion', '折叠面板', '数据展示', '需要时,再展开。', 'v-model · items[{label,value,content}] · multiple', '<apple-accordion :items="questions" />'),
|
|
44
|
+
item('AppleTable', '数据表格', '数据展示', '复杂信息,清晰呈现。', 'columns[{key,label,sortable,width,minWidth,maxWidth}] · rows · rowKey · selectable · pageSize · virtual · height · rowHeight · overscan · resizable | update:selected, column-resize', '<apple-table :columns="columns" :rows="rows" row-key="id" virtual :height="360" :row-height="48" />'),
|
|
45
|
+
item('AppleTree', '树形结构', '数据展示', '有层次,也有条理。', 'v-model · items[{label,value,children}] | select', '<apple-tree v-model="selected" :items="folders" />'),
|
|
46
|
+
item('AppleList', '列表', '数据展示', '内容优先的日常界面。', 'v-model · items[{label,value,description,href,disabled}] · selectable | select(item)', '<apple-list v-model="setting" :items="settings" selectable @select="openSetting" />'),
|
|
47
|
+
item('AppleTimeline', '时间线', '数据展示', '把发生的事串联起来。', 'items[{label,value,description,time,tone}] · orientation(horizontal|vertical) · label', '<apple-timeline :items="events" orientation="horizontal" />'),
|
|
48
|
+
item('AppleStatistic', '统计数值', '数据展示', '重要数据,一目了然。', 'label · value · prefix · suffix · precision', '<apple-statistic label="本月访问" :value="12840" suffix="次" />'),
|
|
49
|
+
item('AppleDialog', '对话框', '反馈', '重要的决定,值得专注。', 'v-model · title · persistent · confirmText · cancelText | confirm, cancel', '<apple-dialog v-model="open" title="保存更改?" @confirm="save">\n 你的更改会同步到所有设备。\n</apple-dialog>'),
|
|
50
|
+
item('AppleDrawer', '抽屉', '反馈', '让补充信息就近展开。', 'v-model · title · placement(left|right|bottom) · width · persistent · loading', '<apple-drawer v-model="open" title="偏好设置" placement="right">内容</apple-drawer>'),
|
|
51
|
+
item('AppleSheet', '底部面板', '反馈', '为拇指设计的临时空间。', 'v-model · title · persistent', '<apple-sheet v-model="open" title="分享">内容</apple-sheet>'),
|
|
52
|
+
item('AppleSnackbar', '轻提示', '反馈', '及时回应,不必打断。', 'v-model · message · title · tone · duration(ms) · action · closable | close, action', "const notice = apple.notify('已保存', { tone: 'success', duration: 4000 })"),
|
|
53
|
+
item('AppleAlert', '提示信息', '反馈', '让状态清楚可见。', 'v-model · title · message · tone · closable | close', '<apple-alert v-model="visible" title="一切已就绪" tone="success" closable>内容已同步。</apple-alert>'),
|
|
54
|
+
item('AppleProgress', '进度条', '反馈', '等待,也能心中有数。', 'modelValue · max · label · indeterminate · showValue · tone', '<apple-progress :model-value="68" label="正在上传" show-value />'),
|
|
55
|
+
item('AppleSpinner', '加载中', '反馈', '给等待一个轻巧的回应。', 'size · label', '<apple-spinner label="正在加载" />'),
|
|
56
|
+
item('AppleSkeleton', '骨架屏', '反馈', '内容到达之前。', 'variant(text|avatar|card|list|table|image) · lines · rows · columns · avatar · width · height · animated · label · motion', '<apple-skeleton variant="list" :rows="3" avatar />'),
|
|
57
|
+
item('AppleEmpty', '空状态', '反馈', '没有内容,也不空洞。', 'title · description | slot: default', '<apple-empty title="还没有收藏" description="喜欢的内容,会出现在这里。" />'),
|
|
58
|
+
item('ApplePopover', '气泡面板', '反馈', '让更多操作触手可及。', 'v-model · label · placement · align · width · disabled | activator({props,open,close,isOpen}), default({close})', '<apple-popover label="更多选项">\n <template #activator><apple-button variant="secondary">更多</apple-button></template>\n <apple-switch v-model="sync" label="自动同步" />\n</apple-popover>'),
|
|
59
|
+
item('AppleTooltip', '文字提示', '反馈', '在需要的时候多说一句。', 'text | slot: default', '<apple-tooltip text="添加到收藏"><apple-button>收藏</apple-button></apple-tooltip>'),
|
|
60
|
+
item('AppleMenu', '下拉菜单', '反馈', '按需展开的操作列表。', 'v-model · items[{label,value,disabled,danger,icon,description}] · label · selected | select(value,item)', '<apple-menu :items="actions" label="更多操作" @select="onAction" />'),
|
|
61
|
+
item('AppleActionSheet', '动作面板', '移动交互', '熟悉、直接的移动操作。', 'v-model · title · message · items[{label,value,disabled,danger}] · cancelText | default slot {select(item),close(value)} | select(value,item)', '<apple-action-sheet v-model="open" title="选择操作" @select="onAction">\n <template #default="{ select }">\n <apple-button @click="select({ label: \'收藏\', value: \'favorite\' })">加入收藏</apple-button>\n </template>\n</apple-action-sheet>'),
|
|
62
|
+
item('ApplePullRefresh', '下拉刷新', '移动交互', '轻轻下拉,获取新内容。', 'v-model(refreshing) · threshold · label · disabled | refresh(done)', '<apple-pull-refresh @refresh="async done => { await reload(); done() }">内容</apple-pull-refresh>'),
|
|
63
|
+
item('AppleInfiniteScroll', '无限滚动', '移动交互', '浏览,不必被翻页打断。', 'loading · finished · error · disabled · distance | load(done), retry(done)', '<apple-infinite-scroll :finished="finished" @load="async done => { await loadMore(); done() }">内容</apple-infinite-scroll>'),
|
|
64
|
+
item('AppleBackTop', '回到顶部', '移动交互', '回到开始,毫不费力。', 'threshold · label', '<apple-back-top :threshold="400" />'),
|
|
65
|
+
item('AppleFloatingGroup', '悬浮操作组', '移动交互', '常用操作,触手可及。', 'backTop · threshold · target · label · motion | default', '<apple-floating-group :threshold="300">\n <apple-button icon-only :icon="Plus" label="添加" />\n</apple-floating-group>'),
|
|
66
|
+
item('AppleAutoSize', '自适应尺寸', '基础', '内容变化,布局随行。', 'axis(height|both) · motion | default', '<apple-auto-size><div v-if="expanded">详情内容</div></apple-auto-size>'),
|
|
67
|
+
item('AppleTransition', '动效容器', '基础', '为页面保留连续感。', 'name(page|slide-x|slide-y|fade) · mode · appear · motion | default', '<apple-transition name="page"><router-view /></apple-transition>'),
|
|
68
|
+
item('AppleMarquee', '通知栏', '移动交互', '简短消息,保持可见。', 'text · duration(seconds) · paused · label · motion', '<apple-marquee text="新的内容已经准备好。" :duration="24" />'),
|
|
69
|
+
]
|
|
70
|
+
export const groups = ['全部组件', '基础', '表单', '导航', '数据展示', '反馈', '移动交互']
|
|
71
|
+
|
|
72
|
+
export const componentId = (name: string) => name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
|
|
73
|
+
export const sections = [
|
|
74
|
+
{ id: 'basics', label: '基础' },
|
|
75
|
+
{ id: 'forms', label: '表单' },
|
|
76
|
+
{ id: 'navigation', label: '导航' },
|
|
77
|
+
{ id: 'data', label: '数据展示' },
|
|
78
|
+
{ id: 'feedback', label: '反馈' },
|
|
79
|
+
{ id: 'mobile', label: '移动交互' },
|
|
80
|
+
].map(section => ({ ...section, items: catalog.filter(item => item.group === section.label) }))
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav class="component-index" aria-label="组件定位">
|
|
3
|
+
<AppleTree :items="treeItems" :model-value="activeId || activeGroup" :expanded="expandedGroups" label="组件目录树" @update:expanded="expanded = $event" @select="navigate">
|
|
4
|
+
<template #item="{ item }">
|
|
5
|
+
<router-link :to="`/components#${item.value}`" :class="['index-link', { 'index-group': item.children, active: activeId === item.value || (item.children && activeGroup === item.value) }]" :aria-current="activeId === item.value ? 'location' : undefined" tabindex="-1" @click.prevent>
|
|
6
|
+
<component :is="icons[item.label]" v-if="item.children" :size="15" aria-hidden="true" />
|
|
7
|
+
<span>{{ item.label }}</span><small v-if="item.children">{{ item.children.length }}</small>
|
|
8
|
+
</router-link>
|
|
9
|
+
</template>
|
|
10
|
+
</AppleTree>
|
|
11
|
+
<p v-if="!treeItems.length" class="index-empty" role="status">未找到组件,请尝试其他关键词。</p>
|
|
12
|
+
</nav>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { computed, ref, watch } from 'vue'
|
|
17
|
+
import { useRoute, useRouter } from 'vue-router'
|
|
18
|
+
import { Bell, Box, MousePointer2, Smartphone, Table2, TextCursorInput } from 'lucide-vue-next'
|
|
19
|
+
import { AppleTree } from 'apptify'
|
|
20
|
+
import type { AppleTreeItem, AppleValue } from 'apptify'
|
|
21
|
+
import { sections, componentId } from '../catalog'
|
|
22
|
+
|
|
23
|
+
const props = defineProps<{ activeGroup: string; activeId: string; search?: string }>()
|
|
24
|
+
const emit = defineEmits<{ navigate: [] }>()
|
|
25
|
+
const router = useRouter()
|
|
26
|
+
const route = useRoute()
|
|
27
|
+
const expanded = ref<AppleValue[]>([props.activeGroup])
|
|
28
|
+
const icons: Record<string, typeof Box> = { '基础': Box, '表单': TextCursorInput, '导航': MousePointer2, '数据展示': Table2, '反馈': Bell, '移动交互': Smartphone }
|
|
29
|
+
const query = computed(() => props.search?.trim().toLocaleLowerCase() ?? '')
|
|
30
|
+
const treeItems = computed<AppleTreeItem[]>(() => sections.flatMap(section => {
|
|
31
|
+
const groupMatches = section.label.toLocaleLowerCase().includes(query.value)
|
|
32
|
+
const items = section.items.filter(item => groupMatches || `${item.label} ${item.name} ${componentId(item.name)} ${item.description}`.toLocaleLowerCase().includes(query.value))
|
|
33
|
+
return items.length ? [{ label: section.label, value: section.id, children: items.map(item => ({ label: item.label, value: componentId(item.name) })) }] : []
|
|
34
|
+
}))
|
|
35
|
+
const expandedGroups = computed(() => query.value ? treeItems.value.map(item => item.value) : expanded.value)
|
|
36
|
+
watch(() => props.activeGroup, group => {
|
|
37
|
+
if (!expanded.value.includes(group)) expanded.value = [...expanded.value, group]
|
|
38
|
+
})
|
|
39
|
+
function navigate(item: AppleTreeItem) {
|
|
40
|
+
const hash = `#${item.value}`
|
|
41
|
+
if (route.hash === hash) {
|
|
42
|
+
const target = document.getElementById(String(item.value))
|
|
43
|
+
if (target) window.scrollTo({ top: target.getBoundingClientRect().top + window.scrollY - 96, behavior: 'instant' })
|
|
44
|
+
} else void router.push(`/components${hash}`)
|
|
45
|
+
emit('navigate')
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<style scoped>
|
|
50
|
+
.component-index { min-width: 0; }
|
|
51
|
+
.component-index :deep(.apple-tree__row) { min-height: 38px; gap: 0; font-size: 12px; border-radius: 6px; }
|
|
52
|
+
.component-index :deep(.apple-tree__toggle), .component-index :deep(.apple-tree__spacer) { flex-basis: 24px; width: 24px; height: 34px; }
|
|
53
|
+
.component-index .index-link { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; padding: 8px 4px; font-size: 12px; color: inherit; text-decoration: none; }
|
|
54
|
+
.component-index .index-group { border-radius: 0; }
|
|
55
|
+
/* The tree row owns the fade; avoid a second, smaller hover background on its link. */
|
|
56
|
+
.component-index .index-link:hover { background: transparent; }
|
|
57
|
+
.index-link > span { flex: 1; overflow-wrap: anywhere; }
|
|
58
|
+
.index-link > svg { flex-shrink: 0; }
|
|
59
|
+
.index-link.active { color: var(--apple-text); font-weight: 600; }
|
|
60
|
+
.index-link small { font-size: 10px; color: var(--apple-secondary); font-variant-numeric: tabular-nums; }
|
|
61
|
+
.index-empty { margin: 12px 8px; font-size: 12px; line-height: 1.7; color: var(--apple-secondary); }
|
|
62
|
+
</style>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<apple-popover v-model="opened" label="用户菜单" align="end" :width="280" panel-class="user-popup">
|
|
3
|
+
<template #activator>
|
|
4
|
+
<apple-button class="user-trigger user-account-trigger" variant="ghost" icon-only label="打开用户菜单" title="用户菜单"><UserRound :size="20" /></apple-button>
|
|
5
|
+
</template>
|
|
6
|
+
<div class="user-summary">
|
|
7
|
+
<apple-avatar name="林初" :size="48" />
|
|
8
|
+
<div><strong>林初 <small>演示账户</small></strong><span>lin.chu@example.com</span></div>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="user-menu-list">
|
|
11
|
+
<apple-button variant="ghost" @click="showProfile"><UserRound :size="17" /><span>个人资料</span><ArrowUpRight :size="14" aria-hidden="true" /></apple-button>
|
|
12
|
+
<router-link to="/settings" @click="opened = false"><Settings2 :size="17" /><span>偏好设置</span><ArrowUpRight :size="14" aria-hidden="true" /></router-link>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="user-menu-list user-menu-examples">
|
|
15
|
+
<apple-button variant="ghost" @click="openAuth('login')"><LogIn :size="17" /><span>登录 <small>Login</small></span><em>示例</em></apple-button>
|
|
16
|
+
<apple-button variant="ghost" @click="openAuth('register')"><UserPlus :size="17" /><span>注册 <small>Register</small></span><em>示例</em></apple-button>
|
|
17
|
+
</div>
|
|
18
|
+
</apple-popover>
|
|
19
|
+
<apple-dialog v-model="authOpen" class="user-auth-dialog" :width="560" :title="authMode === 'login' ? '登录示例' : '注册示例'" :show-footer="false" @after-close="password = ''">
|
|
20
|
+
<template #title>
|
|
21
|
+
<span class="user-auth-heading">
|
|
22
|
+
<span class="user-auth-symbol" aria-hidden="true">a</span>
|
|
23
|
+
<span>{{ authMode === 'login' ? '登录或切换用户' : '创建账户' }}</span>
|
|
24
|
+
</span>
|
|
25
|
+
</template>
|
|
26
|
+
<apple-form :key="authMode" class="user-auth-form" @submit="submitAuth">
|
|
27
|
+
<apple-input v-if="authMode === 'register'" ref="nameInput" v-model="name" label="姓名" autocomplete="name" required>
|
|
28
|
+
<template #prefix><UserRound :size="18" aria-hidden="true" /></template>
|
|
29
|
+
</apple-input>
|
|
30
|
+
<apple-input ref="emailInput" v-model="email" label="电子邮箱" type="email" autocomplete="email" placeholder="name@example.com" required>
|
|
31
|
+
<template #prefix><Mail :size="18" aria-hidden="true" /></template>
|
|
32
|
+
</apple-input>
|
|
33
|
+
<div class="user-auth-password">
|
|
34
|
+
<apple-input v-model="password" label="密码" type="password" :autocomplete="authMode === 'login' ? 'current-password' : 'new-password'" required>
|
|
35
|
+
<template #prefix><LockKeyhole :size="18" aria-hidden="true" /></template>
|
|
36
|
+
</apple-input>
|
|
37
|
+
<apple-button v-if="authMode === 'login'" class="user-auth-forgot" variant="ghost" size="small" @click="showAuthEntry('forgot')">忘记密码?</apple-button>
|
|
38
|
+
</div>
|
|
39
|
+
<p class="user-auth-note">这是表单交互示例,尚未接入账户服务。填写内容不会提交到服务器。</p>
|
|
40
|
+
<div class="user-auth-actions">
|
|
41
|
+
<apple-button class="user-auth-submit" type="submit" size="large">{{ authMode === 'login' ? '体验登录' : '体验注册' }}</apple-button>
|
|
42
|
+
<apple-button class="user-auth-email" variant="outline" size="large" @click="showAuthEntry('email')">邮箱验证码登录</apple-button>
|
|
43
|
+
</div>
|
|
44
|
+
</apple-form>
|
|
45
|
+
<div class="user-auth-alternatives">
|
|
46
|
+
<apple-link href="#" @click.prevent="switchAuthMode">
|
|
47
|
+
{{ authMode === 'login' ? '注册账户' : '已有账户?登录' }}<ArrowUpRight :size="14" aria-hidden="true" />
|
|
48
|
+
</apple-link>
|
|
49
|
+
</div>
|
|
50
|
+
</apple-dialog>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup lang="ts">
|
|
54
|
+
import { nextTick, ref, watch } from 'vue'
|
|
55
|
+
import { useRoute } from 'vue-router'
|
|
56
|
+
import { ArrowUpRight, LockKeyhole, LogIn, Mail, Settings2, UserPlus, UserRound } from 'lucide-vue-next'
|
|
57
|
+
import { useApple } from 'apptify'
|
|
58
|
+
|
|
59
|
+
const apple = useApple()
|
|
60
|
+
const route = useRoute()
|
|
61
|
+
const opened = ref(false)
|
|
62
|
+
const authOpen = ref(false)
|
|
63
|
+
const authMode = ref<'login' | 'register'>('login')
|
|
64
|
+
const name = ref('')
|
|
65
|
+
const email = ref('')
|
|
66
|
+
const password = ref('')
|
|
67
|
+
const nameInput = ref<{ focus: () => void } | null>(null)
|
|
68
|
+
const emailInput = ref<{ focus: () => void } | null>(null)
|
|
69
|
+
watch(() => route.path, () => { opened.value = false; authOpen.value = false })
|
|
70
|
+
|
|
71
|
+
function openAuth(mode: 'login' | 'register') {
|
|
72
|
+
opened.value = false
|
|
73
|
+
authMode.value = mode
|
|
74
|
+
name.value = email.value = password.value = ''
|
|
75
|
+
authOpen.value = true
|
|
76
|
+
}
|
|
77
|
+
function submitAuth() {
|
|
78
|
+
authOpen.value = false
|
|
79
|
+
password.value = ''
|
|
80
|
+
apple.notify(authMode.value === 'login' ? '登录示例已完成' : '注册示例已完成', { tone: 'success' })
|
|
81
|
+
}
|
|
82
|
+
async function switchAuthMode() {
|
|
83
|
+
authMode.value = authMode.value === 'login' ? 'register' : 'login'
|
|
84
|
+
password.value = ''
|
|
85
|
+
await nextTick()
|
|
86
|
+
const firstInput = authMode.value === 'register' ? nameInput.value : emailInput.value
|
|
87
|
+
firstInput?.focus()
|
|
88
|
+
}
|
|
89
|
+
function showAuthEntry(entry: 'forgot' | 'email') {
|
|
90
|
+
apple.notify(entry === 'forgot'
|
|
91
|
+
? '找回密码尚未接入账户服务,此示例不会发送重置邮件。'
|
|
92
|
+
: '邮箱验证码登录尚未接入账户服务,此示例不会发送验证码。')
|
|
93
|
+
}
|
|
94
|
+
function showProfile() {
|
|
95
|
+
opened.value = false
|
|
96
|
+
apple.dialog({ title: '个人资料', message: '林初 · lin.chu@example.com\n这是用于展示账户菜单的演示资料。', confirmText: '知道了', cancelText: '' })
|
|
97
|
+
}
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<style>
|
|
101
|
+
.user-popup.apple-popover { border-radius: 24px; background: var(--apple-surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
102
|
+
.user-popup .user-menu-list > .apple-button > .apple-button__content { width: 100%; justify-content: flex-start; gap: 11px; }
|
|
103
|
+
.user-popup .user-menu-list > .apple-button { min-height: 44px; font-weight: 400; line-height: inherit; }
|
|
104
|
+
.user-popup .user-menu-list > .apple-button:hover:where(:not([data-apple-touch] *)):not(:disabled) { background: var(--apple-hover); color: var(--apple-text); }
|
|
105
|
+
.user-popup .user-menu-list > .apple-button:active:not(:disabled) { background: var(--apple-pressed); color: var(--apple-text); }
|
|
106
|
+
.user-trigger.user-account-trigger { width: 44px; height: 44px; border: 0; background: transparent; }
|
|
107
|
+
.user-trigger.user-account-trigger:focus-visible { outline: 3px solid var(--apple-accent); outline-offset: 2px; }
|
|
108
|
+
.user-auth-dialog.apple-modal { border-radius: 24px; background: var(--apple-surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
109
|
+
.user-auth-dialog .apple-modal-header { position: relative; justify-content: center; padding: 40px 44px 32px; }
|
|
110
|
+
.user-auth-dialog .apple-modal-heading { width: 100%; text-align: center; }
|
|
111
|
+
.user-auth-dialog .apple-modal-heading h2 { font-size: 30px; line-height: 1.35; }
|
|
112
|
+
.user-auth-dialog .apple-modal-header > .apple-overlay-icon { position: absolute; top: 8px; right: 8px; }
|
|
113
|
+
.user-auth-heading { display: flex; flex-direction: column; align-items: center; gap: 22px; }
|
|
114
|
+
.user-auth-symbol { display: grid; place-items: center; box-sizing: border-box; width: 64px; height: 64px; padding-bottom: 8px; border-radius: 16px; background: var(--apple-text); color: var(--apple-surface); font: 600 56px/1 Georgia, serif; }
|
|
115
|
+
.user-auth-dialog .apple-modal-body { padding: 0 64px 36px; }
|
|
116
|
+
.user-auth-form .apple-form__fields { gap: 20px; }
|
|
117
|
+
.user-auth-password { position: relative; }
|
|
118
|
+
.user-auth-password .apple-field__label { padding-right: 110px; }
|
|
119
|
+
.user-auth-password .user-auth-forgot { position: absolute; top: -12px; right: -8px; min-height: 44px; padding: 8px; font-size: 12px; }
|
|
120
|
+
.user-auth-dialog .user-auth-note { margin: 8px 0 20px; font-size: 13px; line-height: 1.75; }
|
|
121
|
+
.user-auth-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
122
|
+
.user-auth-actions .apple-button { width: 100%; padding-inline: 12px; border-radius: var(--apple-radius, 8px); font-size: 14px; }
|
|
123
|
+
.user-auth-alternatives { display: flex; justify-content: center; margin-top: 24px; font-size: 13px; }
|
|
124
|
+
@media (max-width: 480px) {
|
|
125
|
+
.user-auth-dialog .apple-modal-header { padding: 28px 24px 22px; }
|
|
126
|
+
.user-auth-dialog .apple-modal-body { padding: 0 20px 22px; }
|
|
127
|
+
.user-auth-dialog .apple-modal-heading h2 { font-size: 22px; }
|
|
128
|
+
.user-auth-actions { gap: 8px; }
|
|
129
|
+
.user-auth-actions .apple-button { padding-inline: 8px; font-size: 12px; }
|
|
130
|
+
.user-auth-dialog .user-auth-note { margin-block: 0 8px; }
|
|
131
|
+
}
|
|
132
|
+
</style>
|