mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
♻️ refactor: refactor static style (#11010)
* refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style * refactor: refactor static style
This commit is contained in:
@@ -0,0 +1,959 @@
|
||||
# createStaticStyles 迁移指南
|
||||
|
||||
## 📖 概述
|
||||
|
||||
`createStaticStyles` 是 `antd-style` 提供的静态样式创建函数,相比 `createStyles`(hook 方案)具有零运行时开销的优势。样式在模块加载时计算一次,而不是每次组件渲染时计算。
|
||||
|
||||
## 🎯 适用场景
|
||||
|
||||
### ✅ 可以优化的场景
|
||||
|
||||
1. **纯静态样式**:不依赖运行时动态值
|
||||
2. **使用标准 token**:所有 token 都在 `cssVar.json` 中有对应项
|
||||
3. **简单的条件逻辑**:可以通过静态样式拆分处理
|
||||
|
||||
### ❌ 无法优化的场景
|
||||
|
||||
1. **JS 计算函数**:`readableColor()`, `chroma()`, `mix()`, `calc()` 中使用 token 数值
|
||||
2. **复杂的动态 props**:需要运行时计算的复杂逻辑
|
||||
3. **动态 prefixCls**:需要运行时传入的类名前缀(但可以硬编码为 `'ant'`)
|
||||
|
||||
## 🔄 基本转换步骤
|
||||
|
||||
### 1. 样式文件转换
|
||||
|
||||
**之前(createStyles):**
|
||||
|
||||
```typescript
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => {
|
||||
return {
|
||||
root: css`
|
||||
color: ${token.colorText};
|
||||
font-size: ${token.fontSize}px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
**之后(createStaticStyles):**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
root: css`
|
||||
color: ${cssVar.colorText};
|
||||
font-size: ${cssVar.fontSize};
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 组件文件转换
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { useStyles } from './style';
|
||||
|
||||
const Component = () => {
|
||||
const { styles, cx } = useStyles();
|
||||
return <div className={cx(styles.root, className)} />;
|
||||
};
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
import { cx } from 'antd-style';
|
||||
import { styles } from './style';
|
||||
|
||||
const Component = () => {
|
||||
return <div className={cx(styles.root, className)} />;
|
||||
};
|
||||
```
|
||||
|
||||
## 🛠️ 常见场景处理
|
||||
|
||||
### 场景 1: Token 转换
|
||||
|
||||
**规则:**
|
||||
|
||||
- `token.xxx` → `cssVar.xxx`
|
||||
- 注意:`cssVar.fontSize` 已经包含 `px` 单位,不需要再加 `px`
|
||||
|
||||
**示例:**
|
||||
|
||||
```typescript
|
||||
// ❌ 错误
|
||||
font-size: ${cssVar.fontSize}px; // cssVar.fontSize 已经是 "14px"
|
||||
|
||||
// ✅ 正确
|
||||
font-size: ${cssVar.fontSize}; // 直接使用
|
||||
```
|
||||
|
||||
**特殊情况 - calc ():**
|
||||
|
||||
```typescript
|
||||
// ❌ 错误
|
||||
calc(${token.fontSize}px * 2.5)
|
||||
|
||||
// ✅ 正确
|
||||
calc(${cssVar.fontSize} * 2.5) // cssVar.fontSize 已经包含单位
|
||||
```
|
||||
|
||||
### 场景 2: 动态 Props → CSS 变量
|
||||
|
||||
**适用:** 数值、字符串类型的 props
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 在样式文件中使用 CSS 变量(带默认值)
|
||||
2. 在组件中通过 `style` prop 设置 CSS 变量
|
||||
|
||||
**示例:**
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
export const styles = createStaticStyles(({ css }) => {
|
||||
return {
|
||||
root: css`
|
||||
width: var(--component-size, 24px);
|
||||
height: var(--component-size, 24px);
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const Component = ({ size = 24, style, ...rest }) => {
|
||||
const cssVariables = useMemo<Record<string, string>>(
|
||||
() => ({
|
||||
'--component-size': `${size}px`,
|
||||
}),
|
||||
[size],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.root}
|
||||
style={{
|
||||
...cssVariables,
|
||||
...style,
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Video`: `maxHeight`, `maxWidth`, `minHeight`, `minWidth`
|
||||
- `ScrollShadow`: `size`
|
||||
- `MaskShadow`: `size`
|
||||
- `ColorSwatches`: `size`
|
||||
- `Grid`: `rows`, `maxItemWidth`, `gap`
|
||||
- `Layout`: `headerHeight`
|
||||
- `Footer`: `contentMaxWidth`
|
||||
|
||||
### 场景 3: 布尔值 Props → 静态样式拆分
|
||||
|
||||
**适用:** 简单的布尔值 props(2-3 个)
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 创建所有可能的组合样式
|
||||
2. 运行时使用 `cx` 组合
|
||||
|
||||
**示例:**
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
export const styles = createStaticStyles(({ css }) => {
|
||||
return {
|
||||
root: css`
|
||||
/* base styles */
|
||||
`,
|
||||
root_closable_true: css`
|
||||
/* closable styles */
|
||||
`,
|
||||
root_closable_false: css`
|
||||
/* no closable styles */
|
||||
`,
|
||||
root_hasTitle_true: css`
|
||||
/* has title styles */
|
||||
`,
|
||||
root_hasTitle_false: css`
|
||||
/* no title styles */
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
const Component = ({ closable, hasTitle }) => {
|
||||
const className = cx(
|
||||
styles.root,
|
||||
styles[`root_closable_${!!closable}`],
|
||||
styles[`root_hasTitle_${!!hasTitle}`],
|
||||
);
|
||||
return <div className={className} />;
|
||||
};
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Alert`: `closable`, `hasTitle`, `showIcon` → 8 个组合(2×2×2)
|
||||
- `Image`: `alwaysShowActions` → 2 个样式
|
||||
- `StoryBook`: `noPadding` → 2 个样式
|
||||
|
||||
### 场景 4: isDarkMode → 静态样式拆分
|
||||
|
||||
**适用:** 依赖 `isDarkMode` 的条件样式
|
||||
|
||||
**有两种处理方式:**
|
||||
|
||||
#### 方式 A: 直接条件选择(简单场景)
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 创建 `Dark` 和 `Light` 两个静态样式
|
||||
2. 运行时根据 `theme.isDarkMode` 选择
|
||||
|
||||
**示例:**
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
rootDark: css`
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
color: ${cssVar.colorTextLightSolid};
|
||||
`,
|
||||
rootLight: css`
|
||||
background: ${cssVar.colorFillQuaternary};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { useThemeMode } from 'antd-style';
|
||||
|
||||
const Component = () => {
|
||||
const { isDarkMode } = useThemeMode();
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
isDarkMode ? styles.rootDark : styles.rootLight
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
#### 方式 B: 使用 cva 将 isDarkMode 作为 variant(推荐,适用于复杂场景)
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 创建 `Dark` 和 `Light` 两个静态样式
|
||||
2. 在 `cva` 中将 `isDarkMode` 作为 variant prop
|
||||
3. 运行时直接传入 `isDarkMode` 值
|
||||
|
||||
**示例:**
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { cva } from 'class-variance-authority';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
filledDark: css`
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
color: ${cssVar.colorTextLightSolid};
|
||||
`,
|
||||
filledLight: css`
|
||||
background: ${cssVar.colorFillQuaternary};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
outlined: css`
|
||||
border: 1px solid ${cssVar.colorBorder};
|
||||
`,
|
||||
root: css`
|
||||
/* base styles */
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export const variants = cva(styles.root, {
|
||||
defaultVariants: {
|
||||
isDarkMode: false,
|
||||
variant: 'filled',
|
||||
},
|
||||
variants: {
|
||||
isDarkMode: {
|
||||
false: null,
|
||||
true: null, // isDarkMode 本身不添加样式,通过 compoundVariants 组合
|
||||
},
|
||||
variant: {
|
||||
filled: null, // variant 本身不添加样式,通过 compoundVariants 组合
|
||||
outlined: styles.outlined,
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
class: styles.filledDark,
|
||||
isDarkMode: true,
|
||||
variant: 'filled',
|
||||
},
|
||||
{
|
||||
class: styles.filledLight,
|
||||
isDarkMode: false,
|
||||
variant: 'filled',
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { useThemeMode } from 'antd-style';
|
||||
import { variants } from './style';
|
||||
|
||||
const Component = ({ variant = 'filled' }) => {
|
||||
const { isDarkMode } = useThemeMode();
|
||||
return (
|
||||
<div
|
||||
className={variants({ isDarkMode, variant })}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**优势:**
|
||||
|
||||
- ✅ 不需要 `useMemo` 动态创建 variants
|
||||
- ✅ 更符合 `cva` 的设计理念
|
||||
- ✅ 代码更简洁,性能更好
|
||||
- ✅ 类型安全,IDE 自动补全
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `TypewriterEffect`: `textDark` / `textLight`(方式 A)
|
||||
- `Collapse`: `filledDark` / `filledLight`(可优化为方式 B)
|
||||
- `Hotkey`: `inverseThemeDark` / `inverseThemeLight`(可优化为方式 B)
|
||||
- `GuideCard`: `filledDark` / `filledLight`(可优化为方式 B)
|
||||
- `GradientButton`: `buttonDark` / `buttonLight`(方式 A)
|
||||
|
||||
### 场景 5: responsive → 静态 responsive
|
||||
|
||||
**适用:** 使用响应式断点
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 导入静态 `responsive` from `antd-style`
|
||||
2. 使用 `responsive.sm` 替代 `responsive.mobile`
|
||||
3. 从 `createStyles` 参数中移除 `responsive`
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css, responsive }) => ({
|
||||
root: css`
|
||||
${responsive.mobile} {
|
||||
padding: 12px;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { responsive } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
root: css`
|
||||
${responsive.sm} {
|
||||
padding: 12px;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**注意:**
|
||||
|
||||
- `responsive.mobile` → `responsive.sm`
|
||||
- 静态 `responsive` 提供:`xs`, `sm`, `md`, `lg`, `xl`, `xxl`
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Header`: `responsive.mobile` → `responsive.sm`
|
||||
- `FormModal`: `responsive.mobile` → `responsive.sm`
|
||||
- `Hero`: `responsive.mobile` → `responsive.sm`
|
||||
|
||||
### 场景 6: stylish → lobeStaticStylish
|
||||
|
||||
**适用:** 使用自定义 `stylish` 工具
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 导入 `lobeStaticStylish` from `@/styles`
|
||||
2. 替换 `stylish.xxx` → `lobeStaticStylish.xxx`
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css, stylish }) => ({
|
||||
root: css`
|
||||
${stylish.blur};
|
||||
${stylish.variantFilled};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
import { lobeStaticStylish } from '@/styles';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
root: css`
|
||||
${lobeStaticStylish.blur};
|
||||
${lobeStaticStylish.variantFilled};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Button`: `stylish.blur` → `lobeStaticStylish.blur`
|
||||
- `Hero`: `stylish.gradientAnimation` → `lobeStaticStylish.gradientAnimation`
|
||||
|
||||
### 场景 7: prefixCls → 硬编码
|
||||
|
||||
**适用:** 使用动态 `prefixCls` 参数
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 在文件顶部硬编码 `const prefixCls = 'ant'`
|
||||
2. 从 `createStyles` 参数中移除 `prefixCls`
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
export const useStyles = createStyles(({ css }, prefixCls: string) => ({
|
||||
root: css`
|
||||
.${prefixCls}-button {
|
||||
/* styles */
|
||||
}
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
const prefixCls = 'ant';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
root: css`
|
||||
.${prefixCls}-button {
|
||||
/* styles */
|
||||
}
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Alert`, `Collapse`, `FormModal`, `Image`, `Burger`, `DraggablePanel`, `DraggableSideNav`, `Toc`, `ColorSwatches`, `EmojiPicker`, `Form`, `awesome/Features`
|
||||
|
||||
### 场景 8: readableColor () → Token 替换
|
||||
|
||||
**适用:** 使用 `readableColor()` 计算对比色
|
||||
|
||||
**规则:**
|
||||
|
||||
- `readableColor(token.colorPrimary)` → `cssVar.colorTextLightSolid`(主色背景用白色文字)
|
||||
- `readableColor(token.colorTextQuaternary)` → `cssVar.colorText`(浅色背景用深色文字)
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { readableColor } from 'polished';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => ({
|
||||
checked: css`
|
||||
background-color: ${token.colorPrimary};
|
||||
color: ${readableColor(token.colorPrimary)};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
checked: css`
|
||||
background-color: ${cssVar.colorPrimary};
|
||||
color: ${cssVar.colorTextLightSolid};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Checkbox`: `readableColor(token.colorPrimary)` → `cssVar.colorTextLightSolid`
|
||||
|
||||
### 场景 9: rgba () → color-mix ()
|
||||
|
||||
**适用:** 使用 `rgba()` 设置透明度
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 使用 CSS 原生的 `color-mix()` 函数
|
||||
2. 格式:`color-mix(in srgb, ${cssVar.xxx} alpha%, transparent)`
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { rgba } from 'polished';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => ({
|
||||
root: css`
|
||||
background-color: ${rgba(token.colorBgLayout, 0.4)};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
background-color: color-mix(in srgb, ${cssVar.colorBgLayout} 40%, transparent);
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Header`: `rgba(cssVar.colorBgLayout, 0.4)` → `color-mix(...)`
|
||||
- `FormModal`: `rgba(cssVar.colorBgContainer, 0)` → `color-mix(...)`
|
||||
|
||||
### 场景 10: keyframes → css
|
||||
|
||||
**适用:** 使用 `keyframes` 创建动画
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 在 `createStaticStyles` 外部定义 `keyframes`
|
||||
2. 在样式内部使用
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
export const useStyles = createStyles(({ css, keyframes }) => {
|
||||
const spin = keyframes`
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
`;
|
||||
return {
|
||||
icon: css`
|
||||
animation: ${spin} 1s linear infinite;
|
||||
`,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
import { keyframes } from 'antd-style';
|
||||
|
||||
const spin = keyframes`
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
`;
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
icon: css`
|
||||
animation: ${spin} 1s linear infinite;
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `Icon`: `keyframes` 动画
|
||||
- `Skeleton`: `keyframes` shimmer 动画
|
||||
|
||||
## ⚠️ 反模式:避免使用 createVariants (isDarkMode)
|
||||
|
||||
**不推荐的做法:**
|
||||
|
||||
```typescript
|
||||
// ❌ 不推荐:在组件中动态创建 variants
|
||||
export const createVariants = (isDarkMode: boolean) =>
|
||||
cva(styles.root, {
|
||||
variants: {
|
||||
variant: {
|
||||
filled: isDarkMode ? styles.filledDark : styles.filledLight,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 组件中
|
||||
const variants = useMemo(() => createVariants(isDarkMode), [isDarkMode]);
|
||||
```
|
||||
|
||||
**推荐的做法:**
|
||||
|
||||
将 `isDarkMode` 作为 `cva` 的 variant prop(见场景 4 方式 B),这样:
|
||||
|
||||
- ✅ 不需要 `useMemo` 动态创建
|
||||
- ✅ 更符合 `cva` 的设计理念
|
||||
- ✅ 代码更简洁,性能更好
|
||||
- ✅ 类型安全,IDE 自动补全
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:将 isDarkMode 作为 variant prop
|
||||
export const variants = cva(styles.root, {
|
||||
variants: {
|
||||
isDarkMode: {
|
||||
false: null,
|
||||
true: null,
|
||||
},
|
||||
variant: {
|
||||
filled: null,
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
class: styles.filledDark,
|
||||
isDarkMode: true,
|
||||
variant: 'filled',
|
||||
},
|
||||
{
|
||||
class: styles.filledLight,
|
||||
isDarkMode: false,
|
||||
variant: 'filled',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 组件中
|
||||
const { isDarkMode } = useThemeMode();
|
||||
const className = variants({ isDarkMode, variant: 'filled' });
|
||||
```
|
||||
|
||||
## ⚠️ 无法优化的场景
|
||||
|
||||
### 1. JS 计算函数
|
||||
|
||||
**无法优化:**
|
||||
|
||||
- `chroma()` - 颜色计算库
|
||||
- `readableColor()` - 需要运行时计算(但可以用 token 替代)
|
||||
- `mix()` - 颜色混合计算
|
||||
- `calc()` 中使用 token 数值进行复杂计算
|
||||
|
||||
**示例:**
|
||||
|
||||
```typescript
|
||||
// ❌ 无法优化
|
||||
const scale = chroma.bezier([token.colorText, backgroundColor]).scale().colors(6);
|
||||
```
|
||||
|
||||
### 2. 复杂的动态 Props
|
||||
|
||||
**无法优化:**
|
||||
|
||||
- 需要复杂计算的 props
|
||||
- 对象 / 数组类型的 props
|
||||
- 函数类型的 props
|
||||
|
||||
### 3. useTheme Hook
|
||||
|
||||
**无法优化:**
|
||||
|
||||
- 直接使用 `useTheme()` hook 获取运行时值
|
||||
- 例如:`awesome/Giscus/style.ts` 使用 `useTheme()` 获取主题值
|
||||
|
||||
## 📋 迁移检查清单
|
||||
|
||||
### 样式文件检查
|
||||
|
||||
- [ ] `createStyles` → `createStaticStyles`
|
||||
- [ ] `token.xxx` → `cssVar.xxx`
|
||||
- [ ] 移除 `px` 后缀(`cssVar` 已包含单位)
|
||||
- [ ] `responsive.mobile` → `responsive.sm`(如果使用)
|
||||
- [ ] `stylish.xxx` → `lobeStaticStylish.xxx`(如果使用)
|
||||
- [ ] `rgba()` → `color-mix()`(如果使用)
|
||||
- [ ] `readableColor()` → token 替换(如果使用)
|
||||
- [ ] `prefixCls` 参数 → 硬编码 `const prefixCls = 'ant'`(如果使用)
|
||||
- [ ] `isDarkMode` → 静态样式拆分(如果使用)
|
||||
- [ ] 动态 props → CSS 变量(如果使用)
|
||||
|
||||
### 组件文件检查
|
||||
|
||||
- [ ] `useStyles()` → `import { styles } from './style'`
|
||||
- [ ] `import { cx } from 'antd-style'`(如果需要)
|
||||
- [ ] `import { useTheme } from 'antd-style'`(如果需要 `theme.isDarkMode`)
|
||||
- [ ] 动态 props → CSS 变量设置(如果使用)
|
||||
- [ ] `isDarkMode` 条件 → `theme.isDarkMode` 判断(如果使用)
|
||||
|
||||
## 🎯 优化优先级
|
||||
|
||||
### 高优先级(简单优化)
|
||||
|
||||
1. ✅ 纯静态样式(无动态 props)
|
||||
2. ✅ `isDarkMode` 拆分
|
||||
3. ✅ `responsive.mobile` → `responsive.sm`
|
||||
4. ✅ `stylish` → `lobeStaticStylish`
|
||||
5. ✅ `readableColor()` → token 替换
|
||||
|
||||
### 中优先级(需要转换)
|
||||
|
||||
6. ✅ 简单的动态 props → CSS 变量(1-2 个)
|
||||
7. ✅ 布尔值 props → 静态样式拆分(2-3 个)
|
||||
|
||||
### 低优先级(复杂优化)
|
||||
|
||||
8. ⚠️ 多个动态 props → CSS 变量(3+ 个)
|
||||
9. ⚠️ 复杂的条件逻辑拆分
|
||||
|
||||
## 📚 参考示例
|
||||
|
||||
### 完整示例 1: 简单组件
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
padding: ${cssVar.padding};
|
||||
color: ${cssVar.colorText};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { cx } from 'antd-style';
|
||||
import { styles } from './style';
|
||||
|
||||
const Component = ({ className }) => {
|
||||
return <div className={cx(styles.root, className)} />;
|
||||
};
|
||||
```
|
||||
|
||||
### 完整示例 2: 带动态 Props
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
width: var(--component-size, 24px);
|
||||
height: var(--component-size, 24px);
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { cx } from 'antd-style';
|
||||
import { useMemo } from 'react';
|
||||
import { styles } from './style';
|
||||
|
||||
const Component = ({ size = 24, className, style, ...rest }) => {
|
||||
const cssVariables = useMemo<Record<string, string>>(
|
||||
() => ({
|
||||
'--component-size': `${size}px`,
|
||||
}),
|
||||
[size],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(styles.root, className)}
|
||||
style={{
|
||||
...cssVariables,
|
||||
...style,
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 完整示例 3: 带 isDarkMode
|
||||
|
||||
**样式文件:**
|
||||
|
||||
```typescript
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
rootDark: css`
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
color: ${cssVar.colorTextLightSolid};
|
||||
`,
|
||||
rootLight: css`
|
||||
background: ${cssVar.colorFillQuaternary};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
}));
|
||||
```
|
||||
|
||||
**组件文件:**
|
||||
|
||||
```typescript
|
||||
import { cx, useTheme } from 'antd-style';
|
||||
import { styles } from './style';
|
||||
|
||||
const Component = ({ className }) => {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
theme.isDarkMode ? styles.rootDark : styles.rootLight,
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## 🔍 验证步骤
|
||||
|
||||
1. **类型检查:** `pnpm run type-check`
|
||||
2. **运行时测试:** 确保视觉效果一致
|
||||
3. **性能验证:** 检查样式计算是否在模块加载时完成
|
||||
|
||||
## 📊 优化效果
|
||||
|
||||
- ✅ **零运行时开销**:样式在模块加载时计算一次
|
||||
- ✅ **减少重新渲染**:组件不再依赖样式 hook
|
||||
- ✅ **更好的性能**:减少每次渲染的计算开销
|
||||
- ✅ **代码更简洁**:直接导入样式对象
|
||||
|
||||
## 🔧 场景 11: useTheme () → useThemeMode () /cssVar
|
||||
|
||||
**适用:** 组件中只使用 `theme.isDarkMode` 或其他 token 值
|
||||
|
||||
**规则:**
|
||||
|
||||
- 如果只使用 `theme.isDarkMode`,使用 `const { isDarkMode } = useThemeMode()` 替代
|
||||
- 如果使用其他 token(如 `theme.colorText`, `theme.borderRadius` 等),使用 `cssVar` 替代
|
||||
- `useThemeMode()` 比 `useTheme()` 更轻量,只返回 `isDarkMode` 值
|
||||
|
||||
**示例:**
|
||||
|
||||
**之前:**
|
||||
|
||||
```typescript
|
||||
import { useTheme } from 'antd-style';
|
||||
|
||||
const Component = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<div className={theme.isDarkMode ? styles.dark : styles.light}>
|
||||
{theme.colorText}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**之后:**
|
||||
|
||||
```typescript
|
||||
import { cssVar, useThemeMode } from 'antd-style';
|
||||
|
||||
const Component = () => {
|
||||
const { isDarkMode } = useThemeMode();
|
||||
return (
|
||||
<div className={isDarkMode ? styles.dark : styles.light}>
|
||||
{cssVar.colorText}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**已优化示例:**
|
||||
|
||||
- `AuroraBackground`, `Select`, `Input`, `Button`, `DatePicker`, `AutoComplete`, `InputNumber`, `InputPassword`, `InputOPT`, `TextArea`, `SpotlightCardItem`, `Spotlight`, `HotkeyInput` - 只使用 `isDarkMode` → `useThemeMode()`
|
||||
- `Image`, `GradientButton`, `Empty`, `FileTypeIcon`, `FormSubmitFooter`, `CodeEditor`, `LobeChat`, `Drawer`, `Modal`, `Avatar`, `AvatarGroup`, `SkeletonAvatar`, `SkeletonButton`, `SkeletonTags`, `Callout`, `LobeHub`, `GridBackground`, `FolderIcon`, `FileIcon`, `TokenTag`, `ChatSendButton`, `AvatarUploader` - 使用 token → `cssVar`
|
||||
|
||||
**无法优化的文件(需要保留 `useTheme()`):**
|
||||
|
||||
- `useMermaid`, `useStreamMermaid`, `useHighlight`, `useStreamHighlight` - 需要完整的 theme 对象传给第三方库
|
||||
- `Alert`, `Tag`, `Menu`, `EmojiPicker` - 需要实际颜色值传给颜色计算函数
|
||||
- `SkeletonTitle`, `SkeletonTags` - 需要数值进行数学运算
|
||||
- `GridShowcase`, `GridBackground/demos` - 需要实际颜色值传给 `rgba()` 函数
|
||||
- `CustomFonts` - 需要实际字符串值进行字符串拼接
|
||||
- `Giscus/style.ts` - 需要实际颜色值传给 `readableColor()` 和 `rgba()` 函数(其他 token 已优化为 `cssVar`)
|
||||
|
||||
**注意事项:**
|
||||
|
||||
- `useThemeMode()` 只返回 `{ isDarkMode }`,不返回完整的 theme 对象
|
||||
- `cssVar` 的值是字符串(如 `"14px"`, `"#ffffff"`),可以直接在 JSX 中使用
|
||||
- 如果 token 需要用于数值计算(如 `Math.round(theme.fontSize * 1.5)`),需要保留 `useTheme()`
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
`createStaticStyles` 迁移是一个渐进式的优化过程。对于简单的静态样式,可以直接转换;对于复杂的动态场景,需要根据具体情况选择合适的优化策略。关键是要理解每种场景的处理方式,并灵活运用 CSS 变量、静态样式拆分等技术。
|
||||
|
||||
### useTheme () 优化总结
|
||||
|
||||
- ✅ **使用 `useThemeMode()`**:当组件只使用 `theme.isDarkMode` 时
|
||||
- ✅ **使用 `cssVar`**:当组件使用其他 token 值(颜色、尺寸等)时
|
||||
- ⚠️ **保留 `useTheme()`**:当 token 需要用于数值计算或传给第三方库时
|
||||
+9
-6
@@ -132,6 +132,8 @@
|
||||
]
|
||||
},
|
||||
"overrides": {
|
||||
"@lobehub/ui": "^4.3.11",
|
||||
"antd-style": "^4.1.0",
|
||||
"stylelint-config-clean-order": "7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -195,15 +197,15 @@
|
||||
"@lobechat/utils": "workspace:*",
|
||||
"@lobechat/web-crawler": "workspace:*",
|
||||
"@lobehub/analytics": "^1.6.0",
|
||||
"@lobehub/charts": "^4.0.0",
|
||||
"@lobehub/charts": "^4.0.2",
|
||||
"@lobehub/chat-plugin-sdk": "^1.32.4",
|
||||
"@lobehub/chat-plugins-gateway": "^1.9.0",
|
||||
"@lobehub/desktop-ipc-typings": "workspace:*",
|
||||
"@lobehub/editor": "^3.1.1",
|
||||
"@lobehub/icons": "^4.0.0",
|
||||
"@lobehub/editor": "^3.2.1",
|
||||
"@lobehub/icons": "^4.0.2",
|
||||
"@lobehub/market-sdk": "^0.25.0",
|
||||
"@lobehub/tts": "^4.0.0",
|
||||
"@lobehub/ui": "^4.3.1",
|
||||
"@lobehub/tts": "^4.0.2",
|
||||
"@lobehub/ui": "^4.3.11",
|
||||
"@modelcontextprotocol/sdk": "^1.25.1",
|
||||
"@neondatabase/serverless": "^1.0.2",
|
||||
"@next/third-parties": "^16.1.0",
|
||||
@@ -232,13 +234,14 @@
|
||||
"@zumer/snapdom": "^1.9.14",
|
||||
"ahooks": "^3.9.6",
|
||||
"antd": "^6.1.1",
|
||||
"antd-style": "^3.7.1",
|
||||
"antd-style": "^4.1.0",
|
||||
"async-retry": "^1.3.3",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"better-auth": "^1.4.7",
|
||||
"better-auth-harmony": "^1.2.5",
|
||||
"brotli-wasm": "^3.0.1",
|
||||
"chroma-js": "^3.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"cookie": "^1.1.1",
|
||||
"countries-and-timezones": "^3.8.0",
|
||||
|
||||
@@ -1,45 +1,47 @@
|
||||
import { BuiltinRenderProps } from '@lobechat/types';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { CheckCircle, FileText } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
import type { UpdatePromptParams, UpdatePromptState } from '../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
container: css`
|
||||
font-size: 13px;
|
||||
`,
|
||||
fileIcon: css`
|
||||
color: ${token.colorTextTertiary};
|
||||
color: ${cssVar.colorTextTertiary};
|
||||
`,
|
||||
promptCard: css`
|
||||
background: ${token.colorFillTertiary};
|
||||
border-left: 3px solid ${token.colorSuccess};
|
||||
margin-left: 12px;
|
||||
margin-inline-start: 12px;
|
||||
padding: 12px;
|
||||
border-inline-start: 3px solid ${cssVar.colorSuccess};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
promptContent: css`
|
||||
color: ${token.colorText};
|
||||
overflow: auto;
|
||||
|
||||
max-height: 200px;
|
||||
margin-inline: -12px;
|
||||
margin-inline-start: 20px;
|
||||
padding-inline: 12px;
|
||||
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin-left: 20px;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
color: ${cssVar.colorText};
|
||||
word-break: break-word;
|
||||
margin-inline: -12px;
|
||||
padding-inline: 12px;
|
||||
white-space: pre-wrap;
|
||||
`,
|
||||
promptLabel: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusRow: css`
|
||||
color: ${token.colorSuccess};
|
||||
margin-left: 9px;
|
||||
margin-bottom: 6px;
|
||||
margin-block-end: 6px;
|
||||
margin-inline-start: 9px;
|
||||
color: ${cssVar.colorSuccess};
|
||||
`,
|
||||
statusText: css`
|
||||
font-weight: 500;
|
||||
@@ -49,7 +51,6 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
const UpdatePrompt = memo<BuiltinRenderProps<UpdatePromptParams, UpdatePromptState>>(
|
||||
({ pluginState }) => {
|
||||
const { newPrompt } = pluginState || {};
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<Flexbox className={styles.container} gap={8}>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { BuiltinInterventionProps } from '@lobechat/types';
|
||||
import { Avatar, Flexbox , Tooltip } from '@lobehub/ui';
|
||||
import { Avatar, Flexbox, Tooltip } from '@lobehub/ui';
|
||||
import { Input, InputNumber } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { Clock } from 'lucide-react';
|
||||
import { ChangeEvent, memo, useCallback, useEffect, useState } from 'react';
|
||||
@@ -14,11 +14,11 @@ import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
||||
|
||||
import type { ExecuteTaskParams } from '../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
agentCard: css`
|
||||
padding: 4px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
background: ${token.colorFillTertiary};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
agentDescription: css`
|
||||
overflow: hidden;
|
||||
@@ -28,16 +28,16 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
agentTitle: css`
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
container: css`
|
||||
padding-block: 12px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
`,
|
||||
header: css`
|
||||
font-size: 14px;
|
||||
@@ -50,11 +50,11 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
|
||||
color: ${token.colorPrimary};
|
||||
color: ${cssVar.colorPrimary};
|
||||
|
||||
background: ${token.colorPrimaryBg};
|
||||
background: ${cssVar.colorPrimaryBg};
|
||||
`,
|
||||
timeoutInput: css`
|
||||
width: 100px;
|
||||
@@ -70,7 +70,6 @@ const DEFAULT_TIMEOUT = 1_800_000; // 30 minutes
|
||||
*/
|
||||
const ExecuteTaskIntervention = memo<BuiltinInterventionProps<ExecuteTaskParams>>(
|
||||
({ args, onArgsChange, registerBeforeApprove }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('tool');
|
||||
|
||||
// Get agent info from store
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { BuiltinRenderProps } from '@lobechat/types';
|
||||
import { Avatar, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { Clock } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,23 +12,23 @@ import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
||||
|
||||
import type { ExecuteTaskParams, ExecuteTaskState } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
agentTitle: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
container: css`
|
||||
padding-block: 12px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
`,
|
||||
taskContent: css`
|
||||
padding-block: 8px;
|
||||
padding-inline: 12px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
background: ${token.colorFillTertiary};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
timeout: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextTertiary};
|
||||
color: ${cssVar.colorTextTertiary};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -38,7 +38,6 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
*/
|
||||
const ExecuteTaskRender = memo<BuiltinRenderProps<ExecuteTaskParams, ExecuteTaskState>>(
|
||||
({ args }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('tool');
|
||||
|
||||
// Get agent info from store
|
||||
|
||||
@@ -3,29 +3,29 @@
|
||||
import { BuiltinInterventionProps } from '@lobechat/types';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { Radio, RadioChangeEvent } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { ClearTodosParams } from '../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
container: css`
|
||||
padding: 12px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
background: ${token.colorFillTertiary};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
dangerText: css`
|
||||
font-size: 13px;
|
||||
color: ${token.colorError};
|
||||
color: ${cssVar.colorError};
|
||||
`,
|
||||
header: css`
|
||||
color: ${token.colorWarning};
|
||||
color: ${cssVar.colorWarning};
|
||||
`,
|
||||
label: css`
|
||||
font-size: 13px;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
normalText: css`
|
||||
font-size: 13px;
|
||||
@@ -38,7 +38,6 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
*/
|
||||
const ClearTodosIntervention = memo<BuiltinInterventionProps<ClearTodosParams>>(
|
||||
({ args, onArgsChange }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('tool');
|
||||
const [mode, setMode] = useState<ClearTodosParams['mode']>(args?.mode || 'completed');
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { type BuiltinRenderProps } from '@lobechat/types';
|
||||
import { Block, Checkbox } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
import type { TodoItem, TodoList as TodoListType } from '../../types';
|
||||
@@ -12,19 +12,19 @@ export interface TodoListRenderState {
|
||||
}
|
||||
|
||||
// Styles matching TodoItemRow in SortableTodoList
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
itemRow: css`
|
||||
width: 100%;
|
||||
padding-block: 10px;
|
||||
padding-inline: 12px;
|
||||
border-block-end: 1px dashed ${token.colorBorderSecondary};
|
||||
border-block-end: 1px dashed ${cssVar.colorBorderSecondary};
|
||||
|
||||
&:last-child {
|
||||
border-block-end: none;
|
||||
}
|
||||
`,
|
||||
textChecked: css`
|
||||
color: ${token.colorTextQuaternary};
|
||||
color: ${cssVar.colorTextQuaternary};
|
||||
text-decoration: line-through;
|
||||
`,
|
||||
}));
|
||||
@@ -38,11 +38,9 @@ interface ReadOnlyTodoItemProps {
|
||||
* Read-only todo item row, matching the style of TodoItemRow in SortableTodoList
|
||||
*/
|
||||
const ReadOnlyTodoItem = memo<ReadOnlyTodoItemProps>(({ text, completed }) => {
|
||||
const { styles, theme } = useStyles();
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
backgroundColor={theme.colorSuccess}
|
||||
backgroundColor={cssVar.colorSuccess}
|
||||
checked={completed}
|
||||
classNames={{ text: completed ? styles.textChecked : undefined, wrapper: styles.itemRow }}
|
||||
shape={'circle'}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
import { ActionIcon, Checkbox, Flexbox, Input } from '@lobehub/ui';
|
||||
import { InputRef } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { ChangeEvent, KeyboardEvent, memo, useCallback, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { ADD_ITEM_ID, useTodoListStore } from './store';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
addRow: css`
|
||||
padding-block: 10px;
|
||||
padding-inline: 12px;
|
||||
@@ -26,7 +26,6 @@ interface AddItemRowProps {
|
||||
}
|
||||
|
||||
const AddItemRow = memo<AddItemRowProps>(({ placeholder, showDragHandle = true, className }) => {
|
||||
const { styles, cx } = useStyles();
|
||||
const { t } = useTranslation('tool');
|
||||
const inputRef = useRef<InputRef>(null);
|
||||
const defaultPlaceholder = placeholder || t('lobe-gtd.addTodo.placeholder');
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
import { ActionIcon, Checkbox, Flexbox, SortableList } from '@lobehub/ui';
|
||||
import { Input, InputRef } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import { ChangeEvent, KeyboardEvent, memo, useCallback, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useTodoListStore } from './store';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
deleteIcon: css`
|
||||
flex-shrink: 0;
|
||||
opacity: 0;
|
||||
@@ -25,7 +25,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
width: 100%;
|
||||
padding-block: 10px;
|
||||
padding-inline: 4px 12px;
|
||||
border-block-end: 1px dashed ${token.colorBorderSecondary};
|
||||
border-block-end: 1px dashed ${cssVar.colorBorderSecondary};
|
||||
|
||||
&:hover {
|
||||
.drag-handle,
|
||||
@@ -35,7 +35,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
}
|
||||
`,
|
||||
textChecked: css`
|
||||
color: ${token.colorTextQuaternary};
|
||||
color: ${cssVar.colorTextQuaternary};
|
||||
text-decoration: line-through;
|
||||
`,
|
||||
}));
|
||||
@@ -46,7 +46,6 @@ interface TodoItemRowProps {
|
||||
}
|
||||
|
||||
const TodoItemRow = memo<TodoItemRowProps>(({ id, placeholder }) => {
|
||||
const { styles, cx, theme } = useStyles();
|
||||
const { t } = useTranslation('tool');
|
||||
const inputRef = useRef<InputRef>(null);
|
||||
const defaultPlaceholder = placeholder || t('lobe-gtd.todoItem.placeholder');
|
||||
@@ -125,7 +124,7 @@ const TodoItemRow = memo<TodoItemRowProps>(({ id, placeholder }) => {
|
||||
<Flexbox align="center" className={styles.itemRow} gap={4} horizontal width="100%">
|
||||
<SortableList.DragHandle className={cx(styles.dragHandle, 'drag-handle')} size="small" />
|
||||
<Checkbox
|
||||
backgroundColor={theme.colorSuccess}
|
||||
backgroundColor={cssVar.colorSuccess}
|
||||
checked={completed}
|
||||
onChange={handleToggle}
|
||||
shape={'circle'}
|
||||
|
||||
@@ -2,70 +2,68 @@
|
||||
|
||||
import { Alert, Flexbox, Text } from '@lobehub/ui';
|
||||
import { Descriptions } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ComponentType, memo } from 'react';
|
||||
|
||||
import { FileContentDetail } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ token, css }) => {
|
||||
return {
|
||||
cardBody: css`
|
||||
padding-block: 12px 8px;
|
||||
padding-inline: 16px;
|
||||
`,
|
||||
container: css`
|
||||
overflow: hidden;
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
cardBody: css`
|
||||
padding-block: 12px 8px;
|
||||
padding-inline: 16px;
|
||||
`,
|
||||
container: css`
|
||||
overflow: hidden;
|
||||
|
||||
min-width: 360px;
|
||||
max-width: 360px;
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: 12px;
|
||||
`,
|
||||
description: css`
|
||||
margin-block: 0 4px !important;
|
||||
color: ${token.colorTextTertiary};
|
||||
`,
|
||||
footer: css`
|
||||
padding-block: 8px;
|
||||
padding-inline: 16px;
|
||||
border-radius: 8px;
|
||||
min-width: 360px;
|
||||
max-width: 360px;
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: 12px;
|
||||
`,
|
||||
description: css`
|
||||
margin-block: 0 4px !important;
|
||||
color: ${cssVar.colorTextTertiary};
|
||||
`,
|
||||
footer: css`
|
||||
padding-block: 8px;
|
||||
padding-inline: 16px;
|
||||
border-radius: 8px;
|
||||
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
|
||||
background-color: ${token.colorFillQuaternary};
|
||||
`,
|
||||
footerText: css`
|
||||
font-size: 12px !important;
|
||||
color: ${token.colorTextTertiary} !important;
|
||||
`,
|
||||
icon: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
preview: css`
|
||||
overflow: hidden;
|
||||
background-color: ${cssVar.colorFillQuaternary};
|
||||
`,
|
||||
footerText: css`
|
||||
font-size: 12px !important;
|
||||
color: ${cssVar.colorTextTertiary} !important;
|
||||
`,
|
||||
icon: css`
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
preview: css`
|
||||
overflow: hidden;
|
||||
|
||||
max-height: 80px;
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
max-height: 80px;
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
margin-block-end: 0;
|
||||
`,
|
||||
titleRow: css`
|
||||
color: ${token.colorText};
|
||||
`,
|
||||
};
|
||||
});
|
||||
margin-block-end: 0;
|
||||
`,
|
||||
titleRow: css`
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
}));
|
||||
|
||||
interface FileCardProps {
|
||||
FileIcon: ComponentType<{ fileName: string; size: number }>;
|
||||
@@ -77,8 +75,6 @@ interface FileCardProps {
|
||||
}
|
||||
|
||||
const FileCard = memo<FileCardProps>(({ file, FileIcon, labels }) => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
if (file.error) {
|
||||
return (
|
||||
<Flexbox className={styles.container} gap={8}>
|
||||
|
||||
+8
-3
@@ -2,9 +2,10 @@
|
||||
|
||||
import { FileSearchResult } from '@lobechat/types';
|
||||
import { Center, Flexbox, Text, Tooltip } from '@lobehub/ui';
|
||||
import { cx, useThemeMode } from 'antd-style';
|
||||
import { ComponentType, memo } from 'react';
|
||||
|
||||
import { useStyles } from './style';
|
||||
import { styles } from './style';
|
||||
|
||||
export interface FileItemProps extends FileSearchResult {
|
||||
FileIcon: ComponentType<{
|
||||
@@ -19,7 +20,7 @@ export interface FileItemProps extends FileSearchResult {
|
||||
|
||||
const FileItem = memo<FileItemProps>(
|
||||
({ fileId, fileName, relevanceScore, topChunks, FileIcon, isMobile, onFileClick }) => {
|
||||
const { styles, cx } = useStyles();
|
||||
const { isDarkMode } = useThemeMode();
|
||||
|
||||
// Use the first chunk for preview
|
||||
const firstChunk = topChunks[0];
|
||||
@@ -27,7 +28,11 @@ const FileItem = memo<FileItemProps>(
|
||||
return (
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
className={cx(styles.container, isMobile && styles.mobile)}
|
||||
className={cx(
|
||||
styles.container,
|
||||
isDarkMode ? styles.containerDark : styles.containerLight,
|
||||
isMobile && styles.mobile,
|
||||
)}
|
||||
gap={4}
|
||||
horizontal
|
||||
key={fileId}
|
||||
|
||||
+18
-10
@@ -1,7 +1,6 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { lighten } from 'polished';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
badge: css`
|
||||
padding-block: 4px;
|
||||
padding-inline: 6px;
|
||||
@@ -9,9 +8,9 @@ export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
||||
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
|
||||
background: ${token.colorFillSecondary};
|
||||
background: ${cssVar.colorFillSecondary};
|
||||
`,
|
||||
|
||||
container: css`
|
||||
@@ -23,16 +22,25 @@ export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
||||
padding-inline-end: 12px;
|
||||
border-radius: 8px;
|
||||
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
|
||||
background: ${lighten(0.1, token.colorBgElevated)};
|
||||
box-shadow: ${token.boxShadowTertiary};
|
||||
background: color-mix(in srgb, ${cssVar.colorBgElevated} 90%, white);
|
||||
box-shadow: ${cssVar.boxShadowTertiary};
|
||||
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: ${isDarkMode ? lighten(0.15, token.colorBgElevated) : ''};
|
||||
box-shadow: ${token.boxShadowSecondary};
|
||||
box-shadow: ${cssVar.boxShadowSecondary};
|
||||
}
|
||||
`,
|
||||
containerDark: css`
|
||||
&:hover {
|
||||
background: color-mix(in srgb, ${cssVar.colorBgElevated} 85%, white);
|
||||
}
|
||||
`,
|
||||
containerLight: css`
|
||||
&:hover {
|
||||
background: color-mix(in srgb, ${cssVar.colorBgElevated} 90%, white);
|
||||
}
|
||||
`,
|
||||
filename: css`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Tag, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { FileText, NotebookText } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -9,54 +9,51 @@ import { useChatStore } from '@/store/chat';
|
||||
|
||||
import { NotebookDocument } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ token, css }) => {
|
||||
return {
|
||||
container: css`
|
||||
cursor: pointer;
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
container: css`
|
||||
cursor: pointer;
|
||||
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
|
||||
width: 100%;
|
||||
padding-block: 12px;
|
||||
padding-inline: 12px;
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
padding-block: 12px;
|
||||
padding-inline: 12px;
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: 8px;
|
||||
|
||||
background: ${token.colorBgElevated};
|
||||
background: ${cssVar.colorBgElevated};
|
||||
|
||||
&:hover {
|
||||
background: ${token.colorFillSecondary};
|
||||
}
|
||||
`,
|
||||
description: css`
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
icon: css`
|
||||
color: ${token.colorPrimary};
|
||||
`,
|
||||
title: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
&:hover {
|
||||
background: ${cssVar.colorFillSecondary};
|
||||
}
|
||||
`,
|
||||
description: css`
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
icon: css`
|
||||
color: ${cssVar.colorPrimary};
|
||||
`,
|
||||
title: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
font-weight: 500;
|
||||
color: ${token.colorText};
|
||||
`,
|
||||
typeTag: css`
|
||||
font-size: 11px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
font-weight: 500;
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
typeTag: css`
|
||||
font-size: 11px;
|
||||
`,
|
||||
}));
|
||||
|
||||
interface DocumentCardProps {
|
||||
document: NotebookDocument;
|
||||
}
|
||||
|
||||
const DocumentCard = memo<DocumentCardProps>(({ document }) => {
|
||||
const { styles } = useStyles();
|
||||
const openDocument = useChatStore((s) => s.openDocument);
|
||||
|
||||
const handleClick = () => {
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
import type { EditTitleArgs, EditTitleState } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
highlight: css`
|
||||
padding-block-end: 1px;
|
||||
color: ${token.colorText};
|
||||
background: linear-gradient(to top, ${token.gold3} 40%, transparent 40%);
|
||||
color: ${cssVar.colorText};
|
||||
background: linear-gradient(to top, ${cssVar.gold3} 40%, transparent 40%);
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
@@ -20,43 +21,18 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
shinyText: css`
|
||||
color: ${rgba(token.colorText, 0.45)};
|
||||
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
${rgba(token.colorTextBase, 0)} 40%,
|
||||
${token.colorTextSecondary} 50%,
|
||||
${rgba(token.colorTextBase, 0)} 60%
|
||||
);
|
||||
background-clip: text;
|
||||
background-size: 200% 100%;
|
||||
|
||||
animation: shine 1.5s linear infinite;
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const EditTitleInspector = memo<BuiltinInspectorProps<EditTitleArgs, EditTitleState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
const title = args?.title || partialArgs?.title;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isArgumentsStreaming && styles.shinyText)}>
|
||||
<div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
|
||||
{title ? (
|
||||
<Trans
|
||||
components={{ title: <span className={styles.highlight} /> }}
|
||||
|
||||
@@ -1,52 +1,28 @@
|
||||
'use client';
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${token.colorTextDescription};
|
||||
`,
|
||||
shinyText: css`
|
||||
color: ${rgba(token.colorText, 0.45)};
|
||||
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
${rgba(token.colorTextBase, 0)} 40%,
|
||||
${token.colorTextSecondary} 50%,
|
||||
${rgba(token.colorTextBase, 0)} 60%
|
||||
);
|
||||
background-clip: text;
|
||||
background-size: 200% 100%;
|
||||
|
||||
animation: shine 1.5s linear infinite;
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GetPageContentInspector = memo<BuiltinInspectorProps>(({ isArgumentsStreaming }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isArgumentsStreaming && styles.shinyText)}>
|
||||
<div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-page-agent.apiName.getPageContent')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,23 +2,24 @@
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { rgba } from 'polished';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
import type { InitDocumentArgs, InitDocumentState } from '../../../types';
|
||||
import { AnimatedNumber } from '../../components/AnimatedNumber';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
chars: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorTextDescription};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
lines: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorSuccess};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorSuccess};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
@@ -26,40 +27,15 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
`,
|
||||
shinyText: css`
|
||||
color: ${rgba(token.colorText, 0.45)};
|
||||
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
${rgba(token.colorTextBase, 0)} 40%,
|
||||
${token.colorTextSecondary} 50%,
|
||||
${rgba(token.colorTextBase, 0)} 60%
|
||||
);
|
||||
background-clip: text;
|
||||
background-size: 200% 100%;
|
||||
|
||||
animation: shine 1.5s linear infinite;
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
`,
|
||||
title: css`
|
||||
margin-inline-end: 8px;
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const InitPageInspector = memo<BuiltinInspectorProps<InitDocumentArgs, InitDocumentState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming, pluginState }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
// Calculate lines and chars from markdown content
|
||||
const markdown = args?.markdown || partialArgs?.markdown || '';
|
||||
@@ -73,14 +49,14 @@ export const InitPageInspector = memo<BuiltinInspectorProps<InitDocumentArgs, In
|
||||
// During streaming without content, show init
|
||||
if (isArgumentsStreaming && !hasContent) {
|
||||
return (
|
||||
<div className={cx(styles.root, styles.shinyText)}>
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-page-agent.apiName.initPage')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isArgumentsStreaming && styles.shinyText)}>
|
||||
<div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
|
||||
<span className={styles.title}>
|
||||
{t('builtins.lobe-page-agent.apiName.initPage.result')}
|
||||
</span>
|
||||
|
||||
@@ -2,26 +2,27 @@
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { DiffIcon, Minus, Plus } from 'lucide-react';
|
||||
import { rgba } from 'polished';
|
||||
import { type ReactNode, memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
import type { ModifyNodesArgs, ModifyNodesState } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
insert: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorSuccess};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorSuccess};
|
||||
`,
|
||||
modify: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorWarning};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorWarning};
|
||||
`,
|
||||
remove: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorError};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorError};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
@@ -31,42 +32,17 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
`,
|
||||
separator: css`
|
||||
margin-inline: 2px;
|
||||
color: ${token.colorTextQuaternary};
|
||||
`,
|
||||
shinyText: css`
|
||||
color: ${rgba(token.colorText, 0.45)};
|
||||
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
${rgba(token.colorTextBase, 0)} 40%,
|
||||
${token.colorTextSecondary} 50%,
|
||||
${rgba(token.colorTextBase, 0)} 60%
|
||||
);
|
||||
background-clip: text;
|
||||
background-size: 200% 100%;
|
||||
|
||||
animation: shine 1.5s linear infinite;
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
color: ${cssVar.colorTextQuaternary};
|
||||
`,
|
||||
title: css`
|
||||
margin-inline-end: 8px;
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const ModifyNodesInspector = memo<BuiltinInspectorProps<ModifyNodesArgs, ModifyNodesState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
// Count operations by type
|
||||
const counts = useMemo(() => {
|
||||
@@ -101,7 +77,7 @@ export const ModifyNodesInspector = memo<BuiltinInspectorProps<ModifyNodesArgs,
|
||||
// During streaming without operations yet, show init message
|
||||
if (isArgumentsStreaming && !hasOperations) {
|
||||
return (
|
||||
<div className={cx(styles.root, styles.shinyText)}>
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-page-agent.apiName.modifyNodes.init')}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -135,7 +111,7 @@ export const ModifyNodesInspector = memo<BuiltinInspectorProps<ModifyNodesArgs,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isArgumentsStreaming && styles.shinyText)}>
|
||||
<div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
|
||||
<span className={styles.title}>{t('builtins.lobe-page-agent.apiName.modifyNodes')}</span>
|
||||
{statsParts.length > 0 && (
|
||||
<>
|
||||
|
||||
@@ -2,27 +2,28 @@
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import { rgba } from 'polished';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
import type { ReplaceTextArgs, ReplaceTextState } from '../../../types';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
arrow: css`
|
||||
margin-inline: 4px;
|
||||
color: ${token.colorTextQuaternary};
|
||||
color: ${cssVar.colorTextQuaternary};
|
||||
`,
|
||||
from: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
text-decoration: line-through;
|
||||
`,
|
||||
highlight: css`
|
||||
padding-block-end: 1px;
|
||||
color: ${token.colorText};
|
||||
background: linear-gradient(to top, ${token.gold3} 40%, transparent 40%);
|
||||
color: ${cssVar.colorText};
|
||||
background: linear-gradient(to top, ${cssVar.gold3} 40%, transparent 40%);
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
@@ -30,46 +31,21 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
shinyText: css`
|
||||
color: ${rgba(token.colorText, 0.45)};
|
||||
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
${rgba(token.colorTextBase, 0)} 40%,
|
||||
${token.colorTextSecondary} 50%,
|
||||
${rgba(token.colorTextBase, 0)} 60%
|
||||
);
|
||||
background-clip: text;
|
||||
background-size: 200% 100%;
|
||||
|
||||
animation: shine 1.5s linear infinite;
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
stats: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
color: ${token.colorTextSecondary};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin-inline-end: 8px;
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const ReplaceTextInspector = memo<BuiltinInspectorProps<ReplaceTextArgs, ReplaceTextState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming, pluginState }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
const from = args?.searchText || partialArgs?.searchText;
|
||||
const to = args?.newText ?? partialArgs?.newText;
|
||||
@@ -77,7 +53,7 @@ export const ReplaceTextInspector = memo<BuiltinInspectorProps<ReplaceTextArgs,
|
||||
// During streaming without searchText yet, show init message
|
||||
if (isArgumentsStreaming && !from) {
|
||||
return (
|
||||
<div className={cx(styles.root, styles.shinyText)}>
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-page-agent.apiName.replaceText.init')}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -87,7 +63,7 @@ export const ReplaceTextInspector = memo<BuiltinInspectorProps<ReplaceTextArgs,
|
||||
const hasResult = from && to !== undefined;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isArgumentsStreaming && styles.shinyText)}>
|
||||
<div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
|
||||
<span className={styles.title}>{t('builtins.lobe-page-agent.apiName.replaceText')}</span>
|
||||
{hasResult && (
|
||||
<>
|
||||
|
||||
@@ -2,33 +2,22 @@
|
||||
|
||||
import { Center, Flexbox, Text } from '@lobehub/ui';
|
||||
import { Divider } from 'antd';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { type PropsWithChildren, memo } from 'react';
|
||||
import { cx, useThemeMode } from 'antd-style';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
|
||||
import { ProductLogo } from '@/components/Branding';
|
||||
import LangButton from '@/features/User/UserPanel/LangButton';
|
||||
import ThemeButton from '@/features/User/UserPanel/ThemeButton';
|
||||
|
||||
const AuthContainer = memo(({ children }: PropsWithChildren) => {
|
||||
const theme = useTheme();
|
||||
import { styles } from './style';
|
||||
|
||||
const AuthContainer: FC<PropsWithChildren> = ({ children }) => {
|
||||
const { isDarkMode } = useThemeMode();
|
||||
return (
|
||||
<Flexbox
|
||||
height={'100%'}
|
||||
padding={8}
|
||||
style={{
|
||||
position: 'relative',
|
||||
}}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flexbox className={styles.outerContainer} height={'100%'} padding={8} width={'100%'}>
|
||||
<Flexbox
|
||||
className={cx(isDarkMode ? styles.innerContainerDark : styles.innerContainerLight)}
|
||||
height={'100%'}
|
||||
style={{
|
||||
background: theme.colorBgContainer,
|
||||
border: `1px solid ${theme.isDarkMode ? theme.colorBorderSecondary : theme.colorBorder}`,
|
||||
borderRadius: theme.borderRadius,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
}}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flexbox
|
||||
@@ -42,12 +31,7 @@ const AuthContainer = memo(({ children }: PropsWithChildren) => {
|
||||
<ProductLogo size={40} />
|
||||
<Flexbox align={'center'} horizontal>
|
||||
<LangButton placement={'bottomRight'} size={18} />
|
||||
<Divider
|
||||
style={{
|
||||
height: 24,
|
||||
}}
|
||||
type={'vertical'}
|
||||
/>
|
||||
<Divider className={styles.divider} orientation={'vertical'} />
|
||||
<ThemeButton placement={'bottomRight'} size={18} />
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
@@ -62,7 +46,7 @@ const AuthContainer = memo(({ children }: PropsWithChildren) => {
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
AuthContainer.displayName = 'AuthContainer';
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
|
||||
|
||||
// Divider 样式
|
||||
divider: css`
|
||||
height: 24px;
|
||||
`,
|
||||
|
||||
|
||||
|
||||
|
||||
// 内层容器 - 深色模式
|
||||
innerContainerDark: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
|
||||
|
||||
|
||||
// 内层容器 - 浅色模式
|
||||
innerContainerLight: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border: 1px solid ${cssVar.colorBorder};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
|
||||
|
||||
// 外层容器
|
||||
outerContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
}));
|
||||
@@ -5,7 +5,7 @@ import { DOCUMENTS_REFER_URL, PRIVACY_URL, TERMS_URL } from '@lobechat/const';
|
||||
import { Button, Skeleton, Text } from '@lobehub/ui';
|
||||
import { LobeHub } from '@lobehub/ui/brand';
|
||||
import { Col, Flex, Row } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { AuthError } from 'next-auth';
|
||||
import { signIn } from 'next-auth/react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
@@ -16,15 +16,15 @@ import BrandWatermark from '@/components/BrandWatermark';
|
||||
import AuthIcons from '@/components/NextAuth/AuthIcons';
|
||||
import { useUserStore } from '@/store/user';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
button: css`
|
||||
text-transform: capitalize;
|
||||
`,
|
||||
container: css`
|
||||
min-width: 360px;
|
||||
border: 1px solid ${token.colorBorder};
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
background: ${token.colorBgContainer};
|
||||
border: 1px solid ${cssVar.colorBorder};
|
||||
border-radius: ${cssVar.borderRadiusLG}px;
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
contentCard: css`
|
||||
padding-block: 2.5rem;
|
||||
@@ -32,23 +32,23 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
`,
|
||||
description: css`
|
||||
margin: 0;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
footer: css`
|
||||
padding: 1rem;
|
||||
border-block-start: 1px solid ${token.colorBorder};
|
||||
border-block-start: 1px solid ${cssVar.colorBorder};
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
background: ${token.colorBgElevated};
|
||||
background: ${cssVar.colorBgElevated};
|
||||
`,
|
||||
text: css`
|
||||
text-align: center;
|
||||
`,
|
||||
title: css`
|
||||
margin: 0;
|
||||
color: ${token.colorTextHeading};
|
||||
color: ${cssVar.colorTextHeading};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -68,7 +68,6 @@ const BtnListLoading = memo(() => {
|
||||
* ref: https://authjs.dev/guides/pages/signin
|
||||
*/
|
||||
export default memo(() => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('clerk');
|
||||
const router = useRouter();
|
||||
const [loadingProvider, setLoadingProvider] = useState<string | null>(null);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Avatar, Center, Flexbox, FluentEmoji, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { Link2Icon } from 'lucide-react';
|
||||
import React, { memo } from 'react';
|
||||
|
||||
import { ProductLogo } from '@/components/Branding';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
connector: css`
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -18,7 +18,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
connectorLine: css`
|
||||
width: 24px;
|
||||
height: 1px;
|
||||
background-color: ${token.colorBorderSecondary};
|
||||
background-color: ${cssVar.colorBorderSecondary};
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 24px;
|
||||
@@ -35,7 +35,6 @@ interface OAuthApplicationLogoProps {
|
||||
|
||||
const OAuthApplicationLogo = memo<OAuthApplicationLogoProps>(
|
||||
({ isFirstParty, clientDisplayName, logoUrl, size = 72 }) => {
|
||||
const { styles, theme } = useStyles();
|
||||
return isFirstParty ? (
|
||||
<Avatar alt={clientDisplayName} avatar={logoUrl!} shape={'square'} size={size} />
|
||||
) : (
|
||||
@@ -47,7 +46,7 @@ const OAuthApplicationLogo = memo<OAuthApplicationLogoProps>(
|
||||
)}
|
||||
<div className={styles.connectorLine} />
|
||||
<Center className={styles.connector}>
|
||||
<Icon icon={Link2Icon} style={{ color: theme.colorTextSecondary, fontSize: 20 }} />
|
||||
<Icon icon={Link2Icon} style={{ color: cssVar.colorTextSecondary, fontSize: 20 }} />
|
||||
</Center>
|
||||
<div className={styles.connectorLine} />
|
||||
<ProductLogo size={size} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, Icon, InputPassword, Text } from '@lobehub/ui';
|
||||
import { Form } from 'antd';
|
||||
import type { FormInstance, InputRef } from 'antd';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { ChevronLeft, ChevronRight, Lock } from 'lucide-react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -25,7 +25,6 @@ export const SignInPasswordStep = ({
|
||||
onForgotPassword,
|
||||
onSubmit,
|
||||
}: SignInPasswordStepProps) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation('auth');
|
||||
const passwordInputRef = useRef<InputRef>(null);
|
||||
|
||||
@@ -90,7 +89,7 @@ export const SignInPasswordStep = ({
|
||||
icon={ChevronRight}
|
||||
loading={loading}
|
||||
onClick={() => form.submit()}
|
||||
style={{ color: theme.colorPrimary }}
|
||||
style={{ color: cssVar.colorPrimary }}
|
||||
title={t('betterAuth.signin.submit')}
|
||||
variant={'filled'}
|
||||
/>
|
||||
|
||||
@@ -1,40 +1,50 @@
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { type FC, type PropsWithChildren } from 'react';
|
||||
import { cssVar, useThemeMode } from 'antd-style';
|
||||
import { type FC, type PropsWithChildren, useMemo } from 'react';
|
||||
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
|
||||
import { styles } from './DesktopLayoutContainer/style';
|
||||
|
||||
const DesktopLayoutContainer: FC<PropsWithChildren> = ({ children }) => {
|
||||
const theme = useTheme();
|
||||
const { isDarkMode } = useThemeMode();
|
||||
const [expand] = useGlobalStore((s) => [systemStatusSelectors.showLeftPanel(s)]);
|
||||
|
||||
// CSS 变量用于动态样式
|
||||
const outerCssVariables = useMemo<Record<string, string>>(
|
||||
() => ({
|
||||
'--container-padding-left': expand ? '0px' : '8px',
|
||||
'--container-padding-top': isDesktop ? '0px' : '8px',
|
||||
}),
|
||||
[expand, isDesktop],
|
||||
);
|
||||
|
||||
const innerCssVariables = useMemo<Record<string, string>>(() => {
|
||||
const borderRadius =
|
||||
typeof window !== 'undefined' && (window.lobeEnv?.darwinMajorVersion ?? 0) >= 25
|
||||
? '12px'
|
||||
: cssVar.borderRadius;
|
||||
|
||||
return {
|
||||
'--container-border-color': isDarkMode ? cssVar.colorBorderSecondary : cssVar.colorBorder,
|
||||
'--container-border-radius': borderRadius,
|
||||
};
|
||||
}, [isDarkMode]);
|
||||
|
||||
return (
|
||||
<Flexbox
|
||||
className={styles.outerContainer}
|
||||
height={'100%'}
|
||||
padding={8}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
paddingLeft: expand ? 0 : 8,
|
||||
paddingTop: isDesktop ? 0 : 8,
|
||||
position: 'relative',
|
||||
}}
|
||||
style={outerCssVariables}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flexbox
|
||||
className={styles.innerContainer}
|
||||
height={'100%'}
|
||||
style={{
|
||||
background: theme.colorBgContainer,
|
||||
border: `1px solid ${theme.isDarkMode ? theme.colorBorderSecondary : theme.colorBorder}`,
|
||||
borderRadius:
|
||||
// macOS 26's darwin is 25
|
||||
typeof window !== 'undefined' && (window.lobeEnv?.darwinMajorVersion ?? 0) >= 25
|
||||
? 12
|
||||
: theme.borderRadius,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
}}
|
||||
style={innerCssVariables}
|
||||
width={'100%'}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
// 内层容器
|
||||
innerContainer: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border: 1px solid var(--container-border-color, ${cssVar.colorBorder});
|
||||
border-radius: var(--container-border-radius, ${cssVar.borderRadius});
|
||||
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
// 外层容器
|
||||
outerContainer: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
padding-block-start: var(--container-padding-top, 8px);
|
||||
padding-inline-start: var(--container-padding-left, 8px);
|
||||
|
||||
background: ${cssVar.colorBgLayout};
|
||||
`,
|
||||
}));
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cx } from 'antd-style';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { type FC, Suspense } from 'react';
|
||||
import { HotkeysProvider } from 'react-hotkeys-hook';
|
||||
@@ -28,12 +28,12 @@ import DesktopHomeLayout from '../home/_layout';
|
||||
import DesktopAutoOidcOnFirstOpen from './DesktopAutoOidcOnFirstOpen';
|
||||
import DesktopLayoutContainer from './DesktopLayoutContainer';
|
||||
import RegisterHotkeys from './RegisterHotkeys';
|
||||
import { styles } from './style';
|
||||
|
||||
const CloudBanner = dynamic(() => import('@/features/AlertBanner/CloudBanner'));
|
||||
|
||||
const Layout: FC = () => {
|
||||
const { isPWA } = usePlatform();
|
||||
const theme = useTheme();
|
||||
const { showCloudPromotion } = useServerConfigStore(featureFlagsSelectors);
|
||||
|
||||
const { isChecking, loadingComponent } = useMainLayoutRenderingChecking();
|
||||
@@ -51,6 +51,7 @@ const Layout: FC = () => {
|
||||
</Suspense>
|
||||
<DndContextWrapper>
|
||||
<Flexbox
|
||||
className={cx(isPWA ? styles.mainContainerPWA : styles.mainContainer)}
|
||||
height={
|
||||
isDesktop
|
||||
? `calc(100% - ${TITLE_BAR_HEIGHT}px)`
|
||||
@@ -59,10 +60,6 @@ const Layout: FC = () => {
|
||||
: '100%'
|
||||
}
|
||||
horizontal
|
||||
style={{
|
||||
borderTop: isPWA ? `1px solid ${theme.colorBorder}` : undefined,
|
||||
position: 'relative',
|
||||
}}
|
||||
width={'100%'}
|
||||
>
|
||||
<NavPanel />
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
// 主容器 - 非 PWA 模式(无顶部边框)
|
||||
mainContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
|
||||
// 主容器 - PWA 模式(带顶部边框)
|
||||
mainContainerPWA: css`
|
||||
position: relative;
|
||||
border-block-start: 1px solid ${cssVar.colorBorder};
|
||||
`,
|
||||
}));
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ActionIcon, Dropdown, Flexbox, Icon, Skeleton, Tag } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { MessageSquareDashed, Star } from 'lucide-react';
|
||||
import { Suspense, memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -26,8 +26,6 @@ interface TopicItemProps {
|
||||
|
||||
const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) => {
|
||||
const { t } = useTranslation('topic');
|
||||
|
||||
const theme = useTheme();
|
||||
const openTopicInNewWindow = useGlobalStore((s) => s.openTopicInNewWindow);
|
||||
const activeAgentId = useAgentStore((s) => s.activeAgentId);
|
||||
|
||||
@@ -69,7 +67,9 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
|
||||
return (
|
||||
<NavItem
|
||||
active={active && !isInAgentSubRoute}
|
||||
icon={<Icon color={theme.colorTextDescription} icon={MessageSquareDashed} size={'small'} />}
|
||||
icon={
|
||||
<Icon color={cssVar.colorTextDescription} icon={MessageSquareDashed} size={'small'} />
|
||||
}
|
||||
loading={isLoading}
|
||||
onClick={handleClick}
|
||||
title={
|
||||
@@ -78,7 +78,7 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
|
||||
<Tag
|
||||
size={'small'}
|
||||
style={{
|
||||
color: theme.colorTextDescription,
|
||||
color: cssVar.colorTextDescription,
|
||||
fontSize: 10,
|
||||
}}
|
||||
>
|
||||
@@ -104,8 +104,8 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
|
||||
disabled={editing}
|
||||
icon={
|
||||
<ActionIcon
|
||||
color={fav ? theme.colorWarning : undefined}
|
||||
fill={fav ? theme.colorWarning : 'transparent'}
|
||||
color={fav ? cssVar.colorWarning : undefined}
|
||||
fill={fav ? cssVar.colorWarning : 'transparent'}
|
||||
icon={Star}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
import { Dropdown, Icon } from '@lobehub/ui';
|
||||
import { TreeDownRightIcon } from '@lobehub/ui/icons';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
@@ -18,7 +18,6 @@ export interface ThreadItemProps {
|
||||
}
|
||||
|
||||
const ThreadItem = memo<ThreadItemProps>(({ title, id }) => {
|
||||
const theme = useTheme();
|
||||
const [editing, activeThreadId] = useChatStore((s) => [
|
||||
s.threadRenamingId === id,
|
||||
s.activeThreadId,
|
||||
@@ -57,7 +56,9 @@ const ThreadItem = memo<ThreadItemProps>(({ title, id }) => {
|
||||
actions={<Actions dropdownMenu={dropdownMenu} />}
|
||||
active={active && !isInAgentSubRoute}
|
||||
disabled={editing}
|
||||
icon={<Icon color={theme.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />}
|
||||
icon={
|
||||
<Icon color={cssVar.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />
|
||||
}
|
||||
onClick={handleClick}
|
||||
title={title}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { type FC } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
@@ -10,23 +9,15 @@ import { useInitAgentConfig } from '@/hooks/useInitAgentConfig';
|
||||
|
||||
import RegisterHotkeys from './RegisterHotkeys';
|
||||
import Sidebar from './Sidebar';
|
||||
import { styles } from './style';
|
||||
|
||||
const Layout: FC = () => {
|
||||
const theme = useTheme();
|
||||
useInitAgentConfig();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sidebar />
|
||||
<Flexbox
|
||||
flex={1}
|
||||
height={'100%'}
|
||||
style={{
|
||||
background: theme.colorBgContainer,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<Flexbox className={styles.mainContainer} flex={1} height={'100%'}>
|
||||
<Outlet />
|
||||
</Flexbox>
|
||||
{/* ↓ cloud slot ↓ */}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
// 主容器
|
||||
mainContainer: css`
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
}));
|
||||
+4
-6
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Block, Flexbox } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles , responsive } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -9,13 +9,13 @@ import { useConversationStore } from '@/features/Conversation';
|
||||
|
||||
// import { useSend } from '../../features/ChatInput/useSend';
|
||||
|
||||
const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
card: css`
|
||||
padding-block: 8px;
|
||||
padding-inline: 16px;
|
||||
border-radius: 48px;
|
||||
|
||||
${responsive.mobile} {
|
||||
${responsive.sm} {
|
||||
padding-block: 8px;
|
||||
padding-inline: 16px;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
`,
|
||||
|
||||
title: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -40,8 +40,6 @@ const OpeningQuestions = memo<OpeningQuestionsProps>(({ mobile, questions }) =>
|
||||
const { t } = useTranslation('welcome');
|
||||
const [sendMessage] = useConversationStore((s) => [s.sendMessage]);
|
||||
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<p className={styles.title}>{t('guide.questions.title')}</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { KLAVIS_SERVER_TYPES, type KlavisServerType } from '@lobechat/const';
|
||||
import { Alert, Avatar, Button, Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { Divider } from 'antd';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
@@ -55,7 +55,6 @@ interface KlavisToolAuthItemProps {
|
||||
|
||||
const KlavisToolAuthItem = memo<KlavisToolAuthItemProps>(({ tool, onAuthComplete }) => {
|
||||
const { t } = useTranslation('chat');
|
||||
const theme = useTheme();
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [isWaitingAuth, setIsWaitingAuth] = useState(false);
|
||||
|
||||
@@ -196,7 +195,7 @@ const KlavisToolAuthItem = memo<KlavisToolAuthItemProps>(({ tool, onAuthComplete
|
||||
if (typeof tool.icon === 'string') {
|
||||
return <Avatar alt={tool.label} avatar={tool.icon} size={20} style={{ flex: 'none' }} />;
|
||||
}
|
||||
return <Icon fill={theme.colorText} icon={tool.icon} size={20} />;
|
||||
return <Icon fill={cssVar.colorText} icon={tool.icon} size={20} />;
|
||||
};
|
||||
|
||||
const isLoading = isConnecting || isWaitingAuth;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
import NavHeader from '@/features/NavHeader';
|
||||
@@ -12,16 +12,15 @@ import ShareButton from './ShareButton';
|
||||
import Tags from './Tags';
|
||||
|
||||
const Header = memo(() => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<NavHeader
|
||||
left={
|
||||
<Flexbox style={{ backgroundColor: theme.colorBgContainer }}>
|
||||
<Flexbox style={{ backgroundColor: cssVar.colorBgContainer }}>
|
||||
<Tags />
|
||||
</Flexbox>
|
||||
}
|
||||
right={
|
||||
<Flexbox horizontal style={{ backgroundColor: theme.colorBgContainer }}>
|
||||
<Flexbox horizontal style={{ backgroundColor: cssVar.colorBgContainer }}>
|
||||
<WideScreenButton />
|
||||
<NotebookButton />
|
||||
<ShareButton />
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Modal } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { type ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { PortalContent } from '@/features/Portal/router';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
container: css`
|
||||
background: linear-gradient(${token.colorBgElevated}, ${token.colorBgContainer}) !important;
|
||||
background: linear-gradient(${cssVar.colorBgElevated}, ${cssVar.colorBgContainer}) !important;
|
||||
`,
|
||||
}));
|
||||
|
||||
const Layout = () => {
|
||||
const { styles, cx } = useStyles();
|
||||
const [showMobilePortal, isPortalThread, togglePortal] = useChatStore((s) => [
|
||||
s.showPortal,
|
||||
!!s.portalThreadId,
|
||||
@@ -24,12 +23,7 @@ const Layout = () => {
|
||||
const { t } = useTranslation('portal');
|
||||
|
||||
const renderBody = (body: ReactNode) => (
|
||||
<Flexbox
|
||||
gap={8}
|
||||
height={'calc(100% - 52px)'}
|
||||
padding={'0 8px'}
|
||||
style={{ overflow: 'hidden' }}
|
||||
>
|
||||
<Flexbox gap={8} height={'calc(100% - 52px)'} padding={'0 8px'} style={{ overflow: 'hidden' }}>
|
||||
<Flexbox
|
||||
height={'100%'}
|
||||
style={{ marginInline: -8, overflow: 'hidden', position: 'relative' }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { DraggablePanel, DraggablePanelContainer, type DraggablePanelProps } from '@lobehub/ui';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import { createStaticStyles, useResponsive } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { type PropsWithChildren, memo, useState } from 'react';
|
||||
|
||||
@@ -16,7 +16,7 @@ import { chatPortalSelectors, portalThreadSelectors } from '@/store/chat/selecto
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -25,17 +25,16 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
drawer: css`
|
||||
z-index: 10;
|
||||
height: 100%;
|
||||
background: ${token.colorBgContainer};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
panel: css`
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
background: ${token.colorBgContainer};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
}));
|
||||
|
||||
const PortalPanel = memo(({ children }: PropsWithChildren) => {
|
||||
const { styles } = useStyles();
|
||||
const { md = true } = useResponsive();
|
||||
|
||||
const [showPortal, showToolUI, showArtifactUI, showThread] = useChatStore((s) => [
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { BRANDING_NAME } from '@lobechat/business-const';
|
||||
import { Avatar, Button, Flexbox, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { LucideArrowUpRightFromSquare, TelescopeIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
@@ -13,9 +13,9 @@ import { PRIVACY_URL } from '@/const/url';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { preferenceSelectors } from '@/store/user/selectors';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
desc: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
font-size: 18px;
|
||||
@@ -24,8 +24,6 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
}));
|
||||
|
||||
const TelemetryNotification = memo<{ mobile?: boolean }>(({ mobile }) => {
|
||||
const { styles, theme } = useStyles();
|
||||
|
||||
const { t } = useTranslation('common');
|
||||
const isPreferenceInit = useUserStore(preferenceSelectors.isPreferenceInit);
|
||||
|
||||
@@ -46,8 +44,8 @@ const TelemetryNotification = memo<{ mobile?: boolean }>(({ mobile }) => {
|
||||
<Flexbox>
|
||||
<Avatar
|
||||
avatar={<TelescopeIcon />}
|
||||
background={theme.geekblue1}
|
||||
style={{ color: theme.geekblue7 }}
|
||||
background={cssVar.geekblue1}
|
||||
style={{ color: cssVar.geekblue7 }}
|
||||
/>
|
||||
</Flexbox>
|
||||
<Flexbox gap={16}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { KLAVIS_SERVER_TYPES, type KlavisServerType } from '@lobechat/const';
|
||||
import { Avatar, Button, Flexbox, Icon, type ItemType, Segmented } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { ArrowRight, PlusIcon, Store, ToyBrick } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
@@ -36,8 +36,6 @@ type TabType = 'all' | 'installed';
|
||||
* 对于 IconType 类型的 icon,使用 Icon 组件渲染,并根据主题设置填充色
|
||||
*/
|
||||
const KlavisIcon = memo<Pick<KlavisServerType, 'icon' | 'label'>>(({ icon, label }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (typeof icon === 'string') {
|
||||
return (
|
||||
<Image alt={label} height={18} src={icon} style={{ flex: 'none' }} unoptimized width={18} />
|
||||
@@ -45,15 +43,13 @@ const KlavisIcon = memo<Pick<KlavisServerType, 'icon' | 'label'>>(({ icon, label
|
||||
}
|
||||
|
||||
// 使用主题色填充,在深色模式下自动适应
|
||||
return <Icon fill={theme.colorText} icon={icon} size={18} />;
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={18} />;
|
||||
});
|
||||
|
||||
const AgentTool = memo(() => {
|
||||
const { t } = useTranslation('setting');
|
||||
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
// Plugin state management
|
||||
const plugins = config?.plugins || [];
|
||||
|
||||
@@ -356,7 +352,7 @@ const AgentTool = memo(() => {
|
||||
icon={PlusIcon}
|
||||
loading={updating}
|
||||
size={'small'}
|
||||
style={{ color: theme.colorTextSecondary }}
|
||||
style={{ color: cssVar.colorTextSecondary }}
|
||||
type={'text'}
|
||||
>
|
||||
{t('tools.add', { defaultValue: 'Add' })}
|
||||
|
||||
+7
-8
@@ -1,6 +1,6 @@
|
||||
import { type MenuRenderProps } from '@lobehub/editor/es/plugins/slash/react/type';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { type ReactNode, memo, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
import { type MentionListOption } from './types';
|
||||
@@ -23,7 +23,6 @@ const getCursorPosition = (): { x: number; y: number } | null => {
|
||||
|
||||
const MentionDropdown = memo<MenuRenderProps>(
|
||||
({ activeKey, onSelect, open, options, setActiveKey }) => {
|
||||
const theme = useTheme();
|
||||
const activeItemRef = useRef<HTMLDivElement>(null);
|
||||
const [position, setPosition] = useState<{ x: number; y: number } | null>(null);
|
||||
|
||||
@@ -51,10 +50,10 @@ const MentionDropdown = memo<MenuRenderProps>(
|
||||
return (
|
||||
<Flexbox
|
||||
style={{
|
||||
background: theme.colorBgElevated,
|
||||
border: `1px solid ${theme.colorBorderSecondary}`,
|
||||
background: cssVar.colorBgElevated,
|
||||
border: `1px solid ${cssVar.colorBorderSecondary}`,
|
||||
borderRadius: 12,
|
||||
boxShadow: theme.boxShadowSecondary,
|
||||
boxShadow: cssVar.boxShadowSecondary,
|
||||
left: position.x,
|
||||
maxHeight: 260,
|
||||
maxWidth: 400,
|
||||
@@ -70,7 +69,7 @@ const MentionDropdown = memo<MenuRenderProps>(
|
||||
return (
|
||||
<div
|
||||
key={`divider-${(option as any)?.key ?? 'divider'}`}
|
||||
style={{ borderTop: `1px solid ${theme.colorBorderSecondary}` }}
|
||||
style={{ borderTop: `1px solid ${cssVar.colorBorderSecondary}` }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -93,14 +92,14 @@ const MentionDropdown = memo<MenuRenderProps>(
|
||||
paddingInline={12}
|
||||
ref={isActive ? activeItemRef : null}
|
||||
style={{
|
||||
background: isActive ? theme.colorFillSecondary : undefined,
|
||||
background: isActive ? cssVar.colorFillSecondary : undefined,
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
{item.icon && <Flexbox style={{ flex: 'none' }}>{item?.icon as ReactNode}</Flexbox>}
|
||||
<div
|
||||
style={{
|
||||
color: theme.colorText,
|
||||
color: cssVar.colorText,
|
||||
fontSize: 14,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
|
||||
+2
-4
@@ -4,7 +4,7 @@ import { type API, apiPrompt, toolPrompt } from '@lobechat/prompts';
|
||||
import { type LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
||||
import { type IEditor, INSERT_MENTION_COMMAND } from '@lobehub/editor';
|
||||
import { Icon, Image } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
|
||||
@@ -28,14 +28,12 @@ const getKlavisServerType = (identifier: string) =>
|
||||
* 对于 IconType 类型的 icon,使用 Icon 组件渲染,并根据主题设置填充色
|
||||
*/
|
||||
const KlavisIcon = memo<Pick<KlavisServerType, 'icon' | 'label'>>(({ icon, label }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (typeof icon === 'string') {
|
||||
return <Image alt={label} height={20} src={icon} style={{ flex: 'none' }} width={20} />;
|
||||
}
|
||||
|
||||
// 使用主题色填充,在深色模式下自动适应
|
||||
return <Icon fill={theme.colorText} icon={icon} size={20} />;
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={20} />;
|
||||
});
|
||||
|
||||
const toolNameResolver = new ToolNameResolver();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { KLAVIS_SERVER_TYPES, type KlavisServerType } from '@lobechat/const';
|
||||
import { Avatar, Icon, Tag } from '@lobehub/ui';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, useThemeMode } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { AlertCircle, X } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
@@ -23,29 +23,27 @@ import {
|
||||
* Klavis 服务器图标组件
|
||||
*/
|
||||
const KlavisIcon = memo<Pick<KlavisServerType, 'icon' | 'label'>>(({ icon, label }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (typeof icon === 'string') {
|
||||
return (
|
||||
<Image alt={label} height={16} src={icon} style={{ flexShrink: 0 }} unoptimized width={16} />
|
||||
);
|
||||
}
|
||||
|
||||
return <Icon fill={theme.colorText} icon={icon} size={16} />;
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={16} />;
|
||||
});
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
notInstalledTag: css`
|
||||
border-color: ${token.colorWarningBorder};
|
||||
background: ${token.colorWarningBg};
|
||||
border-color: ${cssVar.colorWarningBorder};
|
||||
background: ${cssVar.colorWarningBg};
|
||||
`,
|
||||
tag: css`
|
||||
height: 28px !important;
|
||||
border-radius: ${token.borderRadiusSM}px !important;
|
||||
border-radius: ${cssVar.borderRadiusSM} !important;
|
||||
`,
|
||||
warningIcon: css`
|
||||
flex-shrink: 0;
|
||||
color: ${token.colorWarning};
|
||||
color: ${cssVar.colorWarning};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -55,7 +53,7 @@ interface PluginTagProps {
|
||||
}
|
||||
|
||||
const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
const { styles, theme } = useStyles();
|
||||
const { isDarkMode } = useThemeMode();
|
||||
const { t } = useTranslation('setting');
|
||||
|
||||
// Extract identifier
|
||||
@@ -167,7 +165,7 @@ const PluginTag = memo<PluginTagProps>(({ pluginId, onRemove }) => {
|
||||
? undefined
|
||||
: t('tools.notInstalledWarning', { defaultValue: 'This tool is not installed' })
|
||||
}
|
||||
variant={theme.isDarkMode ? 'filled' : 'outlined'}
|
||||
variant={isDarkMode ? 'filled' : 'outlined'}
|
||||
>
|
||||
{!meta.isInstalled
|
||||
? `${displayTitle} (${t('tools.notInstalled', { defaultValue: 'Not Installed' })})`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { ActionIcon, Flexbox } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
@@ -11,8 +11,9 @@ import StoreSearchBar from '@/app/[variants]/(main)/community/features/Search';
|
||||
import UserAvatar from '@/app/[variants]/(main)/community/features/UserAvatar';
|
||||
import NavHeader from '@/features/NavHeader';
|
||||
|
||||
import { styles } from './Header/style';
|
||||
|
||||
const Header = memo(() => {
|
||||
const theme = useTheme();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -26,8 +27,13 @@ const Header = memo(() => {
|
||||
}
|
||||
};
|
||||
|
||||
const cssVariables: Record<string, string> = {
|
||||
'--header-border-color': cssVar.colorBorderSecondary,
|
||||
};
|
||||
|
||||
return (
|
||||
<NavHeader
|
||||
className={styles.headerContainer}
|
||||
left={
|
||||
<Flexbox align={'center'} flex={1} gap={8} horizontal>
|
||||
<ActionIcon icon={ArrowLeft} onClick={handleGoBack} size={'small'} />
|
||||
@@ -35,9 +41,7 @@ const Header = memo(() => {
|
||||
</Flexbox>
|
||||
}
|
||||
right={<UserAvatar />}
|
||||
style={{
|
||||
borderBottom: `1px solid ${theme.colorBorderSecondary}`,
|
||||
}}
|
||||
style={cssVariables}
|
||||
styles={{
|
||||
left: { flex: 1 },
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
// Header 容器
|
||||
headerContainer: css`
|
||||
border-block-end: 1px solid var(--header-border-color, ${cssVar.colorBorderSecondary});
|
||||
`,
|
||||
}));
|
||||
@@ -9,6 +9,7 @@ import WideScreenContainer from '@/features/WideScreenContainer';
|
||||
|
||||
import { MAX_WIDTH, SCROLL_PARENT_ID } from '../../features/const';
|
||||
import Header from './Header';
|
||||
import { styles } from './style';
|
||||
|
||||
/**
|
||||
* Desktop Discover Detail Layout
|
||||
@@ -18,21 +19,24 @@ const DesktopDiscoverDetailLayout = memo(() => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Flexbox height={'100%'} id={SCROLL_PARENT_ID} style={{ overflowY: 'auto' }} width={'100%'}>
|
||||
<Flexbox
|
||||
className={styles.mainContainer}
|
||||
height={'100%'}
|
||||
id={SCROLL_PARENT_ID}
|
||||
width={'100%'}
|
||||
>
|
||||
<WideScreenContainer
|
||||
className={styles.contentContainer}
|
||||
gap={32}
|
||||
minWidth={MAX_WIDTH}
|
||||
paddingBlock={16}
|
||||
style={{
|
||||
minHeight: '100%',
|
||||
}}
|
||||
wrapperStyle={{
|
||||
minHeight: '100%',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
<div style={{ flex: 1 }} />
|
||||
<div className={styles.spacer} />
|
||||
<Footer />
|
||||
</WideScreenContainer>
|
||||
</Flexbox>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
// 内容容器
|
||||
contentContainer: css`
|
||||
min-height: 100%;
|
||||
`,
|
||||
|
||||
// 主容器
|
||||
mainContainer: css`
|
||||
overflow-y: auto;
|
||||
`,
|
||||
|
||||
// 占位符
|
||||
spacer: css`
|
||||
flex: 1;
|
||||
`,
|
||||
}));
|
||||
+5
-7
@@ -1,14 +1,14 @@
|
||||
import { Avatar, Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -16,7 +16,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -24,8 +24,6 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
|
||||
const KnowledgeItem = memo<{ avatar?: string; description?: string; title: string }>(
|
||||
({ avatar, title, description }) => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<Block gap={12} horizontal padding={12} variant={'outlined'}>
|
||||
<Avatar avatar={avatar} shape={'square'} size={40} style={{ flex: 'none' }} />
|
||||
@@ -36,7 +34,7 @@ const KnowledgeItem = memo<{ avatar?: string; description?: string; title: strin
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Text as={'h2'} className={title} ellipsis>
|
||||
<Text as={'h2'} className={styles.title} ellipsis>
|
||||
{title}
|
||||
</Text>
|
||||
<Text
|
||||
|
||||
+5
-8
@@ -1,7 +1,7 @@
|
||||
import { KLAVIS_SERVER_TYPES, type KlavisServerType } from '@lobechat/const';
|
||||
import { type DiscoverPluginDetail, type PluginSource } from '@lobechat/types';
|
||||
import { Avatar, Block, Flexbox, Icon, Image, Skeleton, Tag, Text } from '@lobehub/ui';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
@@ -15,26 +15,24 @@ import { useDiscoverStore } from '@/store/discover';
|
||||
* For IconType type icon, use Icon component to render with theme fill color
|
||||
*/
|
||||
const KlavisIcon = memo<Pick<KlavisServerType, 'icon' | 'label'>>(({ icon, label }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (typeof icon === 'string') {
|
||||
return <Image alt={label} height={40} src={icon} style={{ flex: 'none' }} width={40} />;
|
||||
}
|
||||
|
||||
// Use theme color fill, automatically adapts in dark mode
|
||||
return <Icon fill={theme.colorText} icon={icon} size={40} />;
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={40} />;
|
||||
});
|
||||
|
||||
KlavisIcon.displayName = 'KlavisIcon';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
clickable: css`
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
.plugin-title {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -42,7 +40,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
noLink: css`
|
||||
cursor: default;
|
||||
@@ -71,7 +69,6 @@ const PluginItem = memo<PluginItemProps>(({ identifier }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const usePluginDetail = useDiscoverStore((s) => s.usePluginDetail);
|
||||
const { data: apiData, isLoading } = usePluginDetail({ identifier, withManifest: false });
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
// Try to get Klavis tool info if API returns no data
|
||||
const klavisTool = useMemo(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { SOCIAL_URL } from '@lobechat/business-const';
|
||||
import { Flexbox, Icon, Tabs, Tag } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { BookOpenIcon, HistoryIcon, LayersIcon, ListIcon, SquareUserIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
@@ -15,17 +15,17 @@ import { AssistantNavKey } from '@/types/discover';
|
||||
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
link: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorInfo};
|
||||
color: ${cssVar.colorInfo};
|
||||
}
|
||||
`,
|
||||
nav: css`
|
||||
border-block-end: 1px solid ${token.colorBorder};
|
||||
border-block-end: 1px solid ${cssVar.colorBorder};
|
||||
`,
|
||||
};
|
||||
});
|
||||
@@ -38,7 +38,6 @@ interface NavProps {
|
||||
const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = AssistantNavKey.Overview }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { pluginCount, knowledgeCount, identifier } = useDetailContext();
|
||||
const { styles } = useStyles();
|
||||
const { source } = useQuery() as { source?: string };
|
||||
const isLegacy = source === 'legacy';
|
||||
const marketplaceLink = identifier
|
||||
|
||||
+3
-4
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Tag } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import qs from 'query-string';
|
||||
import { memo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
@@ -9,7 +9,7 @@ import { Link } from 'react-router-dom';
|
||||
import { useQuery } from '@/hooks/useQuery';
|
||||
import { type AssistantMarketSource } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ token, css }) => {
|
||||
const styles = createStaticStyles(({ cssVar, css }) => {
|
||||
return {
|
||||
tag: css`
|
||||
margin: 0;
|
||||
@@ -17,13 +17,12 @@ const useStyles = createStyles(({ token, css }) => {
|
||||
padding-inline: 12px;
|
||||
border-radius: 16px;
|
||||
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const TagList = memo<{ tags: string[] }>(({ tags }) => {
|
||||
const { styles } = useStyles();
|
||||
const { source } = useQuery() as { source?: AssistantMarketSource };
|
||||
const marketSource = source === 'legacy' ? 'legacy' : undefined;
|
||||
const showTags = Boolean(tags?.length && tags?.length > 0);
|
||||
|
||||
+3
-4
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Tag } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import qs from 'query-string';
|
||||
import { memo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
@@ -9,7 +9,7 @@ import { Link } from 'react-router-dom';
|
||||
import { useQuery } from '@/hooks/useQuery';
|
||||
import { type AssistantMarketSource } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ token, css }) => {
|
||||
const styles = createStaticStyles(({ cssVar, css }) => {
|
||||
return {
|
||||
tag: css`
|
||||
margin: 0;
|
||||
@@ -17,13 +17,12 @@ const useStyles = createStyles(({ token, css }) => {
|
||||
padding-inline: 12px;
|
||||
border-radius: 16px;
|
||||
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const TagList = memo<{ tags: string[] }>(({ tags }) => {
|
||||
const { styles } = useStyles();
|
||||
const { source } = useQuery() as { source?: AssistantMarketSource };
|
||||
const marketSource = source === 'legacy' ? 'legacy' : undefined;
|
||||
const showTags = Boolean(tags?.length && tags?.length > 0);
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
import { Block, Flexbox, Icon, Tag } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { MessageCircleHeartIcon, MessageCircleQuestionIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -13,7 +13,6 @@ import TagList from './TagList';
|
||||
const Overview = memo(() => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { tokenUsage, tags = [], config } = useDetailContext();
|
||||
const theme = useTheme();
|
||||
|
||||
const { systemRole, openingMessage, openingQuestions } = config || {};
|
||||
return (
|
||||
@@ -34,7 +33,7 @@ const Overview = memo(() => {
|
||||
<Title>{t('assistants.details.systemRole.openingMessage')}</Title>
|
||||
<Block align={'flex-start'} gap={12} horizontal padding={16} variant={'outlined'}>
|
||||
<Icon
|
||||
color={theme.colorError}
|
||||
color={cssVar.colorError}
|
||||
icon={MessageCircleHeartIcon}
|
||||
size={20}
|
||||
style={{
|
||||
@@ -53,7 +52,7 @@ const Overview = memo(() => {
|
||||
<Flexbox gap={8}>
|
||||
{openingQuestions?.map((item, key) => (
|
||||
<Block gap={12} horizontal key={key} padding={16} variant={'outlined'}>
|
||||
<Icon color={theme.colorWarning} icon={MessageCircleQuestionIcon} size={20} />
|
||||
<Icon color={cssVar.colorWarning} icon={MessageCircleQuestionIcon} size={20} />
|
||||
<MarkdownRender>{item}</MarkdownRender>
|
||||
</Block>
|
||||
))}
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
import { Block, Flexbox, Icon, Tag } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { CheckIcon, MinusIcon } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo, useMemo } from 'react';
|
||||
@@ -17,7 +17,6 @@ import { useDetailContext } from '../../DetailProvider';
|
||||
|
||||
const Versions = memo(() => {
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
const pathname = usePathname();
|
||||
const { versions = [], currentVersion } = useDetailContext();
|
||||
const { source } = useQuery() as { source?: AssistantMarketSource };
|
||||
@@ -107,7 +106,7 @@ const Versions = memo(() => {
|
||||
dataIndex: 'isValidated',
|
||||
render: (_: any, record: any) => (
|
||||
<Icon
|
||||
color={record.isValidated ? theme.colorSuccess : theme.colorTextDescription}
|
||||
color={record.isValidated ? cssVar.colorSuccess : cssVar.colorTextDescription}
|
||||
icon={record.isValidated ? CheckIcon : MinusIcon}
|
||||
/>
|
||||
),
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
TooltipGroup,
|
||||
} from '@lobehub/ui';
|
||||
import { App } from 'antd';
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, useResponsive } from 'antd-style';
|
||||
import { BookTextIcon, BookmarkCheckIcon, BookmarkIcon, CoinsIcon, DotIcon } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo, useState } from 'react';
|
||||
@@ -29,21 +29,12 @@ import { useCategory } from '../../../(list)/assistant/features/Category/useCate
|
||||
import PublishedTime from '../../../../../../../components/PublishedTime';
|
||||
import { useDetailContext } from './DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
return {
|
||||
desc: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
time: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
`,
|
||||
version: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-size: 13px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
time: css`
|
||||
font-size: 12px;
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
@@ -60,7 +51,6 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
knowledgeCount,
|
||||
userName,
|
||||
} = useDetailContext();
|
||||
const { styles, theme } = useStyles();
|
||||
const { mobile = isMobile } = useResponsive();
|
||||
const { isAuthenticated, signIn, session } = useMarketAuth();
|
||||
const [favoriteLoading, setFavoriteLoading] = useState(false);
|
||||
@@ -228,7 +218,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
gap={mobile ? 12 : 24}
|
||||
horizontal
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
}}
|
||||
>
|
||||
{!mobile && cateButton}
|
||||
@@ -249,7 +239,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
title={t('assistants.withPlugin')}
|
||||
>
|
||||
<Flexbox align={'center'} gap={6} horizontal>
|
||||
<Icon fill={theme.colorTextSecondary} icon={MCP} />
|
||||
<Icon fill={cssVar.colorTextSecondary} icon={MCP} />
|
||||
{pluginCount}
|
||||
</Flexbox>
|
||||
</Tooltip>
|
||||
|
||||
+2
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { App, Dropdown } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ChevronDownIcon } from 'lucide-react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -16,7 +16,7 @@ import { useHomeStore } from '@/store/home';
|
||||
|
||||
import { useDetailContext } from '../../DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
button: css`
|
||||
button {
|
||||
width: 100%;
|
||||
@@ -27,8 +27,6 @@ const useStyles = createStyles(({ css }) => ({
|
||||
const AddAgent = memo<{ mobile?: boolean }>(({ mobile }) => {
|
||||
const { avatar, description, tags, title, config, backgroundColor, identifier, editorData } =
|
||||
useDetailContext();
|
||||
|
||||
const { styles } = useStyles();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const createAgent = useAgentStore((s) => s.createAgent);
|
||||
const refreshAgentList = useHomeStore((s) => s.refreshAgentList);
|
||||
|
||||
+4
-5
@@ -1,16 +1,16 @@
|
||||
import { Avatar, Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { type DiscoverAssistantItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -18,14 +18,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverAssistantItem>(({ avatar, title, description, identifier }) => {
|
||||
const { styles } = useStyles();
|
||||
return (
|
||||
<Block gap={12} horizontal key={identifier} padding={12} variant={'outlined'}>
|
||||
<Avatar avatar={avatar} shape={'square'} size={40} style={{ flex: 'none' }} />
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
import { Collapse } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useDetailContext } from '../../DetailProvider';
|
||||
const Summary = memo(() => {
|
||||
const { description, summary } = useDetailContext();
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Collapse
|
||||
defaultActiveKey={['summary']}
|
||||
@@ -18,7 +17,7 @@ const Summary = memo(() => {
|
||||
children: (
|
||||
<p
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { type CSSProperties, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
back: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -21,7 +21,6 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
|
||||
const Back = memo<{ href: string; style?: CSSProperties }>(({ href, style }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<Link className={styles.back} style={{ marginBottom: 8, ...style }} to={href}>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Button, Flexbox, type FlexboxProps, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
more: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin-block: 0;
|
||||
@@ -25,8 +25,6 @@ interface BlockProps extends FlexboxProps {
|
||||
}
|
||||
|
||||
const Block = memo<BlockProps>(({ title, more, moreLink, children, ...rest }) => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
<Flexbox gap={16} style={{ position: 'relative' }} width={'100%'}>
|
||||
<Flexbox align={'center'} gap={16} horizontal justify={'space-between'} width={'100%'}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { CopyButton, Flexbox } from '@lobehub/ui';
|
||||
import { Breadcrumb as AntdBreadcrumb, type BreadcrumbProps } from 'antd';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
@@ -10,7 +10,6 @@ import { Link } from 'react-router-dom';
|
||||
import { DiscoverTab } from '@/types/discover';
|
||||
|
||||
const Breadcrumb = memo<{ identifier: string; tab: DiscoverTab }>(({ tab, identifier }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation('discover');
|
||||
|
||||
const tabLabel = useMemo(() => {
|
||||
@@ -33,7 +32,7 @@ const Breadcrumb = memo<{ identifier: string; tab: DiscoverTab }>(({ tab, identi
|
||||
gap={4}
|
||||
horizontal
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
}}
|
||||
>
|
||||
@{identifier}
|
||||
@@ -57,7 +56,7 @@ const Breadcrumb = memo<{ identifier: string; tab: DiscoverTab }>(({ tab, identi
|
||||
gap={4}
|
||||
horizontal
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
}}
|
||||
>
|
||||
{identifier}
|
||||
@@ -72,7 +71,7 @@ const Breadcrumb = memo<{ identifier: string; tab: DiscoverTab }>(({ tab, identi
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [tab, identifier, tabLabel, theme.colorTextSecondary]);
|
||||
}, [tab, identifier, tabLabel]);
|
||||
|
||||
return <AntdBreadcrumb items={items} />;
|
||||
});
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, type FlexboxProps, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { type LucideIcon } from 'lucide-react';
|
||||
import { rgba } from 'polished';
|
||||
import { type ReactNode, memo } from 'react';
|
||||
|
||||
import { useServerConfigStore } from '@/store/serverConfig';
|
||||
|
||||
import CardBanner from '../../components/CardBanner';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
background: css`
|
||||
pointer-events: none;
|
||||
|
||||
@@ -31,22 +30,22 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background: ${rgba(token.colorBgContainer, 0.5)};
|
||||
background: color-mix(in srgb, ${cssVar.colorBgContainer} 50%, transparent);
|
||||
}
|
||||
`,
|
||||
container: css`
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
box-shadow:
|
||||
0 0 0 1px ${token.colorFill} inset,
|
||||
${token.boxShadowTertiary};
|
||||
0 0 0 1px ${cssVar.colorFill} inset,
|
||||
${cssVar.boxShadowTertiary};
|
||||
`,
|
||||
header: css`
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 58px;
|
||||
border-block-end: 1px solid ${token.colorBorderSecondary};
|
||||
border-block-end: 1px solid ${cssVar.colorBorderSecondary};
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -57,7 +56,6 @@ interface HighlightBlockProps extends FlexboxProps {
|
||||
}
|
||||
|
||||
const HighlightBlock = memo<HighlightBlockProps>(({ avatar, title, icon, children, ...rest }) => {
|
||||
const { styles } = useStyles();
|
||||
const mobile = useServerConfigStore((s) => s.isMobile);
|
||||
return (
|
||||
<Flexbox className={styles.container} flex={'none'} width={'100%'} {...rest}>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Tag,
|
||||
Text,
|
||||
} from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { startCase } from 'es-toolkit/compat';
|
||||
import { LinkIcon, Share2Icon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
@@ -23,36 +23,36 @@ import { useShare } from '@/hooks/useShare';
|
||||
|
||||
import CardBanner from '../../components/CardBanner';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
banner: css`
|
||||
overflow: hidden;
|
||||
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
|
||||
background: ${token.colorBgContainer};
|
||||
box-shadow: ${token.boxShadowTertiary};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
box-shadow: ${cssVar.boxShadowTertiary};
|
||||
`,
|
||||
copy: css`
|
||||
background: ${token.colorPrimary};
|
||||
background: ${cssVar.colorPrimary};
|
||||
|
||||
&:hover {
|
||||
background: ${token.colorPrimaryHover};
|
||||
background: ${cssVar.colorPrimaryHover};
|
||||
}
|
||||
`,
|
||||
icon: css`
|
||||
border: 1px solid ${token.colorFillSecondary};
|
||||
border: 1px solid ${cssVar.colorFillSecondary};
|
||||
|
||||
svg {
|
||||
fill: ${token.colorTextSecondary};
|
||||
fill: ${cssVar.colorTextSecondary};
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
|
||||
svg {
|
||||
fill: ${token.colorText};
|
||||
fill: ${cssVar.colorText};
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -80,7 +80,6 @@ const ShareButton = memo<ShareButtonProps>(({ meta, ...rest }) => {
|
||||
...meta,
|
||||
});
|
||||
const { t } = useTranslation('common');
|
||||
const { styles, theme } = useStyles();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
let content;
|
||||
@@ -94,7 +93,7 @@ const ShareButton = memo<ShareButtonProps>(({ meta, ...rest }) => {
|
||||
flex={'none'}
|
||||
height={72}
|
||||
style={{
|
||||
backgroundColor: theme.colorBgContainer,
|
||||
backgroundColor: cssVar.colorBgContainer,
|
||||
borderRadius: '50%',
|
||||
overflow: 'hidden',
|
||||
zIndex: 2,
|
||||
@@ -105,7 +104,7 @@ const ShareButton = memo<ShareButtonProps>(({ meta, ...rest }) => {
|
||||
</Center>
|
||||
<Center padding={12} width={'100%'}>
|
||||
<h3 style={{ fontWeight: 'bold', textAlign: 'center' }}>{meta.title}</h3>
|
||||
<Text as={'p'} style={{ color: theme.colorTextSecondary, textAlign: 'center' }}>
|
||||
<Text as={'p'} style={{ color: cssVar.colorTextSecondary, textAlign: 'center' }}>
|
||||
{meta.desc}
|
||||
</Text>
|
||||
{meta.hashtags && (
|
||||
@@ -137,7 +136,7 @@ const ShareButton = memo<ShareButtonProps>(({ meta, ...rest }) => {
|
||||
<Input value={meta.url} variant={'filled'} />
|
||||
<CopyButton
|
||||
className={styles.copy}
|
||||
color={theme.colorBgLayout}
|
||||
color={cssVar.colorBgLayout}
|
||||
content={meta.url}
|
||||
icon={LinkIcon}
|
||||
size={{ blockSize: 36, size: 16 }}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { kebabCase } from 'es-toolkit/compat';
|
||||
import { Heading2, Heading3, Heading4, Heading5 } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { Children, type ComponentProps, type FC, type ReactNode, isValidElement, useEffect, useMemo } from 'react';
|
||||
import {
|
||||
Children,
|
||||
type ComponentProps,
|
||||
type FC,
|
||||
type ReactNode,
|
||||
isValidElement,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
|
||||
import { useToc } from './useToc';
|
||||
|
||||
@@ -30,31 +38,29 @@ const HeadingIcon: any = {
|
||||
h5: Heading5,
|
||||
};
|
||||
|
||||
const useStyles = createStyles(({ css, cx, token }) => {
|
||||
const anchor = cx(css`
|
||||
display: none;
|
||||
margin-inline-start: 0.5rem;
|
||||
color: ${token.colorTextDescription} !important;
|
||||
`);
|
||||
return {
|
||||
anchor,
|
||||
container: css`
|
||||
&:hover {
|
||||
.${anchor} {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
const styles = createStaticStyles(({ cx, css, cssVar }) => ({
|
||||
anchor: cx(
|
||||
'toc-anchor',
|
||||
css`
|
||||
display: none;
|
||||
margin-inline-start: 0.5rem;
|
||||
color: ${cssVar.colorTextDescription} !important;
|
||||
`,
|
||||
};
|
||||
});
|
||||
),
|
||||
container: css`
|
||||
&:hover {
|
||||
.toc-anchor {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const createHeading = (Tag: `h${1 | 2 | 3 | 4 | 5 | 6}`) => {
|
||||
const Heading: FC<ComponentProps<'h2'>> = ({ children, className, style, ...props }) => {
|
||||
const { setToc, setFinished } = useToc();
|
||||
const { cx, styles } = useStyles();
|
||||
const text = useMemo(() => extractTextChildren(children), [children]);
|
||||
const id = kebabCase(text);
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
if (!setToc) return;
|
||||
@@ -73,7 +79,7 @@ const createHeading = (Tag: `h${1 | 2 | 3 | 4 | 5 | 6}`) => {
|
||||
|
||||
if (Tag === 'h1')
|
||||
return (
|
||||
<Tag style={{ color: theme.colorText, ...style }} {...props} id={id}>
|
||||
<Tag style={{ color: cssVar.colorText, ...style }} {...props} id={id}>
|
||||
{children}
|
||||
</Tag>
|
||||
);
|
||||
@@ -81,7 +87,7 @@ const createHeading = (Tag: `h${1 | 2 | 3 | 4 | 5 | 6}`) => {
|
||||
return (
|
||||
<Tag
|
||||
className={cx(styles.container, className)}
|
||||
style={{ color: theme.colorText, ...style }}
|
||||
style={{ color: cssVar.colorText, ...style }}
|
||||
{...props}
|
||||
id={id}
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Anchor, type AnchorProps } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx, responsive } from 'antd-style';
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
import { SCROLL_PARENT_ID } from '@/app/[variants]/(main)/community/features/const';
|
||||
@@ -9,7 +9,9 @@ import { isOnServerSide } from '@/utils/env';
|
||||
|
||||
import { createTOCTree } from './useToc';
|
||||
|
||||
const useStyles = createStyles(({ css, token, responsive, prefixCls }) => {
|
||||
const prefixCls = 'ant';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
toc: css`
|
||||
a {
|
||||
@@ -52,14 +54,14 @@ const useStyles = createStyles(({ css, token, responsive, prefixCls }) => {
|
||||
}
|
||||
|
||||
.${prefixCls}-anchor-link-title-active {
|
||||
color: ${token.colorText} !important;
|
||||
color: ${cssVar.colorText} !important;
|
||||
}
|
||||
|
||||
.${prefixCls}-anchor-link-title:not(.${prefixCls}-anchor-link-title-active) {
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorText};
|
||||
color: ${cssVar.colorText};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,8 +74,6 @@ const useStyles = createStyles(({ css, token, responsive, prefixCls }) => {
|
||||
});
|
||||
|
||||
const Toc = memo<AnchorProps>(({ items, className, ...rest }) => {
|
||||
const { cx, styles } = useStyles();
|
||||
|
||||
const toc = useMemo(() => createTOCTree(items as any), [items]);
|
||||
|
||||
return (
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
import { Block, Flexbox, Icon, Tag } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { CheckIcon, MinusIcon } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo } from 'react';
|
||||
@@ -14,7 +14,6 @@ import { useDetailContext } from '../../../../../../../../../features/MCPPluginD
|
||||
import Title from '../../../../../features/Title';
|
||||
|
||||
const Versions = memo(() => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation('discover');
|
||||
const { versions } = useDetailContext();
|
||||
const pathname = usePathname();
|
||||
@@ -50,7 +49,7 @@ const Versions = memo(() => {
|
||||
dataIndex: 'isValidated',
|
||||
render: (_, record) => (
|
||||
<Icon
|
||||
color={record.isValidated ? theme.colorSuccess : theme.colorTextDescription}
|
||||
color={record.isValidated ? cssVar.colorSuccess : cssVar.colorTextDescription}
|
||||
icon={record.isValidated ? CheckIcon : MinusIcon}
|
||||
/>
|
||||
),
|
||||
|
||||
+2
-3
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Button, Flexbox, Icon } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { Trash2Icon } from 'lucide-react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,7 +12,7 @@ import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
||||
import { useToolStore } from '@/store/tool';
|
||||
import { pluginSelectors } from '@/store/tool/slices/plugin/selectors';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
button: css`
|
||||
button {
|
||||
width: 100%;
|
||||
@@ -24,7 +24,6 @@ const ActionButton = memo(() => {
|
||||
const { t } = useTranslation(['discover', 'plugin']);
|
||||
const detailContext = useDetailContext();
|
||||
const { identifier, haveCloudEndpoint } = detailContext;
|
||||
const { styles } = useStyles();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { isAuthenticated, isLoading: isAuthLoading, signIn } = useMarketAuth();
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Avatar, Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { type DiscoverMcpItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -18,14 +18,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverMcpItem>(({ name, icon, description, identifier }) => {
|
||||
const { styles } = useStyles();
|
||||
return (
|
||||
<Block gap={12} horizontal key={identifier} padding={12} variant={'outlined'}>
|
||||
<Avatar avatar={icon} shape={'square'} size={40} style={{ flex: 'none' }} />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { SOCIAL_URL } from '@lobechat/business-const';
|
||||
import { Flexbox, Icon, Tabs } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { BookOpenIcon, ListIcon, Settings2Icon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
@@ -10,17 +10,17 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { ModelNavKey } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
link: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorInfo};
|
||||
color: ${cssVar.colorInfo};
|
||||
}
|
||||
`,
|
||||
nav: css`
|
||||
border-block-end: 1px solid ${token.colorBorder};
|
||||
border-block-end: 1px solid ${cssVar.colorBorder};
|
||||
`,
|
||||
};
|
||||
});
|
||||
@@ -33,7 +33,6 @@ interface NavProps {
|
||||
|
||||
const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ModelNavKey.Overview }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { styles } = useStyles();
|
||||
|
||||
const nav = (
|
||||
<Tabs
|
||||
|
||||
+3
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { ActionIcon, Block, Flexbox, Icon, Tooltip, TooltipGroup } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { BadgeCheck, BookIcon, ChevronRightIcon, KeyIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -20,7 +20,6 @@ import { useDetailContext } from '../../../DetailProvider';
|
||||
const ProviderList = memo(() => {
|
||||
const { providers = [] } = useDetailContext();
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<TooltipGroup>
|
||||
@@ -140,7 +139,7 @@ const ProviderList = memo(() => {
|
||||
{isLobeHub && (
|
||||
<Tooltip title={t('models.providerInfo.officialTooltip')}>
|
||||
<ActionIcon
|
||||
color={theme.colorSuccess}
|
||||
color={cssVar.colorSuccess}
|
||||
icon={BadgeCheck}
|
||||
size={'small'}
|
||||
variant={'filled'}
|
||||
@@ -170,7 +169,7 @@ const ProviderList = memo(() => {
|
||||
to={urlJoin('/community/provider', record.id)}
|
||||
>
|
||||
<ActionIcon
|
||||
color={theme.colorTextDescription}
|
||||
color={cssVar.colorTextDescription}
|
||||
icon={ChevronRightIcon}
|
||||
size={'small'}
|
||||
variant={'filled'}
|
||||
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { Divider } from 'antd';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -24,11 +24,10 @@ const formatNum = (num: string | number) => {
|
||||
const ParameterItem = memo<ParameterItemProps>(
|
||||
({ docUrl = DEFAULT_DOC_URL, desc, type, defaultValue, range }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Flexbox align={'flex-start'} gap={16}>
|
||||
<p style={{ color: theme.colorTextSecondary, margin: 0 }}>
|
||||
<p style={{ color: cssVar.colorTextSecondary, margin: 0 }}>
|
||||
{desc}{' '}
|
||||
<Link href={docUrl} target={'_blank'}>
|
||||
{t('models.parameterList.docs')}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ModelIcon } from '@lobehub/icons';
|
||||
import { Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import { createStaticStyles, cssVar, useResponsive } from 'antd-style';
|
||||
import { DotIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -13,17 +13,17 @@ import { ModelInfoTags } from '@/components/ModelSelect';
|
||||
import PublishedTime from '../../../../../../../components/PublishedTime';
|
||||
import { useDetailContext } from './DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
time: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
version: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
font-size: 13px;
|
||||
`,
|
||||
};
|
||||
@@ -32,7 +32,6 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
const { identifier, releasedAt, displayName, type, abilities, contextWindowTokens } =
|
||||
useDetailContext();
|
||||
const { styles, theme } = useStyles();
|
||||
const { mobile = isMobile } = useResponsive();
|
||||
const { t } = useTranslation('models');
|
||||
|
||||
@@ -99,7 +98,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
</Flexbox>
|
||||
<div
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
}}
|
||||
>
|
||||
{t(`${identifier}.description`)}
|
||||
|
||||
+3
-4
@@ -3,16 +3,16 @@
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { Button, Icon } from '@lobehub/ui';
|
||||
import { Dropdown } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ChevronDownIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link , useNavigate } from 'react-router-dom';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import { useDetailContext } from '../../DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
button: css`
|
||||
button {
|
||||
width: 100%;
|
||||
@@ -21,7 +21,6 @@ const useStyles = createStyles(({ css }) => ({
|
||||
}));
|
||||
|
||||
const ChatWithModel = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('discover');
|
||||
const { providers = [] } = useDetailContext();
|
||||
const includeLobeHub = providers.some((item) => item.id === 'lobehub');
|
||||
|
||||
+4
-5
@@ -1,18 +1,18 @@
|
||||
import { ModelIcon } from '@lobehub/icons';
|
||||
import { Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { type DiscoverModelItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -20,14 +20,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverModelItem>(({ identifier, displayName }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('models');
|
||||
return (
|
||||
<Block gap={12} horizontal key={identifier} padding={12} variant={'outlined'}>
|
||||
|
||||
+4
-5
@@ -1,18 +1,18 @@
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { type DiscoverModelDetailProviderItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -20,14 +20,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverModelDetailProviderItem>(({ id, name }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('providers');
|
||||
return (
|
||||
<Block gap={12} horizontal key={id} padding={12} variant={'outlined'}>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { SOCIAL_URL } from '@lobechat/business-const';
|
||||
import { Flexbox, Icon, Tabs } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { BookOpenIcon, BrainCircuitIcon, ListIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
@@ -13,17 +13,17 @@ import { ProviderNavKey } from '@/types/discover';
|
||||
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
link: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorInfo};
|
||||
color: ${cssVar.colorInfo};
|
||||
}
|
||||
`,
|
||||
nav: css`
|
||||
border-block-end: 1px solid ${token.colorBorder};
|
||||
border-block-end: 1px solid ${cssVar.colorBorder};
|
||||
`,
|
||||
};
|
||||
});
|
||||
@@ -37,7 +37,6 @@ interface NavProps {
|
||||
const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ProviderNavKey.Overview }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { identifier } = useDetailContext();
|
||||
const { styles } = useStyles();
|
||||
|
||||
const nav = (
|
||||
<Tabs
|
||||
|
||||
+3
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ModelIcon } from '@lobehub/icons';
|
||||
import { ActionIcon, Block, Flexbox, Tooltip, TooltipGroup } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { ChevronRightIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -19,7 +19,6 @@ import { useDetailContext } from '../../../DetailProvider';
|
||||
const ModelList = memo(() => {
|
||||
const { models = [] } = useDetailContext();
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<TooltipGroup>
|
||||
@@ -36,7 +35,7 @@ const ModelList = memo(() => {
|
||||
<ModelIcon model={record.id} size={24} type={'avatar'} />
|
||||
<Flexbox style={{ overflow: 'hidden' }}>
|
||||
<div style={{ fontWeight: 500 }}>{record.displayName}</div>
|
||||
<div style={{ color: theme.colorTextSecondary, fontSize: 12 }}>
|
||||
<div style={{ color: cssVar.colorTextSecondary, fontSize: 12 }}>
|
||||
{record.id}
|
||||
</div>
|
||||
</Flexbox>
|
||||
@@ -132,7 +131,7 @@ const ModelList = memo(() => {
|
||||
<Flexbox align="center" gap={4} horizontal justify={'flex-end'}>
|
||||
<Link style={{ color: 'inherit' }} to={urlJoin('/community/model', record.id)}>
|
||||
<ActionIcon
|
||||
color={theme.colorTextDescription}
|
||||
color={cssVar.colorTextDescription}
|
||||
icon={ChevronRightIcon}
|
||||
size={'small'}
|
||||
variant={'filled'}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Github, ProviderCombine } from '@lobehub/icons';
|
||||
import { ActionIcon, Flexbox } from '@lobehub/ui';
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import { cssVar, useResponsive } from 'antd-style';
|
||||
import { GlobeIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
@@ -11,26 +11,9 @@ import urlJoin from 'url-join';
|
||||
|
||||
import { useDetailContext } from './DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
return {
|
||||
desc: css`
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
time: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
`,
|
||||
version: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-size: 13px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
const { t } = useTranslation('providers');
|
||||
const { identifier, url, modelsUrl, name } = useDetailContext();
|
||||
const { theme } = useStyles();
|
||||
const { mobile = isMobile } = useResponsive();
|
||||
|
||||
return (
|
||||
@@ -64,7 +47,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
target={'_blank'}
|
||||
>
|
||||
<ActionIcon color={theme.colorTextDescription} icon={GlobeIcon} />
|
||||
<ActionIcon color={cssVar.colorTextDescription} icon={GlobeIcon} />
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -76,7 +59,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
target={'_blank'}
|
||||
>
|
||||
<ActionIcon fill={theme.colorTextDescription} icon={Github} />
|
||||
<ActionIcon fill={cssVar.colorTextDescription} icon={Github} />
|
||||
</Link>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
@@ -86,7 +69,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
gap={mobile ? 12 : 24}
|
||||
horizontal
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
}}
|
||||
>
|
||||
{t(`${identifier}.description`)}
|
||||
|
||||
+2
-3
@@ -3,7 +3,7 @@
|
||||
import { isDesktop } from '@lobechat/const';
|
||||
import { Button, Icon } from '@lobehub/ui';
|
||||
import { Dropdown } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ChevronDownIcon, SquareArrowOutUpRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -11,7 +11,7 @@ import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useDetailContext } from '../../DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
button: css`
|
||||
button {
|
||||
width: 100%;
|
||||
@@ -20,7 +20,6 @@ const useStyles = createStyles(({ css }) => ({
|
||||
}));
|
||||
|
||||
const ProviderConfig = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('discover');
|
||||
const { url, modelsUrl, identifier } = useDetailContext();
|
||||
const navigate = useNavigate();
|
||||
|
||||
+4
-5
@@ -1,18 +1,18 @@
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { type DiscoverProviderItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -20,14 +20,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverProviderItem>(({ identifier, name }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('providers');
|
||||
return (
|
||||
<Block gap={12} horizontal key={identifier} padding={12} variant={'outlined'}>
|
||||
|
||||
+4
-5
@@ -1,18 +1,18 @@
|
||||
import { ModelIcon } from '@lobehub/icons';
|
||||
import { Block, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { type DiscoverProviderDetailModelItem } from '@/types/discover';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -20,14 +20,13 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
const RelatedItem = memo<DiscoverProviderDetailModelItem>(({ id, displayName }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('models');
|
||||
return (
|
||||
<Block gap={12} horizontal key={id} padding={12} variant={'outlined'}>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Center } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles , responsive } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
banner: css`
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
@@ -14,7 +14,7 @@ const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
height: 160px;
|
||||
padding: 16px;
|
||||
|
||||
${responsive.mobile} {
|
||||
${responsive.sm} {
|
||||
position: relative;
|
||||
|
||||
width: calc(100% + 32px);
|
||||
@@ -38,9 +38,9 @@ const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
border-radius: ${cssVar.borderRadiusLG};
|
||||
|
||||
background: ${token.colorFillTertiary};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
|
||||
@media (max-width: 1720px) {
|
||||
border-radius: 0;
|
||||
@@ -57,7 +57,7 @@ const useStyles = createStyles(({ css, token, responsive }) => ({
|
||||
height: 64px;
|
||||
min-height: 64px;
|
||||
|
||||
${responsive.mobile} {
|
||||
${responsive.sm} {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
@@ -69,7 +69,6 @@ interface BannerProps {
|
||||
}
|
||||
|
||||
const Banner = memo<BannerProps>(({ avatar, bannerUrl }) => {
|
||||
const { styles } = useStyles();
|
||||
// Use bannerUrl if available, otherwise fall back to blurred avatar
|
||||
const backgroundImage = bannerUrl || avatar;
|
||||
const shouldBlur = !bannerUrl && !!avatar;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { SiGithub, SiX } from '@icons-pack/react-simple-icons';
|
||||
import { ActionIcon, Avatar, Button, Flexbox, Text, Tooltip, TooltipGroup } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { Globe } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -14,7 +14,6 @@ import Banner from './Banner';
|
||||
|
||||
const UserHeader = memo(() => {
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
const { user, isOwner, onEditProfile } = useUserDetailContext();
|
||||
|
||||
const displayName = user.displayName || user.userName || user.namespace;
|
||||
@@ -28,7 +27,7 @@ const UserHeader = memo(() => {
|
||||
avatar={user.avatarUrl || undefined}
|
||||
shape={'square'}
|
||||
size={64}
|
||||
style={{ boxShadow: `0 0 0 4px ${theme.colorBgContainer}`, flexShrink: 0 }}
|
||||
style={{ boxShadow: `0 0 0 4px ${cssVar.colorBgContainer}`, flexShrink: 0 }}
|
||||
/>
|
||||
<Flexbox align={'flex-start'} gap={16} horizontal justify={'space-between'}>
|
||||
<Flexbox
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
TooltipGroup,
|
||||
} from '@lobehub/ui';
|
||||
import { App, Dropdown } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import {
|
||||
AlertTriangle,
|
||||
ClockIcon,
|
||||
@@ -60,20 +60,20 @@ const getStatusTagColor = (status?: AgentStatus) => {
|
||||
}
|
||||
};
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
author: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
footer: css`
|
||||
margin-block-start: 16px;
|
||||
border-block-start: 1px dashed ${token.colorBorder};
|
||||
background: ${token.colorBgContainerSecondary};
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
moreButton: css`
|
||||
position: absolute;
|
||||
@@ -86,16 +86,16 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
statTag: css`
|
||||
border-radius: 4px;
|
||||
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
font-size: 11px;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
|
||||
background: ${token.colorFillTertiary};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -103,7 +103,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
wrapper: css`
|
||||
@@ -129,7 +129,6 @@ const UserAgentCard = memo<UserAgentCardProps>(
|
||||
status,
|
||||
identifier,
|
||||
}) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation(['discover', 'setting']);
|
||||
const navigate = useNavigate();
|
||||
const { message } = App.useApp();
|
||||
@@ -261,7 +260,7 @@ const UserAgentCard = memo<UserAgentCardProps>(
|
||||
{isOwner && (
|
||||
<Dropdown menu={{ items: menuItems }} trigger={['click']}>
|
||||
<div
|
||||
className={`more-button ${styles.moreButton}`}
|
||||
className={cx('more-button', styles.moreButton)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Avatar, Block, Flexbox, Grid, Icon, Tag, Text, Tooltip } from '@lobehub/ui';
|
||||
import { App } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ClockIcon, DownloadIcon, Heart } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo, useCallback } from 'react';
|
||||
@@ -18,12 +18,12 @@ import { formatIntergerNumber } from '@/utils/format';
|
||||
|
||||
import { useUserDetailContext } from './DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
favoriteButton: css`
|
||||
cursor: pointer;
|
||||
@@ -32,7 +32,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
inset-block-start: 12px;
|
||||
inset-inline-end: 12px;
|
||||
|
||||
color: ${token.colorError};
|
||||
color: ${cssVar.colorError};
|
||||
|
||||
opacity: 0;
|
||||
|
||||
@@ -40,21 +40,21 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
`,
|
||||
footer: css`
|
||||
margin-block-start: 16px;
|
||||
border-block-start: 1px dashed ${token.colorBorder};
|
||||
background: ${token.colorBgContainerSecondary};
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
statTag: css`
|
||||
border-radius: 4px;
|
||||
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
font-size: 11px;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
|
||||
background: ${token.colorFillTertiary};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -62,7 +62,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
wrapper: css`
|
||||
@@ -90,7 +90,6 @@ const FavoriteAgentCard = memo<FavoriteAgentCardProps>(
|
||||
onUnfavorite,
|
||||
showUnfavorite,
|
||||
}) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('discover');
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -119,7 +118,7 @@ const FavoriteAgentCard = memo<FavoriteAgentCardProps>(
|
||||
{showUnfavorite && (
|
||||
<Tooltip title={t('user.unfavorite')}>
|
||||
<div
|
||||
className={`favorite-button ${styles.favoriteButton}`}
|
||||
className={cx('favorite-button', styles.favoriteButton)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onUnfavorite(identifier);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Avatar, Block, Flexbox, Grid, Icon, Tag, Text, Tooltip } from '@lobehub/ui';
|
||||
import { App } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ClockIcon, Heart } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo, useCallback } from 'react';
|
||||
@@ -17,12 +17,12 @@ import { useDiscoverStore } from '@/store/discover';
|
||||
|
||||
import { useUserDetailContext } from './DetailProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
favoriteButton: css`
|
||||
cursor: pointer;
|
||||
@@ -31,7 +31,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
inset-block-start: 12px;
|
||||
inset-inline-end: 12px;
|
||||
|
||||
color: ${token.colorError};
|
||||
color: ${cssVar.colorError};
|
||||
|
||||
opacity: 0;
|
||||
|
||||
@@ -39,12 +39,12 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
`,
|
||||
footer: css`
|
||||
margin-block-start: 16px;
|
||||
border-block-start: 1px dashed ${token.colorBorder};
|
||||
background: ${token.colorBgContainerSecondary};
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -52,7 +52,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
wrapper: css`
|
||||
@@ -79,7 +79,6 @@ const FavoritePluginCard = memo<FavoritePluginCardProps>(
|
||||
onUnfavorite,
|
||||
showUnfavorite,
|
||||
}) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('discover');
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -107,7 +106,7 @@ const FavoritePluginCard = memo<FavoritePluginCardProps>(
|
||||
{showUnfavorite && (
|
||||
<Tooltip title={t('user.unfavorite')}>
|
||||
<div
|
||||
className={`favorite-button ${styles.favoriteButton}`}
|
||||
className={cx('favorite-button', styles.favoriteButton)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onUnfavorite(identifier);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Skeleton } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
import ListLoading from '@/app/[variants]/(main)/community/components/ListLoading';
|
||||
@@ -9,7 +9,6 @@ import ListLoading from '@/app/[variants]/(main)/community/components/ListLoadin
|
||||
import Banner from './features/Header/Banner';
|
||||
|
||||
const Loading = memo(() => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Flexbox gap={24} width={'100%'}>
|
||||
{/* User Header Skeleton */}
|
||||
@@ -18,7 +17,7 @@ const Loading = memo(() => {
|
||||
<Skeleton.Avatar
|
||||
shape={'square'}
|
||||
size={64}
|
||||
style={{ boxShadow: `0 0 0 4px ${theme.colorBgContainer}`, flexShrink: 0 }}
|
||||
style={{ boxShadow: `0 0 0 4px ${cssVar.colorBgContainer}`, flexShrink: 0 }}
|
||||
/>
|
||||
<Skeleton paragraph={{ rows: 1 }} />
|
||||
</Flexbox>
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
import { Button, Flexbox, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cx, useThemeMode } from 'antd-style';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import DefaultFooter from '@/features/Setting/Footer';
|
||||
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
||||
|
||||
const useStyles = createStyles(({ css, isDarkMode }) => {
|
||||
const image = isDarkMode
|
||||
? '/images/community_footer_dark.webp'
|
||||
: '/images/community_footer_light.webp';
|
||||
return {
|
||||
footer: css`
|
||||
min-height: 320px;
|
||||
padding-block-start: 32px;
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
footer: css`
|
||||
min-height: 320px;
|
||||
padding-block-start: 32px;
|
||||
|
||||
background-image: url(${image});
|
||||
background-repeat: no-repeat;
|
||||
background-position: center bottom;
|
||||
background-size: 512px auto;
|
||||
background-blend-mode: ${isDarkMode ? 'screen' : 'multiply'};
|
||||
`,
|
||||
};
|
||||
});
|
||||
background-repeat: no-repeat;
|
||||
background-position: center bottom;
|
||||
background-size: 512px auto;
|
||||
`,
|
||||
footer_dark: css`
|
||||
background-image: url('/images/community_footer_dark.webp');
|
||||
background-blend-mode: screen;
|
||||
`,
|
||||
footer_light: css`
|
||||
background-image: url('/images/community_footer_light.webp');
|
||||
background-blend-mode: multiply;
|
||||
`,
|
||||
}));
|
||||
|
||||
const Footer = memo(() => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { styles } = useStyles();
|
||||
const { isDarkMode } = useThemeMode();
|
||||
const { isAuthenticated, signIn } = useMarketAuth();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleSignIn = useCallback(async () => {
|
||||
@@ -42,7 +43,12 @@ const Footer = memo(() => {
|
||||
if (isAuthenticated) return <DefaultFooter />;
|
||||
|
||||
return (
|
||||
<Flexbox align={'center'} className={styles.footer} flex={'none'} gap={4}>
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
className={cx(styles.footer, isDarkMode ? styles.footer_dark : styles.footer_light)}
|
||||
flex={'none'}
|
||||
gap={4}
|
||||
>
|
||||
<Text align={'center'} as={'h2'} fontSize={22} strong>
|
||||
{t('footer.title')}
|
||||
</Text>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
@@ -9,15 +9,20 @@ import UserAvatar from '@/app/[variants]/(main)/community/features/UserAvatar';
|
||||
import NavHeader from '@/features/NavHeader';
|
||||
|
||||
import SortButton from '../features/SortButton';
|
||||
import { styles } from './Header/style';
|
||||
|
||||
const Header = memo(() => {
|
||||
const theme = useTheme();
|
||||
const location = useLocation();
|
||||
// const { activeKey } = useNav();
|
||||
const isHome = location.pathname === '/';
|
||||
|
||||
const cssVariables: Record<string, string> = {
|
||||
'--header-border-color': cssVar.colorBorderSecondary,
|
||||
};
|
||||
|
||||
return (
|
||||
<NavHeader
|
||||
className={styles.headerContainer}
|
||||
left={<StoreSearchBar />}
|
||||
right={
|
||||
!isHome && (
|
||||
@@ -28,9 +33,7 @@ const Header = memo(() => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
style={{
|
||||
borderBottom: `1px solid ${theme.colorBorderSecondary}`,
|
||||
}}
|
||||
style={cssVariables}
|
||||
styles={{
|
||||
left: { flex: 1 },
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
// Header 容器
|
||||
headerContainer: css`
|
||||
border-block-end: 1px solid var(--header-border-color, ${cssVar.colorBorderSecondary});
|
||||
`,
|
||||
}));
|
||||
@@ -6,26 +6,25 @@ import WideScreenContainer from '@/features/WideScreenContainer';
|
||||
import { MAX_WIDTH } from '../../features/const';
|
||||
import Footer from './Footer';
|
||||
import Header from './Header';
|
||||
import { styles } from './style';
|
||||
|
||||
const Layout = () => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Flexbox height={'100%'} style={{ overflowY: 'auto' }} width={'100%'}>
|
||||
<Flexbox className={styles.mainContainer} height={'100%'} width={'100%'}>
|
||||
<WideScreenContainer
|
||||
className={styles.contentContainer}
|
||||
gap={16}
|
||||
minWidth={MAX_WIDTH}
|
||||
paddingBlock={16}
|
||||
style={{
|
||||
minHeight: '100%',
|
||||
}}
|
||||
wrapperStyle={{
|
||||
minHeight: '100%',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
<div style={{ flex: 1 }} />
|
||||
<div className={styles.spacer} />
|
||||
<Footer />
|
||||
</WideScreenContainer>
|
||||
</Flexbox>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
|
||||
// 内容容器
|
||||
contentContainer: css`
|
||||
min-height: 100%;
|
||||
`,
|
||||
|
||||
|
||||
// 主容器
|
||||
mainContainer: css`
|
||||
overflow-y: auto;
|
||||
`,
|
||||
|
||||
// 占位符
|
||||
spacer: css`
|
||||
flex: 1;
|
||||
`,
|
||||
}));
|
||||
@@ -3,10 +3,11 @@ import { Outlet } from 'react-router-dom';
|
||||
|
||||
import CategoryContainer from '../../../components/CategoryContainer';
|
||||
import Category from '../features/Category';
|
||||
import { styles } from './style';
|
||||
|
||||
const Layout = () => {
|
||||
return (
|
||||
<Flexbox gap={24} horizontal style={{ position: 'relative' }} width={'100%'}>
|
||||
<Flexbox className={styles.mainContainer} gap={24} horizontal width={'100%'}>
|
||||
<CategoryContainer>
|
||||
<Category />
|
||||
</CategoryContainer>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
// 主容器
|
||||
mainContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
}));
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ClockIcon } from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
@@ -13,32 +13,32 @@ import { type AssistantMarketSource, type DiscoverAssistantItem } from '@/types/
|
||||
|
||||
import TokenTag from './TokenTag';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
author: css`
|
||||
cursor: pointer;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorPrimary};
|
||||
color: ${cssVar.colorPrimary};
|
||||
}
|
||||
`,
|
||||
code: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
footer: css`
|
||||
margin-block-start: 16px;
|
||||
border-block-start: 1px dashed ${token.colorBorder};
|
||||
background: ${token.colorBgContainerSecondary};
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -46,7 +46,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -68,7 +68,6 @@ const AssistantItem = memo<DiscoverAssistantItem>(
|
||||
backgroundColor,
|
||||
userName,
|
||||
}) => {
|
||||
const { styles } = useStyles();
|
||||
const navigate = useNavigate();
|
||||
const { source } = useQuery() as { source?: AssistantMarketSource };
|
||||
const link = qs.stringifyUrl(
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { MCP } from '@lobehub/icons';
|
||||
import { Flexbox, Icon, Tag, Tooltip } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { BookTextIcon, CoinsIcon, DownloadIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { formatIntergerNumber } from '@/utils/format';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
token: css`
|
||||
border-radius: 4px;
|
||||
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
font-size: 11px;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
|
||||
background: ${token.colorFillTertiary};
|
||||
background: ${cssVar.colorFillTertiary};
|
||||
`,
|
||||
};
|
||||
});
|
||||
@@ -31,7 +31,6 @@ interface TokenTagProps {
|
||||
|
||||
const TokenTag = memo<TokenTagProps>(
|
||||
({ tokenUsage, pluginCount, knowledgeCount, installCount, placement = 'right' }) => {
|
||||
const { styles, theme } = useStyles();
|
||||
const { t } = useTranslation('discover');
|
||||
return (
|
||||
<Flexbox align={'center'} gap={4} horizontal>
|
||||
@@ -61,7 +60,7 @@ const TokenTag = memo<TokenTagProps>(
|
||||
styles={{ root: { pointerEvents: 'none' } }}
|
||||
title={t('assistants.withPlugin')}
|
||||
>
|
||||
<Tag icon={<Icon fill={theme.colorTextSecondary} icon={MCP} />}>{pluginCount}</Tag>
|
||||
<Tag icon={<Icon fill={cssVar.colorTextSecondary} icon={MCP} />}>{pluginCount}</Tag>
|
||||
</Tooltip>
|
||||
)}
|
||||
{Boolean(knowledgeCount && knowledgeCount > 0) && (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Pagination as Page } from 'antd';
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import { createStaticStyles, useResponsive } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
@@ -11,16 +11,18 @@ import { type DiscoverTab } from '@/types/discover';
|
||||
|
||||
const SCROLL_CONTAINER_ID = 'lobe-mobile-scroll-container';
|
||||
|
||||
const useStyles = createStyles(({ css, token, prefixCls }) => {
|
||||
const prefixCls = 'ant';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
page: css`
|
||||
.${prefixCls}-pagination-item-active {
|
||||
border-color: ${token.colorFillSecondary};
|
||||
background: ${token.colorFillSecondary};
|
||||
border-color: ${cssVar.colorFillSecondary};
|
||||
background: ${cssVar.colorFillSecondary};
|
||||
|
||||
&:hover {
|
||||
border-color: ${token.colorFill};
|
||||
background: ${token.colorFill};
|
||||
border-color: ${cssVar.colorFill};
|
||||
background: ${cssVar.colorFill};
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -35,7 +37,6 @@ interface PaginationProps {
|
||||
}
|
||||
|
||||
const Pagination = memo<PaginationProps>(({ tab, currentPage, total, pageSize }) => {
|
||||
const { styles } = useStyles();
|
||||
const { page } = useQuery();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
@@ -3,10 +3,11 @@ import { Outlet } from 'react-router-dom';
|
||||
|
||||
import CategoryContainer from '../../../components/CategoryContainer';
|
||||
import Category from '../features/Category';
|
||||
import { styles } from './style';
|
||||
|
||||
const Layout = () => {
|
||||
return (
|
||||
<Flexbox gap={24} horizontal style={{ position: 'relative' }} width={'100%'}>
|
||||
<Flexbox className={styles.mainContainer} gap={24} horizontal width={'100%'}>
|
||||
<CategoryContainer>
|
||||
<Category />
|
||||
</CategoryContainer>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css }) => ({
|
||||
// 主容器
|
||||
mainContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
}));
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Flexbox, Icon, Tooltip } from '@lobehub/ui';
|
||||
import { useTheme } from 'antd-style';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { Blend, Cloud, LaptopMinimalIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,19 +10,18 @@ interface ConnectionTypeTagProps {
|
||||
|
||||
const ConnectionTypeTag = memo<ConnectionTypeTagProps>(({ type }) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const theme = useTheme();
|
||||
|
||||
const icons = {
|
||||
hybrid: {
|
||||
color: theme.purple,
|
||||
color: cssVar.purple,
|
||||
icon: Blend,
|
||||
},
|
||||
local: {
|
||||
color: theme.colorWarning,
|
||||
color: cssVar.colorWarning,
|
||||
icon: LaptopMinimalIcon,
|
||||
},
|
||||
remote: {
|
||||
color: theme.colorInfo,
|
||||
color: cssVar.colorInfo,
|
||||
icon: Cloud,
|
||||
},
|
||||
};
|
||||
@@ -36,7 +35,7 @@ const ConnectionTypeTag = memo<ConnectionTypeTagProps>(({ type }) => {
|
||||
gap={6}
|
||||
horizontal
|
||||
style={{
|
||||
color: theme.colorTextSecondary,
|
||||
color: cssVar.colorTextSecondary,
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Github } from '@lobehub/icons';
|
||||
import { ActionIcon, Avatar, Block, Flexbox, Icon, Tag, Text, Tooltip } from '@lobehub/ui';
|
||||
import { Spotlight } from '@lobehub/ui/awesome';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { ClockIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -19,27 +19,27 @@ import { type DiscoverMcpItem } from '@/types/discover';
|
||||
import ConnectionTypeTag from './ConnectionTypeTag';
|
||||
import MetaInfo from './MetaInfo';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => {
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
author: css`
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
code: css`
|
||||
font-family: ${token.fontFamilyCode};
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
desc: css`
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
color: ${token.colorTextSecondary};
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
footer: css`
|
||||
margin-block-start: 16px;
|
||||
border-block-start: 1px dashed ${token.colorBorder};
|
||||
background: ${token.colorBgContainerSecondary};
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextDescription};
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
title: css`
|
||||
margin: 0 !important;
|
||||
@@ -47,7 +47,7 @@ const useStyles = createStyles(({ css, token }) => {
|
||||
font-weight: 500 !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorLink};
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -75,7 +75,6 @@ const McpItem = memo<DiscoverMcpItem>(
|
||||
github,
|
||||
}) => {
|
||||
const { t } = useTranslation('discover');
|
||||
const { styles, theme } = useStyles();
|
||||
const navigate = useNavigate();
|
||||
const link = urlJoin('/community/mcp', identifier);
|
||||
return (
|
||||
@@ -150,7 +149,7 @@ const McpItem = memo<DiscoverMcpItem>(
|
||||
rel="noopener noreferrer"
|
||||
target={'_blank'}
|
||||
>
|
||||
<ActionIcon fill={theme.colorTextDescription} icon={Github} />
|
||||
<ActionIcon fill={cssVar.colorTextDescription} icon={Github} />
|
||||
</a>
|
||||
)}
|
||||
</Flexbox>
|
||||
|
||||
@@ -3,15 +3,16 @@ import { Outlet } from 'react-router-dom';
|
||||
|
||||
import CategoryContainer from '../../../components/CategoryContainer';
|
||||
import Category from '../features/Category';
|
||||
import { styles } from './style';
|
||||
|
||||
const Layout = () => {
|
||||
return (
|
||||
<Flexbox gap={24} horizontal style={{ position: 'relative' }} width={'100%'}>
|
||||
<Flexbox className={styles.mainContainer} gap={24} horizontal width={'100%'}>
|
||||
<CategoryContainer>
|
||||
<Category />
|
||||
</CategoryContainer>
|
||||
<Flexbox flex={1} gap={16}>
|
||||
{<Outlet />}
|
||||
<Outlet />
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user