refactor(mcp settings): enhance NpxSearch component layout and styling (#4053)

* refactor: mcp setting ui refactor

* refactor(mcp settings): enhance NpxSearch component layout and styling
This commit is contained in:
Teo 2025-03-28 15:08:24 +08:00 committed by GitHub
parent 5712a58a5e
commit eeb537048b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 65 additions and 46 deletions

View File

@ -8,6 +8,7 @@ import { Button, Card, Flex, Input, Space, Spin, Tag, Typography } from 'antd'
import { npxFinder } from 'npx-scope-finder' import { npxFinder } from 'npx-scope-finder'
import { type FC, useState } from 'react' import { type FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled, { css } from 'styled-components'
import { SettingDivider, SettingGroup, SettingTitle } from '..' import { SettingDivider, SettingGroup, SettingTitle } from '..'
@ -27,7 +28,7 @@ let _searchResults: SearchResult[] = []
const NpxSearch: FC = () => { const NpxSearch: FC = () => {
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
const { Paragraph, Text, Link } = Typography const { Text, Link } = Typography
// Add new state variables for npm scope search // Add new state variables for npm scope search
const [npmScope, setNpmScope] = useState('@modelcontextprotocol') const [npmScope, setNpmScope] = useState('@modelcontextprotocol')
@ -87,42 +88,44 @@ const NpxSearch: FC = () => {
} }
return ( return (
<SettingGroup theme={theme}> <SettingGroup theme={theme} css={SettingGroupCss}>
<SettingTitle>{t('settings.mcp.npx_list.title')}</SettingTitle> <div>
<SettingDivider /> <SettingTitle>
<Paragraph type="secondary" style={{ margin: '0 0 10px 0' }}> {t('settings.mcp.npx_list.title')} <Text type="secondary">{t('settings.mcp.npx_list.desc')}</Text>
{t('settings.mcp.npx_list.desc')} </SettingTitle>
</Paragraph> <SettingDivider />
<Space direction="vertical" style={{ width: '100%' }}> <Space direction="vertical" style={{ width: '100%' }}>
<Space.Compact style={{ width: '100%', marginBottom: 10 }}> <Space.Compact style={{ width: '100%', marginBottom: 10 }}>
<Input <Input
placeholder={t('settings.mcp.npx_list.scope_placeholder')} placeholder={t('settings.mcp.npx_list.scope_placeholder')}
value={npmScope} value={npmScope}
onChange={(e) => setNpmScope(e.target.value)} onChange={(e) => setNpmScope(e.target.value)}
onPressEnter={handleNpmSearch} onPressEnter={handleNpmSearch}
/> />
<Button icon={<SearchOutlined />} onClick={handleNpmSearch} disabled={searchLoading}> <Button icon={<SearchOutlined />} onClick={handleNpmSearch} disabled={searchLoading}>
{t('settings.mcp.npx_list.search')} {t('settings.mcp.npx_list.search')}
</Button> </Button>
</Space.Compact> </Space.Compact>
<HStack alignItems="center" mt="-5px" mb="5px">
<HStack alignItems="center" mt="-5px" mb="5px"> {npmScopes.map((scope) => (
{npmScopes.map((scope) => ( <Tag
<Tag key={scope}
key={scope} onClick={() => {
onClick={() => { if (!searchLoading) {
if (!searchLoading) { setNpmScope(scope)
setNpmScope(scope) setTimeout(handleNpmSearch, 100)
setTimeout(handleNpmSearch, 100) }
} }}
}} style={{ cursor: searchLoading ? 'not-allowed' : 'pointer' }}>
style={{ cursor: searchLoading ? 'not-allowed' : 'pointer' }}> {scope}
{scope} </Tag>
</Tag> ))}
))} </HStack>
</HStack> </Space>
</div>
<ResultList>
{searchLoading ? ( {searchLoading ? (
<div style={{ textAlign: 'center', padding: '20px' }}> <div style={{ textAlign: 'center', padding: '20px' }}>
<Spin /> <Spin />
@ -139,7 +142,7 @@ const NpxSearch: FC = () => {
} }
extra={ extra={
<Flex> <Flex>
<Tag bordered={false} color="magenta"> <Tag bordered={false} color="processing">
v{record.version} v{record.version}
</Tag> </Tag>
<Button <Button
@ -162,22 +165,38 @@ const NpxSearch: FC = () => {
</Flex> </Flex>
}> }>
<Space direction="vertical" size="small"> <Space direction="vertical" size="small">
<Text ellipsis={{ tooltip: true }}>{record.description}</Text> <Text>{record.description}</Text>
<Text ellipsis={{ tooltip: true }} type="secondary"> <Text type="secondary">
{t('settings.mcp.npx_list.usage')}: {record.usage} {t('settings.mcp.npx_list.usage')}: {record.usage}
</Text> </Text>
<Text ellipsis={{ tooltip: true }}> <Link href={record.npmLink} target="_blank" rel="noopener noreferrer">
<Link href={record.npmLink} target="_blank" rel="noopener noreferrer"> {record.npmLink}
{record.npmLink} </Link>
</Link>
</Text>
</Space> </Space>
</Card> </Card>
)) ))
) : null} ) : null}
</Space> </ResultList>
</SettingGroup> </SettingGroup>
) )
} }
const SettingGroupCss = css`
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 0;
`
const ResultList = styled.div`
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
width: calc(100% + 10px);
padding-right: 4px;
overflow-y: scroll;
`
export default NpxSearch export default NpxSearch

View File

@ -1,7 +1,7 @@
import { ThemeMode } from '@renderer/types' import { ThemeMode } from '@renderer/types'
import { Divider } from 'antd' import { Divider } from 'antd'
import Link from 'antd/es/typography/Link' import Link from 'antd/es/typography/Link'
import styled from 'styled-components' import styled, { CSSProp } from 'styled-components'
export const SettingContainer = styled.div<{ theme?: ThemeMode }>` export const SettingContainer = styled.div<{ theme?: ThemeMode }>`
display: flex; display: flex;
@ -80,7 +80,7 @@ export const SettingHelpLink = styled(Link)`
margin: 0 5px; margin: 0 5px;
` `
export const SettingGroup = styled.div<{ theme?: ThemeMode }>` export const SettingGroup = styled.div<{ theme?: ThemeMode; css?: CSSProp }>`
margin-bottom: 20px; margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
border: 0.5px solid var(--color-border); border: 0.5px solid var(--color-border);