v3.5.3版本更新1
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-08-20 18:54:15 +08:00
parent ee493823bf
commit fc2e5b65de
65 changed files with 2297 additions and 875 deletions
+68
View File
@@ -54,3 +54,71 @@ body::-webkit-scrollbar,
padding-bottom: 0 !important;
bottom: 0 !important;
}
.benefit-figure {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 4px;
line-height: 1;
vertical-align: middle;
}
.benefit-figure-prefix,
.benefit-figure-value {
line-height: 1;
font-family: inherit;
font-size: inherit;
font-weight: inherit;
color: inherit;
}
.benefit-figure-icon {
display: block;
flex-shrink: 0;
}
.benefit-figure--sm {
gap: 2px;
}
.benefit-figure--sm .benefit-figure-icon {
width: 12px;
height: 12px;
}
.benefit-figure--md .benefit-figure-icon {
width: 16px;
height: 16px;
}
.benefit-figure--lg .benefit-figure-icon {
width: 20px;
height: 20px;
}
.benefit-figure--xl {
gap: 6px;
}
.benefit-figure--xl .benefit-figure-icon {
width: 28px;
height: 28px;
}
.mu-float-toast {
position: fixed;
top: 28%;
left: 10%;
right: 10%;
z-index: 10020;
padding: 12px 20px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.78);
color: #fff;
font-size: 15px;
line-height: 1.5;
text-align: center;
pointer-events: none;
box-sizing: border-box;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

@@ -0,0 +1,27 @@
import { Image, Text, View } from '@tarojs/components';
import iconStoreBenefit from '../assets/icons/store-benefit.png';
type BenefitFigureSize = 'sm' | 'md' | 'lg' | 'xl';
type BenefitFigureProps = {
value: string;
size?: BenefitFigureSize;
prefix?: string;
className?: string;
};
/** 好客权益金额:门店核销图标 + 数字,替代人民币符号 */
export default function BenefitFigure({
value,
size = 'md',
prefix = '',
className = '',
}: BenefitFigureProps) {
return (
<View className={`benefit-figure benefit-figure--${size} ${className}`.trim()}>
{prefix ? <Text className="benefit-figure-prefix">{prefix}</Text> : null}
<Image className="benefit-figure-icon" src={iconStoreBenefit} mode="aspectFit" />
<Text className="benefit-figure-value">{value}</Text>
</View>
);
}
@@ -1,4 +1,5 @@
import { Text } from '@tarojs/components';
import { Text, View } from '@tarojs/components';
import BenefitFigure from './BenefitFigure';
type CouponBadgeProps = {
amount: number | string;
@@ -10,8 +11,9 @@ export default function CouponBadge({ amount, label = '好客权益' }: CouponBa
const n = Number(amount);
const display = Number.isFinite(n) ? (Number.isInteger(n) ? String(n) : n.toFixed(0)) : String(amount);
return (
<Text className="coupon-badge">
¥{display} {label}
</Text>
<View className="coupon-badge">
<Text></Text>
<BenefitFigure value={`${display} ${label}`} size="sm" />
</View>
);
}
@@ -0,0 +1,32 @@
import { useEffect, useRef, useState } from 'react';
import { CoverView, View } from '@tarojs/components';
import { registerFloatingToastListener } from '../lib/floating-toast';
const TOAST_MS = 2600;
export default function FloatingToastHost() {
const [text, setText] = useState('');
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
return registerFloatingToastListener((message) => {
if (timerRef.current) clearTimeout(timerRef.current);
setText(message);
timerRef.current = setTimeout(() => {
setText('');
timerRef.current = null;
}, TOAST_MS);
});
}, []);
useEffect(() => {
return () => {
if (timerRef.current) clearTimeout(timerRef.current);
};
}, []);
if (!text) return null;
const Box = process.env.TARO_ENV === 'weapp' ? CoverView : View;
return <Box className="mu-float-toast">{text}</Box>;
}
@@ -1,5 +1,6 @@
import type { PropsWithChildren, ReactNode } from 'react';
import { View } from '@tarojs/components';
import FloatingToastHost from './FloatingToastHost';
import { pageShellCssVars, useNavBarMetrics } from '../lib/nav-bar';
type PageShellVariant = 'tab' | 'scroll' | 'sub' | 'plain';
@@ -35,6 +36,7 @@ export default function PageShell({
return (
<View className={classes} style={pageShellCssVars(metrics)}>
{children as ReactNode}
<FloatingToastHost />
</View>
);
}
@@ -14,6 +14,8 @@ type ProductCarouselProps = {
* 依赖 swiper 原生 auto-height:海报有多高,轮播就有多高,无裁切。
*/
imageFit?: 'cover' | 'contain' | 'adaptive';
/** 预览相册(默认等于 images);门店详情可传入封面+环境图合并列表 */
previewUrls?: string[];
};
/** 商品/门店轮播(对齐 h5 ProductCarousel 三变体) */
@@ -23,6 +25,7 @@ export default function ProductCarousel({
variant = 'detail',
previewable = false,
imageFit = 'cover',
previewUrls,
}: ProductCarouselProps) {
const slides = images.length > 0 ? images : [''];
const [activeIndex, setActiveIndex] = useState(0);
@@ -33,10 +36,10 @@ export default function ProductCarousel({
const wrapClass = `${prefix}-wrap${isContain ? ` ${prefix}-wrap--contain` : ''}${isAdaptive ? ` ${prefix}-wrap--adaptive` : ''}`;
function previewAt(index: number) {
const urls = slides.filter(Boolean);
if (!urls.length) return;
const current = slides[index] || urls[0];
Taro.previewImage({ current, urls }).catch(() => undefined);
const album = (previewUrls?.length ? previewUrls : slides).filter(Boolean);
if (!album.length) return;
const current = slides[index] || album[0];
Taro.previewImage({ current, urls: album }).catch(() => undefined);
}
return (
+8 -1
View File
@@ -4,6 +4,7 @@ import { forceReloadAfterAccountMerge } from './auth-nav';
import { resetStoresSessionBootstrap } from './stores-session';
import { resetHomeCatalogBootstrap } from './home-catalog-session';
import { reportClientValidationError } from './client-error';
import { showFloatingToast } from './floating-toast';
function resolveApiBase(): string {
const origin =
@@ -126,7 +127,13 @@ export async function request<T = unknown>(path: string, options: ReqOptions = {
}
export function toast(title: string, icon: 'success' | 'error' | 'none' = 'none') {
Taro.showToast({ title, icon, duration: 1800 });
const text = title.trim();
if (!text) return;
if (icon !== 'success' && showFloatingToast(text)) {
void Taro.hideToast();
return;
}
Taro.showToast({ title: text, icon, duration: 1800 });
}
export type SessionPayload = {
+18
View File
@@ -0,0 +1,18 @@
type FloatingToastListener = (message: string) => void;
const listeners = new Set<FloatingToastListener>();
export function registerFloatingToastListener(fn: FloatingToastListener) {
listeners.add(fn);
return () => {
listeners.delete(fn);
};
}
/** 已有页面宿主时返回 true,否则调用方应回退到原生 toast */
export function showFloatingToast(message: string): boolean {
const text = message.trim();
if (!text || listeners.size === 0) return false;
listeners.forEach((fn) => fn(text));
return true;
}
+21 -2
View File
@@ -1,7 +1,26 @@
/** 金额展示(不依赖 Intl / toLocaleString,兼容微信小程序) */
export function toMoneyNumber(amount: unknown): number {
if (typeof amount === 'number') return Number.isFinite(amount) ? amount : 0;
if (typeof amount === 'string' && amount.trim()) {
const n = Number(amount);
return Number.isFinite(n) ? n : 0;
}
if (amount && typeof amount === 'object') {
const o = amount as { toNumber?: () => number; toString?: () => string };
if (typeof o.toNumber === 'function') {
const n = Number(o.toNumber());
if (Number.isFinite(n)) return n;
}
if (typeof o.toString === 'function' && o.toString !== Object.prototype.toString) {
const n = Number(o.toString());
if (Number.isFinite(n)) return n;
}
}
return 0;
}
export function formatMoney(amount: number | string): string {
const n = typeof amount === 'number' ? amount : Number(amount);
if (!Number.isFinite(n)) return '0.00';
const n = toMoneyNumber(amount);
const fixed = n.toFixed(2);
const [intPart, dec] = fixed.split('.');
const withComma = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+28 -16
View File
@@ -82,8 +82,10 @@ function sceneConfig(scene?: ShareScene): MiniShareSceneConfig {
}
/**
* 组装页面分享:场景配置优先;空字段用 dynamic → 默认分享
* orderDetail 标题支持 {productName}。
* 组装页面分享。
* - productDetail / storeDetailtitle 与 imageUrl 固定用业务字段(不被 HQ 场景配置覆盖)
* - 其它场景:场景配置优先;空字段用 dynamic → 默认分享
* - orderDetail 标题支持 {productName}
*/
export function buildSceneSharePayload(
scene: ShareScene,
@@ -98,23 +100,33 @@ export function buildSceneSharePayload(
): PageSharePayload {
const def = getShareRuntimeSync().default;
const sc = sceneConfig(scene);
let title = (sc.title || '').trim();
if (title && options?.titleVars) {
const vars = options.titleVars;
const missingRequired = Object.entries(vars).some(
([key, value]) => title.includes(`{${key}}`) && !(value != null && String(value).trim()),
);
title = missingRequired ? '' : applyShareTitleTemplate(title, vars);
}
if (!title) {
const preferEntity = scene === 'productDetail' || scene === 'storeDetail';
let title: string;
if (preferEntity) {
title = (options?.dynamicTitle || '').trim() || def.title;
} else {
title = (sc.title || '').trim();
if (title && options?.titleVars) {
const vars = options.titleVars;
const missingRequired = Object.entries(vars).some(
([key, value]) => title.includes(`{${key}}`) && !(value != null && String(value).trim()),
);
title = missingRequired ? '' : applyShareTitleTemplate(title, vars);
}
if (!title) {
title = (options?.dynamicTitle || '').trim() || def.title;
}
}
const desc = (sc.desc || '').trim() || (options?.dynamicDesc || '').trim() || def.desc;
const imgUrl =
(sc.imageUrl || '').trim() ||
(options?.dynamicImageUrl || '').trim() ||
def.imageUrl ||
getDefaultShareImageUrl();
const imgUrl = preferEntity
? (options?.dynamicImageUrl || '').trim() || def.imageUrl || getDefaultShareImageUrl()
: (sc.imageUrl || '').trim() ||
(options?.dynamicImageUrl || '').trim() ||
def.imageUrl ||
getDefaultShareImageUrl();
return {
title,
desc,
+24 -14
View File
@@ -97,23 +97,33 @@ export function buildSceneSharePayload(
): PageSharePayload {
const def = getShareRuntimeSync().default;
const sc = sceneConfig(scene);
let title = (sc.title || '').trim();
if (title && options?.titleVars) {
const vars = options.titleVars;
const missingRequired = Object.entries(vars).some(
([key, value]) => title.includes(`{${key}}`) && !(value != null && String(value).trim()),
);
title = missingRequired ? '' : applyShareTitleTemplate(title, vars);
}
if (!title) {
const preferEntity = scene === 'productDetail' || scene === 'storeDetail';
let title: string;
if (preferEntity) {
title = (options?.dynamicTitle || '').trim() || def.title;
} else {
title = (sc.title || '').trim();
if (title && options?.titleVars) {
const vars = options.titleVars;
const missingRequired = Object.entries(vars).some(
([key, value]) => title.includes(`{${key}}`) && !(value != null && String(value).trim()),
);
title = missingRequired ? '' : applyShareTitleTemplate(title, vars);
}
if (!title) {
title = (options?.dynamicTitle || '').trim() || def.title;
}
}
const desc = (sc.desc || '').trim() || (options?.dynamicDesc || '').trim() || def.desc;
const imgUrl =
(sc.imageUrl || '').trim() ||
(options?.dynamicImageUrl || '').trim() ||
def.imageUrl ||
getDefaultShareImageUrl();
const imgUrl = preferEntity
? (options?.dynamicImageUrl || '').trim() || def.imageUrl || getDefaultShareImageUrl()
: (sc.imageUrl || '').trim() ||
(options?.dynamicImageUrl || '').trim() ||
def.imageUrl ||
getDefaultShareImageUrl();
return {
title,
desc,
+19 -9
View File
@@ -4,6 +4,7 @@ import Taro, { useDidShow, usePullDownRefresh, useShareAppMessage, useShareTimel
import PageShell from '../../components/PageShell';
import WechatShareReady from '../../components/WechatShareReady';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { isLoggedIn, request, toast } from '../../lib/api';
import { navBarStyle, tabNavContentStyle, useNavBarMetrics } from '../../lib/nav-bar';
@@ -150,10 +151,11 @@ export default function BenefitPage() {
<View>
<Text className="benefit-hero-label"></Text>
<View className="benefit-hero-amount">
<Text className="benefit-hero-symbol">¥</Text>
<Text className="benefit-hero-value">
{summary ? formatMoney(summary.totalBalance) : '--'}
</Text>
<BenefitFigure
value={summary ? formatMoney(summary.totalBalance) : '--'}
size="xl"
className="benefit-hero-value"
/>
</View>
</View>
<View className="benefit-hero-logo">
@@ -193,16 +195,19 @@ export default function BenefitPage() {
<View className="benefit-coupon-notch benefit-coupon-notch--right" />
<View className="benefit-coupon-head">
<Text className="benefit-coupon-name">{c.sourceProduct || '好客权益'}</Text>
<Text className="benefit-coupon-balance">¥{formatMoney(c.balance)}</Text>
<BenefitFigure value={formatMoney(c.balance)} size="md" className="benefit-coupon-balance" />
</View>
<Text className="benefit-coupon-no">NO. {c.couponNo}</Text>
<View className="benefit-progress">
<View className="benefit-progress-bar" style={{ width: `${usagePercent(c)}%` }} />
</View>
<View className="benefit-coupon-footer">
<Text className="benefit-coupon-meta">
¥{formatMoney(c.usedAmount)} / ¥{formatMoney(c.totalAmount)}
</Text>
<View className="benefit-coupon-meta">
<Text></Text>
<BenefitFigure value={formatMoney(c.usedAmount)} size="sm" />
<Text>/ </Text>
<BenefitFigure value={formatMoney(c.totalAmount)} size="sm" />
</View>
<Text
className="benefit-coupon-btn"
onClick={() =>
@@ -226,7 +231,12 @@ export default function BenefitPage() {
<View className="benefit-coupon-notch benefit-coupon-notch--right" />
<View className="benefit-coupon-head">
<Text className="benefit-coupon-name">{r.storeName || '门店核销'}</Text>
<Text className="benefit-coupon-balance">-¥{formatMoney(Number(r.amount))}</Text>
<BenefitFigure
prefix="-"
value={formatMoney(Number(r.amount))}
size="md"
className="benefit-coupon-balance"
/>
</View>
<Text className="benefit-coupon-no">NO. {r.redeemNo}</Text>
<View className="benefit-coupon-footer">
+2 -2
View File
@@ -9,6 +9,7 @@ import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import WechatShareReady from '../../components/WechatShareReady';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { bindWechatForUser } from '../../lib/wechat-auth';
import {
@@ -447,8 +448,7 @@ export default function MinePage() {
<View>
<Text className="mine-asset-label"></Text>
<View className="mine-asset-amount">
<Text className="mine-asset-currency">¥</Text>
<Text className="mine-asset-value">{formatMoney(benefitBalance)}</Text>
<BenefitFigure value={formatMoney(benefitBalance)} size="lg" className="mine-asset-value" />
</View>
</View>
<Text
@@ -10,6 +10,7 @@ import { ensurePayReady } from '../../lib/pay-ready';
import { fetchUserProfile } from '../../lib/pay-wechat';
import { request, toast } from '../../lib/api';
import { getProductMainImage } from '../../lib/product-images';
import BenefitFigure from '../../components/BenefitFigure';
type PreviewProduct = {
id: string;
@@ -231,7 +232,11 @@ export default function OrderConfirmPickupPage() {
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
<Text className="order-row-value--price">¥{Number(preview.benefitAmount).toFixed(2)}</Text>
<BenefitFigure
value={Number(preview.benefitAmount).toFixed(2)}
size="sm"
className="order-row-value--price"
/>
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
@@ -13,6 +13,7 @@ import { fetchUserProfile } from '../../lib/pay-wechat';
import { request, toast } from '../../lib/api';
import { canCrossCity, isCrossCityAddress } from '../../lib/product-fulfillment';
import { getProductMainImage } from '../../lib/product-images';
import BenefitFigure from '../../components/BenefitFigure';
type Address = {
id: string;
@@ -384,7 +385,11 @@ export default function OrderConfirmPage() {
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
<Text className="order-row-value--price">¥{preview.benefitAmount.toFixed(2)}</Text>
<BenefitFigure
value={preview.benefitAmount.toFixed(2)}
size="sm"
className="order-row-value--price"
/>
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
@@ -13,6 +13,7 @@ import PageShell from '../../components/PageShell';
import PageNavBar from '../../components/PageNavBar';
import ProductCarousel from '../../components/ProductCarousel';
import WechatShareReady from '../../components/WechatShareReady';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { ensurePayReady } from '../../lib/pay-ready';
import { isLoggedIn, request, toast } from '../../lib/api';
@@ -189,10 +190,10 @@ export default function ProductDetailPage() {
<View className="product-detail-promo-icon">
<Text className="product-detail-promo-icon-text"></Text>
</View>
<Text className="product-detail-promo-title">
·
<Text className="product-detail-promo-amount"> ¥{benefit}</Text>
</Text>
<View className="product-detail-promo-title">
<Text> · </Text>
<BenefitFigure value={String(benefit)} size="sm" className="product-detail-promo-amount" />
</View>
</View>
<Text className="product-detail-promo-desc">
@@ -8,6 +8,7 @@ import RedeemQrCode from '../../components/RedeemQrCode';
import SubPageHeader from '../../components/SubPageHeader';
import { request, toast } from '../../lib/api';
import { formatMoney } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
const POLL_INTERVAL_MS = 2500;
const LAST_REDEEM_RECORD_KEY = 'lastRedeemRecordId';
@@ -154,7 +155,7 @@ export default function RedeemCodePage() {
<Text className="redeem-timer-label"></Text>
</View>
<Text className="u-muted"></Text>
<Text className="redeem-code-amount">¥ {formatMoney(amount)}</Text>
<BenefitFigure value={formatMoney(amount)} size="lg" className="redeem-code-amount" />
{token ? (
<View className="redeem-code-token-wrap" onClick={onTokenTap}>
<Text className="redeem-code-token-label"></Text>
@@ -6,7 +6,8 @@ import PageShell from '../../components/PageShell';
import SubPageHeader from '../../components/SubPageHeader';
import { request, toast } from '../../lib/api';
import { formatShanghaiDateTime } from '../../lib/datetime';
import { formatMoney } from '../../lib/money';
import { formatMoney, toMoneyNumber } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
const LAST_REDEEM_RESULT_KEY = 'lastRedeemResult';
@@ -66,7 +67,7 @@ export default function RedeemSuccessPage() {
}
}, []);
const amount = Number(record?.amount ?? router.params.amount ?? 0);
const amount = toMoneyNumber(record?.amount ?? router.params.amount);
const storeName = record?.storeName || '门店';
const redeemNo = record?.redeemNo || '—';
const redeemedAt = formatChinaDateTime(record?.createdAt);
@@ -119,7 +120,7 @@ export default function RedeemSuccessPage() {
<Text></Text>
</View>
<Text className="redeem-success-title"></Text>
<Text className="redeem-success-amount">¥ {formatMoney(amount)}</Text>
<BenefitFigure value={formatMoney(amount)} size="lg" className="redeem-success-amount" />
<Text className="redeem-success-desc"> {storeName} </Text>
<View className="redeem-success-details">
+11 -7
View File
@@ -7,6 +7,7 @@ import SubPageHeader from '../../components/SubPageHeader';
import { goLogin } from '../../lib/auth-nav';
import { isLoggedIn, request, toast } from '../../lib/api';
import { formatMoney } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
type BenefitSummary = {
totalBalance: number;
@@ -103,7 +104,7 @@ export default function RedeemPage() {
return;
}
if (value > redeemableMax) {
toast(couponId ? '核销金额不能超过该权益可用余额' : '超出可用余额');
toast(couponId ? '核销金额不能超过该权益可用余额' : '核销金额不能超过可用余额');
return;
}
@@ -134,9 +135,11 @@ export default function RedeemPage() {
<Text className="redeem-hero-label">
{couponId ? '当前权益可用余额' : '可用余额'}
</Text>
<Text className="redeem-hero-amount">
¥{redeemableMax > 0 ? formatMoney(redeemableMax) : '--'}
</Text>
<BenefitFigure
value={redeemableMax > 0 ? formatMoney(redeemableMax) : '--'}
size="xl"
className="redeem-hero-amount"
/>
</View>
<View className="redeem-input-wrap">
<Input
@@ -153,9 +156,10 @@ export default function RedeemPage() {
/>
</View>
<View className="redeem-amount-foot">
<Text className="redeem-amount-hint">
¥{formatMoney(redeemableMax)}
</Text>
<View className="redeem-amount-hint">
<Text></Text>
<BenefitFigure value={formatMoney(redeemableMax)} size="sm" />
</View>
<Text className="redeem-fill-max" onClick={fillMaxAmount}>
</Text>
@@ -16,6 +16,7 @@ import ShareNavButton from '../../components/ShareNavButton';
import StoreRedeemMarquee from '../../components/StoreRedeemMarquee';
import WechatShareReady from '../../components/WechatShareReady';
import { request, toast } from '../../lib/api';
import { toMoneyNumber } from '../../lib/money';
import { maskPhone, toDialablePhone } from '../../lib/phone';
import { track } from '../../lib/analytics';
import { formatShanghaiDateTime } from '../../lib/datetime';
@@ -116,9 +117,8 @@ function formatPackagePriceYuan(price: string | number) {
return n.toFixed(2).replace(/\.?0+$/, '');
}
function formatRedeemAmountYuan(amount: number | string) {
const n = typeof amount === 'number' ? amount : Number(amount);
if (!Number.isFinite(n)) return '0';
function formatRedeemAmountYuan(amount: unknown) {
const n = toMoneyNumber(amount);
if (Math.abs(n - Math.round(n)) < 1e-9) return String(Math.round(n));
return n.toFixed(2).replace(/\.?0+$/, '');
}
@@ -323,6 +323,8 @@ export default function StoreDetailPage() {
const envPhotos = envPhotoUrls(store);
const heroImages = uniqueUrls([store.coverUrl, ...(store.carouselUrls || [])]);
/** 预览相册:封面 + 环境图(去重),页面展示仍分开 */
const previewAlbum = uniqueUrls([store.coverUrl, ...envPhotos]);
const packages = store.packages ?? [];
const intro = store.intro?.trim() || '';
@@ -337,10 +339,12 @@ export default function StoreDetailPage() {
}
function previewEnv(index: number) {
if (!envPhotos.length) return;
const current = envPhotos[index];
if (!current) return;
const urls = previewAlbum.length ? previewAlbum : envPhotos;
Taro.previewImage({
current: envPhotos[index],
urls: envPhotos,
current,
urls,
}).catch(() => toast('无法预览图片'));
}
@@ -362,6 +366,7 @@ export default function StoreDetailPage() {
variant="store"
previewable
imageFit="contain"
previewUrls={previewAlbum}
/>
</View>
+11 -1
View File
@@ -98,7 +98,7 @@
.benefit-hero-amount {
display: flex;
align-items: baseline;
align-items: center;
color: var(--color-heritage-red);
}
@@ -109,6 +109,8 @@
}
.benefit-hero-value {
display: inline-flex;
align-items: center;
font-family: var(--font-headline);
font-size: 40px;
font-weight: 700;
@@ -216,6 +218,10 @@
color: var(--color-heritage-red);
}
.benefit-coupon-meta .benefit-figure {
color: inherit;
}
.benefit-coupon-no {
display: block;
font-size: 11px;
@@ -244,6 +250,10 @@
}
.benefit-coupon-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 2px;
font-size: 12px;
color: var(--color-subtle-gray);
}
+1
View File
@@ -304,6 +304,7 @@
position: relative;
display: inline-flex;
align-items: center;
gap: 2px;
background: var(--color-aged-amber);
color: var(--color-on-secondary-container);
padding: 2px 8px;
+3 -1
View File
@@ -215,7 +215,7 @@
.mine-asset-amount {
display: flex;
align-items: baseline;
align-items: center;
color: var(--color-heritage-red);
}
@@ -226,6 +226,8 @@
}
.mine-asset-value {
display: inline-flex;
align-items: center;
font-family: var(--font-headline);
font-size: 24px;
font-weight: 700;
+2
View File
@@ -215,6 +215,8 @@
}
.order-row-value--price {
display: inline-flex;
align-items: center;
color: var(--color-heritage-red);
font-weight: 700;
}
@@ -175,6 +175,10 @@
.product-detail-promo-title {
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px;
font-family: var(--font-headline);
font-size: 16px;
font-weight: 700;
@@ -184,6 +188,7 @@
.product-detail-promo-amount {
color: var(--color-heritage-red);
font-weight: 700;
}
.product-detail-promo-desc {
+13 -3
View File
@@ -24,6 +24,9 @@
}
.redeem-hero-amount {
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-headline);
font-size: 36px;
font-weight: 700;
@@ -92,6 +95,10 @@
}
.redeem-amount-hint {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 2px;
font-size: 12px;
color: var(--color-subtle-gray);
line-height: 1.4;
@@ -279,7 +286,9 @@
}
.redeem-code-amount {
display: block;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-headline);
font-size: 28px;
font-weight: 700;
@@ -350,8 +359,9 @@
}
.redeem-success-amount {
display: block;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-headline);
font-size: 28px;
font-weight: 700;