@fe-free/core 1.5.5 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/package.json +6 -3
- package/src/index.ts +1 -6
- package/src/markdown/code.tsx +30 -0
- package/src/markdown/deep_seek.tsx +53 -0
- package/src/markdown/index.tsx +32 -0
- package/src/markdown/markdown.stories.tsx +140 -0
- package/src/markdown/style.scss +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @fe-free/core
|
|
2
2
|
|
|
3
|
+
## 1.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat: md
|
|
8
|
+
- @fe-free/tool@1.6.1
|
|
9
|
+
|
|
10
|
+
## 1.6.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- feat: markdown
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- @fe-free/tool@1.6.0
|
|
19
|
+
|
|
3
20
|
## 1.5.5
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fe-free/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"author": "",
|
|
@@ -29,14 +29,17 @@
|
|
|
29
29
|
"ahooks": "^3.7.8",
|
|
30
30
|
"axios": "^1.6.5",
|
|
31
31
|
"classnames": "^2.5.1",
|
|
32
|
+
"github-markdown-css": "^5.8.1",
|
|
32
33
|
"lodash-es": "^4.17.21",
|
|
33
34
|
"react-ace": "^11.0.1",
|
|
34
|
-
"react-markdown": "^9.0
|
|
35
|
+
"react-markdown": "^9.1.0",
|
|
35
36
|
"react-router-dom": "^6.16.0",
|
|
36
37
|
"react-syntax-highlighter": "^15.5.0",
|
|
38
|
+
"rehype-raw": "^7.0.0",
|
|
39
|
+
"remark-gfm": "^4.0.1",
|
|
37
40
|
"vanilla-jsoneditor": "^0.23.1",
|
|
38
41
|
"zustand": "^4.5.4",
|
|
39
|
-
"@fe-free/tool": "1.
|
|
42
|
+
"@fe-free/tool": "1.6.1"
|
|
40
43
|
},
|
|
41
44
|
"peerDependencies": {
|
|
42
45
|
"@ant-design/pro-components": "^2.8.7",
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
export { useGlobalInfiniteScroll } from './ahooks/use_global_infinite_scroll';
|
|
2
2
|
export { useGlobalRequest } from './ahooks/use_global_request';
|
|
3
|
-
|
|
4
3
|
export { LoadingButton } from './button';
|
|
5
|
-
|
|
6
4
|
export { CRUD, CRUDDetail, CRUDOfSimple, OperateDelete, useDelete } from './crud';
|
|
7
5
|
export type { CRUDDetailProps, CRUDMethods, CRUDOfSimpleProps, CRUDProps } from './crud';
|
|
8
|
-
|
|
9
6
|
export { Editor } from './editor';
|
|
10
7
|
export type { EditorProps } from './editor';
|
|
11
8
|
export { EditorJavascript } from './editor_javascript';
|
|
@@ -16,7 +13,6 @@ export { EditorLogs } from './editor_logs';
|
|
|
16
13
|
export type { EditorLogsProps } from './editor_logs';
|
|
17
14
|
export { EditorMarkdown } from './editor_markdown';
|
|
18
15
|
export type { EditorMarkdownProps } from './editor_markdown';
|
|
19
|
-
|
|
20
16
|
export {
|
|
21
17
|
ProFormEditor,
|
|
22
18
|
ProFormJSON,
|
|
@@ -28,8 +24,7 @@ export {
|
|
|
28
24
|
ProFormSwitchNumber,
|
|
29
25
|
proFormSelectSearchProps,
|
|
30
26
|
} from './form';
|
|
31
|
-
|
|
27
|
+
export { Markdown } from './markdown';
|
|
32
28
|
export { Table } from './table';
|
|
33
29
|
export type { TableProps } from './table';
|
|
34
|
-
|
|
35
30
|
export { CustomValueTypeEnum, customValueTypeMap } from './value_type_map';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
2
|
+
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
3
|
+
|
|
4
|
+
function CodeBlock(props: any) {
|
|
5
|
+
const { children, className, ...rest } = props;
|
|
6
|
+
const match = /language-(\w+)/.exec(props.className || '');
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div className="markdown-body-code-block">
|
|
10
|
+
{match ? (
|
|
11
|
+
<SyntaxHighlighter
|
|
12
|
+
{...rest}
|
|
13
|
+
style={vscDarkPlus}
|
|
14
|
+
language={match?.[1]}
|
|
15
|
+
showLineNumbers
|
|
16
|
+
PreTag="div"
|
|
17
|
+
wrapLongLines
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</SyntaxHighlighter>
|
|
21
|
+
) : (
|
|
22
|
+
<code {...rest} className={className}>
|
|
23
|
+
{children}
|
|
24
|
+
</code>
|
|
25
|
+
)}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { CodeBlock };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DownOutlined, UpOutlined } from '@ant-design/icons';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
function DeepSeekBlock(props: { children: string }) {
|
|
5
|
+
const [show, setShow] = useState(true);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div className="markdown-body-deep-seek-block mb-3 text-[#00000099] text-[14px] flex flex-col gap-2">
|
|
9
|
+
<div
|
|
10
|
+
className="cursor-pointer"
|
|
11
|
+
onClick={() => {
|
|
12
|
+
setShow((v) => !v);
|
|
13
|
+
}}
|
|
14
|
+
>
|
|
15
|
+
深度思考 {show ? <UpOutlined /> : <DownOutlined />}
|
|
16
|
+
</div>
|
|
17
|
+
{show && (
|
|
18
|
+
<div className="relative pl-[15px]">
|
|
19
|
+
<div className="top=0 absolute left-0 h-full w-[2px] bg-[#00000014]" />
|
|
20
|
+
{props.children === '<br/>' ? undefined : props.children}
|
|
21
|
+
</div>
|
|
22
|
+
)}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function processWithDeepSeek(text: string) {
|
|
28
|
+
// 开始 <think> 才算开始
|
|
29
|
+
if (!text.startsWith('<think>')) {
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const [left, right] = text.split('</think>');
|
|
34
|
+
|
|
35
|
+
let newText = text;
|
|
36
|
+
|
|
37
|
+
// 如果 think 部分是 <think>\n\n</think>,相当于没有,则直接返回 right
|
|
38
|
+
if (text.startsWith('<think>\n\n</think>')) {
|
|
39
|
+
newText = right;
|
|
40
|
+
}
|
|
41
|
+
// 否则做一些处理
|
|
42
|
+
else {
|
|
43
|
+
newText =
|
|
44
|
+
left
|
|
45
|
+
.replace('<think>\n', '<think>')
|
|
46
|
+
.replace('\n</think>', '</think>')
|
|
47
|
+
.replace(/\n/g, '<br/>') + (right || '');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return newText;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { DeepSeekBlock, processWithDeepSeek };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import 'github-markdown-css/github-markdown.css';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import ReactMarkdown from 'react-markdown';
|
|
4
|
+
import rehypeRaw from 'rehype-raw';
|
|
5
|
+
import remarkGfm from 'remark-gfm';
|
|
6
|
+
import { CodeBlock } from './code';
|
|
7
|
+
import { DeepSeekBlock, processWithDeepSeek } from './deep_seek';
|
|
8
|
+
import './style.scss';
|
|
9
|
+
|
|
10
|
+
function Markdown(props: { children: string }) {
|
|
11
|
+
const newChildren = useMemo(() => {
|
|
12
|
+
return processWithDeepSeek(props.children);
|
|
13
|
+
}, [props.children]);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className="markdown-body">
|
|
17
|
+
<ReactMarkdown
|
|
18
|
+
remarkPlugins={[remarkGfm]}
|
|
19
|
+
rehypePlugins={[rehypeRaw]}
|
|
20
|
+
components={{
|
|
21
|
+
code: CodeBlock,
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
think: DeepSeekBlock,
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{newChildren}
|
|
27
|
+
</ReactMarkdown>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { Markdown };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Markdown } from '@fe-free/core';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Markdown> = {
|
|
5
|
+
title: '@fe-free/core/Markdown',
|
|
6
|
+
component: Markdown,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Markdown>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
children: `
|
|
17
|
+
# Markdown 组件示例
|
|
18
|
+
|
|
19
|
+
这是一个 **Markdown** 组件的基本用法示例。
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 支持的特性
|
|
24
|
+
|
|
25
|
+
- 标题
|
|
26
|
+
- 列表
|
|
27
|
+
- 代码高亮
|
|
28
|
+
- 表格
|
|
29
|
+
- 链接与图片
|
|
30
|
+
- 引用
|
|
31
|
+
- 内联代码
|
|
32
|
+
- 分割线
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 代码高亮
|
|
37
|
+
|
|
38
|
+
\`\`\`typescript
|
|
39
|
+
function hello(name: string): string {
|
|
40
|
+
return \`Hello, \${name}!\`;
|
|
41
|
+
}
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
\`\`\`js
|
|
45
|
+
// long line long line long line long line long line long line long line long line long line long line long line long line long line
|
|
46
|
+
function hello(name: string): string {
|
|
47
|
+
return \`Hello, \${name}!\`;
|
|
48
|
+
}
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 表格
|
|
54
|
+
|
|
55
|
+
| 姓名 | 年龄 | 城市 | 职业 | 邮箱 | 状态 |状态 |状态 |状态 |
|
|
56
|
+
| ------ | ---- | ------ | ---------- | --------------------- | ------ |------ |------ |------ |
|
|
57
|
+
| 张三 | 28 | 北京 | 前端开发 | zhangsan@example.com | 在职 |
|
|
58
|
+
| 李四 | 32 | 上海 | 产品经理 | lisi@example.com | 离职 |
|
|
59
|
+
| 王五 | 24 | 广州 | 设计师 | wangwu@example.com | 在职 |
|
|
60
|
+
| 赵六 | 29 | 深圳 | 测试工程师 | zhaoliu@example.com | 实习 |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 链接与图片
|
|
65
|
+
|
|
66
|
+
[访问 Ant Design 官网](https://ant.design)
|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 引用
|
|
73
|
+
|
|
74
|
+
> 这是一段引用文本,可以用于强调内容。
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 内联代码
|
|
79
|
+
|
|
80
|
+
你可以在文本中嵌入 \`const a = 1;\` 这样的内联代码。
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 分割线
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
`,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const DeepSeek: Story = {
|
|
92
|
+
args: {
|
|
93
|
+
children: `<think>
|
|
94
|
+
好的,我现在需要处理用户的问题。用户一开始用中文打招呼“你好”,然后我的回应应该遵循之前设定的角色和技能。首先,我需要确认用户是否是前端工程师求职者,或者他们需要哪方面的帮助。根据角色设定,我应该先了解他们的具体情况,比如技术栈、工作年限、项目经验和目标城市。
|
|
95
|
+
|
|
96
|
+
用户可能没有详细说明他们的需求,所以我需要引导他们提供更多信息。根据技能1中的步骤,我应该先询问他们的技术栈、工作年限、项目经验和目标城市。同时,我需要保持友好和专业,确保用户感到被理解和支持。
|
|
97
|
+
|
|
98
|
+
另外,用户可能对生成卡通头像感兴趣,但根据限制,我需要先处理求职相关的问题,再提及头像生成。因此,在初始回复中,我应该先专注于求职建议,然后在适当的时候提到头像生成选项。
|
|
99
|
+
|
|
100
|
+
我需要确保回复符合Markdown格式,使用适当的标题和列表结构,使信息清晰易读。同时,避免使用复杂术语,保持语言简洁明了,适合不同水平的用户。
|
|
101
|
+
|
|
102
|
+
现在,我需要按照模板组织回复,先欢迎用户,然后分步骤询问必要的信息,最后提到头像生成的选项。确保每个问题都明确,帮助用户逐步提供所需的信息,以便我能够提供有针对性的建议。
|
|
103
|
+
</think>
|
|
104
|
+
|
|
105
|
+
你好!欢迎来到前端工程师求职助手。为了提供更有针对性的建议,请告诉我以下信息:
|
|
106
|
+
|
|
107
|
+
### 1. 你的技术栈
|
|
108
|
+
- 是否掌握核心三件套(HTML/CSS/JavaScript)?
|
|
109
|
+
- 熟悉哪些前端框架(React/Vue/Angular等)?
|
|
110
|
+
- 是否有Node.js/Webpack/Vite等工程化经验?
|
|
111
|
+
|
|
112
|
+
### 2. 工作年限
|
|
113
|
+
- 应届毕业生/1-3年经验/3-5年经验/5年以上?
|
|
114
|
+
|
|
115
|
+
### 3. 项目亮点
|
|
116
|
+
- 请用一句话描述你最具代表性的项目(如:主导开发日均UV百万级的电商前端架构)
|
|
117
|
+
|
|
118
|
+
### 4. 目标城市
|
|
119
|
+
- 期望在哪个城市发展?
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
💡 **小贴士**:需要生成专属前端工程师卡通头像吗?可同步告知:
|
|
124
|
+
1. 意向职位(如:高级前端开发)
|
|
125
|
+
2. 工作年限
|
|
126
|
+
3. 目标城市
|
|
127
|
+
|
|
128
|
+
我会根据你的信息提供:求职策略+技术提升路径+简历优化建议+面试指南+定制头像(如需)
|
|
129
|
+
`,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const DeepSeekPending: Story = {
|
|
134
|
+
args: {
|
|
135
|
+
children: `<think>
|
|
136
|
+
好的,我现在需要处理用户的问题。用户一开始用中文打招呼“你好”,然后我的回应应该遵循之前设定的角色和技能。首先,我需要确认用户是否是前端工程师求职者,或者他们需要哪方面的帮助。根据角色设定,我应该先了解他们的具体情况,比如技术栈、工作年限、项目经验和目标城市。
|
|
137
|
+
|
|
138
|
+
`,
|
|
139
|
+
},
|
|
140
|
+
};
|