style: overlay scroller

This commit is contained in:
jialin
2025-04-28 10:05:06 +08:00
parent 838e0f9910
commit 4b748ee43a
18 changed files with 144 additions and 149 deletions
+2 -1
View File
@@ -8,7 +8,8 @@ module.exports = {
'@typescript-eslint/class-name-casing': 'off' '@typescript-eslint/class-name-casing': 'off'
}, },
globals: { globals: {
Global: 'readonly' Global: 'readonly',
React: 'readonly'
}, },
ignorePatterns: ['public/static/'] ignorePatterns: ['public/static/']
}; };
+8 -19
View File
@@ -8,7 +8,7 @@ import React, {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import TitleTip from './title-tip'; import { TooltipOverlayScroller } from '../overlay-scroller';
// type TagProps = React.ComponentProps<typeof Tag>; // type TagProps = React.ComponentProps<typeof Tag>;
@@ -91,23 +91,12 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
); );
return ( return (
<Tooltip <TooltipOverlayScroller
overlayInnerStyle={{ paddingInline: 0 }} toolTipProps={{
destroyTooltipOnHide={false} ...tooltipProps,
title={ destroyTooltipOnHide: false
isOverflowing || showTitle ? ( }}
<TitleTip title={isOverflowing || showTitle ? children : false}
isOverflowing={isOverflowing}
title={title}
showTitle={showTitle}
>
{children}
</TitleTip>
) : (
false
)
}
{...tooltipProps}
> >
{ghost ? ( {ghost ? (
<div ref={contentRef} style={tagStyle} data-overflow={isOverflowing}> <div ref={contentRef} style={tagStyle} data-overflow={isOverflowing}>
@@ -139,7 +128,7 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
{children} {children}
</Tag> </Tag>
)} )}
</Tooltip> </TooltipOverlayScroller>
); );
}; };
+4 -13
View File
@@ -1,4 +1,4 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import { OverlayScroller } from '@/components/overlay-scroller';
import React from 'react'; import React from 'react';
interface TitleTipProps { interface TitleTipProps {
@@ -10,27 +10,18 @@ interface TitleTipProps {
const TitleTip: React.FC<TitleTipProps> = (props) => { const TitleTip: React.FC<TitleTipProps> = (props) => {
const { isOverflowing, showTitle, title, children } = props; const { isOverflowing, showTitle, title, children } = props;
const { initialize } = useOverlayScroller();
const scrollRef = React.useRef<any>(null);
React.useEffect(() => {
if (scrollRef.current) {
initialize(scrollRef.current);
}
}, [initialize, scrollRef.current]);
return ( return (
<div style={{ maxHeight: 200, overflowY: 'auto' }} ref={scrollRef}> <OverlayScroller maxHeight={200}>
<div <div
style={{ style={{
width: 'fit-content', width: 'fit-content',
maxWidth: 'var(--width-tooltip-max)', maxWidth: 'var(--width-tooltip-max)'
paddingInline: 8
}} }}
> >
{isOverflowing || showTitle ? title || children : ''} {isOverflowing || showTitle ? title || children : ''}
</div> </div>
</div> </OverlayScroller>
); );
}; };
+1 -16
View File
@@ -13,24 +13,9 @@
padding-inline: 12px 10px; padding-inline: 12px 10px;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
background-color: rgb(56, 56, 56); background-color: var(--color-editor-header-bg);
.ant-select-selector {
background-color: rgba(255, 255, 255, 9%) !important;
color: rgba(255, 255, 255, 70%);
border-radius: var(--border-radius-2px);
.ant-select-selection-item {
color: rgba(255, 255, 255, 70%);
}
}
.ant-select-arrow {
color: rgba(255, 255, 255, 70%);
}
} }
// set scrollbar style // set scrollbar style
.scrollbar { .scrollbar {
.slider { .slider {
border-radius: 6px; border-radius: 6px;
@@ -36,7 +36,7 @@ const CodeHeaderWrapper = styled.div`
border-top-left-radius: 4px; border-top-left-radius: 4px;
border-top-right-radius: 4px; border-top-right-radius: 4px;
&.dark { &.dark {
background-color: #383838; background-color: var(--color-editor-header-bg);
color: rgba(255, 255, 255, 0.65); color: rgba(255, 255, 255, 0.65);
} }
`; `;
+5 -2
View File
@@ -9,6 +9,7 @@ const HighlightCode: React.FC<{
lang?: string; lang?: string;
copyable?: boolean; copyable?: boolean;
theme?: 'light' | 'dark'; theme?: 'light' | 'dark';
fixedTheme?: 'light' | 'dark';
height?: string | number; height?: string | number;
style?: React.CSSProperties; style?: React.CSSProperties;
copyValue?: string; copyValue?: string;
@@ -19,14 +20,16 @@ const HighlightCode: React.FC<{
copyValue, copyValue,
lang = 'bash', lang = 'bash',
copyable = true, copyable = true,
theme = 'dark', theme,
height = 'auto' height = 'auto'
} = props; } = props;
const { userSettings } = useUserSettings(); const { userSettings } = useUserSettings();
const currentTheme = React.useMemo(() => { const currentTheme = React.useMemo(() => {
return theme || userSettings.theme === 'realDark' ? 'dark' : 'light'; const res = theme || userSettings.theme === 'realDark' ? 'dark' : 'light';
console.log('currentTheme:', res, userSettings.theme, '===>', theme);
return res;
}, [theme, userSettings.theme]); }, [theme, userSettings.theme]);
return ( return (
+3 -1
View File
@@ -31,7 +31,9 @@ const LogsList: React.FC<LogsListProps> = forwardRef((props, ref) => {
initialized initialized
} = useOverlayScroller({ } = useOverlayScroller({
options: { options: {
theme: 'os-theme-light' scrollbars: {
theme: 'os-theme-light'
}
} }
}); });
const [innerHieght, setInnerHeight] = useState( const [innerHieght, setInnerHeight] = useState(
@@ -33,10 +33,7 @@ const CodeViewer = (props: any) => {
); );
}; };
const FullMarkdown: React.FC<FullMarkdownProps> = ({ const FullMarkdown: React.FC<FullMarkdownProps> = ({ content, theme }) => {
content,
theme = 'light'
}) => {
const escapedContent = useMemo(() => { const escapedContent = useMemo(() => {
return escapeMhchem(escapeBrackets(escapeDollarNumber(content))); return escapeMhchem(escapeBrackets(escapeDollarNumber(content)));
}, [content]); }, [content]);
@@ -1,5 +1,4 @@
.markdown-viewer { .markdown-viewer {
font-family: var(--font-family) !important;
word-break: break-word; word-break: break-word;
font-size: var(--font-size-base); font-size: var(--font-size-base);
+42 -13
View File
@@ -1,4 +1,6 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller, {
OverlayScrollerOptions
} from '@/hooks/use-overlay-scroller';
import { Tooltip, TooltipProps } from 'antd'; import { Tooltip, TooltipProps } from 'antd';
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -10,16 +12,18 @@ const Wrapper = styled.div<{ $maxHeight?: number }>`
width: 100%; width: 100%;
`; `;
const OverlayScroller: React.FC<any> = ({ export const OverlayScroller: React.FC<
children, OverlayScrollerOptions & {
maxHeight, maxHeight?: number;
theme, style?: React.CSSProperties;
style children: React.ReactNode;
}) => { }
> = ({ children, maxHeight, scrollbars, oppositeTheme, style }) => {
const scroller = React.useRef<any>(null); const scroller = React.useRef<any>(null);
const { initialize } = useOverlayScroller({ const { initialize } = useOverlayScroller({
options: { options: {
theme: theme || 'os-theme-light' scrollbars,
oppositeTheme
} }
}); });
@@ -36,7 +40,6 @@ const OverlayScroller: React.FC<any> = ({
className="overlay-scroller-wrapper" className="overlay-scroller-wrapper"
$maxHeight={maxHeight || 200} $maxHeight={maxHeight || 200}
hidden={false} hidden={false}
as="div"
style={{ style={{
paddingInlineStart: 8, paddingInlineStart: 8,
paddingInlineEnd: 8, paddingInlineEnd: 8,
@@ -48,17 +51,43 @@ const OverlayScroller: React.FC<any> = ({
); );
}; };
/**
*
* @param maxHeight: use for scrollbars
* @param theme: because this component is used for tooltip, so the default theme always is light
* @returns
*/
export const TooltipOverlayScroller: React.FC< export const TooltipOverlayScroller: React.FC<
TooltipProps & { maxHeight?: number } OverlayScrollerOptions & {
> = ({ children, maxHeight, title, ...rest }) => { maxHeight?: number;
title?: React.ReactNode;
children: React.ReactNode;
toolTipProps?: TooltipProps;
}
> = ({
children,
maxHeight,
title,
toolTipProps,
scrollbars,
oppositeTheme
}) => {
const { overlayInnerStyle, ...rest } = toolTipProps || {};
return ( return (
<Tooltip <Tooltip
overlayInnerStyle={{ overlayInnerStyle={{
paddingInline: 0 paddingInline: 0,
...overlayInnerStyle
}} }}
title={ title={
title && ( title && (
<OverlayScroller maxHeight={maxHeight}>{title}</OverlayScroller> <OverlayScroller
scrollbars={{ ...scrollbars, theme: 'os-theme-light' }}
maxHeight={maxHeight}
oppositeTheme={oppositeTheme}
>
{title}
</OverlayScroller>
) )
} }
{...rest} {...rest}
+6 -17
View File
@@ -1,4 +1,3 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import 'simplebar-react/dist/simplebar.min.css'; import 'simplebar-react/dist/simplebar.min.css';
@@ -37,29 +36,19 @@ export interface ColumnProps {
interface SimpleTableProps { interface SimpleTableProps {
theme?: 'dark' | 'light'; theme?: 'dark' | 'light';
maxHeight?: number | string;
columns: ColumnProps[]; columns: ColumnProps[];
dataSource: any[]; dataSource: any[];
bordered?: boolean; bordered?: boolean;
rowKey?: string; rowKey: string;
} }
const SimpleTabel: React.FC<SimpleTableProps> = (props) => { const SimpleTabel: React.FC<SimpleTableProps> = (props) => {
const { const { columns, dataSource, rowKey, bordered = true } = props;
columns,
dataSource,
rowKey,
bordered = true,
theme = 'dark'
} = props;
const scroller = React.useRef<any>(null);
const { initialize } = useOverlayScroller();
React.useEffect(() => {
initialize(scroller.current);
}, [initialize]);
return ( return (
<div style={{ maxHeight: 240 }} ref={scroller}> <div>
<table <table
className={classNames('simple-table', theme, { className={classNames('simple-table', {
'simple-table-bordered': bordered 'simple-table-bordered': bordered
})} })}
> >
@@ -74,7 +63,7 @@ const SimpleTabel: React.FC<SimpleTableProps> = (props) => {
rowIndex={index} rowIndex={index}
columns={columns} columns={columns}
dataList={dataSource} dataList={dataSource}
key={rowKey ? item[rowKey] : index} key={item[rowKey]}
></TableRow> ></TableRow>
); );
})} })}
-5
View File
@@ -25,8 +25,3 @@
} }
} }
} }
.simplebar-scrollbar::before {
background: var(--color-scroll-bg);
width: var(--scrollbar-size);
}
+30 -33
View File
@@ -3,10 +3,10 @@ import { StatusType } from '@/config/types';
import { InfoCircleOutlined } from '@ant-design/icons'; import { InfoCircleOutlined } from '@ant-design/icons';
import { Button, Divider, Tooltip } from 'antd'; import { Button, Divider, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useMemo } from 'react';
import 'simplebar-react/dist/simplebar.min.css'; import 'simplebar-react/dist/simplebar.min.css';
import CopyButton from '../copy-button'; import CopyButton from '../copy-button';
import SimpleOverlay from '../simple-overlay'; import { TooltipOverlayScroller } from '../overlay-scroller';
import CopyStyle from './copy-btn.less'; import CopyStyle from './copy-btn.less';
import './index.less'; import './index.less';
@@ -47,17 +47,13 @@ const StatusTag: React.FC<StatusTagProps> = ({
type = 'tag' type = 'tag'
}) => { }) => {
const { text, status } = statusValue; const { text, status } = statusValue;
const [statusColor, setStatusColor] = useState<{
const statusColor = useMemo<{
text: string; text: string;
bg: string; bg: string;
border?: string; border?: string;
}>({ }>(() => {
text: '', return StatusColorMap[status];
bg: ''
});
useEffect(() => {
setStatusColor(StatusColorMap[status]);
}, [status]); }, [status]);
const statusMessage = useMemo(() => { const statusMessage = useMemo(() => {
@@ -85,6 +81,7 @@ const StatusTag: React.FC<StatusTagProps> = ({
} }
return <span>{text}</span>; return <span>{text}</span>;
}; };
const renderTitle = useMemo(() => { const renderTitle = useMemo(() => {
return ( return (
<div className={CopyStyle['status-content-wrapper']}> <div className={CopyStyle['status-content-wrapper']}>
@@ -118,24 +115,21 @@ const StatusTag: React.FC<StatusTagProps> = ({
})} })}
</div> </div>
<SimpleOverlay style={{ maxHeight: 200 }}> <div
<div style={{
style={{ width: 'max-content',
width: 'max-content', maxWidth: 250,
maxWidth: 250, whiteSpace: 'pre-wrap',
paddingInline: 10, wordBreak: 'break-word'
whiteSpace: 'pre-wrap', }}
wordBreak: 'break-word' >
}} {statusMessage}
> {statusMessage && <span className="m-r-5"></span>}
{statusMessage} {extra}
{statusMessage && <span className="m-r-5"></span>} {messageLink && (
{extra} <span dangerouslySetInnerHTML={{ __html: messageLink }}></span>
{messageLink && ( )}
<span dangerouslySetInnerHTML={{ __html: messageLink }}></span> </div>
)}
</div>
</SimpleOverlay>
</div> </div>
); );
}, [statusValue]); }, [statusValue]);
@@ -150,11 +144,14 @@ const StatusTag: React.FC<StatusTagProps> = ({
}} }}
> >
{statusValue.message ? ( {statusValue.message ? (
<Tooltip <TooltipOverlayScroller
trigger={['hover']}
title={renderTitle} title={renderTitle}
destroyTooltipOnHide={true} scrollbars={{
overlayInnerStyle={{ paddingInline: 0 }} autoHide: 'never'
}}
toolTipProps={{
destroyTooltipOnHide: true
}}
> >
<span className="txt err"> <span className="txt err">
<span className="m-r-5"> <span className="m-r-5">
@@ -162,7 +159,7 @@ const StatusTag: React.FC<StatusTagProps> = ({
</span> </span>
{renderContent()} {renderContent()}
</span> </span>
</Tooltip> </TooltipOverlayScroller>
) : ( ) : (
<span className="txt">{renderContent()}</span> <span className="txt">{renderContent()}</span>
)} )}
+5 -6
View File
@@ -13,6 +13,7 @@ html {
--scrollbar-handle-hover-bg: rgba(0, 0, 0, 55%); --scrollbar-handle-hover-bg: rgba(0, 0, 0, 55%);
--color-editor-dark: #282c34; --color-editor-dark: #282c34;
--color-editor-light: #fafafa; --color-editor-light: #fafafa;
--color-editor-header-bg: #383838;
--color-scrollbar-track: #f4f5f4; // according to: --ant-color-fill-tertiary --color-scrollbar-track: #f4f5f4; // according to: --ant-color-fill-tertiary
--color-fill-sider: #f4f5f4; --color-fill-sider: #f4f5f4;
--color-bg-1: #f4f5f4; --color-bg-1: #f4f5f4;
@@ -69,13 +70,10 @@ html {
--seal-transition-func: cubic-bezier(0, 0, 1, 1); --seal-transition-func: cubic-bezier(0, 0, 1, 1);
--color-green-fill-light: rgb(243 251 248); --color-green-fill-light: rgb(243 251 248);
--ant-rate-star-color: #fadb14; --ant-rate-star-color: #fadb14;
--color-fill-mask: rgba(255, 255, 255, 60%); --color-fill-spin-bg: rgba(255, 255, 255, 60%);
--width-tooltip-max: 300px; --width-tooltip-max: 300px;
--color-bg-tooltip: '#fff'; --color-bg-tooltip: '#fff';
// ======== input ============ // ======== input ============
--ant-input-active-shadow: 0 0 0 2px rgba(5, 255, 105, 6%);
--ant-input-active-border-color: #007bff;
--ant-input-hover-border-color: #2997ff;
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%); --box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
--ant-border-radius-lg: 4px; --ant-border-radius-lg: 4px;
--color-selected-bg: rgba(230, 230, 230, 88%); --color-selected-bg: rgba(230, 230, 230, 88%);
@@ -88,10 +86,11 @@ html[data-theme='realDark'] {
--color-logs-bg: #141414; --color-logs-bg: #141414;
--color-white-1: #141414; --color-white-1: #141414;
--color-fill-sider: #1f1f1f; --color-fill-sider: #1f1f1f;
--color-editor-dark: #141414; --color-editor-dark: #00101f;
--color-editor-light: #fafafa; --color-editor-light: #fafafa;
--color-fill-mask: rgba(255, 255, 255, 10%); --color-fill-spin-bg: rgba(55, 55, 55, 50%);
--color-bg-tooltip: #424242; --color-bg-tooltip: #424242;
--color-editor-header-bg: #292929;
background: #141414; background: #141414;
} }
+24 -9
View File
@@ -1,11 +1,20 @@
import { userSettingsHelperAtom } from '@/atoms/settings';
import { useAtom } from 'jotai';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import { import {
UseOverlayScrollbarsParams, UseOverlayScrollbarsParams,
useOverlayScrollbars useOverlayScrollbars
} from 'overlayscrollbars-react'; } from 'overlayscrollbars-react';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import useUserSettings from './use-user-settings';
export interface OverlayScrollerOptions {
oppositeTheme?: boolean;
scrollbars?: {
theme?: 'os-theme-light' | 'os-theme-dark';
autoHide?: 'never' | 'scroll' | 'leave' | 'move';
autoHideDelay?: number;
clickScroll?: boolean | 'instant';
};
}
export const overlaySollerOptions: UseOverlayScrollbarsParams = { export const overlaySollerOptions: UseOverlayScrollbarsParams = {
options: { options: {
@@ -25,13 +34,19 @@ export const overlaySollerOptions: UseOverlayScrollbarsParams = {
defer: true defer: true
}; };
/**
*
* @param options.theme: if set theme, it will fix the theme
* @returns
*/
export default function useOverlayScroller(data?: { export default function useOverlayScroller(data?: {
options?: any; options?: OverlayScrollerOptions;
events?: any; events?: any;
defer?: boolean; defer?: boolean;
}) { }) {
const [useSettings] = useAtom(userSettingsHelperAtom); const { userSettings } = useUserSettings();
const { options, events, defer = true } = data || {}; const { options, events, defer = true } = data || {};
const { scrollbars, oppositeTheme } = options || {};
const scrollEventElement = React.useRef<any>(null); const scrollEventElement = React.useRef<any>(null);
const instanceRef = React.useRef<any>(null); const instanceRef = React.useRef<any>(null);
const initialized = React.useRef(false); const initialized = React.useRef(false);
@@ -47,13 +62,13 @@ export default function useOverlayScroller(data?: {
x: 'hidden' x: 'hidden'
}, },
scrollbars: { scrollbars: {
theme:
options?.theme || useSettings.theme === 'light'
? 'os-theme-dark'
: 'os-theme-light',
autoHide: 'scroll', autoHide: 'scroll',
autoHideDelay: 600, autoHideDelay: 600,
clickScroll: 'instant' clickScroll: 'instant',
...scrollbars,
theme:
scrollbars?.theme ||
(userSettings.theme === 'light' ? 'os-theme-dark' : 'os-theme-light')
} }
}, },
events: { events: {
@@ -1,6 +1,7 @@
import AutoTooltip from '@/components/auto-tooltip'; import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons'; import DropdownButtons from '@/components/drop-down-buttons';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import { TooltipOverlayScroller } from '@/components/overlay-scroller';
import RowChildren from '@/components/seal-table/components/row-children'; import RowChildren from '@/components/seal-table/components/row-children';
import SimpleTabel, { ColumnProps } from '@/components/simple-table'; import SimpleTabel, { ColumnProps } from '@/components/simple-table';
import InfoColumn from '@/components/simple-table/info-column'; import InfoColumn from '@/components/simple-table/info-column';
@@ -137,6 +138,7 @@ const RenderRayactorDownloading = (props: {
<SimpleTabel <SimpleTabel
columns={downloadList} columns={downloadList}
dataSource={[...mainWorker, ...list]} dataSource={[...mainWorker, ...list]}
rowKey="worker_name"
theme="light" theme="light"
></SimpleTabel> ></SimpleTabel>
</div> </div>
@@ -473,11 +475,13 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
return null; return null;
} }
return ( return (
<Tooltip <TooltipOverlayScroller
overlayInnerStyle={{ toolTipProps={{
width: 'max-content', overlayInnerStyle: {
maxWidth: '520px', width: 'max-content',
minWidth: '400px' maxWidth: '520px',
minWidth: '400px'
}
}} }}
title={renderDistributedServer(severList)} title={renderDistributedServer(severList)}
> >
@@ -501,7 +505,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
id: 'models.table.acrossworker' id: 'models.table.acrossworker'
})} })}
</ThemeTag> </ThemeTag>
</Tooltip> </TooltipOverlayScroller>
); );
}; };
+1 -1
View File
@@ -58,7 +58,7 @@
top: 0; top: 0;
padding-top: 150px; padding-top: 150px;
text-align: center; text-align: center;
background-color: var(--color-fill-mask); background-color: var(--color-fill-spin-bg);
} }
} }
@@ -284,7 +284,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef((props, ref) => {
<OverlayScroller <OverlayScroller
maxHeight={500} maxHeight={500}
style={{ paddingInline: '16px' }} style={{ paddingInline: '16px' }}
theme="os-theme-dark" oppositeTheme={true}
> >
<DynamicParams <DynamicParams
ref={formRef} ref={formRef}