- Moved the `toEditorCode` and `getCodeLanguageExtension` functions from CodeBlockEditor to a new utility file, `codeBlockEditorUtils.js`, for better code organization and reusability. - Updated imports in CodeDiffViewer and DiffLabel components to reference the new utility file, ensuring consistent functionality across the application.
117 lines
3.1 KiB
JavaScript
117 lines
3.1 KiB
JavaScript
import { useMemo, useState } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import { Button, Modal, Typography, theme, Flex } from 'antd'
|
|
import { presentableDiff } from '@codemirror/merge'
|
|
import CodeDiffViewer from './CodeDiffViewer'
|
|
import { toEditorCode } from './codeBlockEditorUtils'
|
|
|
|
const { Link, Text } = Typography
|
|
|
|
const SQUARE_COUNT = 10
|
|
|
|
const countLines = (str) => {
|
|
if (!str) return 0
|
|
const parts = str.split('\n')
|
|
if (parts[parts.length - 1] === '') parts.pop()
|
|
return Math.max(parts.length, 1)
|
|
}
|
|
|
|
export function getCodeDiffStats(oldCode, newCode, language = 'javascript') {
|
|
const oldText = toEditorCode(oldCode, language)
|
|
const newText = toEditorCode(newCode, language)
|
|
const changes = presentableDiff(oldText, newText)
|
|
let additions = 0
|
|
let deletions = 0
|
|
|
|
for (const change of changes) {
|
|
const deleted = oldText.slice(change.fromA, change.toA)
|
|
const added = newText.slice(change.fromB, change.toB)
|
|
if (deleted) deletions += countLines(deleted)
|
|
if (added) additions += countLines(added)
|
|
}
|
|
|
|
return { additions, deletions }
|
|
}
|
|
|
|
export default function DiffLabel({
|
|
oldCode = '',
|
|
newCode = '',
|
|
language = 'javascript'
|
|
}) {
|
|
const { token } = theme.useToken()
|
|
const [open, setOpen] = useState(false)
|
|
const [viewerReady, setViewerReady] = useState(false)
|
|
const { additions, deletions } = useMemo(
|
|
() => getCodeDiffStats(oldCode, newCode, language),
|
|
[oldCode, newCode, language]
|
|
)
|
|
|
|
const greenCount = Math.round(
|
|
(additions / (additions + deletions)) * SQUARE_COUNT
|
|
)
|
|
|
|
return (
|
|
<>
|
|
<Link
|
|
className='diff-label'
|
|
onClick={() => {
|
|
setOpen(true)
|
|
}}
|
|
>
|
|
<Flex gap='small' align='center' style={{ marginTop: 0.5 }}>
|
|
<Text style={{ color: token.colorSuccess }}>+{additions}</Text>
|
|
<Flex gap='4px' align='center' style={{ marginBottom: 2 }}>
|
|
{Array.from({ length: SQUARE_COUNT }).map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className='diff-label-square'
|
|
style={{
|
|
backgroundColor:
|
|
i < greenCount ? token.colorSuccess : token.colorError
|
|
}}
|
|
/>
|
|
))}
|
|
</Flex>
|
|
<Text style={{ color: token.colorError }}>-{deletions}</Text>
|
|
</Flex>
|
|
</Link>
|
|
<Modal
|
|
closeIcon={false}
|
|
open={open}
|
|
width='90%'
|
|
destroyOnClose
|
|
afterOpenChange={setViewerReady}
|
|
onCancel={() => {
|
|
setOpen(false)
|
|
}}
|
|
footer={
|
|
<Button
|
|
onClick={() => {
|
|
setOpen(false)
|
|
}}
|
|
>
|
|
Close
|
|
</Button>
|
|
}
|
|
>
|
|
{viewerReady ? (
|
|
<CodeDiffViewer
|
|
oldCode={oldCode}
|
|
newCode={newCode}
|
|
language={language}
|
|
/>
|
|
) : null}
|
|
</Modal>
|
|
</>
|
|
)
|
|
}
|
|
|
|
DiffLabel.propTypes = {
|
|
oldCode: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
newCode: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
language: PropTypes.oneOfType([
|
|
PropTypes.string,
|
|
PropTypes.arrayOf(PropTypes.string)
|
|
])
|
|
}
|