diff --git a/web/src/components/SiderBar.js b/web/src/components/SiderBar.js index 503dc81a..46d728da 100644 --- a/web/src/components/SiderBar.js +++ b/web/src/components/SiderBar.js @@ -80,7 +80,7 @@ const SiderBar = () => { itemKey: 'channel', to: '/channel', icon: , - className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle', + className: isAdmin() ? '' : 'tableHiddle', }, { text: t('聊天'), @@ -101,7 +101,7 @@ const SiderBar = () => { icon: , className: localStorage.getItem('enable_data_export') === 'true' - ? 'semi-navigation-item-normal' + ? '' : 'tableHiddle', }, { @@ -109,7 +109,7 @@ const SiderBar = () => { itemKey: 'redemption', to: '/redemption', icon: , - className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle', + className: isAdmin() ? '' : 'tableHiddle', }, { text: t('钱包'), @@ -122,7 +122,7 @@ const SiderBar = () => { itemKey: 'user', to: '/user', icon: , - className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle', + className: isAdmin() ? '' : 'tableHiddle', }, { text: t('日志'), @@ -137,7 +137,7 @@ const SiderBar = () => { icon: , className: localStorage.getItem('enable_drawing') === 'true' - ? 'semi-navigation-item-normal' + ? '' : 'tableHiddle', }, { @@ -147,7 +147,7 @@ const SiderBar = () => { icon: , className: localStorage.getItem('enable_task') === 'true' - ? 'semi-navigation-item-normal' + ? '' : 'tableHiddle', }, { diff --git a/web/src/helpers/render.js b/web/src/helpers/render.js index 310fc3ea..5342d741 100644 --- a/web/src/helpers/render.js +++ b/web/src/helpers/render.js @@ -1,6 +1,6 @@ import i18next from 'i18next'; import { Modal, Tag, Typography } from '@douyinfe/semi-ui'; -import { copy, showSuccess } from './utils.js'; +import { copy, isMobile, showSuccess } from './utils.js'; export function renderText(text, limit) { if (text.length > limit) { @@ -67,6 +67,73 @@ export function renderRatio(ratio) { return {ratio}x {i18next.t('倍率')}; } +const measureTextWidth = (text, style = { + fontSize: '14px', + fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' +}, containerWidth) => { + const span = document.createElement('span'); + + span.style.visibility = 'hidden'; + span.style.position = 'absolute'; + span.style.whiteSpace = 'nowrap'; + span.style.fontSize = style.fontSize; + span.style.fontFamily = style.fontFamily; + + span.textContent = text; + + document.body.appendChild(span); + const width = span.offsetWidth; + + document.body.removeChild(span); + + return width; +}; + +export function truncateText(text, maxWidth = 200) { + if (!isMobile()) { + return text; + } + if (!text) return text; + + try { + // Handle percentage-based maxWidth + let actualMaxWidth = maxWidth; + if (typeof maxWidth === 'string' && maxWidth.endsWith('%')) { + const percentage = parseFloat(maxWidth) / 100; + // Use window width as fallback container width + actualMaxWidth = window.innerWidth * percentage; + } + + const width = measureTextWidth(text); + if (width <= actualMaxWidth) return text; + + let left = 0; + let right = text.length; + let result = text; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const truncated = text.slice(0, mid) + '...'; + const currentWidth = measureTextWidth(truncated); + + if (currentWidth <= actualMaxWidth) { + result = truncated; + left = mid + 1; + } else { + right = mid - 1; + } + } + + return result; + } catch (error) { + console.warn('Text measurement failed, falling back to character count', error); + if (text.length > 20) { + return text.slice(0, 17) + '...'; + } + return text; + } +} + export const renderGroupOption = (item) => { const { disabled, diff --git a/web/src/pages/Playground/Playground.js b/web/src/pages/Playground/Playground.js index 3468d2b1..8579d1cc 100644 --- a/web/src/pages/Playground/Playground.js +++ b/web/src/pages/Playground/Playground.js @@ -7,7 +7,7 @@ import { SSE } from 'sse'; import { IconSetting } from '@douyinfe/semi-icons'; import { StyleContext } from '../../context/Style/index.js'; import { useTranslation } from 'react-i18next'; -import { renderGroupOption } from '../../helpers/render.js'; +import { renderGroupOption, truncateText } from '../../helpers/render.js'; const roleInfo = { user: { @@ -99,9 +99,10 @@ const Playground = () => { const { success, message, data } = res.data; if (success) { let localGroupOptions = Object.entries(data).map(([group, info]) => ({ - label: info.desc, + label: truncateText(info.desc, "50%"), value: group, - ratio: info.ratio + ratio: info.ratio, + fullLabel: info.desc // 保存完整文本用于tooltip })); if (localGroupOptions.length === 0) {