Review changes batch 5 of 6
This commit is contained in:
+508
-142
@@ -1,185 +1,551 @@
|
||||
<!-- 公共组件:F/R/N/M 剩余页面的高规格多任务母版;内容独立,视觉表面统一复用完整位图。 -->
|
||||
<!-- 公共组件:F/R/N/M 普通任务页母版;业务结构按类型区分,视觉继承各模块基准页。 -->
|
||||
<template>
|
||||
<view class="module-page" :class="[
|
||||
`module-page--${page.template}`,
|
||||
{
|
||||
'module-state--ready': moduleState === 'ready',
|
||||
'module-state--empty': moduleState === 'empty',
|
||||
'module-state--success': moduleState === 'success',
|
||||
'module-state--error': moduleState === 'error'
|
||||
}
|
||||
]">
|
||||
<view
|
||||
class="module-page"
|
||||
:class="[
|
||||
`module-page--${moduleKey}`,
|
||||
`module-page--${page.template}`,
|
||||
`module-state--${moduleState}`,
|
||||
]"
|
||||
>
|
||||
<ModulePageBackground :module="moduleKey" />
|
||||
<view class="module-page__header"><PageHeader :title="page.title" /></view>
|
||||
|
||||
<view v-if="moduleState === 'ready'" class="module-page__content">
|
||||
<view class="page-intro">
|
||||
<image class="page-intro__seal" src="/static/assets/foundation/transparent/brand-seal.png" mode="aspectFit" />
|
||||
<view><text class="page-intro__number">{{ page.number }}</text><text class="page-intro__subtitle">{{ page.subtitle }}</text></view>
|
||||
<view v-if="moduleState === 'loading'" class="module-page__loading">
|
||||
<AppLoading
|
||||
:text="`正在整理${page.title}`"
|
||||
description="请稍候,内容正在归卷。"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view v-else-if="moduleState === 'ready'" class="module-page__content">
|
||||
<view class="module-lead">
|
||||
<image
|
||||
src="/static/assets/modules/genealogy/transparent/section-divider.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>{{ page.subtitle }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="page.template === 'form'" class="module-panel">
|
||||
<image class="module-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view class="module-panel__body module-form">
|
||||
<text class="module-heading">{{ page.title }}</text>
|
||||
<text class="module-copy">{{ page.subtitle }}</text>
|
||||
<view v-for="field in page.fields" :key="field" class="form-row">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" /><text>{{ field }}</text><input :placeholder="`请输入${field}`" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<text v-if="page.note" class="form-note">{{ normalizedNote }}</text>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
<view v-if="page.template === 'form'" class="module-panel module-form">
|
||||
<text class="section-eyebrow">填写信息</text>
|
||||
<view v-for="field in page.fields" :key="field" class="form-row">
|
||||
<image :src="fieldAsset" mode="scaleToFill" />
|
||||
<text>{{ field }}</text>
|
||||
<input
|
||||
:placeholder="`请输入${field}`"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="page.note" class="form-note">{{ normalizedNote }}</text>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
|
||||
<view v-else-if="page.template === 'list'" class="content-stack">
|
||||
<view v-for="item in page.sections" :key="item[0]" class="list-card" @click="openPreview(item)">
|
||||
<image src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
|
||||
<view class="list-card__copy"><text>{{ item[0] }}</text><text>{{ item[1] }}</text><text>点按查看详情</text></view>
|
||||
<view
|
||||
v-for="item in page.sections"
|
||||
:key="item[0]"
|
||||
class="list-card"
|
||||
@click="openPreview(item)"
|
||||
>
|
||||
<image :src="contentAsset" mode="scaleToFill" />
|
||||
<view class="list-card__copy">
|
||||
<text>{{ item[0] }}</text>
|
||||
<text>{{ item[1] }}</text>
|
||||
<text>查看详情</text>
|
||||
</view>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
|
||||
<view v-else-if="page.template === 'detail'" class="module-panel module-panel--detail">
|
||||
<image class="module-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view class="module-panel__body module-detail">
|
||||
<text class="detail-eyebrow">{{ page.number }} · 家族档案</text>
|
||||
<text class="module-heading">{{ page.title }}</text>
|
||||
<text class="module-copy">{{ page.subtitle }}</text>
|
||||
<view v-for="item in page.sections" :key="item[0]" class="detail-card">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" /><view><text>{{ item[0] }}</text><text>{{ item[1] }}</text></view>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="page.template === 'timeline'" class="content-stack">
|
||||
<view v-for="(item, index) in page.sections" :key="item[0]" class="timeline-row">
|
||||
<image src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
|
||||
<view><text>第 {{ index + 1 }} 则</text><text>{{ item[0] }}</text><text>{{ item[1] }}</text></view>
|
||||
<view
|
||||
v-else-if="page.template === 'detail'"
|
||||
class="module-panel module-detail"
|
||||
>
|
||||
<text class="section-eyebrow">档案详情</text>
|
||||
<view v-for="item in page.sections" :key="item[0]" class="detail-card">
|
||||
<image :src="contentAsset" mode="scaleToFill" />
|
||||
<view
|
||||
><text>{{ item[0] }}</text
|
||||
><text>{{ item[1] }}</text></view
|
||||
>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
|
||||
<view v-else-if="page.template === 'settings'" class="module-panel">
|
||||
<image class="module-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view class="module-panel__body module-settings">
|
||||
<text class="module-heading">{{ page.title }}</text><text class="module-copy">{{ page.subtitle }}</text>
|
||||
<view v-for="item in page.sections" :key="item[0]" class="settings-row" @click="openPreview(item)">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" /><view><text>{{ item[0] }}</text><text>{{ item[1] }}</text></view><text>查看</text>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
<view
|
||||
v-else-if="page.template === 'timeline'"
|
||||
class="content-stack timeline-stack"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in page.sections"
|
||||
:key="item[0]"
|
||||
class="timeline-row"
|
||||
>
|
||||
<image :src="contentAsset" mode="scaleToFill" />
|
||||
<view
|
||||
><text>第 {{ index + 1 }} 则</text><text>{{ item[0] }}</text
|
||||
><text>{{ item[1] }}</text></view
|
||||
>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
|
||||
<view v-else class="module-panel">
|
||||
<image class="module-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view class="module-panel__body status-card">
|
||||
<text class="status-card__eyebrow">{{ page.badge }} · 服务说明</text><text class="status-card__lead">{{ page.lead }}</text><text class="status-card__note">{{ normalizedNote }}</text>
|
||||
<view
|
||||
v-else-if="page.template === 'settings'"
|
||||
class="module-panel module-settings"
|
||||
>
|
||||
<text class="section-eyebrow">服务与设置</text>
|
||||
<view
|
||||
v-for="item in page.sections"
|
||||
:key="item[0]"
|
||||
class="settings-row"
|
||||
@click="openPreview(item)"
|
||||
>
|
||||
<image :src="fieldAsset" mode="scaleToFill" />
|
||||
<view
|
||||
><text>{{ item[0] }}</text
|
||||
><text>{{ normalizedSectionCopy(item[1]) }}</text></view
|
||||
>
|
||||
<text>查看</text>
|
||||
</view>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
|
||||
<view v-else class="module-panel status-card">
|
||||
<image
|
||||
class="status-card__skin"
|
||||
:src="contentAsset"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="status-card__body">
|
||||
<text class="status-card__eyebrow">{{ page.badge }} · 服务说明</text>
|
||||
<text class="status-card__lead">{{ page.lead }}</text>
|
||||
<text class="status-card__note">{{ normalizedNote }}</text>
|
||||
<AppButton block :label="page.action" @click="completeAction" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="module-page__content module-page__content--state">
|
||||
<view class="module-panel">
|
||||
<image class="module-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view class="module-panel__body status-card">
|
||||
<text class="status-card__eyebrow">{{ stateCopy.eyebrow }}</text><text class="status-card__lead">{{ stateCopy.title }}</text><text class="status-card__note">{{ stateCopy.copy }}</text>
|
||||
<AppButton block :type="moduleState === 'error' ? 'secondary' : 'primary'" :label="stateCopy.action" @click="moduleState = 'ready'" />
|
||||
<view class="module-panel status-card">
|
||||
<image
|
||||
class="status-card__skin"
|
||||
:src="contentAsset"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="status-card__body">
|
||||
<text class="status-card__eyebrow">{{ stateCopy.eyebrow }}</text>
|
||||
<text class="status-card__lead">{{ stateCopy.title }}</text>
|
||||
<text class="status-card__note">{{ stateCopy.copy }}</text>
|
||||
<AppButton
|
||||
block
|
||||
:type="moduleState === 'error' ? 'secondary' : 'primary'"
|
||||
:label="stateCopy.action"
|
||||
@click="moduleState = 'ready'"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<AppTabbar v-if="page.tab" :active="page.tab" />
|
||||
<AppToast :visible="toastVisible" :message="toastMessage" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
import AppButton from '@/components/AppButton.vue'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import AppTabbar from '@/components/AppTabbar.vue'
|
||||
import AppToast from '@/components/AppToast.vue'
|
||||
import ModulePageBackground from '@/components/ModulePageBackground.vue'
|
||||
import { pageCatalog } from '@/data/page-catalog.js'
|
||||
import { computed, onUnmounted, ref } from "vue";
|
||||
import AppButton from "@/components/AppButton.vue";
|
||||
import AppLoading from "@/components/AppLoading.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import AppTabbar from "@/components/AppTabbar.vue";
|
||||
import AppToast from "@/components/AppToast.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import { pageCatalog } from "@/data/page-catalog.js";
|
||||
|
||||
const props = defineProps({ pageId: { type: String, required: true } })
|
||||
const page = computed(() => pageCatalog[props.pageId])
|
||||
const moduleKey = computed(() => ({ f: 'family', r: 'records', n: 'notification', m: 'profile' }[props.pageId[0]] || 'profile'))
|
||||
const props = defineProps({ pageId: { type: String, required: true } });
|
||||
const page = computed(() => pageCatalog[props.pageId]);
|
||||
const moduleKey = computed(
|
||||
() =>
|
||||
({ f: "family", r: "records", n: "notification", m: "profile" })[
|
||||
props.pageId[0]
|
||||
] || "profile",
|
||||
);
|
||||
const assetModule = computed(
|
||||
() =>
|
||||
({
|
||||
family: "family",
|
||||
records: "records",
|
||||
notification: "notification",
|
||||
profile: "profile",
|
||||
})[moduleKey.value],
|
||||
);
|
||||
const contentAsset = computed(
|
||||
() =>
|
||||
`/static/assets/modules/${assetModule.value}/transparent/module-content-frame.png`,
|
||||
);
|
||||
const fieldAsset = computed(
|
||||
() =>
|
||||
`/static/assets/modules/${assetModule.value}/transparent/module-field-frame.png`,
|
||||
);
|
||||
const query = (() => {
|
||||
if (typeof location !== 'undefined') return Object.fromEntries(new URLSearchParams(location.hash.split('?')[1] || ''))
|
||||
const pages = getCurrentPages(); return pages[pages.length - 1]?.options || {}
|
||||
})()
|
||||
const moduleState = ref('ready')
|
||||
const toastVisible = ref(false)
|
||||
const toastMessage = ref('')
|
||||
let toastTimer = null
|
||||
if (query.state === 'empty' || query.state === 'success' || query.state === 'error') moduleState.value = query.state
|
||||
const normalizedNote = computed(() => (page.value.note || '').replace(/待接入|服务待接入|功能待接入/g, '将在后续功能阶段开放'))
|
||||
const stateCopy = computed(() => ({
|
||||
empty: { eyebrow: `${page.value.number} · 暂无内容`, title: `还没有${page.value.title}记录`, copy: '完成第一条记录后,内容会按时间或类别整理在这里。', action: page.value.action },
|
||||
success: { eyebrow: '本地预览已保存', title: `${page.value.title}内容已更新`, copy: '当前候选已展示完整操作结果;正式数据将在接口阶段接入。', action: '继续查看' },
|
||||
error: { eyebrow: '内容暂不可用', title: `暂时无法打开${page.value.title}`, copy: '请稍后重新进入,现有资料不会受到影响。', action: '重新查看' }
|
||||
}[moduleState.value] || {}))
|
||||
const completeAction = () => { moduleState.value = 'success' }
|
||||
if (typeof location !== "undefined")
|
||||
return Object.fromEntries(
|
||||
new URLSearchParams(location.hash.split("?")[1] || ""),
|
||||
);
|
||||
const pages = getCurrentPages();
|
||||
return pages[pages.length - 1]?.options || {};
|
||||
})();
|
||||
const moduleState = ref(
|
||||
["loading", "empty", "success", "error"].includes(query.state)
|
||||
? query.state
|
||||
: "ready",
|
||||
);
|
||||
const toastVisible = ref(false);
|
||||
const toastMessage = ref("");
|
||||
let toastTimer = null;
|
||||
const normalizedNote = computed(() =>
|
||||
(page.value.note || "").replace(
|
||||
/待接入|服务待接入|功能待接入/g,
|
||||
"将在后续功能阶段开放",
|
||||
),
|
||||
);
|
||||
const normalizedSectionCopy = (copy) =>
|
||||
String(copy || "").replace(/待接入|功能待接入/g, "后续功能阶段开放");
|
||||
const stateCopy = computed(
|
||||
() =>
|
||||
({
|
||||
empty: {
|
||||
eyebrow: "暂无内容",
|
||||
title: `还没有${page.value.title}记录`,
|
||||
copy: "完成第一条记录后,内容会按时间或类别整理在这里。",
|
||||
action: page.value.action,
|
||||
},
|
||||
success: {
|
||||
eyebrow: "操作结果",
|
||||
title: `${page.value.title}内容已更新`,
|
||||
copy: "当前页面已展示操作结果;正式数据将在接口阶段接入。",
|
||||
action: "继续查看",
|
||||
},
|
||||
error: {
|
||||
eyebrow: "内容暂不可用",
|
||||
title: `暂时无法打开${page.value.title}`,
|
||||
copy: "请稍后重新进入,现有资料不会受到影响。",
|
||||
action: "重新查看",
|
||||
},
|
||||
})[moduleState.value] || {},
|
||||
);
|
||||
const completeAction = () => {
|
||||
moduleState.value = "success";
|
||||
};
|
||||
const openPreview = (item) => {
|
||||
toastMessage.value = item[0]
|
||||
toastVisible.value = true
|
||||
if (toastTimer) clearTimeout(toastTimer)
|
||||
toastTimer = setTimeout(() => { toastVisible.value = false; toastTimer = null }, 1800)
|
||||
}
|
||||
onUnmounted(() => { if (toastTimer) clearTimeout(toastTimer) })
|
||||
toastMessage.value = item[0];
|
||||
toastVisible.value = true;
|
||||
if (toastTimer) clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => {
|
||||
toastVisible.value = false;
|
||||
toastTimer = null;
|
||||
}, 1800);
|
||||
};
|
||||
onUnmounted(() => {
|
||||
if (toastTimer) clearTimeout(toastTimer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.module-page { position: relative; min-height: 100vh; overflow: hidden; background: $paper; }
|
||||
.module-page__header, .module-page__content { position: relative; z-index: 2; }
|
||||
.module-page__content { padding: 20rpx 24rpx 50rpx; }
|
||||
.page-intro { display: flex; align-items: center; min-height: 86rpx; margin: 0 8rpx 14rpx; }
|
||||
.page-intro__seal { width: 66rpx; height: 66rpx; margin-right: 13rpx; }
|
||||
.page-intro__number, .page-intro__subtitle { display: block; }
|
||||
.page-intro__number { color: $brand-red; font-size: 23rpx; font-weight: 700; letter-spacing: 3rpx; }
|
||||
.page-intro__subtitle { margin-top: 5rpx; color: $ink-muted; font-size: 20rpx; }
|
||||
.module-panel { position: relative; width: 100%; height: min(640px, calc((100vw - 24px) * 1.48)); }
|
||||
.module-panel__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.module-panel__body { position: absolute; inset: 7.5% 8%; }
|
||||
.module-heading { display: block; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 34rpx; font-weight: 700; }
|
||||
.module-copy { display: block; margin-top: 8rpx; color: $ink-muted; font-size: 20rpx; line-height: 1.5; }
|
||||
.form-row { position: relative; height: 76rpx; margin-top: 12rpx; }
|
||||
.form-row image, .detail-card image, .settings-row image, .list-card > image, .timeline-row > image { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.form-row > text { position: absolute; top: 26rpx; left: 22rpx; z-index: 1; color: $ink; font-size: 21rpx; font-weight: 700; }
|
||||
.form-row input { position: absolute; top: 0; right: 18rpx; bottom: 0; left: 164rpx; z-index: 1; height: 76rpx; color: $ink; font-size: 21rpx; line-height: 76rpx; }
|
||||
.form-placeholder { color: #a79884; }
|
||||
.form-note { display: block; margin-top: 14rpx; color: $ink-muted; font-size: 19rpx; text-align: center; }
|
||||
.module-form > .app-button, .module-detail > .app-button, .module-settings > .app-button, .content-stack > .app-button { margin-top: 18rpx; }
|
||||
.content-stack { display: flex; flex-direction: column; gap: 14rpx; }
|
||||
.list-card, .timeline-row { position: relative; width: 100%; height: calc((100vw - 24px) * .34286); min-height: 220rpx; }
|
||||
.list-card__copy { position: absolute; inset: 19% 9%; z-index: 1; }
|
||||
.list-card__copy text { display: block; }
|
||||
.list-card__copy text:first-child { color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 29rpx; font-weight: 700; }
|
||||
.list-card__copy text:nth-child(2) { margin-top: 9rpx; color: $ink-muted; font-size: 20rpx; }
|
||||
.list-card__copy text:last-child { margin-top: 9rpx; color: $brand-red; font-size: 18rpx; }
|
||||
.detail-eyebrow { display: block; color: $brand-red; font-size: 21rpx; letter-spacing: 3rpx; }
|
||||
.module-detail .module-heading { margin-top: 9rpx; }
|
||||
.detail-card, .settings-row { position: relative; min-height: 88rpx; margin-top: 14rpx; }
|
||||
.detail-card > view { position: relative; z-index: 1; padding: 18rpx 24rpx; }
|
||||
.detail-card text, .settings-row text { display: block; }
|
||||
.detail-card text:first-child { color: $brand-red; font-size: 21rpx; font-weight: 700; }
|
||||
.detail-card text:last-child { margin-top: 7rpx; color: $ink-muted; font-size: 20rpx; line-height: 1.45; }
|
||||
.timeline-row > view { position: absolute; inset: 17% 9%; z-index: 1; }
|
||||
.timeline-row text { display: block; }
|
||||
.timeline-row text:first-child { color: $brand-red; font-size: 18rpx; letter-spacing: 2rpx; }
|
||||
.timeline-row text:nth-child(2) { margin-top: 5rpx; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 29rpx; font-weight: 700; }
|
||||
.timeline-row text:last-child { margin-top: 8rpx; color: $ink-muted; font-size: 20rpx; }
|
||||
.settings-row > view { position: absolute; top: 19rpx; left: 22rpx; z-index: 1; }
|
||||
.settings-row > view text:first-child { color: $ink; font-size: 22rpx; font-weight: 700; }
|
||||
.settings-row > view text:last-child { margin-top: 5rpx; color: $ink-muted; font-size: 18rpx; }
|
||||
.settings-row > text { position: absolute; top: 34rpx; right: 22rpx; z-index: 1; color: $brand-red; font-size: 18rpx; }
|
||||
.status-card { top: 28%; text-align: center; }
|
||||
.status-card__eyebrow { display: block; color: $brand-red; font-size: 21rpx; letter-spacing: 3rpx; }
|
||||
.status-card__lead { display: block; margin-top: 14rpx; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 35rpx; font-weight: 700; }
|
||||
.status-card__note { display: block; margin-top: 17rpx; color: $ink-muted; font-size: 21rpx; line-height: 1.65; }
|
||||
.status-card .app-button { margin: 30rpx auto 0; }
|
||||
.module-page__content--state { padding-top: 18rpx; }
|
||||
@media (min-width: 400px) { .module-page__content { padding-right: 32rpx; padding-left: 32rpx; } }
|
||||
.module-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
background: $paper;
|
||||
}
|
||||
.module-page__header,
|
||||
.module-page__content,
|
||||
.module-page__loading {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.module-page__loading {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
}
|
||||
.module-page__content {
|
||||
padding: 16rpx 26rpx 56rpx;
|
||||
}
|
||||
.module-lead {
|
||||
position: relative;
|
||||
height: 56rpx;
|
||||
margin: 0 12rpx 18rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 23rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.module-lead image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.module-lead text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
.module-panel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.section-eyebrow {
|
||||
display: block;
|
||||
margin: 2rpx 8rpx 14rpx;
|
||||
color: $brand-red;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 29rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.form-row {
|
||||
position: relative;
|
||||
height: 84rpx;
|
||||
margin-top: 14rpx;
|
||||
}
|
||||
.form-row image,
|
||||
.detail-card image,
|
||||
.settings-row image,
|
||||
.list-card > image,
|
||||
.timeline-row > image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.form-row > text {
|
||||
position: absolute;
|
||||
top: 28rpx;
|
||||
left: 26rpx;
|
||||
z-index: 1;
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.form-row input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 22rpx;
|
||||
bottom: 0;
|
||||
left: 178rpx;
|
||||
z-index: 1;
|
||||
height: 84rpx;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
line-height: 84rpx;
|
||||
}
|
||||
.form-placeholder {
|
||||
color: #9e8e79;
|
||||
}
|
||||
.form-note {
|
||||
display: block;
|
||||
margin: 18rpx 18rpx 0;
|
||||
color: $ink-muted;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
.module-form > .app-button,
|
||||
.module-detail > .app-button,
|
||||
.module-settings > .app-button,
|
||||
.content-stack > .app-button {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.content-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.list-card,
|
||||
.timeline-row {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 188rpx;
|
||||
}
|
||||
.list-card__copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 34rpx 46rpx 28rpx;
|
||||
}
|
||||
.list-card__copy text {
|
||||
display: block;
|
||||
}
|
||||
.list-card__copy text:first-child {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.list-card__copy text:nth-child(2) {
|
||||
margin-top: 10rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.list-card__copy text:last-child {
|
||||
margin-top: 11rpx;
|
||||
color: $brand-red;
|
||||
font-size: 21rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.detail-card {
|
||||
position: relative;
|
||||
min-height: 170rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
.detail-card > view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 34rpx 44rpx;
|
||||
}
|
||||
.detail-card text,
|
||||
.settings-row text {
|
||||
display: block;
|
||||
}
|
||||
.detail-card text:first-child {
|
||||
color: $brand-red;
|
||||
font-size: 23rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.detail-card text:last-child {
|
||||
margin-top: 10rpx;
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.timeline-row > view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 29rpx 44rpx;
|
||||
}
|
||||
.timeline-row text {
|
||||
display: block;
|
||||
}
|
||||
.timeline-row text:first-child {
|
||||
color: $brand-red;
|
||||
font-size: 21rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.timeline-row text:nth-child(2) {
|
||||
margin-top: 6rpx;
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.timeline-row text:last-child {
|
||||
margin-top: 9rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 23rpx;
|
||||
}
|
||||
.settings-row {
|
||||
position: relative;
|
||||
min-height: 94rpx;
|
||||
margin-top: 14rpx;
|
||||
}
|
||||
.settings-row > view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 20rpx 98rpx 18rpx 26rpx;
|
||||
}
|
||||
.settings-row > view text:first-child {
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.settings-row > view text:last-child {
|
||||
margin-top: 6rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
}
|
||||
.settings-row > text {
|
||||
position: absolute;
|
||||
top: 34rpx;
|
||||
right: 28rpx;
|
||||
z-index: 1;
|
||||
color: $brand-red;
|
||||
font-size: 21rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-card {
|
||||
min-height: 330rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.status-card__skin {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.status-card__body {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 70rpx 60rpx 48rpx;
|
||||
}
|
||||
.status-card__eyebrow {
|
||||
display: block;
|
||||
color: $brand-red;
|
||||
font-size: 23rpx;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.status-card__lead {
|
||||
display: block;
|
||||
margin-top: 14rpx;
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 35rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.status-card__note {
|
||||
display: block;
|
||||
margin-top: 17rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.status-card .app-button {
|
||||
margin: 28rpx auto 0;
|
||||
}
|
||||
.module-page__content--state {
|
||||
padding-top: 72rpx;
|
||||
}
|
||||
.module-page--family .section-eyebrow {
|
||||
color: #9f2c23;
|
||||
}
|
||||
.module-page--records .section-eyebrow {
|
||||
color: #8c261f;
|
||||
}
|
||||
.module-page--notification .section-eyebrow {
|
||||
color: #9b2b21;
|
||||
}
|
||||
.module-page--profile .section-eyebrow {
|
||||
color: #a22d24;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.module-page__content {
|
||||
padding-right: 34rpx;
|
||||
padding-left: 34rpx;
|
||||
}
|
||||
}
|
||||
@media (max-width: 340px) {
|
||||
.module-page__content {
|
||||
padding-right: 20rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
.form-row input {
|
||||
left: 162rpx;
|
||||
}
|
||||
.status-card__body {
|
||||
padding-right: 44rpx;
|
||||
padding-left: 44rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user