feat: add ThemeTag

This commit is contained in:
jialin
2025-04-28 10:05:06 +08:00
parent fb90d79eb3
commit 548e1378f5
8 changed files with 116 additions and 49 deletions
+28
View File
@@ -0,0 +1,28 @@
import useUserSettings from '@/hooks/use-user-settings';
import { Tag, TagProps } from 'antd';
import React from 'react';
const ThemeTag: React.FC<TagProps & { opacity?: number }> = ({
opacity,
style,
children,
...restProps
}) => {
const { userSettings } = useUserSettings();
const { isDarkTheme } = userSettings;
return (
<Tag
{...restProps}
style={{
...style,
opacity: isDarkTheme ? 1 : opacity
}}
>
{children}
</Tag>
);
};
ThemeTag.displayName = 'ThemeTag';
export default ThemeTag;
+19 -8
View File
@@ -2,8 +2,9 @@ import fallbackImg from '@/assets/images/img.png';
import AutoTooltip from '@/components/auto-tooltip'; import AutoTooltip from '@/components/auto-tooltip';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import TagWrapper from '@/components/tags-wrapper'; import TagWrapper from '@/components/tags-wrapper';
import ThemeTag from '@/components/tags-wrapper/theme-tag';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Tag, Typography } from 'antd'; import { Typography } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
@@ -31,9 +32,10 @@ const CatalogItem: React.FC<CatalogItemProps> = (props) => {
const renderTag = (sItem: any) => { const renderTag = (sItem: any) => {
return ( return (
<Tag <ThemeTag
key={sItem} key={sItem}
className="tag-item" className="tag-item"
opacity={0.7}
style={{ style={{
marginRight: 0, marginRight: 0,
display: 'flex', display: 'flex',
@@ -42,12 +44,11 @@ const CatalogItem: React.FC<CatalogItemProps> = (props) => {
padding: '2px 6px', padding: '2px 6px',
borderRadius: 4, borderRadius: 4,
fontSize: 12, fontSize: 12,
opacity: 0.7,
height: 22 height: 22
}} }}
> >
{sItem}B {sItem}B
</Tag> </ThemeTag>
); );
}; };
@@ -119,21 +120,31 @@ const CatalogItem: React.FC<CatalogItemProps> = (props) => {
<div className="tags"> <div className="tags">
{data.categories.map((sItem, i) => { {data.categories.map((sItem, i) => {
return ( return (
<Tag key={sItem} className="tag-item" color="blue"> <ThemeTag
key={sItem}
className="tag-item"
color="blue"
opacity={0.7}
>
{_.find(modelCategories, { value: sItem })?.label || sItem} {_.find(modelCategories, { value: sItem })?.label || sItem}
</Tag> </ThemeTag>
); );
})} })}
{data.capabilities?.length > 0 && {data.capabilities?.length > 0 &&
data.capabilities.map((sItem, i) => { data.capabilities.map((sItem, i) => {
return ( return (
<Tag key={sItem} className="tag-item" color="purple"> <ThemeTag
key={sItem}
className="tag-item"
color="purple"
opacity={0.7}
>
{_.map(_.split(sItem, '/'), (s: string) => { {_.map(_.split(sItem, '/'), (s: string) => {
return _.split(s, '_').join(' '); return _.split(s, '_').join(' ');
}) })
.reverse() .reverse()
.join(' ')} .join(' ')}
</Tag> </ThemeTag>
); );
})} })}
{data.sizes?.length > 0 && ( {data.sizes?.length > 0 && (
@@ -5,6 +5,7 @@ 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';
import StatusTag from '@/components/status-tag'; import StatusTag from '@/components/status-tag';
import ThemeTag from '@/components/tags-wrapper/theme-tag';
import { HandlerOptions } from '@/hooks/use-chunk-fetch'; import { HandlerOptions } from '@/hooks/use-chunk-fetch';
import useDownloadStream from '@/hooks/use-download-stream'; import useDownloadStream from '@/hooks/use-download-stream';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
@@ -17,7 +18,7 @@ import {
ThunderboltFilled ThunderboltFilled
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Col, Progress, Row, Tag, Tooltip, notification } from 'antd'; import { Button, Col, Progress, Row, Tooltip, notification } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import _ from 'lodash'; import _ from 'lodash';
import React, { useCallback, useEffect, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo } from 'react';
@@ -480,7 +481,8 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
}} }}
title={renderDistributedServer(severList)} title={renderDistributedServer(severList)}
> >
<Tag <ThemeTag
opacity={0.75}
color="processing" color="processing"
style={{ style={{
marginRight: 0, marginRight: 0,
@@ -491,7 +493,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
overflow: 'hidden', overflow: 'hidden',
opacity: 0.75,
borderRadius: 12 borderRadius: 12
}} }}
> >
@@ -499,7 +500,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
{intl.formatMessage({ {intl.formatMessage({
id: 'models.table.acrossworker' id: 'models.table.acrossworker'
})} })}
</Tag> </ThemeTag>
</Tooltip> </Tooltip>
); );
}; };
@@ -533,7 +534,8 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
<InfoColumn fieldList={fieldList} data={offloadData}></InfoColumn> <InfoColumn fieldList={fieldList} data={offloadData}></InfoColumn>
} }
> >
<Tag <ThemeTag
opacity={0.75}
color="cyan" color="cyan"
style={{ style={{
display: 'flex', display: 'flex',
@@ -543,7 +545,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
overflow: 'hidden', overflow: 'hidden',
opacity: 0.75,
borderRadius: 12 borderRadius: 12
}} }}
> >
@@ -551,7 +552,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
{intl.formatMessage({ {intl.formatMessage({
id: 'models.table.cpuoffload' id: 'models.table.cpuoffload'
})} })}
</Tag> </ThemeTag>
</Tooltip> </Tooltip>
); );
}, [ }, [
+18 -14
View File
@@ -1,6 +1,7 @@
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import MarkdownViewer from '@/components/markdown-viewer'; import MarkdownViewer from '@/components/markdown-viewer';
import SimpleOverlay from '@/components/simple-overlay'; import SimpleOverlay from '@/components/simple-overlay';
import ThemeTag from '@/components/tags-wrapper/theme-tag';
import useRequestToken from '@/hooks/use-request-token'; import useRequestToken from '@/hooks/use-request-token';
import { import {
DownOutlined, DownOutlined,
@@ -8,7 +9,7 @@ import {
RightOutlined RightOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Empty, Spin, Tag, Tooltip } from 'antd'; import { Button, Empty, Spin, Tooltip } from 'antd';
import { some } from 'lodash'; import { some } from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css'; import 'overlayscrollbars/overlayscrollbars.css';
import React, { import React, {
@@ -317,26 +318,29 @@ const ModelCard: React.FC<{
<div className="model-card-wrap"> <div className="model-card-wrap">
<div className="flex-center"> <div className="flex-center">
{modelType && ( {modelType && (
<Tag className="tag-item" color="gold"> <ThemeTag className="tag-item" color="gold" opacity={0.65}>
<span style={{ opacity: 0.65 }}> <span className="m-r-5">
<span className="m-r-5"> {intl.formatMessage({ id: 'models.architecture' })}:
{intl.formatMessage({ id: 'models.architecture' })}:
</span>
{modelType}
</span> </span>
</Tag> {modelType}
</ThemeTag>
)} )}
{isGGUFModel && ( {isGGUFModel && (
<Tag className="tag-item" color="magenta"> <ThemeTag className="tag-item" color="magenta" opacity={0.65}>
<span style={{ opacity: 0.65 }}>GGUF</span> GGUF
</Tag> </ThemeTag>
)} )}
{!!modelTags.length && {!!modelTags.length &&
modelTags.map((tag: string, index: number) => { modelTags.map((tag: string, index: number) => {
return ( return (
<Tag className="tag-item" color="geekblue" key={index}> <ThemeTag
<span style={{ opacity: 0.65 }}>{tag}</span> className="tag-item"
</Tag> color="geekblue"
key={index}
opacity={0.65}
>
{tag}
</ThemeTag>
); );
})} })}
</div> </div>
@@ -1,8 +1,8 @@
import { TooltipOverlayScroller } from '@/components/overlay-scroller'; import { TooltipOverlayScroller } from '@/components/overlay-scroller';
import ThemeTag from '@/components/tags-wrapper/theme-tag';
import { convertFileSize } from '@/utils'; import { convertFileSize } from '@/utils';
import { InfoCircleOutlined } from '@ant-design/icons'; import { InfoCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Tag } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import React from 'react'; import React from 'react';
@@ -29,7 +29,8 @@ const FilePartsTag = (props: { parts: any[] }) => {
return ( return (
<TooltipOverlayScroller title={<FileParts fileList={parts}></FileParts>}> <TooltipOverlayScroller title={<FileParts fileList={parts}></FileParts>}>
<Tag <ThemeTag
opacity={0.7}
className="tag-item" className="tag-item"
color="purple" color="purple"
style={{ style={{
@@ -43,7 +44,7 @@ const FilePartsTag = (props: { parts: any[] }) => {
{ n: parts.length } { n: parts.length }
)} )}
</span> </span>
</Tag> </ThemeTag>
</TooltipOverlayScroller> </TooltipOverlayScroller>
); );
}; };
@@ -65,7 +66,8 @@ const ModelFileItem: React.FC<ModelFileItemProps> = (props) => {
const quanType = getFileType(path); const quanType = getFileType(path);
if (quanType) { if (quanType) {
return ( return (
<Tag <ThemeTag
opacity={0.7}
className="tag-item" className="tag-item"
color="cyan" color="cyan"
style={{ style={{
@@ -73,7 +75,7 @@ const ModelFileItem: React.FC<ModelFileItemProps> = (props) => {
}} }}
> >
{_.toUpper(quanType)} {_.toUpper(quanType)}
</Tag> </ThemeTag>
); );
} }
return null; return null;
@@ -91,7 +93,8 @@ const ModelFileItem: React.FC<ModelFileItemProps> = (props) => {
<div className="title">{item.path}</div> <div className="title">{item.path}</div>
<div className="tags flex-between"> <div className="tags flex-between">
<span className="flex-center gap-8"> <span className="flex-center gap-8">
<Tag <ThemeTag
opacity={0.7}
className="tag-item" className="tag-item"
color="green" color="green"
style={{ style={{
@@ -99,7 +102,7 @@ const ModelFileItem: React.FC<ModelFileItemProps> = (props) => {
}} }}
> >
{convertFileSize(item.size)} {convertFileSize(item.size)}
</Tag> </ThemeTag>
{getModelQuantizationType(item)} {getModelQuantizationType(item)}
<FilePartsTag parts={item.parts}></FilePartsTag> <FilePartsTag parts={item.parts}></FilePartsTag>
</span> </span>
@@ -37,7 +37,6 @@
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;
height: 22px; height: 22px;
opacity: 0.7;
} }
.btn { .btn {
+1 -1
View File
@@ -4,7 +4,7 @@
width: max-content; width: max-content;
height: max-content; height: max-content;
padding: 32px; padding: 32px;
background-color: rgba(255, 255, 255, 90%); background-color: var(--ant-modal-content-bg);
:global(.field-wrapper) { :global(.field-wrapper) {
background-color: transparent !important; background-color: transparent !important;
+32 -11
View File
@@ -3,6 +3,7 @@ import { userAtom } from '@/atoms/user';
import Footer from '@/components/footer'; import Footer from '@/components/footer';
import useUserSettings from '@/hooks/use-user-settings'; import useUserSettings from '@/hooks/use-user-settings';
import { useModel } from '@umijs/max'; import { useModel } from '@umijs/max';
import { ConfigProvider, theme } from 'antd';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useEffect } from 'react'; import { useEffect } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -37,7 +38,7 @@ const FormWrapper = styled.div`
width: max-content; width: max-content;
height: max-content; height: max-content;
padding: 32px; padding: 32px;
background-color: rgba(255, 255, 255, 90%); background-color: var(--ant-modal-content-bg);
.field-wrapper { .field-wrapper {
background-color: transparent !important; background-color: transparent !important;
@@ -49,10 +50,15 @@ const FormWrapper = styled.div`
`; `;
const Login = () => { const Login = () => {
const { themeData } = useUserSettings(); const { themeData, userSettings } = useUserSettings();
const { token } = theme.useToken();
const [userInfo, setUserInfo] = useAtom(userAtom); const [userInfo, setUserInfo] = useAtom(userAtom);
const { initialState, setInitialState } = useModel('@@initialState') || {}; const { initialState, setInitialState } = useModel('@@initialState') || {};
const globalCssvars: Record<string, any> = {
'--ant-modal-content-bg': 'rgba(255, 255, 255, 0.9)'
};
const gotoDefaultPage = async (userInfo: any) => { const gotoDefaultPage = async (userInfo: any) => {
if (!userInfo || userInfo?.require_password_change) { if (!userInfo || userInfo?.require_password_change) {
return; return;
@@ -74,15 +80,30 @@ const Login = () => {
}, []); }, []);
return ( return (
<div> <ConfigProvider
<Wrapper></Wrapper> componentSize="large"
<Box> key={userSettings.colorPrimary}
<FormWrapper> theme={{
{userInfo?.require_password_change ? <PasswordForm /> : <LoginForm />} algorithm: userSettings.isDarkTheme
</FormWrapper> ? theme.darkAlgorithm
<Footer /> : theme.defaultAlgorithm,
</Box> ...themeData
</div> }}
>
<div style={globalCssvars}>
<Wrapper></Wrapper>
<Box>
<FormWrapper>
{userInfo?.require_password_change ? (
<PasswordForm />
) : (
<LoginForm />
)}
</FormWrapper>
<Footer />
</Box>
</div>
</ConfigProvider>
); );
}; };