diff --git a/index.html b/index.html index 7e2defb..a25646f 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - Popi.art | AI动画制作平台 · 角色生成 · AI分镜(故事板) + POPi.art | AI动画制作平台 · 角色生成 · AI分镜(故事板) diff --git a/src/api/api.ts b/src/api/api.ts index 58b03db..03a79d1 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -72,6 +72,7 @@ type PaymentStatusResponse = { message?: string; data?: PaymentStatusData; }; +const paymentRequestConfig: AxiosRequestConfig = { skipGlobalErrorHandler: true }; export type AuthUser = Record; export type AuthData = ApiParams & { token?: string; @@ -610,54 +611,70 @@ export const getPlanList = (type: EntityId): Promise => { - return request.post("/trade/subscription/payByGatewayAliPay", { - origin: "skillhub", - ...params, - }); + return request.post( + "/trade/subscription/payByGatewayAliPay", + { + origin: "skillhub", + ...params, + }, + paymentRequestConfig, + ); }; // 订阅微信下单 export const createSubscriptionOrderByWxPay = (params: ApiPayload): Promise => { - return request.post("/trade/subscription/payByGatewayWxPay", { - origin: "skillhub", - ...params, - }); + return request.post( + "/trade/subscription/payByGatewayWxPay", + { + origin: "skillhub", + ...params, + }, + paymentRequestConfig, + ); }; // 订阅支付宝支付结果查询 export const checkGatewayPayment = (params: ApiPayload): Promise => { - return request.post("/trade/subscription/checkGatewayPayment", params); + return request.post("/trade/subscription/checkGatewayPayment", params, paymentRequestConfig); }; // 订阅微信支付结果查询 export const checkGatewayWxPayment = (params: ApiPayload): Promise => { - return request.post("/trade/subscription/checkGatewayWxPayment", params); + return request.post("/trade/subscription/checkGatewayWxPayment", params, paymentRequestConfig); }; // 积分包支付宝下单 export const createPointsOrder = (params: ApiPayload): Promise => { - return request.post("/users/pointPackage/payByGatewayAliPay", { - origin: "skillhub", - ...params, - }); + return request.post( + "/users/pointPackage/payByGatewayAliPay", + { + origin: "skillhub", + ...params, + }, + paymentRequestConfig, + ); }; // 积分包微信下单 export const createPointsOrderByWxPay = (params: ApiPayload): Promise => { - return request.post("/users/pointPackage/payByGatewayWxPay", { - origin: "skillhub", - ...params, - }); + return request.post( + "/users/pointPackage/payByGatewayWxPay", + { + origin: "skillhub", + ...params, + }, + paymentRequestConfig, + ); }; // 积分包支付宝支付结果查询 export const checkPointsPayment = (params: ApiPayload): Promise => { - return request.post("/users/pointPackage/checkGatewayPayment", params); + return request.post("/users/pointPackage/checkGatewayPayment", params, paymentRequestConfig); }; // 积分包微信支付结果查询 export const checkPointsWxPayment = (params: ApiPayload): Promise => { - return request.post("/users/pointPackage/checkGatewayWxPayment", params); + return request.post("/users/pointPackage/checkGatewayWxPayment", params, paymentRequestConfig); }; // 积分包列表 diff --git a/src/assets/images/explore/hero/heroBG1.png b/src/assets/images/explore/hero/heroBG1.png index a043e9d..dc21f94 100644 Binary files a/src/assets/images/explore/hero/heroBG1.png and b/src/assets/images/explore/hero/heroBG1.png differ diff --git a/src/assets/images/explore/hero/heroBG3.png b/src/assets/images/explore/hero/heroBG3.png index 592b03c..50f99d3 100644 Binary files a/src/assets/images/explore/hero/heroBG3.png and b/src/assets/images/explore/hero/heroBG3.png differ diff --git a/src/components/AssetGalleryTile/index.scss b/src/components/AssetGalleryTile/index.scss index 6762738..84a4dba 100644 --- a/src/components/AssetGalleryTile/index.scss +++ b/src/components/AssetGalleryTile/index.scss @@ -112,7 +112,6 @@ .assetGalleryTile_voice { border-radius: 26px; - background: #b884dd; .assetGalleryTile__voiceCover { position: absolute; @@ -204,6 +203,7 @@ } .assetGalleryTile_voice_disabled { + .assetGalleryTile__voiceCenterControl, .assetGalleryTile__voiceCaption { cursor: default; @@ -216,4 +216,4 @@ height: 100%; object-fit: contain; object-position: center; -} +} \ No newline at end of file diff --git a/src/dialog/index.tsx b/src/dialog/index.tsx index 1ab5e0d..286b837 100644 --- a/src/dialog/index.tsx +++ b/src/dialog/index.tsx @@ -22,6 +22,7 @@ let dialogHistorySyncing = false; let closeCharacterDetailModalImpl: (() => void) | null = null; let closeAssetDetailsModalImpl: (() => void) | null = null; let closeFoldersAssetDetailsModalImpl: (() => void) | null = null; +let paySubscribeDialogOpen = false; export function closeCharacterDetailModal(): void { closeCharacterDetailModalImpl?.(); @@ -186,17 +187,28 @@ interface OpenPaySubscribeDialogOptions { } export async function openPaySubscribeDialog({ type, plan }: OpenPaySubscribeDialogOptions): Promise { - const { default: PaySubscribe } = await import("@/dialog/pay-subscribe"); - let close = () => {}; - const modal = openDialogWithHistory({ - title: null, - icon: null, - closable: true, - footer: null, - style: { width: "fit-content", maxWidth: "calc(100vw - 32px)", borderRadius: "9px", padding: "0" }, - content: , - }); - close = modal.close; + if (paySubscribeDialogOpen) return; + paySubscribeDialogOpen = true; + + try { + const { default: PaySubscribe } = await import("@/dialog/pay-subscribe"); + let close = () => {}; + const modal = openDialogWithHistory({ + title: null, + icon: null, + closable: true, + footer: null, + style: { width: "fit-content", maxWidth: "calc(100vw - 32px)", borderRadius: "9px", padding: "0" }, + content: , + afterClose: () => { + paySubscribeDialogOpen = false; + }, + }); + close = modal.close; + } catch (error) { + paySubscribeDialogOpen = false; + throw error; + } } // 积分不足弹窗 diff --git a/src/dialog/pay-subscribe/index.tsx b/src/dialog/pay-subscribe/index.tsx index c6f7760..9519600 100644 --- a/src/dialog/pay-subscribe/index.tsx +++ b/src/dialog/pay-subscribe/index.tsx @@ -1,9 +1,9 @@ /** - * 订阅 / 积分支付弹窗 - * - * 微信:打开即预拉二维码;蒙层在首次同意前盖住二维码;同意一次后切回微信不再蒙层,并轮询。 - * 支付宝:无二维码,蒙层始终存在;每次点「同意并支付」才下单拿链接并跳转,再轮询。 - */ + * 订阅 / 积分支付弹窗 + * + * 微信:同意后下单拉二维码;拿到有效二维码后移除蒙层并轮询。 + * 支付宝:无二维码,蒙层始终存在;每次点「同意并支付」才下单拿链接并跳转,再轮询。 + */ import { Message, Modal } from "@arco-design/web-react"; import { useTranslation } from "react-i18next"; import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -111,16 +111,20 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P afterPaySuccessRef.current = afterPaySuccess; }, [afterPaySuccess]); - const [paymentMethod, setPaymentMethod] = useState("WXPAY"); - /** 微信侧是否已点过「同意并支付」(本会话内切回微信不再出蒙层) */ - const [wxAgreed, setWxAgreed] = useState(false); - const [submitting, setSubmitting] = useState(false); - const [codeUrl, setCodeUrl] = useState(""); - + const [paymentMethod, setPaymentMethod] = useState("WXPAY"); + /** 微信侧是否已点过「同意并支付」(本会话内切回微信不再出蒙层) */ + const [wxAgreed, setWxAgreed] = useState(false); + const [submitting, setSubmitting] = useState(false); + const [codeUrl, setCodeUrl] = useState(""); + const wxOrderRef = useRef(null); - const pollAbortRef = useRef(false); - const pollStartTimeRef = useRef(0); - const pollTimerRef = useRef(null); + const mountedRef = useRef(true); + const requestSeqRef = useRef(0); + const activePollSeqRef = useRef(0); + const submittingRef = useRef(false); + const pollAbortRef = useRef(false); + const pollStartTimeRef = useRef(0); + const pollTimerRef = useRef(null); const paymentInfo = useMemo(() => { if (payType === "subscribe") { @@ -153,23 +157,9 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P /** 支付宝始终蒙层;微信仅首次同意前蒙层 */ const showAgreementOverlay = paymentMethod === "ALIPAY" || !wxAgreed; - useEffect(() => { - return () => { - pollAbortRef.current = true; - if (pollTimerRef.current != null) { - window.clearTimeout(pollTimerRef.current); - pollTimerRef.current = null; - } - }; - }, []); - - const safeClose = useCallback(() => { - onClose(); - }, [onClose]); - - const requireLogin = useCallback((): boolean => { - if (!getToken() || !user) { - Message.warning(t("auth.please_login_first")); + const requireLogin = useCallback((): boolean => { + if (!getToken() || !user) { + Message.warning(t("auth.please_login_first")); return false; } return true; @@ -177,12 +167,39 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P const stopPolling = useCallback(() => { pollAbortRef.current = true; + activePollSeqRef.current += 1; if (pollTimerRef.current != null) { window.clearTimeout(pollTimerRef.current); pollTimerRef.current = null; } }, []); - const isPollingAborted = useCallback(() => pollAbortRef.current, []); + const isPollingActive = useCallback((pollSeq: number) => mountedRef.current && !pollAbortRef.current && activePollSeqRef.current === pollSeq, []); + const setSubmittingState = useCallback((nextSubmitting: boolean) => { + submittingRef.current = nextSubmitting; + if (mountedRef.current) { + setSubmitting(nextSubmitting); + } + }, []); + + useEffect(() => { + return () => { + mountedRef.current = false; + requestSeqRef.current += 1; + stopPolling(); + submittingRef.current = false; + }; + }, [stopPolling]); + + const safeClose = useCallback(() => { + onClose(); + }, [onClose]); + + const nextPaymentRequestSeq = useCallback(() => { + requestSeqRef.current += 1; + return requestSeqRef.current; + }, []); + + const isPaymentRequestActive = useCallback((requestSeq: number) => mountedRef.current && requestSeqRef.current === requestSeq, []); // 轮询支付状态 const startPaymentPoll = useCallback( @@ -190,18 +207,20 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P const tradeNo = orderRes.trade_no ?? orderRes.tradeNo; if (!tradeNo) return; - stopPolling(); - pollAbortRef.current = false; - pollStartTimeRef.current = Date.now(); - - void (async () => { - const { paymentMethod: method, payType: ctxPayType } = ctx; - - for (;;) { - if (pollAbortRef.current) return; - - if (Date.now() - pollStartTimeRef.current >= PAYMENT_POLL_MAX_MS) { - openPayNoticeModal("warning", { + stopPolling(); + pollAbortRef.current = false; + pollStartTimeRef.current = Date.now(); + const pollSeq = activePollSeqRef.current + 1; + activePollSeqRef.current = pollSeq; + + void (async () => { + const { paymentMethod: method, payType: ctxPayType } = ctx; + + for (;;) { + if (!isPollingActive(pollSeq)) return; + + if (Date.now() - pollStartTimeRef.current >= PAYMENT_POLL_MAX_MS) { + openPayNoticeModal("warning", { title: t("subscribe.pay_notice_timeout_title"), content: t("subscribe.pay_result_timeout"), okText: t("button.okay"), @@ -212,11 +231,11 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P try { const { data: statusRes } = await fetchPaymentStatus(tradeNo, method, ctxPayType); - if (isPollingAborted()) return; - - const tradeStatus = extractTradeStatus(statusRes, method); - if (!tradeStatus) { - await sleep(PAYMENT_POLL_INTERVAL_MS); + if (!isPollingActive(pollSeq)) return; + + const tradeStatus = extractTradeStatus(statusRes, method); + if (!tradeStatus) { + await sleep(PAYMENT_POLL_INTERVAL_MS); continue; } @@ -248,30 +267,31 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P }); return; } - - await sleep(PAYMENT_POLL_INTERVAL_MS); - } catch { - await sleep(PAYMENT_POLL_INTERVAL_MS); - } - } - })(); - }, - [isPollingAborted, safeClose, setUser, stopPolling, t], - ); + + await sleep(PAYMENT_POLL_INTERVAL_MS); + } catch { + if (!isPollingActive(pollSeq)) return; + await sleep(PAYMENT_POLL_INTERVAL_MS); + } + } + })(); + }, + [isPollingActive, safeClose, setUser, stopPolling, t], + ); // 调度轮询 const schedulePoll = useCallback( (orderRes: PaymentOrderData, method: PaymentMethod) => { - if (pollTimerRef.current != null) { - window.clearTimeout(pollTimerRef.current); - } - const ctx: PollContext = { paymentMethod: method, payType }; - pollTimerRef.current = window.setTimeout(() => { - startPaymentPoll(orderRes, ctx); - }, PAYMENT_POLL_INTERVAL_MS); - }, - [payType, startPaymentPoll], - ); + if (!mountedRef.current) return; + stopPolling(); + const ctx: PollContext = { paymentMethod: method, payType }; + pollTimerRef.current = window.setTimeout(() => { + if (!mountedRef.current) return; + startPaymentPoll(orderRes, ctx); + }, PAYMENT_POLL_INTERVAL_MS); + }, + [payType, startPaymentPoll, stopPolling], + ); // 解析套餐ID const resolvePlanIds = useCallback(() => { @@ -296,31 +316,29 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P return requireLogin(); }, [requireLogin, resolvePlanIds, safeClose, t]); - /** 微信预下单:仅拉 code_url,不跳转 */ - const fetchWxOrder = useCallback( - async (options?: { silent?: boolean }) => { - if (submitting) return null; - - const { id, subscriptionId, packageId } = resolvePlanIds(); - if (!id) { - if (!options?.silent) { - openPayNoticeModal("warning", { - title: t("subscribe.pay_notice_missing_plan_title"), - content: t("subscribe.missing_plan_info"), - okText: t("button.okay"), - onOk: safeClose, - }); - } - return null; - } - - if (options?.silent) { - if (!getToken() || !user) return null; - } else if (!requireLogin()) { - return null; - } - setSubmitting(true); - const returnUrl = buildPaymentReturnUrl(payType, "WXPAY"); + /** 微信下单:仅拉 code_url,不跳转 */ + const fetchWxOrder = useCallback( + async () => { + if (submittingRef.current) return null; + + const requestSeq = nextPaymentRequestSeq(); + stopPolling(); + const { id, subscriptionId, packageId } = resolvePlanIds(); + if (!id) { + openPayNoticeModal("warning", { + title: t("subscribe.pay_notice_missing_plan_title"), + content: t("subscribe.missing_plan_info"), + okText: t("button.okay"), + onOk: safeClose, + }); + return null; + } + + if (!requireLogin()) { + return null; + } + setSubmittingState(true); + const returnUrl = buildPaymentReturnUrl(payType, "WXPAY"); try { if (payType === "subscribe") { @@ -328,60 +346,93 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P returnUrl, subscriptionId, }); + if (!isPaymentRequestActive(requestSeq)) return null; if (!res) return null; + if (!res.code_url) { + openPayNoticeModal("error", { + title: t("subscribe.pay_notice_start_failed_title"), + content: t("subscribe.pay_start_failed"), + okText: t("button.okay"), + }); + return null; + } wxOrderRef.current = res; - setCodeUrl(res.code_url ?? ""); + setCodeUrl(res.code_url); return res; } const { data: res } = await createPointsOrderByWxPay({ returnUrl, packageId }); + if (!isPaymentRequestActive(requestSeq)) return null; if (!res) return null; + if (!res.code_url) { + openPayNoticeModal("error", { + title: t("subscribe.pay_notice_start_failed_title"), + content: t("subscribe.pay_start_failed"), + okText: t("button.okay"), + }); + return null; + } wxOrderRef.current = res; - setCodeUrl(res.code_url ?? ""); + setCodeUrl(res.code_url); return res; - } catch { - openPayNoticeModal("error", { - title: t("subscribe.pay_notice_start_failed_title"), - content: t("subscribe.pay_start_failed"), - okText: t("button.okay"), - onOk: safeClose, - }); - return null; - } finally { - setSubmitting(false); - } - }, - [payType, requireLogin, resolvePlanIds, safeClose, submitting, t, user], - ); - - /** 支付宝下单:同意后才调用,拿链接并跳转 */ - const fetchAlipayAndRedirect = useCallback(async () => { - if (submitting) return null; - if (!assertPlanAndLogin()) return null; - - const { subscriptionId, packageId } = resolvePlanIds(); - setSubmitting(true); - const returnUrl = buildPaymentReturnUrl(payType, "ALIPAY"); - - try { - const res = payType === "subscribe" ? (await createSubscriptionOrder({ returnUrl, subscriptionId })).data : (await createPointsOrder({ returnUrl, packageId })).data; - - if (res?.url) { - schedulePoll(res, "ALIPAY"); - location.href = res.url; - } - return res; - } catch { - openPayNoticeModal("error", { - title: t("subscribe.pay_notice_start_failed_title"), - content: t("subscribe.pay_start_failed"), - okText: t("button.okay"), - onOk: safeClose, - }); - return null; - } finally { - setSubmitting(false); - } - }, [assertPlanAndLogin, payType, resolvePlanIds, safeClose, schedulePoll, submitting, t]); + } catch { + if (isPaymentRequestActive(requestSeq)) { + openPayNoticeModal("error", { + title: t("subscribe.pay_notice_start_failed_title"), + content: t("subscribe.pay_start_failed"), + okText: t("button.okay"), + }); + } + return null; + } finally { + if (isPaymentRequestActive(requestSeq)) { + setSubmittingState(false); + } + } + }, + [isPaymentRequestActive, nextPaymentRequestSeq, payType, requireLogin, resolvePlanIds, safeClose, setSubmittingState, stopPolling, t], + ); + + /** 支付宝下单:同意后才调用,拿链接并跳转 */ + const fetchAlipayAndRedirect = useCallback(async () => { + if (submittingRef.current) return null; + if (!assertPlanAndLogin()) return null; + + const requestSeq = nextPaymentRequestSeq(); + stopPolling(); + const { subscriptionId, packageId } = resolvePlanIds(); + setSubmittingState(true); + const returnUrl = buildPaymentReturnUrl(payType, "ALIPAY"); + + try { + const res = payType === "subscribe" ? (await createSubscriptionOrder({ returnUrl, subscriptionId })).data : (await createPointsOrder({ returnUrl, packageId })).data; + if (!isPaymentRequestActive(requestSeq)) return null; + + if (res?.url) { + schedulePoll(res, "ALIPAY"); + location.href = res.url; + return res; + } + openPayNoticeModal("error", { + title: t("subscribe.pay_notice_start_failed_title"), + content: t("subscribe.pay_start_failed"), + okText: t("button.okay"), + }); + return null; + } catch { + if (isPaymentRequestActive(requestSeq)) { + openPayNoticeModal("error", { + title: t("subscribe.pay_notice_start_failed_title"), + content: t("subscribe.pay_start_failed"), + okText: t("button.okay"), + }); + } + return null; + } finally { + if (isPaymentRequestActive(requestSeq)) { + setSubmittingState(false); + } + } + }, [assertPlanAndLogin, isPaymentRequestActive, nextPaymentRequestSeq, payType, resolvePlanIds, schedulePoll, setSubmittingState, stopPolling, t]); const resumeWxPolling = useCallback(() => { if (wxOrderRef.current) { @@ -389,65 +440,46 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P } }, [schedulePoll]); - /** 换套餐:重置微信同意态,预拉微信码 */ - useEffect(() => { - if (!planId) return; - - const cancellation = { current: false }; + /** 换套餐:重置支付态,不自动创建订单 */ + useEffect(() => { + nextPaymentRequestSeq(); stopPolling(); + setSubmittingState(false); setWxAgreed(false); setPaymentMethod("WXPAY"); - setCodeUrl(""); wxOrderRef.current = null; + setCodeUrl(""); + }, [nextPaymentRequestSeq, planId, setSubmittingState, stopPolling]); - void (async () => { - if (!cancellation.current) { - await fetchWxOrder({ silent: true }); - } - })(); + const handlePaymentMethodChange = useCallback( + (method: PaymentMethod) => { + if (method === paymentMethod) return; + if (submittingRef.current) return; - return () => { - cancellation.current = true; - }; - }, [fetchWxOrder, planId, stopPolling]); - - const handlePaymentMethodChange = useCallback( - (method: PaymentMethod) => { - if (method === paymentMethod) return; - - stopPolling(); - setPaymentMethod(method); - - if (method === "WXPAY") { - if (!codeUrl && !wxOrderRef.current?.code_url) { - void fetchWxOrder(); - } else if (wxAgreed) { - resumeWxPolling(); - } - } - }, - [codeUrl, fetchWxOrder, paymentMethod, resumeWxPolling, stopPolling, wxAgreed], - ); - - const handleAgreeAndPay = useCallback(async () => { - if (submitting) return; - if (!assertPlanAndLogin()) return; - - if (paymentMethod === "ALIPAY") { - await fetchAlipayAndRedirect(); - return; - } - - setWxAgreed(true); - - let order: PaymentOrderData | null = wxOrderRef.current; - if (!order?.code_url && !codeUrl) { - order = await fetchWxOrder(); + nextPaymentRequestSeq(); + stopPolling(); + setPaymentMethod(method); + setWxAgreed(false); + setCodeUrl(""); + wxOrderRef.current = null; + }, + [nextPaymentRequestSeq, paymentMethod, stopPolling], + ); + + const handleAgreeAndPay = useCallback(async () => { + if (submittingRef.current) return; + + if (paymentMethod === "ALIPAY") { + await fetchAlipayAndRedirect(); + return; } - if (order) { - resumeWxPolling(); - } - }, [assertPlanAndLogin, codeUrl, fetchAlipayAndRedirect, fetchWxOrder, paymentMethod, resumeWxPolling, submitting]); + + const order = await fetchWxOrder(); + if (order?.code_url) { + setWxAgreed(true); + resumeWxPolling(); + } + }, [fetchAlipayAndRedirect, fetchWxOrder, paymentMethod, resumeWxPolling]); const wxLogo = new URL("@/assets/images/logo_wxpay.png", import.meta.url).href; const alipayLogo = new URL("@/assets/images/logo_alipay.png", import.meta.url).href; @@ -461,6 +493,7 @@ export default function PaySubscribe({ onClose, type, plan, afterPaySuccess }: P + {isPopoverOpen ? ( + + ) : null} as="span" className="voicePage__speechEmotionContent" /> @@ -1379,7 +1475,11 @@ function SpeechEmotionPopoverPortal({ editor, maxLength }: { editor: Editor | nu const applyEmotion = useCallback( (emotion: SpeechEmotionKey) => { if (!editor || !popover) return; - applySpeechEmotionToSelection(editor, popover, emotion, maxLength); + if (popover.kind === "selection") { + applySpeechEmotionToSelection(editor, popover, emotion, maxLength); + } else { + applySpeechEmotionToSegment(editor, popover, emotion, maxLength); + } closeSpeechEmotionPopover(); }, [editor, maxLength, popover], @@ -1395,22 +1495,29 @@ function SpeechEmotionPopoverPortal({ editor, maxLength }: { editor: Editor | nu style={{ top: popover.top, left: popover.left }} >
- {SPEECH_EMOTION_OPTIONS.map((emotion) => ( - - ))} + {SPEECH_EMOTION_OPTIONS.map((emotion) => { + const isActive = popover.kind === "segment" && popover.emotion === emotion; + return ( + + ); + })}
, document.body, diff --git a/src/pages/Voice/index.scss b/src/pages/Voice/index.scss index 0e329b9..a0569d2 100644 --- a/src/pages/Voice/index.scss +++ b/src/pages/Voice/index.scss @@ -2058,75 +2058,70 @@ $upload-crop-selection-rail-height: 3px; --speech-emotion-label: #6b7280; display: inline; - padding: 3px 5px; - border-radius: 6px; - background: var(--speech-emotion-bg); - box-decoration-break: clone; - -webkit-box-decoration-break: clone; } .voicePage__speechEmotionSegment_happy { - --speech-emotion-bg: #fff4c2; - --speech-emotion-label: #d49b00; + --speech-emotion-bg: rgba(246, 195, 68, 0.16); + --speech-emotion-label: rgb(246, 195, 68); } .voicePage__speechEmotionSegment_sad { - --speech-emotion-bg: #dfeeff; - --speech-emotion-label: #3977d3; + --speech-emotion-bg: rgba(90, 127, 191, 0.16); + --speech-emotion-label: rgb(90, 127, 191); } .voicePage__speechEmotionSegment_angry { - --speech-emotion-bg: #ffe1df; - --speech-emotion-label: #d94a48; + --speech-emotion-bg: rgba(200, 76, 76, 0.16); + --speech-emotion-label: rgb(200, 76, 76); } .voicePage__speechEmotionSegment_fearful { - --speech-emotion-bg: #eadfff; - --speech-emotion-label: #7a54d8; + --speech-emotion-bg: rgba(122, 108, 157, 0.16); + --speech-emotion-label: rgb(122, 108, 157); } .voicePage__speechEmotionSegment_disgusted { - --speech-emotion-bg: #dff4df; - --speech-emotion-label: #3f9c54; + --speech-emotion-bg: rgba(110, 139, 94, 0.16); + --speech-emotion-label: rgb(110, 139, 94); } .voicePage__speechEmotionSegment_surprised { - --speech-emotion-bg: #ffe9cf; - --speech-emotion-label: #dd7d22; + --speech-emotion-bg: rgba(242, 153, 74, 0.16); + --speech-emotion-label: rgb(242, 153, 74); } .voicePage__speechEmotionSegment_calm { - --speech-emotion-bg: #e8edf4; - --speech-emotion-label: #66758a; + --speech-emotion-bg: rgba(154, 160, 166, 0.16); + --speech-emotion-label: rgb(154, 160, 166); } .voicePage__speechEmotionSegment_fluent { - --speech-emotion-bg: #dff7f5; - --speech-emotion-label: #229b92; -} - -.voicePage__speechEmotionSegment_whisper { - --speech-emotion-bg: #efe7df; - --speech-emotion-label: #8a6a52; + --speech-emotion-bg: rgba(79, 179, 191, 0.16); + --speech-emotion-label: rgb(79, 179, 191); } .voicePage__speechEmotionLabel { display: inline-flex; align-items: center; gap: 3px; - min-height: 22px; + min-height: 24px; margin-right: 5px; - padding: 2px 5px; + padding: 2px 7px; border-radius: 6px; background: var(--speech-emotion-label); - font-size: 12px; + font-size: 13px; font-weight: 600; - line-height: 18px; + line-height: 20px; color: #ffffff; vertical-align: baseline; + cursor: pointer; user-select: none; } +.voicePage__speechEmotionLabel_active { + gap: 5px; +} + .voicePage__speechEmotionRemove { display: inline-flex; align-items: center; @@ -2136,10 +2131,10 @@ $upload-crop-selection-rail-height: 3px; margin: 0 -2px 0 0; padding: 0; border: none; - border-radius: 50%; - background: rgba(255, 255, 255, 0.24); + border-radius: 0; + background: transparent; color: #ffffff; - font-size: 10px; + font-size: 12px; font-weight: 700; line-height: 1; cursor: pointer; @@ -2147,6 +2142,10 @@ $upload-crop-selection-rail-height: 3px; .voicePage__speechEmotionContent { display: inline; + padding: 3px 5px; + background: var(--speech-emotion-bg); + box-decoration-break: clone; + -webkit-box-decoration-break: clone; } .voicePage__lyricsSectionTagPopover { @@ -2242,7 +2241,7 @@ $upload-crop-selection-rail-height: 3px; .voicePage__speechEmotionPopover { position: fixed; z-index: 10050; - width: 188px; + width: 155px; padding: 5px; border-radius: 9px; background: #ffffff; @@ -2261,22 +2260,25 @@ $upload-crop-selection-rail-height: 3px; align-items: center; justify-content: center; min-width: 0; + width: 70px; height: 24px; margin: 0; - padding: 0 8px; - border: 1px solid #e5e6eb; + padding: 0; + border: none; border-radius: 5px; background: #f9f9f9; - font-size: 12px; - font-weight: 500; + font-size: 14px; + font-weight: 400; line-height: normal; color: #666666; cursor: pointer; } -.voicePage__speechEmotionPopoverOption:hover { +.voicePage__speechEmotionPopoverOption:hover, +.voicePage__speechEmotionPopoverOption_active, +.voicePage__speechEmotionPopoverOption_active:hover { background: #f0f0f0; - color: #5c3bc7; + color: #666666; } .voicePage__speechPausePopover {