feat: migrate app routes and business modules
This commit is contained in:
@@ -0,0 +1,729 @@
|
||||
<template>
|
||||
<view class="poem-page">
|
||||
<GenealogyPageBackground />
|
||||
<view class="poem-page__header">
|
||||
<PageHeader
|
||||
:title="pageTitle"
|
||||
:action="poemState === 'list' || poemState === 'empty' ? '维护' : ''"
|
||||
custom-back
|
||||
@action="enterManagement"
|
||||
@back="requestBack"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="poem-panel" :class="`poem-state--${poemState}`">
|
||||
<AppLoading
|
||||
v-if="poemState === 'loading'"
|
||||
text="正在读取字辈诗"
|
||||
description="正在整理家谱的传承字序。"
|
||||
/>
|
||||
|
||||
<view v-else-if="poemState === 'list'" class="poem-list">
|
||||
<text class="poem-list__eyebrow">{{ genealogyName }} · 传承字序</text>
|
||||
<text class="poem-list__title">{{ generationRangeTitle }}</text>
|
||||
<text class="poem-list__copy">按已记录的世代和字辈展示传承字序。</text>
|
||||
<view class="poem-rows">
|
||||
<view
|
||||
v-for="item in visiblePoemRows"
|
||||
:key="item.poemId"
|
||||
class="poem-row"
|
||||
:class="{
|
||||
'poem-row--disabled':
|
||||
item.status === GENERATION_POEM_STATUS.DISABLED,
|
||||
}"
|
||||
>
|
||||
<text class="poem-row__number">第 {{ item.generationNo }} 世</text>
|
||||
<text class="poem-row__character">{{ item.generationText }}</text>
|
||||
<text class="poem-row__status">{{
|
||||
item.status === GENERATION_POEM_STATUS.DISABLED
|
||||
? "已停用·记录保留"
|
||||
: "传承字序"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="remainingPoemCount > 0"
|
||||
class="poem-load-more"
|
||||
role="button"
|
||||
:aria-label="'继续加载后续字辈,剩余 ' + remainingPoemCount + ' 代'"
|
||||
@click="loadMorePoems"
|
||||
>
|
||||
<text>继续加载后续字辈(剩余 {{ remainingPoemCount }} 代)</text>
|
||||
</view>
|
||||
<view
|
||||
class="poem-action"
|
||||
role="button"
|
||||
:aria-label="canManage ? '继续维护字辈诗' : '查看字辈列表'"
|
||||
@click="enterManagement"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/scroll-primary.png"
|
||||
mode="aspectFit"
|
||||
/><text>{{ canManage ? "继续维护字辈诗" : "查看字辈列表" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="poemState === 'edit'" class="poem-editor">
|
||||
<text class="poem-list__eyebrow">统一维护</text>
|
||||
<text class="poem-list__title">填写完整字辈</text>
|
||||
<text class="poem-list__copy"
|
||||
>保存前可先查看调整结果。没有分隔符时,每个字对应一代;多个字可用空格、逗号、分号、顿号、斜杠或竖线分开。</text
|
||||
>
|
||||
<view class="poem-field">
|
||||
<text>字辈内容</text>
|
||||
<textarea
|
||||
v-model="poemDraft"
|
||||
auto-height
|
||||
:disabled="saving"
|
||||
:maxlength="MAX_GENERATION_POEM_INPUT_LENGTH"
|
||||
placeholder="例如:启宗敦本,或 克勤 克俭 承先 启后"
|
||||
placeholder-class="poem-placeholder"
|
||||
@input="invalidatePreview"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="poemError" class="poem-field-error">{{ poemError }}</text>
|
||||
<view class="poem-policy">
|
||||
<text>这次未填写到的后续字辈</text>
|
||||
<view
|
||||
class="poem-policy__option"
|
||||
:class="{ 'poem-policy__option--disabled': saving }"
|
||||
role="checkbox"
|
||||
:aria-checked="disableMissing"
|
||||
:aria-disabled="saving"
|
||||
aria-label="停用未填写到的后续字辈"
|
||||
@click="toggleDisableMissing"
|
||||
>
|
||||
<image
|
||||
:src="
|
||||
disableMissing
|
||||
? '/static/assets/foundation/transparent/scroll-primary.png'
|
||||
: '/static/assets/foundation/transparent/scroll-secondary.png'
|
||||
"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text
|
||||
:class="{ 'poem-policy__option-text--active': disableMissing }"
|
||||
>{{ disableMissing ? "停用并保留记录" : "保持原状态" }}</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<text class="poem-preview">{{ previewSummary }}</text>
|
||||
<view class="poem-editor__actions">
|
||||
<view
|
||||
class="poem-action"
|
||||
:class="{ 'poem-action--disabled': previewing || saving }"
|
||||
role="button"
|
||||
:aria-disabled="previewing || saving"
|
||||
aria-label="取消"
|
||||
@click="requestLeaveEditor"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/scroll-secondary.png"
|
||||
mode="aspectFit"
|
||||
/><text class="poem-action__secondary">取消</text>
|
||||
</view>
|
||||
<view
|
||||
class="poem-action"
|
||||
:class="{ 'poem-action--disabled': previewing || saving }"
|
||||
role="button"
|
||||
:aria-disabled="previewing || saving"
|
||||
aria-label="查看调整结果"
|
||||
@click="previewPoems"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/scroll-secondary.png"
|
||||
mode="aspectFit"
|
||||
/><text class="poem-action__secondary">{{
|
||||
previewing ? "正在查看" : "查看调整结果"
|
||||
}}</text>
|
||||
</view>
|
||||
<view
|
||||
class="poem-action"
|
||||
:class="{ 'poem-action--disabled': !canSave || saving }"
|
||||
role="button"
|
||||
:aria-disabled="!canSave || saving"
|
||||
aria-label="保存字辈"
|
||||
@click="savePoems"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/scroll-primary.png"
|
||||
mode="aspectFit"
|
||||
/><text>{{ saving ? "正在保存" : "保存字辈" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="poem-state-card">
|
||||
<text class="poem-list__eyebrow">{{
|
||||
poemState === "empty" ? "尚未建立字辈" : "字辈暂不可用"
|
||||
}}</text>
|
||||
<text class="poem-list__title">{{
|
||||
poemState === "empty"
|
||||
? "暂时没有可显示的字辈"
|
||||
: "暂时无法读取字辈诗"
|
||||
}}</text>
|
||||
<text class="poem-list__copy">{{ stateCopy }}</text>
|
||||
<view
|
||||
class="poem-action"
|
||||
role="button"
|
||||
:aria-label="poemState === 'empty' ? '查看字辈列表' : '重新读取'"
|
||||
@click="handleStateAction"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/scroll-primary.png"
|
||||
mode="aspectFit"
|
||||
/><text>{{
|
||||
poemState === "empty" ? "查看字辈列表" : "重新读取"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<AppDialog
|
||||
:visible="discardVisible"
|
||||
title="放弃字辈修改?"
|
||||
message="当前修改还没有保存,确认返回后将不会保留。"
|
||||
confirm-text="放弃修改"
|
||||
cancel-text="继续编辑"
|
||||
show-cancel
|
||||
compact-actions
|
||||
:close-on-mask="false"
|
||||
@confirm="confirmDiscard"
|
||||
@cancel="cancelDiscard"
|
||||
/>
|
||||
<view v-if="feedbackMessage" class="poem-feedback"
|
||||
><text>{{ feedbackMessage }}</text></view
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onBackPress, onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import AppLoading from "@/components/AppLoading.vue";
|
||||
import GenealogyPageBackground from "@/components/genealogy/PageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
createRequestController,
|
||||
isRequestCancelled
|
||||
} from "@/services/api/request-controller.js";
|
||||
import { generationPoemApi } from "@/services/api/generation-poem-service.js";
|
||||
import { getRequestErrorMessage } from "@/services/api/request-error-message.js";
|
||||
import {
|
||||
MAX_GENERATION_POEM_INPUT_LENGTH,
|
||||
GENERATION_POEM_STATUS,
|
||||
validateGenerationPoemText,
|
||||
} from "@/utils/genealogy/generation-poem.js";
|
||||
import { handleBackPress, runBackGuard } from "@/utils/navigation/gateway.js";
|
||||
|
||||
const POEM_RENDER_BATCH_SIZE = 50;
|
||||
const genealogyId = ref("");
|
||||
const genealogyName = ref("当前家谱");
|
||||
const poemState = ref("loading");
|
||||
const poemError = ref("");
|
||||
const feedbackMessage = ref("");
|
||||
const discardVisible = ref(false);
|
||||
const canManage = ref(false);
|
||||
const previewing = ref(false);
|
||||
const saving = ref(false);
|
||||
const poemDraft = ref("");
|
||||
const disableMissing = ref(false);
|
||||
const editorSnapshot = ref(null);
|
||||
const poemRows = ref([]);
|
||||
const visiblePoemCount = ref(POEM_RENDER_BATCH_SIZE);
|
||||
const preview = ref(null);
|
||||
const previewSignature = ref("");
|
||||
const poemListController = createRequestController();
|
||||
const poemPreviewController = createRequestController();
|
||||
const poemSaveController = createRequestController();
|
||||
let requestSequence = 0;
|
||||
let pageActive = true;
|
||||
|
||||
const visiblePoemRows = computed(() =>
|
||||
poemRows.value.slice(0, visiblePoemCount.value),
|
||||
);
|
||||
const remainingPoemCount = computed(() =>
|
||||
Math.max(0, poemRows.value.length - visiblePoemCount.value),
|
||||
);
|
||||
const pageTitle = computed(() =>
|
||||
poemState.value === "edit" ? "维护字辈诗" : "字辈诗",
|
||||
);
|
||||
const generationRangeTitle = computed(() => {
|
||||
if (!poemRows.value.length) return "尚未建立字辈";
|
||||
const first = poemRows.value[0].generationNo;
|
||||
const last = poemRows.value[poemRows.value.length - 1].generationNo;
|
||||
return first === last ? `第 ${first} 世字辈` : `第 ${first}—${last} 世字辈`;
|
||||
});
|
||||
const draftSignature = computed(
|
||||
() => `${poemDraft.value}\u0000${disableMissing.value}`,
|
||||
);
|
||||
const canSave = computed(
|
||||
() =>
|
||||
Boolean(preview.value) && previewSignature.value === draftSignature.value,
|
||||
);
|
||||
const previewSummary = computed(() => {
|
||||
if (previewing.value) return "正在查看调整结果。";
|
||||
if (!preview.value) return "请先查看调整结果,再保存。";
|
||||
return `调整结果:新增 ${preview.value.createCount} 条,更新 ${preview.value.updateCount} 条,保留 ${preview.value.keepCount} 条,停用 ${preview.value.disableCount} 条。`;
|
||||
});
|
||||
const stateCopy = computed(() =>
|
||||
poemState.value === "empty"
|
||||
? "当前尚未添加可用的字辈,可进入维护页面查看。"
|
||||
: "暂未读取到可展示的字辈,请稍后重试。",
|
||||
);
|
||||
const isDirty = computed(() =>
|
||||
Boolean(
|
||||
poemState.value === "edit" &&
|
||||
editorSnapshot.value &&
|
||||
(poemDraft.value !== editorSnapshot.value.poemDraft ||
|
||||
disableMissing.value !== editorSnapshot.value.disableMissing),
|
||||
),
|
||||
);
|
||||
const discardConfirmation = createDiscardConfirmation((visible) => {
|
||||
discardVisible.value = visible;
|
||||
});
|
||||
const requestDiscardConfirmation = discardConfirmation.request;
|
||||
const confirmDiscard = discardConfirmation.confirm;
|
||||
const cancelDiscard = discardConfirmation.cancel;
|
||||
|
||||
const applyRows = (rows) => {
|
||||
poemRows.value = rows;
|
||||
visiblePoemCount.value = POEM_RENDER_BATCH_SIZE;
|
||||
const named = rows.find((item) => item.genealogyName);
|
||||
genealogyName.value = named?.genealogyName || "当前家谱";
|
||||
};
|
||||
const loadPoems = async ({ management = false } = {}) => {
|
||||
if (!genealogyId.value) {
|
||||
poemState.value = "error";
|
||||
return false;
|
||||
}
|
||||
const sequence = ++requestSequence;
|
||||
poemState.value = "loading";
|
||||
poemError.value = "";
|
||||
try {
|
||||
const rows = management
|
||||
? await generationPoemApi.getGenerationPoemManagement(genealogyId.value, {
|
||||
requestController: poemListController,
|
||||
})
|
||||
: await generationPoemApi.getGenerationPoems(genealogyId.value, {
|
||||
requestController: poemListController,
|
||||
});
|
||||
if (!pageActive || sequence !== requestSequence) return false;
|
||||
applyRows(rows);
|
||||
canManage.value = management;
|
||||
poemState.value = rows.length ? "list" : "empty";
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (!pageActive || isRequestCancelled(error) || sequence !== requestSequence) return false;
|
||||
poemState.value = "error";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const loadMorePoems = () => {
|
||||
visiblePoemCount.value = Math.min(
|
||||
poemRows.value.length,
|
||||
visiblePoemCount.value + POEM_RENDER_BATCH_SIZE,
|
||||
);
|
||||
};
|
||||
const invalidatePreview = () => {
|
||||
poemError.value = "";
|
||||
preview.value = null;
|
||||
previewSignature.value = "";
|
||||
};
|
||||
const toggleDisableMissing = () => {
|
||||
if (saving.value) return;
|
||||
disableMissing.value = !disableMissing.value;
|
||||
invalidatePreview();
|
||||
};
|
||||
const openEditor = () => {
|
||||
if (!canManage.value) return false;
|
||||
poemDraft.value = poemRows.value
|
||||
.filter((item) => item.status === GENERATION_POEM_STATUS.ACTIVE)
|
||||
.map((item) => item.generationText)
|
||||
.join(" ");
|
||||
disableMissing.value = false;
|
||||
preview.value = null;
|
||||
previewSignature.value = "";
|
||||
editorSnapshot.value = Object.freeze({
|
||||
poemDraft: poemDraft.value,
|
||||
disableMissing: disableMissing.value,
|
||||
});
|
||||
poemState.value = "edit";
|
||||
return true;
|
||||
};
|
||||
const enterManagement = async () => {
|
||||
if (previewing.value || saving.value) return;
|
||||
const loaded = await loadPoems({ management: true });
|
||||
if (pageActive && loaded) openEditor();
|
||||
};
|
||||
const requestLeaveEditor = async () => {
|
||||
if (previewing.value || saving.value) return false;
|
||||
if (isDirty.value) {
|
||||
const confirmed = await requestDiscardConfirmation();
|
||||
if (!confirmed) return false;
|
||||
}
|
||||
poemState.value = poemRows.value.length ? "list" : "empty";
|
||||
editorSnapshot.value = null;
|
||||
poemError.value = "";
|
||||
return true;
|
||||
};
|
||||
const validateDraft = () => {
|
||||
const validation = validateGenerationPoemText(poemDraft.value);
|
||||
if (!validation.valid) {
|
||||
poemError.value = validation.message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const previewPoems = async () => {
|
||||
if (previewing.value || saving.value || !validateDraft()) return;
|
||||
const submittedDraft = {
|
||||
poemText: poemDraft.value,
|
||||
disableMissing: disableMissing.value,
|
||||
};
|
||||
const submittedSignature = draftSignature.value;
|
||||
previewing.value = true;
|
||||
poemError.value = "";
|
||||
try {
|
||||
const previewResult = await generationPoemApi.previewGenerationPoemBatch(
|
||||
genealogyId.value,
|
||||
submittedDraft,
|
||||
{ requestController: poemPreviewController },
|
||||
);
|
||||
if (!pageActive || submittedSignature !== draftSignature.value) return;
|
||||
preview.value = previewResult;
|
||||
previewSignature.value = submittedSignature;
|
||||
} catch (error) {
|
||||
if (pageActive && !isRequestCancelled(error))
|
||||
poemError.value = getRequestErrorMessage(error, "暂时无法查看调整结果,请稍后重试。");
|
||||
} finally {
|
||||
if (pageActive) previewing.value = false;
|
||||
}
|
||||
};
|
||||
const savePoems = async () => {
|
||||
if (!canSave.value || saving.value || !validateDraft()) return;
|
||||
saving.value = true;
|
||||
poemError.value = "";
|
||||
try {
|
||||
await generationPoemApi.saveGenerationPoemBatch(
|
||||
genealogyId.value,
|
||||
{
|
||||
poemText: poemDraft.value,
|
||||
disableMissing: disableMissing.value,
|
||||
},
|
||||
{ requestController: poemSaveController },
|
||||
);
|
||||
if (!pageActive) return;
|
||||
feedbackMessage.value = "字辈已保存,正在刷新列表。";
|
||||
const loaded = await loadPoems({ management: true });
|
||||
if (!pageActive) return;
|
||||
if (!loaded) {
|
||||
poemError.value = "字辈已保存,但页面暂时未更新,请稍后重新查看。";
|
||||
return;
|
||||
}
|
||||
editorSnapshot.value = null;
|
||||
feedbackMessage.value = "字辈已保存。";
|
||||
} catch (error) {
|
||||
if (pageActive && !isRequestCancelled(error))
|
||||
poemError.value = getRequestErrorMessage(error, "字辈保存失败,请稍后重试。");
|
||||
} finally {
|
||||
if (pageActive) saving.value = false;
|
||||
}
|
||||
};
|
||||
const requestBack = () =>
|
||||
runBackGuard({
|
||||
transientOpen: discardVisible.value,
|
||||
internalTrail: poemState.value === "edit",
|
||||
submitting: previewing.value || saving.value,
|
||||
"close-transient": cancelDiscard,
|
||||
"pop-internal-trail": requestLeaveEditor,
|
||||
"block-submitting": () => true,
|
||||
});
|
||||
const handleStateAction = () =>
|
||||
poemState.value === "empty" ? enterManagement() : loadPoems();
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = String(query?.genealogyId || "");
|
||||
loadPoems();
|
||||
});
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
onUnload(() => {
|
||||
pageActive = false;
|
||||
++requestSequence;
|
||||
poemListController.abort();
|
||||
poemPreviewController.abort();
|
||||
poemSaveController.abort();
|
||||
discardConfirmation.dispose();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../styles/adaptive-frame-profiles.scss";
|
||||
.poem-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.poem-page__header {
|
||||
z-index: 3;
|
||||
}
|
||||
.poem-panel {
|
||||
@include adaptive-genealogy-state-panel;
|
||||
z-index: 2;
|
||||
width: calc(100% - 32rpx);
|
||||
margin: 18rpx auto 0;
|
||||
padding: 76rpx 8%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.poem-panel > .app-loading {
|
||||
grid-area: 1 / 1 / -1 / -1;
|
||||
}
|
||||
.poem-list,
|
||||
.poem-editor,
|
||||
.poem-state-card {
|
||||
min-width: 0;
|
||||
}
|
||||
.poem-list__eyebrow {
|
||||
display: block;
|
||||
color: $brand-red;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.poem-list__title {
|
||||
display: block;
|
||||
margin-top: 11rpx;
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: clamp(19px, 35rpx, 24px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.poem-list__copy {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
line-height: 1.55;
|
||||
}
|
||||
.poem-rows {
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.poem-load-more {
|
||||
display: flex;
|
||||
min-height: 88rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 14rpx;
|
||||
background: url("/static/assets/foundation/transparent/scroll-secondary.png")
|
||||
center / contain no-repeat;
|
||||
}
|
||||
.poem-load-more text {
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.poem-row {
|
||||
@include adaptive-genealogy-form-field;
|
||||
display: grid;
|
||||
min-height: 72rpx;
|
||||
margin-top: 10rpx;
|
||||
grid-template-columns: minmax(116rpx, 38%) minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
}
|
||||
.poem-row__number {
|
||||
z-index: 1;
|
||||
grid-column: 1;
|
||||
margin-left: 24rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
}
|
||||
.poem-row__character {
|
||||
z-index: 1;
|
||||
grid-column: 2;
|
||||
min-width: 0;
|
||||
padding: 12rpx 16rpx 12rpx 0;
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: clamp(17px, 32rpx, 22px);
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
.poem-row__status {
|
||||
z-index: 1;
|
||||
grid-column: 3;
|
||||
margin-right: 22rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(14px, 22rpx, 17px);
|
||||
}
|
||||
.poem-row--disabled .poem-row__character,
|
||||
.poem-row--disabled .poem-row__status {
|
||||
color: $ink-muted;
|
||||
opacity: 0.62;
|
||||
}
|
||||
.poem-action {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
min-height: 88rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.poem-action--disabled {
|
||||
opacity: 0.55;
|
||||
}
|
||||
.poem-action image {
|
||||
grid-area: 1 / 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.poem-action text {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
grid-area: 1 / 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #fff9ed;
|
||||
font-size: clamp(15px, 25rpx, 18px);
|
||||
font-weight: 700;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.poem-field {
|
||||
@include adaptive-genealogy-form-field;
|
||||
display: grid;
|
||||
min-height: 118rpx;
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.poem-field > text {
|
||||
z-index: 1;
|
||||
grid-area: 1 / 1;
|
||||
align-self: center;
|
||||
margin-left: 24rpx;
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 22rpx, 17px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.poem-field textarea {
|
||||
z-index: 1;
|
||||
grid-area: 1 / 1;
|
||||
box-sizing: border-box;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
min-height: 118rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-left: 164rpx;
|
||||
padding-top: 34rpx;
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 22rpx, 17px);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.poem-placeholder {
|
||||
color: #a79884;
|
||||
}
|
||||
.poem-field-error {
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
color: $brand-red;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
line-height: max(1.35em, clamp(19px, 34rpx, 24px));
|
||||
text-align: right;
|
||||
}
|
||||
.poem-policy {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.poem-policy > text {
|
||||
color: $ink;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.poem-policy__option {
|
||||
display: grid;
|
||||
width: 248rpx;
|
||||
min-height: 88rpx;
|
||||
}
|
||||
.poem-policy__option--disabled {
|
||||
opacity: 0.55;
|
||||
}
|
||||
.poem-policy__option image {
|
||||
grid-area: 1 / 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.poem-policy__option text {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
grid-area: 1 / 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.poem-policy__option .poem-policy__option-text--active {
|
||||
color: #fff9ed;
|
||||
}
|
||||
.poem-preview {
|
||||
display: block;
|
||||
margin-top: 22rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.poem-editor__actions {
|
||||
display: flex;
|
||||
gap: 14rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.poem-editor__actions .poem-action {
|
||||
width: calc((100% - 28rpx) / 3);
|
||||
margin-top: 0;
|
||||
}
|
||||
.poem-action .poem-action__secondary {
|
||||
color: $ink;
|
||||
}
|
||||
.poem-state-card {
|
||||
padding: 180rpx 4% 70rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.poem-state-card .poem-list__eyebrow {
|
||||
text-align: center;
|
||||
}
|
||||
.poem-state-card .poem-list__copy {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.poem-state-card .poem-action {
|
||||
width: 420rpx;
|
||||
max-width: 100%;
|
||||
margin: 34rpx auto 0;
|
||||
}
|
||||
.poem-feedback {
|
||||
position: fixed;
|
||||
z-index: 30;
|
||||
top: 138rpx;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
min-width: 260rpx;
|
||||
min-height: 74rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 34rpx;
|
||||
transform: translateX(-50%);
|
||||
background: url("/static/assets/foundation/transparent/scroll-secondary.png")
|
||||
center / contain no-repeat;
|
||||
}
|
||||
.poem-feedback text {
|
||||
z-index: 1;
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 22rpx, 17px);
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.poem-panel {
|
||||
width: calc(100% - 48rpx);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user