完成70%
This commit is contained in:
@@ -1,627 +1,48 @@
|
||||
<!-- 页面编号:F-09;用途:照片选择、说明、上传进度与失败重试视觉候选。 -->
|
||||
<!-- 页面编号:F-09;用途:相册照片写入。没有文件上传与 OSS 回执 owner 时关闭。 -->
|
||||
<template>
|
||||
<view
|
||||
class="media-upload-page"
|
||||
:class="`media-upload-state--${uploadState}`"
|
||||
>
|
||||
<view class="media-upload-page">
|
||||
<ModulePageBackground module="family" />
|
||||
<view class="media-upload-header"><PageHeader title="添加照片" custom-back @back="requestBack" /></view>
|
||||
|
||||
<view class="media-upload-header"><PageHeader title="添加照片" custom-back @back="returnToAlbum" /></view>
|
||||
<view class="media-upload-content">
|
||||
<view v-if="uploadState === 'invalid'" class="media-invalid-card">
|
||||
<text class="media-state-card__eyebrow">相册入口无效</text>
|
||||
<text class="media-state-card__title">没有找到当前相册</text>
|
||||
<text class="media-state-card__copy">页面不会把照片归入其他家谱或其他相册。</text>
|
||||
<view class="media-preview-action" @click="returnFromInvalid">
|
||||
<AppButton block :label="genealogyId ? '返回相册列表' : '返回上一页'" />
|
||||
</view>
|
||||
<view class="media-state-card">
|
||||
<text class="media-state-card__eyebrow">文件服务待接入</text>
|
||||
<text class="media-state-card__title">照片上传暂不可用</text>
|
||||
<text class="media-state-card__copy">照片写入接口要求已有 `ossId`。当前没有经 Apifox 核实的文件上传 owner、真实 OSS 回执或访问 URL,页面不再从本地图片库选择图片,也不会生成上传预览。</text>
|
||||
<AppButton block :label="hasValidContext ? '返回相册列表' : '返回上一页'" @click="returnToAlbum" />
|
||||
</view>
|
||||
|
||||
<view v-else class="media-album-card">
|
||||
<image
|
||||
class="media-album-card__cover"
|
||||
:src="album.cover"
|
||||
:alt="album.name"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="media-album-card__copy">
|
||||
<text class="media-album-card__eyebrow">当前相册</text>
|
||||
<text class="media-album-card__title">{{ album.name }}</text>
|
||||
<text class="media-album-card__limit">最多可选择 9 张</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="uploadState === 'permission' && album" class="media-permission-card">
|
||||
<text class="media-state-card__eyebrow">照片访问权限</text>
|
||||
<text class="media-state-card__title">需要照片访问权限</text>
|
||||
<text class="media-state-card__copy"
|
||||
>授权后才能选择照片;当前只验证选择与说明流程,不会上传。</text
|
||||
>
|
||||
<view class="media-permission-action" @click="selectMockPhotos">
|
||||
<AppButton block label="重新授权" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="uploadState === 'preview'" class="media-preview-card">
|
||||
<text class="media-state-card__eyebrow">本地流程预览</text>
|
||||
<text class="media-preview-title">{{ selectedPhotos.length }} 张照片已完成本地校验</text>
|
||||
<text class="media-state-card__copy"
|
||||
>照片尚未上传,也没有加入“{{ album.name }}”;返回后不会保存。</text
|
||||
>
|
||||
<view class="media-preview-action" @click="returnToAlbum">
|
||||
<AppButton block label="返回当前相册(不上传)" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template v-else-if="album">
|
||||
<view class="media-section-heading">
|
||||
<text>选择照片</text>
|
||||
<text>{{ selectedPhotos.length }} / {{ MAX_PHOTOS }}</text>
|
||||
</view>
|
||||
|
||||
<view class="media-photo-grid">
|
||||
<view
|
||||
v-for="(photo, index) in selectedPhotos"
|
||||
:key="photo.id"
|
||||
class="media-photo-tile"
|
||||
:class="{
|
||||
'media-photo-tile--active': index === activePhotoIndex,
|
||||
}"
|
||||
@click="selectPhoto(index)"
|
||||
>
|
||||
<image
|
||||
class="media-photo-tile__image"
|
||||
:src="photo.src"
|
||||
:alt="photo.alt"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<text class="media-photo-order">{{ index + 1 }}</text>
|
||||
<text
|
||||
v-if="index === activePhotoIndex"
|
||||
class="media-photo-current"
|
||||
>当前</text
|
||||
>
|
||||
<view
|
||||
v-if="!isLocked"
|
||||
class="media-photo-remove"
|
||||
@click.stop="removePhoto(index)"
|
||||
>
|
||||
<text>删除</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="selectedPhotos.length < MAX_PHOTOS && !isLocked"
|
||||
class="media-add-tile"
|
||||
@click="selectedPhotos.length ? addMockPhoto() : selectMockPhotos()"
|
||||
>
|
||||
<text class="media-add-tile__title">{{
|
||||
selectedPhotos.length ? "继续添加" : "选择照片"
|
||||
}}</text>
|
||||
<text class="media-add-tile__copy">{{
|
||||
selectedPhotos.length ? `还可选择 ${MAX_PHOTOS - selectedPhotos.length} 张` : "最多 9 张"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="selectedPhotos.length" class="media-description-panel">
|
||||
<view class="media-batch-field">
|
||||
<view class="media-field-heading">
|
||||
<text>整批说明</text><text>必填</text>
|
||||
</view>
|
||||
<textarea
|
||||
v-model="batchDescription"
|
||||
auto-height
|
||||
:disabled="isLocked"
|
||||
maxlength="120"
|
||||
placeholder="例如:2024 年春节全家团圆留影"
|
||||
placeholder-class="media-field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="validationMessage" class="media-field-error">{{
|
||||
validationMessage
|
||||
}}</text>
|
||||
|
||||
<view v-if="activePhoto" class="media-photo-field">
|
||||
<view class="media-photo-editor">
|
||||
<image
|
||||
class="media-photo-editor__thumb"
|
||||
:src="activePhoto.src"
|
||||
:alt="activePhoto.alt"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="media-photo-editor__copy">
|
||||
<text class="media-photo-editor__position"
|
||||
>第 {{ activePhotoIndex + 1 }} 张 / 共
|
||||
{{ selectedPhotos.length }} 张</text
|
||||
>
|
||||
<text class="media-photo-editor__hint"
|
||||
>正在编辑此照片的说明</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="media-field-heading">
|
||||
<text>当前照片说明</text><text>选填</text>
|
||||
</view>
|
||||
<textarea
|
||||
:value="activePhoto.note"
|
||||
auto-height
|
||||
:disabled="isLocked"
|
||||
maxlength="80"
|
||||
placeholder="补充人物、时间或拍摄地点"
|
||||
placeholder-class="media-field-placeholder"
|
||||
@input="updateActiveNote"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="media-primary-action" @click="generatePreview">
|
||||
<AppButton
|
||||
block
|
||||
:disabled="isSubmitting"
|
||||
:label="
|
||||
isSubmitting
|
||||
? '正在校验'
|
||||
: selectedPhotos.length
|
||||
? `生成 ${selectedPhotos.length} 张照片预览`
|
||||
: '选择照片'
|
||||
"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<AppDialog
|
||||
:visible="discardVisible"
|
||||
title="放弃照片草稿?"
|
||||
message="已选择的照片和说明尚未上传,确认返回后不会保留。"
|
||||
confirm-text="放弃并返回"
|
||||
cancel-text="继续整理"
|
||||
show-cancel
|
||||
:close-on-mask="false"
|
||||
@confirm="confirmDiscard"
|
||||
@cancel="cancelDiscard"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onBackPress, onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import AppButton from "@/components/AppButton.vue";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import { findFamilyAlbumFixture } from "@/data/mock.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
goBack,
|
||||
handleBackPress,
|
||||
returnTo,
|
||||
runBackGuard,
|
||||
} from "@/utils/navigation.js";
|
||||
import { goBack, returnTo } from "@/utils/navigation.js";
|
||||
|
||||
const MAX_PHOTOS = 9;
|
||||
const genealogyId = ref("");
|
||||
const albumId = ref("");
|
||||
const album = ref(null);
|
||||
const uploadState = ref("initial");
|
||||
const activePhotoIndex = ref(0);
|
||||
const batchDescription = ref("");
|
||||
const validationMessage = ref("");
|
||||
const selectedPhotos = ref([]);
|
||||
const isSubmitting = ref(false);
|
||||
const discardVisible = ref(false);
|
||||
let previewTimer = null;
|
||||
|
||||
const mockLibrary = [
|
||||
{ id: "reunion", src: "/static/assets/modules/family/f08/f08-reunion-hero.png", alt: "春节团圆时三代家人的合影", note: "" },
|
||||
{ id: "portrait", src: "/static/assets/modules/family/f08/f08-family-portrait.png", alt: "家人在院落前的春节合影", note: "" },
|
||||
{ id: "table", src: "/static/assets/modules/family/f08/f08-reunion-table.png", alt: "家人围坐吃年夜饭", note: "" },
|
||||
{ id: "home", src: "/static/assets/modules/family/f08/f08-ancestral-home.png", alt: "祖居院落的复古旧照", note: "" },
|
||||
{ id: "ancestor", src: "/static/assets/modules/family/f08/f08-ancestral-portrait.png", alt: "老一辈家人在祖居门前的合影", note: "" },
|
||||
];
|
||||
|
||||
const activePhoto = computed(
|
||||
() => selectedPhotos.value[activePhotoIndex.value] || null,
|
||||
);
|
||||
const isLocked = computed(() => isSubmitting.value);
|
||||
const isDirty = computed(() =>
|
||||
Boolean(
|
||||
selectedPhotos.value.length ||
|
||||
batchDescription.value.trim() ||
|
||||
selectedPhotos.value.some((photo) => photo.note.trim()),
|
||||
),
|
||||
);
|
||||
const discardConfirmation = createDiscardConfirmation((visible) => {
|
||||
discardVisible.value = visible;
|
||||
});
|
||||
const requestDiscardConfirmation = discardConfirmation.request;
|
||||
const confirmDiscard = discardConfirmation.confirm;
|
||||
const cancelDiscard = discardConfirmation.cancel;
|
||||
|
||||
const makeSelectedPhotos = () =>
|
||||
mockLibrary.slice(0, 4).map((photo) => ({ ...photo, note: "" }));
|
||||
|
||||
const selectMockPhotos = () => {
|
||||
selectedPhotos.value = makeSelectedPhotos();
|
||||
activePhotoIndex.value = 0;
|
||||
validationMessage.value = "";
|
||||
uploadState.value = "selected";
|
||||
};
|
||||
|
||||
const selectPhoto = (index) => {
|
||||
if (!isLocked.value) activePhotoIndex.value = index;
|
||||
};
|
||||
|
||||
const removePhoto = (index) => {
|
||||
if (isLocked.value) return;
|
||||
selectedPhotos.value.splice(index, 1);
|
||||
activePhotoIndex.value = Math.max(
|
||||
0,
|
||||
Math.min(activePhotoIndex.value, selectedPhotos.value.length - 1),
|
||||
);
|
||||
};
|
||||
|
||||
const addMockPhoto = () => {
|
||||
if (isLocked.value || selectedPhotos.value.length >= MAX_PHOTOS) return;
|
||||
const nextIndex = selectedPhotos.value.length;
|
||||
const next = mockLibrary[nextIndex % mockLibrary.length];
|
||||
selectedPhotos.value.push({
|
||||
...next,
|
||||
id: `${next.id}-${nextIndex + 1}`,
|
||||
note: "",
|
||||
});
|
||||
};
|
||||
|
||||
const updateActiveNote = (event) => {
|
||||
if (!isLocked.value && activePhoto.value) {
|
||||
activePhoto.value.note = event.detail.value;
|
||||
}
|
||||
};
|
||||
|
||||
const generatePreview = () => {
|
||||
if (isSubmitting.value || !album.value) return;
|
||||
if (!selectedPhotos.value.length) {
|
||||
selectMockPhotos();
|
||||
return;
|
||||
}
|
||||
if (!batchDescription.value.trim()) {
|
||||
validationMessage.value = "请填写整批照片说明";
|
||||
return;
|
||||
}
|
||||
validationMessage.value = "";
|
||||
isSubmitting.value = true;
|
||||
const selectedCount = selectedPhotos.value.length;
|
||||
const timer = setTimeout(() => {
|
||||
if (previewTimer !== timer) return;
|
||||
previewTimer = null;
|
||||
isSubmitting.value = false;
|
||||
uploadState.value = selectedCount > 0 ? "preview" : "selected";
|
||||
}, 280);
|
||||
previewTimer = timer;
|
||||
};
|
||||
|
||||
const returnToAlbum = () =>
|
||||
returnTo("F08", {
|
||||
genealogyId: genealogyId.value,
|
||||
albumId: albumId.value,
|
||||
});
|
||||
const returnFromInvalid = () =>
|
||||
genealogyId.value
|
||||
? returnTo("F07", { genealogyId: genealogyId.value })
|
||||
: goBack();
|
||||
|
||||
const requestBack = () =>
|
||||
runBackGuard({
|
||||
transientOpen: discardVisible.value,
|
||||
dirty: isDirty.value,
|
||||
submitting: isSubmitting.value,
|
||||
"close-transient": cancelDiscard,
|
||||
"block-submitting": () => true,
|
||||
"confirm-discard": requestDiscardConfirmation,
|
||||
});
|
||||
|
||||
const hasValidContext = computed(() => /^[1-9]\d*$/.test(genealogyId.value) && /^[1-9]\d*$/.test(albumId.value));
|
||||
onLoad((query) => {
|
||||
genealogyId.value = String(query.genealogyId || "");
|
||||
albumId.value = String(query.albumId || "");
|
||||
album.value = findFamilyAlbumFixture(genealogyId.value, albumId.value);
|
||||
if (!album.value) {
|
||||
uploadState.value = "invalid";
|
||||
return;
|
||||
}
|
||||
uploadState.value = ["permission", "selected", "preview"].includes(query.state)
|
||||
? query.state
|
||||
: "initial";
|
||||
if (["selected", "preview"].includes(uploadState.value)) {
|
||||
selectedPhotos.value = makeSelectedPhotos();
|
||||
batchDescription.value = "春节团圆照片整理";
|
||||
}
|
||||
});
|
||||
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
onUnload(() => {
|
||||
if (previewTimer) clearTimeout(previewTimer);
|
||||
discardConfirmation.dispose();
|
||||
genealogyId.value = String(query?.genealogyId || "");
|
||||
albumId.value = String(query?.albumId || "");
|
||||
});
|
||||
const returnToAlbum = () => hasValidContext.value
|
||||
? returnTo("F07", { genealogyId: genealogyId.value })
|
||||
: goBack();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
||||
|
||||
.media-upload-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.media-upload-header,
|
||||
.media-upload-content {
|
||||
z-index: 1;
|
||||
}
|
||||
.media-upload-content {
|
||||
padding: 20rpx 24rpx calc(48rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
.media-album-card {
|
||||
@include adaptive.adaptive-family-panel;
|
||||
display: grid;
|
||||
min-height: 154rpx;
|
||||
box-sizing: border-box;
|
||||
grid-template-columns: 132rpx minmax(0, 1fr);
|
||||
gap: 20rpx;
|
||||
align-items: center;
|
||||
padding: 14rpx 20rpx;
|
||||
}
|
||||
.media-album-card__cover {
|
||||
width: 132rpx;
|
||||
height: 132rpx;
|
||||
border: 2rpx solid rgba(179, 133, 63, 0.62);
|
||||
box-shadow: 0 6rpx 14rpx rgba(91, 60, 32, 0.12);
|
||||
}
|
||||
.media-album-card__copy text,
|
||||
.media-state-card__eyebrow,
|
||||
.media-state-card__title,
|
||||
.media-state-card__copy,
|
||||
.media-preview-title {
|
||||
display: block;
|
||||
}
|
||||
.media-album-card__eyebrow {
|
||||
color: $brand-red;
|
||||
font-size: 21rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.media-album-card__title {
|
||||
margin-top: 7rpx;
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 31rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-album-card__limit {
|
||||
margin-top: 7rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
}
|
||||
.media-section-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 24rpx 8rpx 12rpx;
|
||||
color: $brand-red;
|
||||
font-size: 25rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-section-heading text:last-child {
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
.media-photo-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12rpx;
|
||||
}
|
||||
.media-photo-tile,
|
||||
.media-add-tile {
|
||||
min-width: 0;
|
||||
min-height: 44px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
aspect-ratio: 1;
|
||||
border: 2rpx solid rgba(179, 133, 63, 0.62);
|
||||
background: rgba(247, 241, 231, 0.88);
|
||||
}
|
||||
.media-photo-tile {
|
||||
position: relative;
|
||||
}
|
||||
.media-photo-tile--active {
|
||||
outline: 4rpx solid rgba(159, 44, 35, 0.78);
|
||||
outline-offset: -4rpx;
|
||||
}
|
||||
.media-photo-tile__image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.media-photo-order,
|
||||
.media-photo-current {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
color: #fffaf0;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
.media-photo-order {
|
||||
top: 7rpx;
|
||||
left: 7rpx;
|
||||
min-width: 34rpx;
|
||||
padding: 3rpx 7rpx;
|
||||
border-radius: 999px;
|
||||
background: rgba(43, 31, 23, 0.78);
|
||||
text-align: center;
|
||||
}
|
||||
.media-photo-current {
|
||||
bottom: 7rpx;
|
||||
left: 7rpx;
|
||||
padding: 4rpx 8rpx;
|
||||
background: rgba(74, 45, 27, 0.84);
|
||||
}
|
||||
.media-photo-remove {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
color: #fffaf0;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
.media-photo-remove text {
|
||||
padding: 7rpx 8rpx;
|
||||
background: rgba(145, 36, 29, 0.88);
|
||||
}
|
||||
.media-add-tile {
|
||||
display: flex;
|
||||
min-height: 44px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-style: dashed;
|
||||
color: $brand-red;
|
||||
text-align: center;
|
||||
}
|
||||
.media-add-tile__title {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-add-tile__copy {
|
||||
margin-top: 6rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 19rpx;
|
||||
}
|
||||
.media-description-panel {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.media-batch-field,
|
||||
.media-photo-field {
|
||||
padding: 18rpx 20rpx 20rpx;
|
||||
border: 2rpx solid rgba(179, 133, 63, 0.55);
|
||||
background: rgba(250, 246, 237, 0.76);
|
||||
}
|
||||
.media-photo-field {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
.media-photo-editor {
|
||||
display: grid;
|
||||
grid-template-columns: 78rpx minmax(0, 1fr);
|
||||
gap: 14rpx;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
padding-bottom: 14rpx;
|
||||
border-bottom: 1px solid rgba(179, 133, 63, 0.32);
|
||||
}
|
||||
.media-photo-editor__thumb {
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
border: 2rpx solid rgba(159, 44, 35, 0.62);
|
||||
}
|
||||
.media-photo-editor__copy text {
|
||||
display: block;
|
||||
}
|
||||
.media-photo-editor__position {
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-photo-editor__hint {
|
||||
margin-top: 6rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
.media-field-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-field-heading text:last-child {
|
||||
color: $brand-red;
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.media-batch-field textarea,
|
||||
.media-photo-field textarea {
|
||||
width: 100%;
|
||||
min-height: 92rpx;
|
||||
margin-top: 12rpx;
|
||||
box-sizing: border-box;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.media-field-placeholder {
|
||||
color: #9e8e79;
|
||||
}
|
||||
.media-field-error {
|
||||
display: block;
|
||||
margin: 9rpx 6rpx 0;
|
||||
color: $brand-red;
|
||||
font-size: 21rpx;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.media-primary-action {
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
.media-permission-card,
|
||||
.media-preview-card,
|
||||
.media-invalid-card {
|
||||
@include adaptive.adaptive-family-panel;
|
||||
min-height: 410rpx;
|
||||
margin-top: 24rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 98rpx 46rpx 58rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.media-state-card__eyebrow {
|
||||
color: $brand-red;
|
||||
font-size: 22rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.media-state-card__title,
|
||||
.media-preview-title {
|
||||
margin-top: 12rpx;
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 35rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.media-state-card__copy {
|
||||
margin-top: 16rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.media-permission-action,
|
||||
.media-preview-action {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
@media (max-width: 340px) {
|
||||
.media-upload-content {
|
||||
padding-right: 16rpx;
|
||||
padding-left: 16rpx;
|
||||
}
|
||||
.media-photo-grid {
|
||||
gap: 8rpx;
|
||||
}
|
||||
.media-album-card {
|
||||
grid-template-columns: 116rpx minmax(0, 1fr);
|
||||
gap: 14rpx;
|
||||
}
|
||||
.media-album-card__cover {
|
||||
width: 116rpx;
|
||||
height: 116rpx;
|
||||
}
|
||||
}
|
||||
.media-upload-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }
|
||||
.media-upload-header, .media-upload-content { z-index: 1; }
|
||||
.media-upload-content { padding: 20rpx 24rpx calc(48rpx + env(safe-area-inset-bottom)); }
|
||||
.media-state-card { @include adaptive.adaptive-family-panel; min-height: 410rpx; box-sizing: border-box; padding: 98rpx 46rpx 58rpx; text-align: center; }
|
||||
.media-state-card text { display: block; }
|
||||
.media-state-card__eyebrow { color: $brand-red; font-size: 22rpx; letter-spacing: 2rpx; }
|
||||
.media-state-card__title { margin-top: 12rpx; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 35rpx; font-weight: 700; }
|
||||
.media-state-card__copy { margin-top: 16rpx; color: $ink-muted; font-size: 23rpx; line-height: 1.65; }
|
||||
.media-state-card .app-button { margin-top: 30rpx; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user