diff.tsx 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { checksum } from "@opencode-ai/util/encode"
  2. import { FileDiff } from "@pierre/diffs"
  3. import { createMediaQuery } from "@solid-primitives/media"
  4. import { createEffect, createMemo, onCleanup, splitProps } from "solid-js"
  5. import { createDefaultOptions, type DiffProps, styleVariables } from "../pierre"
  6. import { getWorkerPool } from "../pierre/worker"
  7. export function Diff<T>(props: DiffProps<T>) {
  8. let container!: HTMLDivElement
  9. const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"])
  10. const mobile = createMediaQuery("(max-width: 640px)")
  11. const options = createMemo(() => {
  12. const opts = {
  13. ...createDefaultOptions(props.diffStyle),
  14. ...others,
  15. }
  16. if (!mobile()) return opts
  17. return {
  18. ...opts,
  19. disableLineNumbers: true,
  20. }
  21. })
  22. let instance: FileDiff<T> | undefined
  23. createEffect(() => {
  24. const opts = options()
  25. const workerPool = getWorkerPool(props.diffStyle)
  26. const annotations = local.annotations
  27. const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : ""
  28. const afterContents = typeof local.after?.contents === "string" ? local.after.contents : ""
  29. instance?.cleanUp()
  30. instance = new FileDiff<T>(opts, workerPool)
  31. container.innerHTML = ""
  32. instance.render({
  33. oldFile: {
  34. ...local.before,
  35. contents: beforeContents,
  36. cacheKey: checksum(beforeContents),
  37. },
  38. newFile: {
  39. ...local.after,
  40. contents: afterContents,
  41. cacheKey: checksum(afterContents),
  42. },
  43. lineAnnotations: annotations,
  44. containerWrapper: container,
  45. })
  46. })
  47. onCleanup(() => {
  48. instance?.cleanUp()
  49. })
  50. return <div data-component="diff" style={styleVariables} ref={container} />
  51. }