├── .editorconfig ├── .env ├── .eslintrc ├── .github └── workflows │ ├── build.yml │ ├── dependabot.yml │ ├── lint.yml │ ├── rebase.yml │ └── test.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .umirc.ts ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src ├── global.css ├── layouts │ ├── __tests__ │ │ └── index.test.tsx │ ├── index.css │ └── index.tsx └── pages │ ├── __tests__ │ └── index.test.tsx │ ├── components │ └── ChangeLog.tsx │ ├── document.ejs │ ├── index.css │ └── index.tsx ├── tsconfig.json ├── typings.d.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | ESLINT=1 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-umi", 3 | "rules": { 4 | "jsx-a11y/accessible-emoji": 0 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - name: checkout 9 | uses: actions/checkout@master 10 | 11 | - name: install 12 | run: yarn 13 | 14 | - name: build 15 | run: yarn run build 16 | -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: '' # See documentation for possible values 9 | directory: '/' # Location of package manifests 10 | schedule: 11 | interval: 'daily' 12 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: [push] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - name: checkout 9 | uses: actions/checkout@master 10 | 11 | - name: install 12 | run: yarn 13 | 14 | - name: lint 15 | run: yarn run lint 16 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Automatic Rebase 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | with: 13 | fetch-depth: 0 14 | - name: Automatic Rebase 15 | uses: cirrus-actions/rebase@1.3 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test CI 2 | on: [push] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - name: checkout 9 | uses: actions/checkout@master 10 | 11 | - name: install 12 | run: yarn 13 | 14 | - name: test 15 | run: yarn test -- --coverage 16 | - name: Generate coverage 17 | run: bash <(curl -s https://codecov.io/bash) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /package-lock.json 8 | 9 | # production 10 | /dist 11 | 12 | # misc 13 | .DS_Store 14 | 15 | # umi 16 | .umi 17 | .umi-production 18 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 100, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.umirc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'umi'; 2 | 3 | // ref: https://umijs.org/config/ 4 | const config = defineConfig({ 5 | routes: [ 6 | { 7 | path: '/', 8 | component: '../layouts/index', 9 | routes: [{ path: '/', component: '../pages/index' }], 10 | }, 11 | ], 12 | antd: {}, 13 | title: 'Ant Design CHANGELOG Generator', 14 | favicon: 'https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png', 15 | }); 16 | 17 | export default config; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ant Design Changelog Editor 2 | 3 | ``` 4 | cd ant-design 5 | npm run changelog 6 | ``` 7 | 8 | ![Preview](https://user-images.githubusercontent.com/507615/89773062-c8647d80-db35-11ea-8767-d4ff70a75ae3.png) 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev", 5 | "build": "umi build", 6 | "test": "umi test", 7 | "lint": "eslint src", 8 | "postinstall": "umi g tmp", 9 | "prettier": "prettier -c --write '**/*'", 10 | "pretty-quick": "pretty-quick" 11 | }, 12 | "dependencies": { 13 | "antd": "^5.20.0", 14 | "react": "^18.0.0", 15 | "react-dom": "^18.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/jest": "^26.0.13", 19 | "@types/react": "^18.0.0", 20 | "@types/react-dom": "^18.0.0", 21 | "@types/react-test-renderer": "^16.0.3", 22 | "@typescript-eslint/eslint-plugin": "^3.9.0", 23 | "@typescript-eslint/parser": "^3.9.0", 24 | "@umijs/preset-react": "^1.6.4", 25 | "babel-eslint": "^10.1.0", 26 | "eslint": "^7.8.1", 27 | "eslint-config-umi": "^1.4.0", 28 | "eslint-plugin-flowtype": "^5.2.0", 29 | "eslint-plugin-import": "^2.14.0", 30 | "eslint-plugin-jsx-a11y": "^6.3.1", 31 | "eslint-plugin-react": "^7.20.6", 32 | "eslint-plugin-react-hooks": "^4.1.0", 33 | "husky": "^4.2.5", 34 | "react-test-renderer": "^16.7.0", 35 | "typescript": "^4.0.2", 36 | "umi": "^3.2.20" 37 | }, 38 | "husky": { 39 | "hooks": { 40 | "pre-commit": "pretty-quick --staged" 41 | } 42 | }, 43 | "engines": { 44 | "node": ">=10.0.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | font-family: Avenir, -apple-system, BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, 10 | noto sans, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji, sans-serif !important; 11 | } 12 | 13 | td { 14 | vertical-align: top; 15 | } 16 | -------------------------------------------------------------------------------- /src/layouts/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | import BasicLayout from '..'; 2 | import React from 'react'; 3 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 4 | 5 | describe('Layout: BasicLayout', () => { 6 | it('Render correctly', () => { 7 | const wrapper: ReactTestRenderer = renderer.create(); 8 | expect(wrapper.root.children.length).toBe(1); 9 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 10 | expect(outerLayer.type).toBe('div'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/layouts/index.css: -------------------------------------------------------------------------------- 1 | .normal { 2 | text-align: center; 3 | } 4 | 5 | .title { 6 | font-size: 2.5rem; 7 | font-weight: normal; 8 | letter-spacing: -1px; 9 | background: darkslateblue; 10 | padding: 0.6em 0; 11 | color: white; 12 | margin: 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/layouts/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.css'; 3 | 4 | const BasicLayout: React.FC = (props) => { 5 | return
{props.children}
; 6 | }; 7 | 8 | export default BasicLayout; 9 | -------------------------------------------------------------------------------- /src/pages/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | import Index from '..'; 2 | import React from 'react'; 3 | import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; 4 | 5 | describe('Page: index', () => { 6 | beforeEach(() => { 7 | Object.defineProperty(window, 'matchMedia', { 8 | writable: true, 9 | value: jest.fn().mockImplementation((query) => ({ 10 | matches: false, 11 | media: query, 12 | onchange: null, 13 | addListener: jest.fn(), // deprecated 14 | removeListener: jest.fn(), // deprecated 15 | addEventListener: jest.fn(), 16 | removeEventListener: jest.fn(), 17 | dispatchEvent: jest.fn(), 18 | })), 19 | }); 20 | // @ts-ignore 21 | window.changelog = [ 22 | { 23 | pr: '23118', 24 | hash: 'd968fce4dc1cfa3924fef53f6239677ded10ff11', 25 | title: 'chore: Add warning for async', 26 | author: 'zombieJ', 27 | english: 28 | 'Table add warning info when async mode dataSource length not match with pageSize.', 29 | chinese: 'Table 在异步数据下 dataSource长度与 pageSize 不匹配时,添加警告信息。', 30 | }, 31 | { 32 | pr: '23114', 33 | hash: '405d4613609321b2aa06e34d4cca2ef3388b9318', 34 | title: 'fix: substitute "易用行" with "易用性"', 35 | author: 'stimulate', 36 | english: 'fix: substitute "易用行" with "易用性"', 37 | chinese: 'fix: substitute "易用行" with "易用性"', 38 | }, 39 | { 40 | pr: '23115', 41 | hash: 'f3df9ec89446b6f2efd6391be8ff162a2633e983', 42 | title: 'fix: Input background with dark mode', 43 | author: 'zombieJ', 44 | english: 'Fix Input with affix background style in dark theme.', 45 | chinese: '修复 Input 在暗黑模式下使用 affix 的背景样式问题。', 46 | }, 47 | { 48 | pr: '23113', 49 | hash: '8e56354de2c146cc8b549491d87779e0f1ff803d', 50 | title: 'style: 💄 Tweak Table hover background color', 51 | author: 'afc163', 52 | english: 'Tweak Table hover background color.', 53 | chinese: '微调 Table 行 hover 时的背景色。', 54 | }, 55 | { 56 | pr: '23110', 57 | hash: 'a10631993432242965ea79658b2c2119fdd28fc3', 58 | title: 'fix: Table selection style', 59 | author: 'zombieJ', 60 | english: 'Fix Table selection row with hover background style.', 61 | chinese: '修复 Table 选择行在 hover 时的背景样式问题。', 62 | }, 63 | { 64 | pr: '23108', 65 | hash: '9b9839d4d93ef67f70b9bc532189a01dc8e9d7a5', 66 | title: 'docs: Update Form normalize desc', 67 | author: 'zombieJ', 68 | english: 'docs: Update Form normalize desc', 69 | chinese: 'docs: Update Form normalize desc', 70 | }, 71 | { 72 | pr: '23097', 73 | hash: '2cbad48ace47e83f55d25063cca01c40796078d4', 74 | title: 'style: optimize select dropdown style in rtl', 75 | author: 'xrkffgg', 76 | english: 'optimize select dropdown style in rtl', 77 | chinese: '优化 Select RTL 模式下拉框样式', 78 | }, 79 | { 80 | pr: '23087', 81 | hash: '37ad43bc9fff4588d0e864950aa61b721cc09101', 82 | title: 'fix: Tabs bottom style', 83 | author: 'zombieJ', 84 | english: 'Fix Tabs bottom card active tab wrong height style.', 85 | chinese: '修复 Tabs 下方卡片布局激活标签的高度问题。', 86 | }, 87 | { 88 | pr: '23078', 89 | hash: 'a8b976b8028969cf33161cd44e6b47495bdaf97e', 90 | title: 'docs: update Radio.Button', 91 | author: 'afc163', 92 | english: 'docs: update Radio.Button', 93 | chinese: 'docs: update Radio.Button', 94 | }, 95 | { 96 | pr: '23081', 97 | hash: '4794bae529a8e954d9cd02ec2d8021518a35d327', 98 | title: 'fix: Calendar missing style', 99 | author: 'zombieJ', 100 | english: 'Fix Calendar missing style prop support.', 101 | chinese: '修复 Calendar 不支持 style 的问题。', 102 | }, 103 | { 104 | pr: '23076', 105 | hash: '192146d2a2fab902e861f1693e05f01d296fb48d', 106 | title: 'style: optimize mentions dropdown in RTL', 107 | author: 'xrkffgg', 108 | english: 'optimize mentions dropdown style in RTL', 109 | chinese: '优化 Mentions RTL 模式下拉框样式', 110 | }, 111 | { 112 | pr: '23074', 113 | hash: 'ecf025548b0e5b7cbfb5a59b7881e5eec53bcb62', 114 | title: 'chore: adjust RangePicker style', 115 | author: 'zombieJ', 116 | english: 'chore: adjust RangePicker style', 117 | chinese: 'chore: adjust RangePicker style', 118 | }, 119 | { 120 | pr: '22857', 121 | hash: 'e652eef04ce2e3dbd570e4bc52049325ecb31632', 122 | title: 'style: add rtl base', 123 | author: 'xrkffgg', 124 | english: 'none', 125 | chinese: 'none', 126 | }, 127 | { 128 | pr: '22595', 129 | hash: '4d31ed89946c4133ff1f8792aca8abae1021ee55', 130 | title: 'style: optimize datepicker rtl style', 131 | author: 'xrkffgg', 132 | english: 'optimization DatePicker RTL style', 133 | chinese: '优化 DatePicker 的 RTL 样式', 134 | }, 135 | { 136 | hash: 'b6829a0a924053e445714b07f0b5f99bf7d67a31', 137 | title: 'style: fix color picker z-index', 138 | }, 139 | ]; 140 | }); 141 | it('Render correctly', () => { 142 | const wrapper: ReactTestRenderer = renderer.create(); 143 | expect(wrapper.root.children.length).toBe(1); 144 | const outerLayer = wrapper.root.children[0] as ReactTestInstance; 145 | expect(outerLayer.type).toBe('div'); 146 | expect(outerLayer.children.length).toBe(2); 147 | }); 148 | }); 149 | -------------------------------------------------------------------------------- /src/pages/components/ChangeLog.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // https://github.com/orgs/ant-design/teams/ant-design-collaborators/members 4 | const MAINTAINERS = [ 5 | // 'zombiej', 6 | // 'afc163', 7 | // 'chenshuai2144', 8 | // 'shaodahong', 9 | // 'xrkffgg', 10 | // 'AshoneA', 11 | // 'yesmeck', 12 | // 'bang88', 13 | // 'yoyo837', 14 | // 'hengkx', 15 | // 'Rustin-Liu', 16 | // 'fireairforce', 17 | // 'Kermit-Xuan', 18 | ].map((author: string) => author.toLowerCase()); 19 | 20 | export interface ChangeLogProps { 21 | hashList: string[]; 22 | lang: 'chinese' | 'english'; 23 | formValues: Record< 24 | string, 25 | { 26 | use: boolean; 27 | chinese: string; 28 | english: string; 29 | type: string; 30 | pr: string; 31 | author: string; 32 | component: string; 33 | } 34 | >; 35 | } 36 | 37 | function getIcon(type: string) { 38 | switch (type) { 39 | case 'bug': 40 | return '🐞'; 41 | case 'style': 42 | return '💄'; 43 | case 'feature': 44 | return '🆕'; 45 | case 'hotFeature': 46 | return '🔥'; 47 | case 'locale': 48 | return '🌐'; 49 | case 'doc': 50 | return '📖'; 51 | case 'test': 52 | return '✅'; 53 | case 'notice': 54 | return '🛎'; 55 | case 'accessibility': 56 | return '⌨️'; 57 | case 'deprecated': 58 | return '🗑'; 59 | case 'refactor': 60 | return '🛠'; 61 | case 'perf': 62 | return '⚡️'; 63 | case 'rtl': 64 | return '💄'; 65 | case 'ts': 66 | return '🤖'; 67 | 68 | default: 69 | return '🚫'; 70 | } 71 | } 72 | 73 | export default function ChangeLog({ hashList, formValues, lang }: ChangeLogProps) { 74 | const lines: string[] = []; 75 | const rtlLines: string[] = []; 76 | const tsLines: string[] = []; 77 | const componentLines: Record = {}; 78 | 79 | hashList.forEach((hash) => { 80 | const entity = formValues[hash]; 81 | 82 | if (!entity) { 83 | return; 84 | } 85 | 86 | let content = ''; 87 | if (entity.use) { 88 | const icon = getIcon(entity.type); 89 | const iconStr = icon ? `${icon} ` : ''; 90 | content += `- ${iconStr}${entity[lang].trim()}`; 91 | 92 | if (lang === 'english') { 93 | content += ' '; 94 | } 95 | 96 | if (entity.pr) { 97 | content += `[#${entity.pr}](https://github.com/ant-design/ant-design/pull/${entity.pr})`; 98 | } else { 99 | const showHash = hash.slice(0, 7); 100 | content += `[${showHash}](https://github.com/ant-design/ant-design/commit/${showHash})`; 101 | } 102 | 103 | if (entity.author && !MAINTAINERS.includes(entity.author.toLowerCase())) { 104 | content += ` [@${entity.author}](https://github.com/${entity.author})`; 105 | } 106 | 107 | switch (entity.type) { 108 | case 'rtl': 109 | rtlLines.push(content); 110 | break; 111 | case 'ts': 112 | tsLines.push(content); 113 | break; 114 | default: 115 | if (entity.component) { 116 | componentLines[entity.component] = componentLines[entity.component] || []; 117 | componentLines[entity.component].push(content); 118 | } else { 119 | lines.push(content); 120 | } 121 | } 122 | } 123 | }); 124 | 125 | const componentContext = Object.keys(componentLines) 126 | .map((component) => { 127 | const cLines = componentLines[component]; 128 | if (cLines.length > 1) { 129 | return `- ${component}\n${cLines.map((str) => ` ${str}`).join('\n')}`; 130 | } 131 | return cLines[0]; 132 | }) 133 | .join('\n'); 134 | 135 | return ( 136 |
146 |       {componentContext ? `${componentContext}\n` : null}
147 |       {lines.join('\n')}
148 |       {rtlLines.length ? `\n- RTL\n${rtlLines.map((str) => `  ${str}`).join('\n')}` : null}
149 |       {tsLines.length ? `\n- TypeScript\n${tsLines.map((str) => `  ${str}`).join('\n')}` : null}
150 |     
151 | ); 152 | } 153 | -------------------------------------------------------------------------------- /src/pages/document.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Ant Design CHANGELOG Generator 8 | 130 | 131 | 132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /src/pages/index.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 24px 24px 0 24px; 3 | } 4 | 5 | .unselected { 6 | opacity: 0.3; 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Table, Input, Form, Select, Checkbox, Typography, Divider, Avatar, Layout } from 'antd'; 3 | import ChangeLog from './components/ChangeLog'; 4 | import styles from './index.css'; 5 | 6 | export default function () { 7 | const [dataSource, setDataSource] = React.useState([]); 8 | 9 | const columns = [ 10 | { 11 | align: 'center', 12 | title: '', 13 | dataIndex: 'hash', 14 | width: 50, 15 | render: (value: string, { hash }: any) => ( 16 | 17 | 18 | 19 | ), 20 | }, 21 | { 22 | title: 'PR / Commit', 23 | dataIndex: 'hash', 24 | width: 80, 25 | render(value: string, { hash }: any) { 26 | return ( 27 | <> 28 | 29 | 30 | 31 | 36 | {value.slice(0, 7)} 37 | 38 | 39 | ); 40 | }, 41 | }, 42 | { 43 | title: 'Category', 44 | dataIndex: 'emoji', 45 | width: 140, 46 | render(value = '', { hash }: any) { 47 | return ( 48 | <> 49 | 50 | 71 | 72 | 73 | 74 | 75 | 76 | ); 77 | }, 78 | }, 79 | { 80 | title: '🇨🇳 中文日志', 81 | dataIndex: 'chinese', 82 | render(value = '', { hash }: any) { 83 | return ( 84 | 85 | 86 | 87 | ); 88 | }, 89 | }, 90 | { 91 | title: '🇺🇸 English Changelog', 92 | dataIndex: 'english', 93 | render(value = '', { hash }: any) { 94 | return ( 95 | 96 | 97 | 98 | ); 99 | }, 100 | }, 101 | { 102 | title: '👩🏻‍💻 Author', 103 | dataIndex: 'author', 104 | width: 100, 105 | render(value = '', { hash }: any) { 106 | return ( 107 | 108 | 109 | 110 | ); 111 | }, 112 | }, 113 | ]; 114 | 115 | const [form] = Form.useForm(); 116 | 117 | const items = Form.useWatch((values) => values, form); 118 | 119 | React.useEffect(() => { 120 | const changelog = (window as any).changelog || []; 121 | setDataSource(changelog); 122 | 123 | const formValues: Record = {}; 124 | changelog.forEach( 125 | ({ 126 | hash, 127 | chinese = '', 128 | english = '', 129 | author = '', 130 | pr = '', 131 | component = '', 132 | title = '', 133 | }: any) => { 134 | chinese = chinese.trim() ? `${chinese.trim()}。` : ''; 135 | english = english.trim() ? `${english.trim()}.` : ''; 136 | 137 | chinese = chinese.replace('。。', '。'); 138 | english = english.replace('..', '.'); 139 | const type = undefined as string | undefined; 140 | 141 | const values = { chinese, english, author, type, use: true, pr, component }; 142 | 143 | if (title.includes('rtl') || english.includes('rtl')) { 144 | values.type = 'rtl'; 145 | } else if ( 146 | english.includes('style') || 147 | chinese.includes('样式') || 148 | title.includes('💄') 149 | ) { 150 | values.type = 'style'; 151 | } else if ( 152 | english.includes('fix') || 153 | english.includes('bug') || 154 | title.includes('fix') || 155 | title.includes('🐞') || 156 | title.includes('🐛') || 157 | title.includes('bug') || 158 | chinese.includes('修复') || 159 | chinese.includes('修正') 160 | ) { 161 | values.type = 'bug'; 162 | } else if (english.includes('docs:') || title.includes('docs:')) { 163 | values.type = 'doc'; 164 | values.use = false; 165 | } 166 | 167 | formValues[hash] = values; 168 | }, 169 | ); 170 | form.setFieldsValue(formValues); 171 | }, [form]); 172 | 173 | return ( 174 |
175 | 176 | 181 | CHANGELOG Generator 182 | 183 |
184 | 185 | 186 | { 191 | const selectedKeys = Object.entries(items).map(([key, { use }]) => use ? key : undefined).filter(Boolean); 192 | return selectedKeys.includes(record.hash) ? '' : styles.unselected; 193 | }} 194 | dataSource={dataSource} 195 | pagination={false} 196 | size="small" 197 | scroll={{ y: 'calc(100vh - 160px)' }} 198 | /> 199 | 200 | 201 | 205 | {(form) => { 206 | const formValues = form.getFieldsValue(true); 207 | const hashList = dataSource.map((item: { hash: string }) => item.hash); 208 | return ( 209 | <> 210 | 🇨🇳 中文日志 211 | 212 | 🇬🇧 English Changelog 213 | 214 | 215 | ); 216 | }} 217 | 218 | 219 | 220 | 221 | 222 | ); 223 | } 224 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "importHelpers": true, 7 | "jsx": "react", 8 | "esModuleInterop": true, 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "strict": true, 12 | "paths": { 13 | "@/*": ["src/*"], 14 | "@tmp/*": ["src/pages/.umi/*"] 15 | }, 16 | "allowSyntheticDefaultImports": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.png'; 3 | --------------------------------------------------------------------------------