Files
jiapuapp/pages/genealogy/g01-my-genealogies.vue
T
2026-07-21 13:06:36 +08:00

1272 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号G-01用途我的家谱列表与首次分流本轮仍待用户重新审核 -->
<template>
<view
class="page-shell genealogy-index"
:class="{ 'genealogy-index--split': isListLayout }"
>
<GenealogyPageBackground />
<PageHeader
root
title="我的家谱"
:unread-count="unreadCount"
@notice="toNotifications"
/>
<view class="genealogy-content">
<view v-if="isLoading" class="state-panel state-panel--loading">
<AppLoading
text="正在整理家谱"
description="请稍候,家族记忆正在归卷。"
/>
</view>
<view v-else-if="hasError" class="state-panel state-panel--error">
<view class="error-panel__content">
<image
class="error-panel__seal"
src="/static/assets/foundation/transparent/brand-seal.png"
mode="aspectFit"
/>
<text class="state-title">暂时无法读取家谱</text>
<text class="state-copy">网络或服务暂不可用请稍后重新查看</text>
<image
class="error-panel__divider"
src="/static/assets/modules/genealogy/transparent/section-divider.png"
mode="scaleToFill"
/>
<view
class="state-retry"
hover-class="action-hover"
@click="retryLoad"
>
<text class="state-retry__copy">重新加载</text>
</view>
</view>
</view>
<template v-else-if="hasGenealogies">
<view class="genealogy-fixed-zone">
<view class="current-slip" @click="openSwitcher">
<view class="current-summary">
<view class="current-seal">
<text class="current-seal-title">家谱</text>
</view>
<text class="current-name">{{ currentGenealogy.name }}</text>
<text class="current-switch-copy">切换</text>
</view>
<view class="current-info-divider"></view>
<view class="current-meta">
<view class="current-meta-item">
<image
class="current-meta-icon"
src="/static/assets/foundation/transparent/meta-location.png"
mode="aspectFit"
/>
<text class="current-meta-item-text">{{
currentGenealogy.location
}}</text>
</view>
<view class="current-meta-item">
<image
class="current-meta-icon"
src="/static/assets/foundation/transparent/meta-member.png"
mode="aspectFit"
/>
<text class="current-meta-item-text"
>{{ currentGenealogy.memberCount }} 位成员</text
>
</view>
<view class="current-meta-item">
<image
class="current-meta-icon"
src="/static/assets/foundation/transparent/meta-admin.png"
mode="aspectFit"
/>
<text class="current-meta-item-text">{{ currentRoleLabel }}</text>
</view>
</view>
</view>
<view class="shortcut-grid">
<view
v-for="item in visibleShortcuts"
:key="item.key"
class="shortcut-item"
@click="openShortcut(item.key)"
>
<image class="shortcut-icon" :src="item.icon" mode="aspectFit" />
<text class="shortcut-label">{{ item.label }}</text>
</view>
</view>
<image
class="section-divider"
src="/static/assets/modules/genealogy/transparent/section-divider.png"
mode="scaleToFill"
/>
</view>
<scroll-view
class="genealogy-list-scroll"
scroll-y
:scroll-top="listScrollCommand"
@scroll="handleListScroll"
>
<view class="genealogy-lower">
<view v-if="createdGenealogies.length" class="list-section">
<view class="section-heading"><text>我创建的</text></view>
<GenealogyCard
v-for="item in createdGenealogies"
:key="item.id"
:genealogy="item"
role="管理员"
:selected="item.id === currentGenealogy.id"
@select="openGenealogy"
/>
</view>
<view v-if="joinedGenealogies.length" class="list-section">
<view class="section-heading"><text>我加入的</text></view>
<GenealogyCard
v-for="item in joinedGenealogies"
:key="item.id"
:genealogy="item"
role="成员"
@select="openGenealogy"
/>
</view>
<view class="list-section application-section">
<view class="section-heading"><text>加入申请</text></view>
<view
v-for="item in applicationRecords"
:key="item.id"
class="application-record"
hover-class="action-hover"
@click="openApplication(item)"
>
<view class="application-record__main">
<view class="application-record__title-row">
<text class="application-record__name">{{
item.name
}}</text>
<text
class="application-record__status"
:class="`application-record__status--${item.tone}`"
>{{ item.statusLabel }}</text
>
</view>
<text class="application-record__copy">{{
item.description
}}</text>
</view>
<image
class="application-record__chevron"
src="/static/assets/foundation/transparent/chevron-right.png"
mode="aspectFit"
/>
</view>
</view>
<view class="create-action" @click="openAddDialog">
<image
class="create-cloud"
src="/static/assets/modules/genealogy/transparent/create-cloud.png"
mode="aspectFit"
/>
<image
class="create-icon"
src="/static/assets/modules/genealogy/transparent/add.png"
mode="aspectFit"
/>
<text>添加家谱</text>
<image
class="create-cloud create-cloud--right"
src="/static/assets/modules/genealogy/transparent/create-cloud.png"
mode="aspectFit"
/>
</view>
</view>
</scroll-view>
</template>
<view v-else class="genealogy-empty-state">
<view class="empty-panel">
<view class="empty-panel__content">
<view class="empty-seal">
<text class="empty-seal__text">家谱</text>
</view>
<text class="empty-title">还没有加入任何家谱</text>
<text class="empty-copy"
>先搜索家族是否已有家谱再选择加入或创建</text
>
<image
class="empty-divider"
src="/static/assets/modules/genealogy/transparent/section-divider.png"
mode="scaleToFill"
/>
<view
class="empty-search-action"
hover-class="action-hover"
@click="applyToJoin"
>
<text
class="empty-search-action__copy empty-search-action__copy--primary"
>搜索家谱</text
>
</view>
<view
class="empty-invite-action"
hover-class="action-hover"
@click="joinByInvite"
>
<text class="empty-invite-action__copy">邀请码加入</text>
</view>
<view
class="empty-create-action"
hover-class="action-hover"
@click="createGenealogy"
>
<text class="empty-create-action__copy">创建家谱</text>
</view>
<text class="empty-create-note"
>确认没有现有家谱后再创建避免重复建谱</text
>
</view>
</view>
</view>
</view>
<view
v-if="addDialogVisible"
class="add-dialog-layer"
@click="closeAddDialog"
>
<view class="add-dialog" @click.stop>
<view class="add-dialog__content">
<view class="add-dialog__body">
<view class="add-dialog__heading">
<text class="dialog-title">添加家谱</text>
<text class="dialog-copy">建议先搜索已有家谱避免重复创建</text>
<view
class="add-dialog__close"
role="button"
aria-label="关闭"
hover-class="action-hover"
@click="closeAddDialog"
>
<image
class="add-dialog__close-icon"
src="/static/assets/modules/genealogy/transparent/g01-dialog-close.png"
mode="aspectFit"
/>
</view>
</view>
<view class="add-dialog__actions">
<AppButton block label="搜索家谱" @click="applyToJoin" />
<AppButton
block
type="secondary"
label="邀请码加入"
@click="joinByInvite"
/>
<AppButton
block
type="secondary"
label="继续创建家谱"
@click="createGenealogy"
/>
</view>
</view>
</view>
</view>
</view>
<view
v-if="switcherVisible"
class="genealogy-switcher-layer"
@click="closeSwitcher"
>
<view
class="genealogy-switcher"
role="dialog"
aria-modal="true"
aria-label="切换当前家谱"
@click.stop
>
<view class="genealogy-switcher__content">
<text class="dialog-title">切换当前家谱</text>
<view
class="genealogy-switcher__close"
role="button"
aria-label="关闭"
hover-class="action-hover"
@click="closeSwitcher"
>
<image
class="genealogy-switcher__close-icon"
src="/static/assets/modules/genealogy/transparent/g01-dialog-close.png"
mode="aspectFit"
/>
</view>
<scroll-view class="genealogy-switcher__list" scroll-y>
<view
v-for="item in availableGenealogies"
:key="item.id"
class="switcher-item"
:class="{
'switcher-item--active': item.id === selectedGenealogyId,
}"
@click="selectGenealogy(item)"
>
<view>
<text class="switcher-item__name">{{ item.name }}</text>
<text class="switcher-item__meta"
>{{ item.location }} · {{ item.memberCount }} 位成员</text
>
</view>
<text class="switcher-item__state">{{
item.id === selectedGenealogyId ? "当前" : "选择"
}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
<AppTabbar active="genealogy" />
</view>
</template>
<script setup>
import { computed, nextTick, ref } from "vue";
import { onBackPress, onLoad, onShow } from "@dcloudio/uni-app";
import AppLoading from "@/components/AppLoading.vue";
import AppTabbar from "@/components/AppTabbar.vue";
import AppButton from "@/components/AppButton.vue";
import GenealogyCard from "@/components/GenealogyCard.vue";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import { genealogies, notifications } from "@/data/mock.js";
import { genealogyContext } from "@/utils/genealogy-context.js";
const isLoading = ref(false);
const hasError = ref(false);
const list = ref(genealogies);
const forceEmptyState = ref(false);
const addDialogVisible = ref(false);
const switcherVisible = ref(false);
const storedGenealogyId = Number(genealogyContext.getCurrentGenealogyId());
const selectedGenealogyId = ref(
genealogies.some((item) => item.id === storedGenealogyId)
? storedGenealogyId
: genealogies[0]?.id || null,
);
const listScrollCommand = ref(0);
const currentListScrollTop = ref(0);
const readPresentationState = () => {
if (typeof location !== "undefined") {
const query = new URLSearchParams(location.hash.split("?")[1] || "");
return query.get("state") || "default";
}
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
return currentPage?.options?.state || "default";
};
const syncEmptyStateFromRoute = () => {
const presentationState = readPresentationState();
forceEmptyState.value = presentationState === "empty";
isLoading.value = presentationState === "loading";
hasError.value = presentationState === "error";
};
onLoad((query) => {
const requestedId = Number(query?.genealogyId);
if (genealogies.some((item) => item.id === requestedId)) {
selectedGenealogyId.value = requestedId;
genealogyContext.setCurrentGenealogyId(requestedId);
} else if (selectedGenealogyId.value) {
genealogyContext.setCurrentGenealogyId(selectedGenealogyId.value);
}
syncEmptyStateFromRoute();
});
onShow(() => {
syncEmptyStateFromRoute();
});
const unreadCount = computed(
() => notifications.filter((item) => item.unread).length,
);
const hasGenealogies = computed(
() => !forceEmptyState.value && list.value.length > 0,
);
const isListLayout = computed(
() => !isLoading.value && !hasError.value && hasGenealogies.value,
);
const createdGenealogies = computed(() =>
list.value.filter((item) => item.membership === "created"),
);
const joinedGenealogies = computed(() =>
list.value.filter((item) => item.membership === "joined"),
);
const availableGenealogies = computed(() => list.value);
const currentGenealogy = computed(
() =>
availableGenealogies.value.find(
(item) => item.id === selectedGenealogyId.value,
) || availableGenealogies.value[0],
);
const isCurrentGenealogyOwner = computed(
() => currentGenealogy.value?.membership === "created",
);
const currentRoleLabel = computed(() =>
isCurrentGenealogyOwner.value ? "管理员" : "成员",
);
// 仅用于页面样式阶段覆盖加入申请的关键状态,不作为接口数据。
const applicationRecords = [
{
id: "pending",
name: "汤氏南阳宗谱",
statusLabel: "审核中",
tone: "pending",
description: "申请已提交,等待管理员审核",
},
{
id: "rejected",
name: "汤氏清河家谱",
statusLabel: "被拒绝",
tone: "rejected",
description: "可修改关系说明后重新申请",
},
{
id: "removed",
name: "汤氏汝南支谱",
statusLabel: "已退出",
tone: "muted",
description: "如需恢复成员身份,可重新申请加入",
},
];
const shortcuts = [
{
key: "tree",
label: "世系图",
icon: "/static/assets/modules/genealogy/transparent/shortcut-tree.png",
},
{
key: "members",
label: "成员",
icon: "/static/assets/modules/genealogy/transparent/shortcut-members.png",
},
{
key: "poem",
label: "字辈诗",
icon: "/static/assets/modules/genealogy/transparent/shortcut-generation-poem.png",
},
{
key: "applications",
label: "申请审核",
icon: "/static/assets/modules/genealogy/transparent/shortcut-application.png",
},
];
const visibleShortcuts = computed(() =>
isCurrentGenealogyOwner.value
? shortcuts
: shortcuts.filter((item) => item.key !== "applications"),
);
const openGenealogy = (genealogy) => {
genealogyContext.setCurrentGenealogyId(genealogy.id);
uni.navigateTo({
url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${genealogy.id}`,
});
};
const createGenealogy = () =>
uni.navigateTo({ url: "/pages/genealogy/g03-create-genealogy" });
const applyToJoin = () =>
uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
const joinByInvite = () =>
uni.navigateTo({
url: "/pages/genealogy/g06-search-genealogies?mode=invite",
});
const toNotifications = () =>
uni.navigateTo({ url: "/pages/notification/n01-message-center" });
const openAddDialog = () => {
addDialogVisible.value = true;
};
const closeAddDialog = () => {
addDialogVisible.value = false;
};
onBackPress(() => {
if (switcherVisible.value) {
closeSwitcher();
return true;
}
if (addDialogVisible.value) {
closeAddDialog();
return true;
}
return false;
});
const openSwitcher = () => {
switcherVisible.value = true;
};
const closeSwitcher = () => {
switcherVisible.value = false;
};
const handleListScroll = (event) => {
currentListScrollTop.value = Number(event?.detail?.scrollTop || 0);
};
const resetListScroll = async () => {
listScrollCommand.value = currentListScrollTop.value;
await nextTick();
listScrollCommand.value = 0;
currentListScrollTop.value = 0;
};
const selectGenealogy = async (genealogy) => {
selectedGenealogyId.value = genealogy.id;
genealogyContext.setCurrentGenealogyId(genealogy.id);
closeSwitcher();
await resetListScroll();
};
const openApplication = (record) => {
const statusQuery = record.id === "pending" ? "pending" : record.id;
uni.navigateTo({
url: `/pages/genealogy/g09-my-applications?status=${statusQuery}`,
});
};
const retryLoad = () => {
hasError.value = false;
isLoading.value = false;
};
const openShortcut = (key) => {
if (!currentGenealogy.value) return;
const genealogyId = currentGenealogy.value.id;
genealogyContext.setCurrentGenealogyId(genealogyId);
const paths = {
tree: `/pages/tree/t01-tree-overview?genealogyId=${currentGenealogy.value.id}`,
members: `/pages/genealogy/g05-genealogy-overview?genealogyId=${currentGenealogy.value.id}`,
poem: `/pages/genealogy/g12-generation-poems?genealogyId=${currentGenealogy.value.id}`,
applications: `/pages/genealogy/g10-application-review?genealogyId=${currentGenealogy.value.id}`,
};
uni.navigateTo({ url: paths[key] });
};
</script>
<style scoped lang="scss">
.genealogy-index {
display: flex;
min-height: 100vh;
flex-direction: column;
overflow: hidden;
background: #f9f6ef;
}
.genealogy-content {
z-index: 1;
padding: 24rpx 32rpx 176rpx;
}
.genealogy-index--split {
display: flex;
height: 100vh;
min-height: 0;
flex-direction: column;
padding-bottom: calc(112rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.genealogy-index--split .genealogy-content {
display: flex;
min-height: 0;
flex: 1;
flex-direction: column;
padding-bottom: 0;
}
.genealogy-fixed-zone {
flex: 0 0 auto;
}
.genealogy-list-scroll {
width: 100%;
height: 0;
min-height: 0;
flex: 1;
}
.current-slip {
display: block;
min-height: 268rpx;
padding: 30rpx 34rpx 28rpx;
box-sizing: border-box;
background: url("/static/assets/modules/genealogy/transparent/current-slip-frame.png") center / 100% 100% no-repeat;
}
.current-seal {
display: flex;
width: 80rpx;
height: 128rpx;
flex: 0 0 auto;
align-items: center;
justify-content: center;
margin-right: 24rpx;
background: url("/static/assets/modules/genealogy/transparent/current-seal-frame.png") center / 100% 100% no-repeat;
color: #fff7e7;
}
.current-seal-title {
color: #fff7e7;
font-family: "STKaiti", "KaiTi", serif;
font-size: 32rpx;
font-weight: 700;
letter-spacing: 2rpx;
writing-mode: vertical-rl;
}
.current-summary {
display: flex;
min-width: 0;
align-items: center;
}
.current-name {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 50rpx;
font-weight: 700;
overflow-wrap: anywhere;
}
.current-switch-copy {
flex: 0 0 auto;
margin-left: auto;
color: $brand-red;
font-size: 28rpx;
}
.current-info-divider {
width: 100%;
height: 1rpx;
margin: 14rpx 0 16rpx;
background: rgba(181, 138, 75, 0.48);
}
.current-meta {
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
margin-top: 0;
color: #62584c;
font-size: 27rpx;
font-weight: 500;
line-height: 1.4;
}
.current-meta-item {
display: flex;
align-items: center;
margin: 0;
flex-wrap: wrap;
.current-meta-item-text {
overflow-wrap: anywhere;
}
}
.current-meta-icon {
width: 36rpx;
height: 36rpx;
margin-right: 8rpx;
opacity: 1;
}
.shortcut-grid {
display: flex;
min-height: 194rpx;
align-items: center;
margin-top: 24rpx;
padding: 8rpx 0;
}
.shortcut-item {
display: flex;
min-width: 0;
flex: 1;
flex-direction: column;
align-items: center;
}
.shortcut-icon {
width: 82rpx;
height: 82rpx;
}
.shortcut-label {
width: 100%;
margin-top: 12rpx;
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 29rpx;
font-weight: 700;
text-align: center;
overflow-wrap: anywhere;
}
.section-divider {
display: block;
width: 100%;
height: 30rpx;
margin: 4rpx 0 0;
}
.genealogy-lower {
padding: 12rpx 0 36rpx;
}
.list-section {
margin-top: 16rpx;
}
.section-heading {
display: flex;
min-height: 56rpx;
align-items: center;
margin-bottom: 8rpx;
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 34rpx;
font-weight: 700;
}
.section-heading::before {
width: 8rpx;
height: 34rpx;
margin-right: 14rpx;
border-radius: 8rpx;
background: $brand-red;
content: "";
}
.list-section + .list-section {
margin-top: 18rpx;
}
.application-record {
display: flex;
min-height: 138rpx;
align-items: center;
box-sizing: border-box;
padding: 22rpx 26rpx;
background: url("/static/assets/modules/genealogy/transparent/list-slip-frame.png") center / 100% 100% no-repeat;
}
.application-record + .application-record {
margin-top: 12rpx;
}
.application-record__main {
min-width: 0;
flex: 1;
}
.application-record__title-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.application-record__name {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 32rpx;
font-weight: 700;
overflow-wrap: anywhere;
}
.application-record__status {
flex: 0 0 auto;
margin-left: 16rpx;
color: #7f4f16;
font-size: 27rpx;
font-weight: 600;
}
.application-record__status--rejected {
color: #a7160c;
}
.application-record__status--muted {
color: #62584c;
}
.application-record__copy {
display: block;
margin-top: 10rpx;
color: #62584c;
font-size: 28rpx;
font-weight: 500;
line-height: 1.4;
}
.application-record__chevron {
width: 32rpx;
height: 32rpx;
margin-left: 14rpx;
}
.create-action {
display: flex;
min-height: 96rpx;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: 30rpx;
}
.create-action {
width: 350rpx;
margin: 32rpx auto 0;
border: 2rpx solid $brand-red;
border-radius: 48rpx;
background: rgba(255, 249, 238, 0.66);
color: $brand-red;
font-family: "STKaiti", "KaiTi", serif;
font-size: 32rpx;
font-weight: 700;
letter-spacing: 3rpx;
}
.create-icon {
width: 38rpx;
height: 38rpx;
margin-right: 12rpx;
}
.create-action .create-icon {
width: 40rpx;
height: 40rpx;
margin: 0 8rpx;
}
.create-cloud {
width: 54rpx;
height: 28rpx;
flex: 0 0 auto;
}
.create-action > text {
flex: 0 0 auto;
text-align: center;
}
.create-cloud--right {
transform: scaleX(-1);
}
.state-panel {
display: flex;
min-height: 540rpx;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 42rpx;
box-sizing: border-box;
text-align: center;
}
.state-title {
margin-top: 24rpx;
color: $ink;
font-family: serif;
font-size: 38rpx;
font-weight: 700;
}
.state-copy {
margin-top: 14rpx;
color: $ink-muted;
font-size: 25rpx;
line-height: 1.7;
}
.state-panel--error {
min-height: 1120rpx;
padding: 0;
background: url("/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png") center / 100% 100% no-repeat;
}
.error-panel__content {
display: flex;
width: 100%;
min-height: 1120rpx;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 50rpx 28rpx 46rpx;
}
.error-panel__seal {
width: 132rpx;
height: 136rpx;
}
.state-panel--error .state-title {
display: block;
margin-top: 30rpx;
color: #392719;
font-family: "STKaiti", "KaiTi", serif;
font-size: 42rpx;
font-weight: 700;
letter-spacing: 2rpx;
}
.state-panel--error .state-copy {
display: block;
min-height: 72rpx;
margin-top: 16rpx;
color: #786654;
font-size: 27rpx;
line-height: 1.65;
}
.error-panel__divider {
display: block;
width: 100%;
height: 30rpx;
margin-top: 28rpx;
}
.state-panel--error .state-retry {
width: 560rpx;
min-height: 124rpx;
margin-top: 22rpx;
}
.genealogy-empty-state {
min-height: 1120rpx;
}
.empty-panel {
min-height: 1120rpx;
background: url("/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png") center / 100% 100% no-repeat;
}
.empty-panel__content {
display: flex;
min-height: 1120rpx;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 50rpx 28rpx 46rpx;
text-align: center;
}
.empty-seal {
display: flex;
width: 120rpx;
height: 184rpx;
align-items: center;
justify-content: center;
background: url("/static/assets/modules/genealogy/transparent/current-seal-frame.png") center / 100% 100% no-repeat;
}
.empty-seal__text {
color: #fff7e7;
font-family: "STKaiti", "KaiTi", serif;
font-size: 32rpx;
font-weight: 700;
letter-spacing: 2rpx;
writing-mode: vertical-rl;
}
.empty-title {
display: block;
margin-top: 30rpx;
color: #392719;
font-family: "STKaiti", "KaiTi", serif;
font-size: 48rpx;
font-weight: 700;
letter-spacing: 2rpx;
}
.empty-copy {
display: block;
min-height: 84rpx;
margin-top: 18rpx;
color: #786654;
font-size: 28rpx;
line-height: 1.65;
}
.empty-divider {
display: block;
width: 100%;
height: 30rpx;
margin-top: 26rpx;
}
.empty-search-action,
.empty-invite-action {
display: flex;
width: 560rpx;
min-height: 124rpx;
align-items: center;
justify-content: center;
}
.empty-search-action {
margin-top: 26rpx;
background: url("/static/assets/foundation/transparent/a01-scroll-primary-v3.png") center / contain no-repeat;
}
.empty-invite-action {
margin-top: 22rpx;
background: url("/static/assets/foundation/transparent/a01-scroll-secondary-v3.png") center / contain no-repeat;
}
.empty-search-action__copy,
.empty-invite-action__copy {
color: #7b4e24;
font-family: "STKaiti", "KaiTi", serif;
font-size: 34rpx;
font-weight: 700;
letter-spacing: 3rpx;
}
.empty-search-action__copy--primary {
color: #fff9ec;
}
.empty-create-action {
display: flex;
align-items: center;
justify-content: center;
min-height: 76rpx;
margin-top: 14rpx;
color: $brand-red;
}
.empty-create-action__copy {
font-family: "STKaiti", "KaiTi", serif;
font-size: 31rpx;
}
.empty-create-note {
display: block;
color: $ink-muted;
font-size: 26rpx;
line-height: 38rpx;
}
.state-retry {
display: flex;
width: 360rpx;
min-height: 96rpx;
align-items: center;
justify-content: center;
margin-top: 30rpx;
background: url("/static/assets/foundation/transparent/a01-scroll-primary-v3.png") center / contain no-repeat;
}
.state-retry__copy {
color: #fff9ec;
font-family: "STKaiti", "KaiTi", serif;
font-size: 29rpx;
}
.add-dialog-layer {
position: fixed;
z-index: 40;
inset: 0;
display: flex;
align-items: flex-end;
justify-content: center;
box-sizing: border-box;
background: rgba(34, 20, 12, 0.68);
}
.add-dialog {
width: 100%;
min-height: 780rpx;
max-height: calc(100vh - 80rpx);
box-sizing: border-box;
border: 1px solid transparent;
border-image-source: url("/static/assets/modules/genealogy/transparent/g01-add-sheet-background-v3.png");
border-image-slice: 220 0 1 0 fill;
border-image-width: 118rpx 0 1rpx;
border-image-repeat: stretch;
}
.add-dialog__content {
display: flex;
min-height: 780rpx;
max-height: calc(100vh - 80rpx);
flex-direction: column;
align-items: stretch;
box-sizing: border-box;
padding: 96rpx 52rpx calc(96rpx + env(safe-area-inset-bottom));
overflow-y: auto;
}
.add-dialog__body {
margin: auto 0;
}
.add-dialog__heading {
display: grid;
grid-template-columns: minmax(0, 1fr) 96rpx;
}
.add-dialog .dialog-title,
.add-dialog .dialog-copy {
display: block;
grid-column: 1;
text-align: left;
}
.add-dialog__close {
display: flex;
grid-column: 2;
grid-row: 1 / span 2;
align-self: start;
justify-self: end;
width: 80rpx;
height: 80rpx;
align-items: center;
justify-content: center;
margin-right: -22rpx;
}
.add-dialog__close-icon {
width: 80rpx;
height: 80rpx;
}
.add-dialog__actions {
display: flex;
flex-direction: column;
align-items: center;
margin: 62rpx -32rpx 0;
}
.add-dialog__actions > .app-button {
width: 595rpx;
max-width: 100%;
min-height: 96rpx;
}
.add-dialog__actions > .app-button + .app-button {
margin-top: 24rpx;
}
.genealogy-switcher-layer {
position: fixed;
z-index: 40;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 40rpx;
background: rgba(34, 20, 12, 0.58);
}
.genealogy-switcher {
width: 670rpx;
max-width: 100%;
min-height: 600rpx;
max-height: calc(100vh - 120rpx);
box-sizing: border-box;
border: 1px solid transparent;
border-image-source: url("/static/assets/modules/auth/transparent/a01-scroll-dialog-v3.png");
border-image-slice: 300 260 360 260 fill;
border-image-width: 110rpx 48rpx 132rpx 48rpx;
border-image-repeat: stretch;
}
.genealogy-switcher__content {
display: grid;
min-height: 600rpx;
max-height: calc(100vh - 120rpx);
grid-template-rows: auto minmax(0, 1fr);
align-items: center;
box-sizing: border-box;
padding: 120rpx 58rpx 140rpx;
}
.genealogy-switcher__content > .dialog-title {
grid-area: 1 / 1;
}
.genealogy-switcher__close {
display: flex;
grid-area: 1 / 1;
align-self: start;
justify-self: end;
width: 80rpx;
height: 80rpx;
align-items: center;
justify-content: center;
margin-top: -42rpx;
margin-right: -24rpx;
}
.genealogy-switcher__close-icon {
width: 80rpx;
height: 80rpx;
}
.genealogy-switcher__list {
grid-area: 2 / 1;
width: 100%;
min-height: 0;
max-height: calc(100vh - 456rpx);
margin-top: 24rpx;
overflow-y: auto;
}
.dialog-title {
color: $brand-red;
font-family: "STKaiti", "KaiTi", serif;
font-size: 42rpx;
font-weight: 700;
letter-spacing: 4rpx;
}
.dialog-copy {
margin-top: 12rpx;
color: $ink-muted;
font-size: 25rpx;
line-height: 1.5;
}
.switcher-item {
display: flex;
width: 100%;
min-height: 112rpx;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding: 18rpx 16rpx;
border: 1rpx solid transparent;
border-bottom-color: rgba(181, 138, 75, 0.42);
}
.switcher-item__name,
.switcher-item__meta {
display: block;
}
.switcher-item__name {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 32rpx;
font-weight: 700;
}
.switcher-item__meta {
margin-top: 6rpx;
color: #62584c;
font-size: 24rpx;
}
.switcher-item__state {
color: $brand-red;
font-size: 25rpx;
font-weight: 600;
}
.switcher-item--active {
border-color: rgba(159, 23, 15, 0.22);
background: rgba(159, 23, 15, 0.055);
}
.switcher-item--active .switcher-item__name {
color: $brand-red;
}
.action-hover {
opacity: 0.82;
}
@media screen and (max-width: 340px) {
.genealogy-content {
padding-right: 20rpx;
padding-left: 20rpx;
}
.current-name {
font-size: 40rpx;
}
.shortcut-label {
font-size: 23rpx;
}
.current-meta-icon {
width: 32rpx;
height: 32rpx;
}
.create-action {
width: 320rpx;
}
.create-cloud {
width: 46rpx;
}
}
</style>