From 77ae0b527e4b1a8277b0391d0acbc7d82b08e4ea Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:15:46 -0500 Subject: wip: desktop work --- packages/ui/src/components/diff.css | 24 +++++ packages/ui/src/components/diff.tsx | 172 ++++++++++++++++++++++++++++++++++++ packages/ui/src/components/index.ts | 1 + packages/ui/src/styles/colors.css | 76 +++------------- packages/ui/src/styles/index.css | 1 + 5 files changed, 212 insertions(+), 62 deletions(-) create mode 100644 packages/ui/src/components/diff.css create mode 100644 packages/ui/src/components/diff.tsx (limited to 'packages/ui/src') diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/diff.css new file mode 100644 index 000000000..6f9a0d73d --- /dev/null +++ b/packages/ui/src/components/diff.css @@ -0,0 +1,24 @@ +[data-component="diff"] { + [data-slot="diff-hunk-separator-line-number"] { + position: sticky; + left: 0; + background-color: hsla(209, 96%, 90%, 1); + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + + [data-slot="diff-hunk-separator-line-number-icon"] { + aspect-ratio: 1; + width: 24px; + height: 24px; + } + } + [data-slot="diff-hunk-separator-content"] { + position: sticky; + background-color: hsla(210, 100%, 96%, 1); + width: var(--pjs-column-content-width); + left: var(--pjs-column-number-width); + padding-left: 8px; + } +} diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx new file mode 100644 index 000000000..88215bcb0 --- /dev/null +++ b/packages/ui/src/components/diff.tsx @@ -0,0 +1,172 @@ +import { + type FileContents, + FileDiff, + type DiffLineAnnotation, + type HunkData, + DiffFileRendererOptions, + // registerCustomTheme, +} from "@pierre/precision-diffs" +import { ComponentProps, createEffect, splitProps } from "solid-js" + +export type DiffProps = Omit, "themes"> & { + before: FileContents + after: FileContents + annotations?: DiffLineAnnotation[] + class?: string + classList?: ComponentProps<"div">["classList"] +} + +// registerCustomTheme("opencode", () => import("./theme.json")) + +// interface ThreadMetadata { +// threadId: string +// } + +export function Diff(props: DiffProps) { + let container!: HTMLDivElement + const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"]) + + // const lineAnnotations: DiffLineAnnotation[] = [ + // { + // side: "additions", + // // The line number specified for an annotation is the visual line number + // // you see in the number column of a diff + // lineNumber: 16, + // metadata: { threadId: "68b329da9893e34099c7d8ad5cb9c940" }, + // }, + // ] + + // If you ever want to update the options for an instance, simple call + // 'setOptions' with the new options. Bear in mind, this does NOT merge + // existing properties, it's a full replace + // instance.setOptions({ + // ...instance.options, + // theme: "pierre-dark", + // themes: undefined, + // }) + + // When ready to render, simply call .render with old/new file, optional + // annotations and a container element to hold the diff + createEffect(() => { + const instance = new FileDiff({ + theme: "pierre-light", + // Or can also provide a 'themes' prop, which allows the code to adapt + // to your OS light or dark theme + // themes: { dark: 'pierre-night', light: 'pierre-light' }, + // When using the 'themes' prop, 'themeType' allows you to force 'dark' + // or 'light' theme, or inherit from the OS ('system') theme. + themeType: "system", + // Disable the line numbers for your diffs, generally not recommended + disableLineNumbers: false, + // Whether code should 'wrap' with long lines or 'scroll'. + overflow: "scroll", + // Normally you shouldn't need this prop, but if you don't provide a + // valid filename or your file doesn't have an extension you may want to + // override the automatic detection. You can specify that language here: + // https://shiki.style/languages + // lang?: SupportedLanguages; + // 'diffStyle' controls whether the diff is presented side by side or + // in a unified (single column) view + diffStyle: "unified", + // Line decorators to help highlight changes. + // 'bars' (default): + // Shows some red-ish or green-ish (theme dependent) bars on the left + // edge of relevant lines + // + // 'classic': + // shows '+' characters on additions and '-' characters on deletions + // + // 'none': + // No special diff indicators are shown + diffIndicators: "bars", + // By default green-ish or red-ish background are shown on added and + // deleted lines respectively. Disable that feature here + disableBackground: false, + // Diffs are split up into hunks, this setting customizes what to show + // between each hunk. + // + // 'line-info' (default): + // Shows a bar that tells you how many lines are collapsed. If you are + // using the oldFile/newFile API then you can click those bars to + // expand the content between them + // + // 'metadata': + // Shows the content you'd see in a normal patch file, usually in some + // format like '@@ -60,6 +60,22 @@'. You cannot use these to expand + // hidden content + // + // 'simple': + // Just a subtle bar separator between each hunk + // hunkSeparators: "line-info", + hunkSeparators(hunkData: HunkData) { + const fragment = document.createDocumentFragment() + const numCol = document.createElement("div") + numCol.innerHTML = ` ` + numCol.dataset["slot"] = "diff-hunk-separator-line-number" + fragment.appendChild(numCol) + const contentCol = document.createElement("div") + contentCol.textContent = `${hunkData.lines} unmodified lines` + contentCol.dataset["slot"] = "diff-hunk-separator-content" + fragment.appendChild(contentCol) + return fragment + }, + // On lines that have both additions and deletions, we can run a + // separate diff check to mark parts of the lines that change. + // 'none': + // Do not show these secondary highlights + // + // 'char': + // Show changes at a per character granularity + // + // 'word': + // Show changes but rounded up to word boundaries + // + // 'word-alt' (default): + // Similar to 'word', however we attempt to minimize single character + // gaps between highlighted changes + lineDiffType: "word-alt", + // If lines exceed these character lengths then we won't perform the + // line lineDiffType check + maxLineDiffLength: 1000, + // If any line in the diff exceeds this value then we won't attempt to + // syntax highlight the diff + maxLineLengthForHighlighting: 1000, + // Enabling this property will hide the file header with file name and + // diff stats. + disableFileHeader: true, + // You can optionally pass a render function for rendering out line + // annotations. Just return the dom node to render + // renderAnnotation(annotation: DiffLineAnnotation): HTMLElement { + // // Despite the diff itself being rendered in the shadow dom, + // // annotations are inserted via the web components 'slots' api and you + // // can use all your normal normal css and styling for them + // const element = document.createElement("div") + // element.innerText = annotation.metadata.threadId + // return element + // }, + ...others, + }) + + instance.render({ + oldFile: local.before, + newFile: local.after, + lineAnnotations: local.annotations, + containerWrapper: container, + }) + }) + + return ( +
+ ) +} diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 0024c9e76..16cbb7d95 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -3,6 +3,7 @@ export * from "./button" export * from "./checkbox" export * from "./collapsible" export * from "./dialog" +export * from "./diff" export * from "./icon" export * from "./icon-button" export * from "./input" diff --git a/packages/ui/src/styles/colors.css b/packages/ui/src/styles/colors.css index b0ddf36b7..79877d3cf 100644 --- a/packages/ui/src/styles/colors.css +++ b/packages/ui/src/styles/colors.css @@ -1,41 +1,5 @@ :root { - --grey-dark-1: #ffffff; - --grey-dark-2: #ffffff; - --grey-dark-3: #ffffff; - --grey-dark-4: #ffffff; - --grey-dark-5: #ffffff; - --grey-dark-6: #ffffff; - --grey-dark-7: #ffffff; - --grey-dark-8: #ffffff; - --grey-dark-9: #ffffff; - --grey-dark-10: #ffffff; - --grey-dark-11: #ffffff; - --grey-dark-12: #ffffff; - --grey-light-1: #ffffff; - --grey-dark-alpha-1: #ffffff; - --grey-dark-alpha-2: #ffffff; - --grey-dark-alpha-3: #ffffff; - --grey-dark-alpha-4: #ffffff; - --grey-dark-alpha-5: #ffffff; - --grey-dark-alpha-6: #ffffff; - --grey-dark-alpha-7: #ffffff; - --grey-dark-alpha-8: #ffffff; - --grey-dark-alpha-9: #ffffff; - --grey-dark-alpha-10: #ffffff; - --grey-dark-alpha-11: #ffffff; - --grey-dark-alpha-12: #ffffff; --smoke-dark-1: #131010; - --grey-light-2: #ffffff; - --grey-light-3: #ffffff; - --grey-light-4: #ffffff; - --grey-light-5: #ffffff; - --grey-light-6: #ffffff; - --grey-light-7: #ffffff; - --grey-light-8: #ffffff; - --grey-light-9: #ffffff; - --grey-light-10: #ffffff; - --grey-light-11: #ffffff; - --grey-light-12: #ffffff; --smoke-dark-2: #1b1818; --smoke-dark-3: #252121; --smoke-dark-4: #2d2828; @@ -59,19 +23,19 @@ --smoke-light-10: #848181; --smoke-light-11: #656363; --smoke-light-12: #211e1e; - --smoke-dark-alpha-1: #bb000003; - --smoke-dark-alpha-2: #f9b4b40b; - --smoke-dark-alpha-3: #f9caca16; - --smoke-dark-alpha-4: #ffd5d51e; - --smoke-dark-alpha-5: #fce2e226; - --smoke-dark-alpha-6: #fce2e231; - --smoke-dark-alpha-7: #fce8e83f; - --smoke-dark-alpha-8: #fff1f159; - --smoke-dark-alpha-9: #fff3f067; - --smoke-dark-alpha-10: #fff2f276; - --smoke-dark-alpha-11: #fff7f7b2; + --smoke-dark-alpha-1: #82383803; + --smoke-dark-alpha-2: #e6c6c60b; + --smoke-dark-alpha-3: #edd5d516; + --smoke-dark-alpha-4: #f2e1e11e; + --smoke-dark-alpha-5: #f5e8e826; + --smoke-dark-alpha-6: #f5e8e831; + --smoke-dark-alpha-7: #f7ecec3f; + --smoke-dark-alpha-8: #faf5f559; + --smoke-dark-alpha-9: #faf5f467; + --smoke-dark-alpha-10: #fbf5f576; + --smoke-dark-alpha-11: #fcf9f9b2; --smoke-light-alpha-1: #55000003; - --smoke-dark-alpha-12: #fffafaf0; + --smoke-dark-alpha-12: #fdfbfbf0; --smoke-light-alpha-2: #25000007; --smoke-light-alpha-3: #1100000f; --smoke-light-alpha-4: #0c000017; @@ -149,8 +113,8 @@ --cobalt-light-4: #daeaff; --cobalt-light-5: #c8e0ff; --cobalt-light-6: #b4d2ff; - --cobalt-light-7: #98bfff; --cobalt-dark-alpha-1: #0011f211; + --cobalt-light-7: #98bfff; --cobalt-dark-alpha-2: #0048fe1c; --cobalt-dark-alpha-3: #004dff49; --cobalt-dark-alpha-4: #064dfd6b; @@ -161,8 +125,8 @@ --cobalt-dark-alpha-9: #034cff; --cobalt-dark-alpha-10: #003bffed; --cobalt-dark-alpha-11: #89b5ff; - --cobalt-dark-alpha-12: #cde2ff; --cobalt-light-8: #73a4ff; + --cobalt-dark-alpha-12: #cde2ff; --cobalt-light-9: #034cff; --cobalt-light-10: #0443de; --cobalt-light-11: #1251ec; @@ -481,16 +445,4 @@ --mint-light-alpha-10: #0cc7006c; --mint-light-alpha-11: #016800cf; --mint-light-alpha-12: #022e00e2; - --grey-light-alpha-1: #ffffff; - --grey-light-alpha-2: #ffffff; - --grey-light-alpha-3: #ffffff; - --grey-light-alpha-4: #ffffff; - --grey-light-alpha-5: #ffffff; - --grey-light-alpha-6: #ffffff; - --grey-light-alpha-7: #ffffff; - --grey-light-alpha-8: #ffffff; - --grey-light-alpha-9: #ffffff; - --grey-light-alpha-10: #ffffff; - --grey-light-alpha-11: #ffffff; - --grey-light-alpha-12: #ffffff; } diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index 7ae6b73e4..94fa894d4 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -8,6 +8,7 @@ @import "../components/accordion.css" layer(components); @import "../components/button.css" layer(components); @import "../components/checkbox.css" layer(components); +@import "../components/diff.css" layer(components); @import "../components/collapsible.css" layer(components); @import "../components/dialog.css" layer(components); @import "../components/icon.css" layer(components); -- cgit v1.2.3