fix: remove unused code and deps & optimize subtitle logic.

This commit is contained in:
quemingyi.wudong 2025-04-11 18:22:52 +08:00
parent b79f5bcfc5
commit dc4124e362
10 changed files with 18 additions and 365 deletions

View File

@ -7,12 +7,9 @@
"@reduxjs/toolkit": "^1.8.3",
"@volcengine/rtc": "4.66.1",
"@arco-design/web-react": "^2.65.0",
"autolinker": "^4.0.0",
"i18next": "^21.8.16",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-i18next": "^11.18.3",
"react-redux": "^8.0.2",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",

View File

@ -1,38 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
.bubbleWrapper {
position: relative;
width: 118px;
height: 46px;
.bubbleLogo {
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
z-index: 1;
}
.bubbleText {
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 13px;
color: black;
font-weight: 400;
line-height: 16px;
text-align: center;
top: 0px;
}
.bubble-direction-left {
transform: scaleX(-1);
}
}

View File

@ -1,35 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
import React from 'react';
import Bubble from '@/assets/img/bubble.svg';
import styles from './index.module.less';
type IBubbleMsgProps = {
text?: string;
direction?: 'left' | 'right';
} & React.HTMLAttributes<HTMLDivElement>;
enum Direction {
Left = 'left',
Right = 'right',
}
function BubbleMsg(props: IBubbleMsgProps) {
const { text = '', direction = Direction.Right, style = {}, className = '' } = props;
return (
<div style={style} className={`${styles.bubbleWrapper} ${className}`}>
<img
className={`${styles.bubbleLogo} ${styles[`bubble-direction-${direction}`]}`}
src={Bubble}
alt="Logo"
/>
<div className={styles.bubbleText}>{text}</div>
</div>
);
}
export default BubbleMsg;

View File

@ -1,48 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
.wrapper {
width: max-content;
padding: 4px 4px;
border-radius: 4px;
border: 1px solid;
display: flex;
flex-direction: row;
justify-content: flex-start;
gap: 4px;
align-items: center;
background: var(--background-color-bg-5, rgba(241, 243, 245, 1));
border: 0px;
.item {
cursor: pointer;
color: var(--text-color-text-2, rgba(66, 70, 78, 1));
font-family: PingFang SC;
font-size: 13px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0.003em;
text-align: center;
border: 0px;
}
.selected {
box-shadow: 0px 0px 0px 1px rgba(213, 219, 227, 0.7);
background: var(--background-color-bg-1, rgba(255, 255, 255, 1));
border-radius: 4px;
}
.selected-text {
background: linear-gradient(90deg, #004FFF 38.86%, #9865FF 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-family: PingFang SC;
font-size: 13px;
font-weight: 500;
line-height: 22px;
letter-spacing: 0.003em;
}
}

View File

@ -1,43 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
import { useMemo } from 'react';
import { Button } from '@arco-design/web-react';
import styles from './index.module.less';
interface IProps {
value?: string;
onChange: (key: string) => void;
options: {
label: string;
key: string;
}[];
}
function ButtonRadio(props: IProps) {
const { value, onChange, options } = props;
const selected =
useMemo(() => options.find((item) => item.key === value), [value]) || options?.[0];
const handleClick = (key: string) => {
onChange?.(key);
};
return (
<div className={styles.wrapper}>
{options.map(({ label, key }) => (
<Button
type="text"
key={key}
className={`${styles.item} ${key === selected.key ? styles.selected : ''}`}
onClick={() => handleClick(key)}
>
<span className={key === selected.key ? styles['selected-text'] : ''}>{label}</span>
</Button>
))}
</div>
);
}
export default ButtonRadio;

View File

@ -1,36 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
import { useEffect, useRef } from 'react';
const getDom = async (url: string) => {
const res = await fetch(url);
if (res) {
const text = await res.text();
// https://developer.mozilla.org/zh-CN/docs/Web/API/DOMParser
return new window.DOMParser().parseFromString(text, 'text/xml');
}
return undefined;
};
function MenuIcon({ src, className = '' }: { src: string; className?: string }) {
const wrapper = useRef<HTMLDivElement>(null);
const renderSVG = async () => {
const svg = await getDom(src);
if (svg?.documentElement instanceof SVGSVGElement) {
wrapper.current?.replaceChildren(svg.documentElement);
}
};
useEffect(() => {
src && renderSVG();
}, [src]);
return <span ref={wrapper} className={className} />;
}
export default MenuIcon;

View File

@ -1,69 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
/* AudioWave.css */
@keyframes audioWave {
0% {
transform: scale(0.5);
opacity: 1;
}
100% {
transform: scale(2.5);
opacity: 0;
}
}
.wave-container {
position: absolute;
width: 150px;
height: 150px;
}
.wave {
position: absolute;
border: 1px solid gray;
border-color: rgba(0, 0, 0, .06);
border-radius: 50%;
width: 100%;
height: 100%;
animation: audioWave 9s infinite;
opacity: 0;
}
.wave:nth-child(1) {
animation-delay: -1s;
}
.wave:nth-child(2) {
animation-delay: -2s;
}
.wave:nth-child(3) {
animation-delay: -3s;
}
.wave:nth-child(4) {
animation-delay: -4s;
}
.wave:nth-child(5) {
animation-delay: -5s;
}
.wave:nth-child(6) {
animation-delay: -6s;
}
.wave:nth-child(7) {
animation-delay: -7s;
}
.wave:nth-child(8) {
animation-delay: -8s;
}
.wave:nth-child(9) {
animation-delay: -9s;
}

View File

@ -1,26 +0,0 @@
/**
* Copyright 2025 Beijing Volcano Engine Technology Co., Ltd. All Rights Reserved.
* SPDX-license-identifier: BSD-3-Clause
*/
import React from 'react';
import styles from './index.module.less';
type IRippleWaveProps = React.HTMLAttributes<HTMLDivElement>;
const LEVEL = 9;
function RippleWave(props: IRippleWaveProps) {
const { className = '', style = {} } = props;
return (
<div style={style} className={`${styles['wave-container']} ${className}`}>
{Array(LEVEL)
.fill(0)
.map((_, index) => {
return <div key={`ripple-level-${index}`} className={styles.wave} />;
})}
</div>
);
}
export default RippleWave;

View File

@ -230,40 +230,18 @@ export const roomSlice = createSlice({
},
setHistoryMsg: (state, { payload }) => {
const { paragraph, definite } = payload;
const lastMsg = state.msgHistory.at(-1)! || {};
/** 是否需要再创建新句子 */
const shouldCreateSentence = payload.definite;
state.isUserTalking = payload.user === state.localUser.userId;
const fromBot = payload.user === config.BotName;
/**
* Bot definite
* User paragraph
*/
const lastMsgCompleted = fromBot ? lastMsg.definite : lastMsg.paragraph;
if (state.msgHistory.length) {
const lastMsg = state.msgHistory.at(-1)!;
/** 当前讲话人更新字幕 */
if (lastMsg.user === payload.user) {
/** 如果上一句话是完整的 & 本次的话也是完整的, 则直接塞入 */
if (lastMsg.definite) {
state.msgHistory.push({
value: payload.text,
time: new Date().toString(),
user: payload.user,
definite,
paragraph,
});
} else {
/** 话未说完, 更新文字内容 */
lastMsg.value = payload.text;
lastMsg.time = new Date().toString();
lastMsg.paragraph = paragraph;
lastMsg.definite = definite;
lastMsg.user = payload.user;
}
/** 如果本次的话已经说完了, 提前塞入空字符串做准备 */
if (shouldCreateSentence) {
state.msgHistory.push({
value: '',
time: new Date().toString(),
user: '',
});
}
} else {
/** 换人说话了,塞入新句子 */
/** 如果上一句话是完整的则新增语句 */
if (lastMsgCompleted) {
state.msgHistory.push({
value: payload.text,
time: new Date().toString(),
@ -271,6 +249,13 @@ export const roomSlice = createSlice({
definite,
paragraph,
});
} else {
/** 话未说完, 更新文字内容 */
lastMsg.value = payload.text;
lastMsg.time = new Date().toString();
lastMsg.paragraph = paragraph;
lastMsg.definite = definite;
lastMsg.user = payload.user;
}
} else {
/** 首句话首字不会被打断 */

View File

@ -1059,7 +1059,7 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.9", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
@ -2638,13 +2638,6 @@ at-least-node@^1.0.0:
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
autolinker@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-4.0.0.tgz#aa1f9a52786b727b0ecee8cd7d4a97e0e3ef59f1"
integrity sha512-fl5Kh6BmEEZx+IWBfEirnRUU5+cOiV0OK7PEt0RBKvJMJ8GaRseIOeDU3FKf4j3CE5HVefcjHmhYPOcaVt0bZw==
dependencies:
tslib "^2.3.0"
autoprefixer@^10.4.7:
version "10.4.8"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.8.tgz#92c7a0199e1cfb2ad5d9427bd585a3d75895b9e5"
@ -4971,13 +4964,6 @@ html-minifier-terser@^6.0.2:
relateurl "^0.2.7"
terser "^5.10.0"
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "3.1.0"
html-tags@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961"
@ -5077,13 +5063,6 @@ human-signals@^2.1.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
i18next@^21.8.16:
version "21.8.16"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.8.16.tgz#31fe4682e4e2077dbf229a88e5a58b7020e4ddc8"
integrity sha512-acJLCk38YMfEPjBR/1vS13SFY7rBQLs9E5m1tSRnWc9UW3f+SZszgH+NP1fZRA1+O+CdG2eLGGmuUMJW52EwzQ==
dependencies:
"@babel/runtime" "^7.17.2"
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@ -7759,14 +7738,6 @@ react-helmet@^6.1.0:
react-fast-compare "^3.1.1"
react-side-effect "^2.1.0"
react-i18next@^11.18.3:
version "11.18.3"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.3.tgz#50211810bcc9fdea2d70c8aefdfff5f1eb39a923"
integrity sha512-EttTX31HbqzZymUM3SIrMPuvamfSXFZVsDHm/ZAqoDfTLjhzlwyxqfbDNxcKNAGOi2mjZaXfR7hSNMlvLNpB/g==
dependencies:
"@babel/runtime" "^7.14.5"
html-parse-stringify "^3.0.1"
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@ -9327,11 +9298,6 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
w3c-hr-time@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"