Unified diff mode improvements (#167)
* Bump to v0.2.0 * Better colors in unfied mode * New legend (wip) * Working prototype * Clean up * Consistency tweaks * Clean up
This commit is contained in:
@ -8,8 +8,9 @@ import { BufferAttribute, BufferGeometry, Mesh } from 'three'
|
|||||||
import { WireframeColors, WireframeModel } from './WireframeModel'
|
import { WireframeColors, WireframeModel } from './WireframeModel'
|
||||||
import { Buffer } from 'buffer'
|
import { Buffer } from 'buffer'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import { BeforeAfterModel } from './BeforeAfterModel'
|
import { UnifiedModel } from './UnifiedModel'
|
||||||
import { BeakerIcon } from '@primer/octicons-react'
|
import { BeakerIcon } from '@primer/octicons-react'
|
||||||
|
import { LegendBox, LegendLabel } from './Legend'
|
||||||
|
|
||||||
function loadGeometry(file: string, checkUV = false): BufferGeometry {
|
function loadGeometry(file: string, checkUV = false): BufferGeometry {
|
||||||
const loader = new OBJLoader()
|
const loader = new OBJLoader()
|
||||||
@ -28,13 +29,10 @@ function loadGeometry(file: string, checkUV = false): BufferGeometry {
|
|||||||
return geometry
|
return geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loader3DBeforeAfter({
|
function Loader3DUnified({ before, after }: { before: string; after: string }) {
|
||||||
before,
|
const [showUnchanged, setShowUnchanged] = useState(true)
|
||||||
after,
|
const [showAdditions, setShowAdditions] = useState(true)
|
||||||
}: {
|
const [showDeletions, setShowDeletions] = useState(true)
|
||||||
before: string
|
|
||||||
after: string
|
|
||||||
}) {
|
|
||||||
const cameraRef = useRef<any>()
|
const cameraRef = useRef<any>()
|
||||||
const [beforeGeometry, setBeforeGeometry] = useState<BufferGeometry>()
|
const [beforeGeometry, setBeforeGeometry] = useState<BufferGeometry>()
|
||||||
const [afterGeometry, setAfterGeometry] = useState<BufferGeometry>()
|
const [afterGeometry, setAfterGeometry] = useState<BufferGeometry>()
|
||||||
@ -45,13 +43,38 @@ function Loader3DBeforeAfter({
|
|||||||
setAfterGeometry(loadGeometry(after, true))
|
setAfterGeometry(loadGeometry(after, true))
|
||||||
}, [after])
|
}, [after])
|
||||||
return beforeGeometry && afterGeometry ? (
|
return beforeGeometry && afterGeometry ? (
|
||||||
<Viewer3D cameraRef={cameraRef} geometry={beforeGeometry}>
|
<>
|
||||||
<BeforeAfterModel
|
<Viewer3D cameraRef={cameraRef} geometry={beforeGeometry}>
|
||||||
beforeGeometry={beforeGeometry}
|
<UnifiedModel
|
||||||
afterGeometry={afterGeometry}
|
beforeGeometry={beforeGeometry}
|
||||||
cameraRef={cameraRef}
|
afterGeometry={afterGeometry}
|
||||||
/>
|
cameraRef={cameraRef}
|
||||||
</Viewer3D>
|
showUnchanged={showUnchanged}
|
||||||
|
showAdditions={showAdditions}
|
||||||
|
showDeletions={showDeletions}
|
||||||
|
/>
|
||||||
|
</Viewer3D>
|
||||||
|
<LegendBox>
|
||||||
|
<LegendLabel
|
||||||
|
text="Unchanged"
|
||||||
|
color="neutral"
|
||||||
|
enabled={showUnchanged}
|
||||||
|
onChange={enabled => setShowUnchanged(enabled)}
|
||||||
|
/>
|
||||||
|
<LegendLabel
|
||||||
|
text="Additions"
|
||||||
|
color="success"
|
||||||
|
enabled={showAdditions}
|
||||||
|
onChange={enabled => setShowAdditions(enabled)}
|
||||||
|
/>
|
||||||
|
<LegendLabel
|
||||||
|
text="Deletions"
|
||||||
|
color="danger"
|
||||||
|
enabled={showDeletions}
|
||||||
|
onChange={enabled => setShowDeletions(enabled)}
|
||||||
|
/>
|
||||||
|
</LegendBox>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Box p={3}>
|
<Box p={3}>
|
||||||
<Text>Sorry, the rich diff can't be displayed for this file.</Text>
|
<Text>Sorry, the rich diff can't be displayed for this file.</Text>
|
||||||
@ -96,9 +119,15 @@ export function CadDiff({ before, after }: FileDiff): React.ReactElement {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box display="flex" height={300} overflow="hidden" minWidth={0}>
|
<Box
|
||||||
|
display="flex"
|
||||||
|
height={300}
|
||||||
|
overflow="hidden"
|
||||||
|
minWidth={0}
|
||||||
|
position="relative"
|
||||||
|
>
|
||||||
{canShowUnified && showUnified && (
|
{canShowUnified && showUnified && (
|
||||||
<Loader3DBeforeAfter before={before} after={after} />
|
<Loader3DUnified before={before} after={after} />
|
||||||
)}
|
)}
|
||||||
{!showUnified && (
|
{!showUnified && (
|
||||||
<>
|
<>
|
||||||
|
51
src/components/diff/Legend.tsx
Normal file
51
src/components/diff/Legend.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { DotFillIcon } from '@primer/octicons-react'
|
||||||
|
import { Box, Label, Text } from '@primer/react'
|
||||||
|
import { PropsWithChildren } from 'react'
|
||||||
|
|
||||||
|
export type LegendLabelProps = {
|
||||||
|
text: string
|
||||||
|
color: 'neutral' | 'danger' | 'success'
|
||||||
|
enabled: boolean
|
||||||
|
onChange?: (enabled: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LegendLabel({
|
||||||
|
text,
|
||||||
|
color,
|
||||||
|
enabled,
|
||||||
|
onChange,
|
||||||
|
}: LegendLabelProps): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<Box py={1}>
|
||||||
|
<Label
|
||||||
|
onClick={() => onChange && onChange(!enabled)}
|
||||||
|
sx={{
|
||||||
|
border: 'none',
|
||||||
|
backgroundColor: enabled
|
||||||
|
? `${color}.subtle`
|
||||||
|
: 'transparent',
|
||||||
|
color: `${color}.muted`,
|
||||||
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DotFillIcon size={16} />
|
||||||
|
<Text color="fg.default">{text}</Text>
|
||||||
|
</Label>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LegendBox({ children }: PropsWithChildren): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
top={2}
|
||||||
|
left={2}
|
||||||
|
p={2}
|
||||||
|
backgroundColor="canvas.default"
|
||||||
|
color="fg.muted"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
@ -4,21 +4,27 @@ import { BufferGeometry } from 'three'
|
|||||||
import { Geometry, Base, Subtraction, Intersection } from '@react-three/csg'
|
import { Geometry, Base, Subtraction, Intersection } from '@react-three/csg'
|
||||||
import { BaseModel } from './BaseModel'
|
import { BaseModel } from './BaseModel'
|
||||||
|
|
||||||
type BeforeAfterModelProps = {
|
type UnifiedModelProps = {
|
||||||
beforeGeometry: BufferGeometry
|
beforeGeometry: BufferGeometry
|
||||||
afterGeometry: BufferGeometry
|
afterGeometry: BufferGeometry
|
||||||
cameraRef: MutableRefObject<any>
|
cameraRef: MutableRefObject<any>
|
||||||
|
showUnchanged: boolean
|
||||||
|
showAdditions: boolean
|
||||||
|
showDeletions: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BeforeAfterModel({
|
export function UnifiedModel({
|
||||||
beforeGeometry,
|
beforeGeometry,
|
||||||
afterGeometry,
|
afterGeometry,
|
||||||
cameraRef,
|
cameraRef,
|
||||||
}: BeforeAfterModelProps) {
|
showUnchanged,
|
||||||
|
showAdditions,
|
||||||
|
showDeletions,
|
||||||
|
}: UnifiedModelProps) {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const commonColor = theme?.colors.fg.default
|
const commonColor = theme?.colors.fg.muted
|
||||||
const additionsColor = theme?.colors.success.fg
|
const additionsColor = theme?.colors.success.muted
|
||||||
const deletionsColor = theme?.colors.danger.fg
|
const deletionsColor = theme?.colors.danger.muted
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// TODO: here we give beforeGeometry for auto camera centering,
|
// TODO: here we give beforeGeometry for auto camera centering,
|
||||||
@ -29,7 +35,7 @@ export function BeforeAfterModel({
|
|||||||
<meshPhongMaterial
|
<meshPhongMaterial
|
||||||
color={commonColor}
|
color={commonColor}
|
||||||
transparent
|
transparent
|
||||||
opacity={0.95}
|
opacity={showUnchanged ? 0.8 : 0}
|
||||||
/>
|
/>
|
||||||
<Geometry>
|
<Geometry>
|
||||||
<Base geometry={beforeGeometry} />
|
<Base geometry={beforeGeometry} />
|
||||||
@ -38,7 +44,11 @@ export function BeforeAfterModel({
|
|||||||
</mesh>
|
</mesh>
|
||||||
{/* Additions */}
|
{/* Additions */}
|
||||||
<mesh>
|
<mesh>
|
||||||
<meshPhongMaterial color={additionsColor} />
|
<meshPhongMaterial
|
||||||
|
color={additionsColor}
|
||||||
|
transparent
|
||||||
|
opacity={showAdditions ? 1 : 0}
|
||||||
|
/>
|
||||||
<Geometry>
|
<Geometry>
|
||||||
<Base geometry={afterGeometry} />
|
<Base geometry={afterGeometry} />
|
||||||
<Subtraction geometry={beforeGeometry} />
|
<Subtraction geometry={beforeGeometry} />
|
||||||
@ -46,7 +56,11 @@ export function BeforeAfterModel({
|
|||||||
</mesh>
|
</mesh>
|
||||||
{/* Deletions */}
|
{/* Deletions */}
|
||||||
<mesh>
|
<mesh>
|
||||||
<meshPhongMaterial color={deletionsColor} />
|
<meshPhongMaterial
|
||||||
|
color={deletionsColor}
|
||||||
|
transparent
|
||||||
|
opacity={showDeletions ? 1 : 0}
|
||||||
|
/>
|
||||||
<Geometry>
|
<Geometry>
|
||||||
<Base geometry={beforeGeometry} />
|
<Base geometry={beforeGeometry} />
|
||||||
<Subtraction geometry={afterGeometry} />
|
<Subtraction geometry={afterGeometry} />
|
Reference in New Issue
Block a user