Spaces:
Paused
Paused
Changes pane: its diff in Pi Web's diff theme
Browse files- piweb/hf-design.patch +46 -14
piweb/hf-design.patch
CHANGED
|
@@ -4243,7 +4243,7 @@ index 0000000..8d003fe
|
|
| 4243 |
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
| 4244 |
+OTHER DEALINGS IN THE FONT SOFTWARE.
|
| 4245 |
diff --git a/app/globals.css b/app/globals.css
|
| 4246 |
-
index 49e70be..
|
| 4247 |
--- a/app/globals.css
|
| 4248 |
+++ b/app/globals.css
|
| 4249 |
@@ -24,46 +24,109 @@
|
|
@@ -5914,7 +5914,7 @@ index 49e70be..75bdab8 100644
|
|
| 5914 |
textarea,
|
| 5915 |
input,
|
| 5916 |
select {
|
| 5917 |
-
@@ -2746,3 +2372,
|
| 5918 |
display: none !important;
|
| 5919 |
}
|
| 5920 |
}
|
|
@@ -6231,9 +6231,12 @@ index 49e70be..75bdab8 100644
|
|
| 6231 |
+/* Pi Web's code and diff viewers (components/highlighting.ts: @pierre/diffs, Shiki): their shadow
|
| 6232 |
+ roots read these. The design system's code type (text-code: 12px on 18px, ligatures off), the
|
| 6233 |
+ surface they sit on (--code-bg), the state colours for additions and deletions, and a neutral
|
| 6234 |
-
+ "modified" (selection), never the library's blue.
|
|
|
|
|
|
|
| 6235 |
+.code-diff,
|
| 6236 |
-
+.code-file
|
|
|
|
| 6237 |
+ --code-bg: var(--bg);
|
| 6238 |
+ --diffs-font-family: var(--font-mono);
|
| 6239 |
+ --diffs-header-font-family: var(--font-ui);
|
|
@@ -6249,6 +6252,13 @@ index 49e70be..75bdab8 100644
|
|
| 6249 |
+ --diffs-bg-deletion-override: color-mix(in srgb, var(--danger) 12%, var(--bg));
|
| 6250 |
+ --diffs-bg-addition-emphasis-override: color-mix(in srgb, var(--success) 26%, transparent);
|
| 6251 |
+ --diffs-bg-deletion-emphasis-override: color-mix(in srgb, var(--danger) 26%, transparent);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6252 |
+ min-width: 0;
|
| 6253 |
+ padding-block: 6px;
|
| 6254 |
+ background: var(--code-bg);
|
|
@@ -6257,7 +6267,8 @@ index 49e70be..75bdab8 100644
|
|
| 6257 |
+/* The background goes on the viewer's host itself: its theme sets these two there (:host), which
|
| 6258 |
+ beats a value inherited from the wrapper; a document rule on the host beats the :host rule. */
|
| 6259 |
+.code-diff diffs-container,
|
| 6260 |
-
+.code-file diffs-container
|
|
|
|
| 6261 |
+ --diffs-light-bg: var(--code-bg);
|
| 6262 |
+ --diffs-dark-bg: var(--code-bg);
|
| 6263 |
+}
|
|
@@ -8596,10 +8607,10 @@ index f0e2e95..3ecbf91 100644
|
|
| 8596 |
font-family: var(--font-mono);
|
| 8597 |
diff --git a/app/shell.css b/app/shell.css
|
| 8598 |
new file mode 100644
|
| 8599 |
-
index 0000000..
|
| 8600 |
--- /dev/null
|
| 8601 |
+++ b/app/shell.css
|
| 8602 |
-
@@ -0,0 +1,
|
| 8603 |
+/* The app's frame, as Claude Code Desktop's: the conversation's header (the
|
| 8604 |
+ title and its menu; a button per pane on the right), the tiles (the chat
|
| 8605 |
+ and the panes it opened: Terminal, Changes, Browser, Files) and the Changes
|
|
@@ -9085,7 +9096,6 @@ index 0000000..150b9c1
|
|
| 9085 |
+.changes-file {
|
| 9086 |
+ display: flex;
|
| 9087 |
+ align-items: baseline;
|
| 9088 |
-
+ line-height: var(--size-row);
|
| 9089 |
+ gap: 6px;
|
| 9090 |
+ width: 100%;
|
| 9091 |
+ min-height: var(--size-row);
|
|
@@ -9096,6 +9106,7 @@ index 0000000..150b9c1
|
|
| 9096 |
+ color: var(--text);
|
| 9097 |
+ font: inherit;
|
| 9098 |
+ font-size: 12.5px;
|
|
|
|
| 9099 |
+ text-align: left;
|
| 9100 |
+ cursor: pointer;
|
| 9101 |
+}
|
|
@@ -9109,7 +9120,9 @@ index 0000000..150b9c1
|
|
| 9109 |
+.changes-file-status.is-modified, .changes-file-status.is-renamed { color: var(--warning); }
|
| 9110 |
+.changes-file-status.is-added, .changes-file-status.is-untracked { color: var(--success); }
|
| 9111 |
+.changes-file-status.is-deleted, .changes-file-status.is-conflict { color: var(--danger); }
|
| 9112 |
-
+
|
|
|
|
|
|
|
| 9113 |
+.changes-diff-head {
|
| 9114 |
+ display: flex;
|
| 9115 |
+ flex-shrink: 0;
|
|
@@ -9119,7 +9132,7 @@ index 0000000..150b9c1
|
|
| 9119 |
+ padding: 0 8px 0 12px;
|
| 9120 |
+}
|
| 9121 |
+.changes-diff-path { flex: 1 1 auto; min-width: 0; overflow: hidden; color: var(--text-muted); font-family: var(--font-mono); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
| 9122 |
-
+.changes-diff-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0
|
| 9123 |
+.changes-diff-tip { flex-shrink: 0; padding: 6px 12px; border-top: 1px solid var(--line); color: var(--text-dim); font-size: 12px; }
|
| 9124 |
+@container (max-width: 720px) {
|
| 9125 |
+ .changes-body { flex-direction: column; }
|
|
@@ -32164,10 +32177,10 @@ index 0000000..a620a61
|
|
| 32164 |
+export { CodeFile } from "./CodeFile";
|
| 32165 |
diff --git a/components/highlighting.test.mjs b/components/highlighting.test.mjs
|
| 32166 |
new file mode 100644
|
| 32167 |
-
index 0000000..
|
| 32168 |
--- /dev/null
|
| 32169 |
+++ b/components/highlighting.test.mjs
|
| 32170 |
-
@@ -0,0 +1,
|
| 32171 |
+import assert from "node:assert/strict";
|
| 32172 |
+import test from "node:test";
|
| 32173 |
+import { createJiti } from "jiti";
|
|
@@ -32196,6 +32209,21 @@ index 0000000..3d8fca8
|
|
| 32196 |
+ assert.match(UNSAFE_CSS, /font-weight: calc\(var\(--font-mono-weight, 400\) \+ 200\)/);
|
| 32197 |
+ assert.doesNotMatch(UNSAFE_CSS, /#[0-9a-f]{3,6}\b/i);
|
| 32198 |
+});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32199 |
diff --git a/components/highlighting.ts b/components/highlighting.ts
|
| 32200 |
new file mode 100644
|
| 32201 |
index 0000000..773b858
|
|
@@ -32431,10 +32459,10 @@ index f7b4749..0000000
|
|
| 32431 |
-}
|
| 32432 |
diff --git a/components/ui/baselines.test.mjs b/components/ui/baselines.test.mjs
|
| 32433 |
new file mode 100644
|
| 32434 |
-
index 0000000..
|
| 32435 |
--- /dev/null
|
| 32436 |
+++ b/components/ui/baselines.test.mjs
|
| 32437 |
-
@@ -0,0 +1,
|
| 32438 |
+import assert from "node:assert/strict";
|
| 32439 |
+import { readFileSync } from "node:fs";
|
| 32440 |
+import test from "node:test";
|
|
@@ -32470,6 +32498,10 @@ index 0000000..cda684d
|
|
| 32470 |
+ const body = rule(selector);
|
| 32471 |
+ assert.match(body, /align-items: baseline/, selector);
|
| 32472 |
+ assert.ok(body.includes(`line-height: ${line}`), `${selector}: line box of ${line}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32473 |
+ }
|
| 32474 |
+ assert.match(rule(".tool-call-head"), /align-items: baseline/);
|
| 32475 |
+ assert.match(css, /\.tool-call-head > svg,\n\.tool-call-row > :not\(\.tool-call-head, \.tool-call-meta\) \{ align-self: center; \}/);
|
|
|
|
| 4243 |
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
| 4244 |
+OTHER DEALINGS IN THE FONT SOFTWARE.
|
| 4245 |
diff --git a/app/globals.css b/app/globals.css
|
| 4246 |
+
index 49e70be..cf5f144 100644
|
| 4247 |
--- a/app/globals.css
|
| 4248 |
+++ b/app/globals.css
|
| 4249 |
@@ -24,46 +24,109 @@
|
|
|
|
| 5914 |
textarea,
|
| 5915 |
input,
|
| 5916 |
select {
|
| 5917 |
+
@@ -2746,3 +2372,507 @@ span.token.table {
|
| 5918 |
display: none !important;
|
| 5919 |
}
|
| 5920 |
}
|
|
|
|
| 6231 |
+/* Pi Web's code and diff viewers (components/highlighting.ts: @pierre/diffs, Shiki): their shadow
|
| 6232 |
+ roots read these. The design system's code type (text-code: 12px on 18px, ligatures off), the
|
| 6233 |
+ surface they sit on (--code-bg), the state colours for additions and deletions, and a neutral
|
| 6234 |
+
+ "modified" (selection), never the library's blue. Every viewer takes them, the Changes pane's
|
| 6235 |
+
+ too (components/ChangesPane.tsx renders its own): without them the library's own theme shows,
|
| 6236 |
+
+ its near-black background in bands above and below the lines and beside the line numbers. */
|
| 6237 |
+.code-diff,
|
| 6238 |
+
+.code-file,
|
| 6239 |
+
+.changes-diff-scroll {
|
| 6240 |
+ --code-bg: var(--bg);
|
| 6241 |
+ --diffs-font-family: var(--font-mono);
|
| 6242 |
+ --diffs-header-font-family: var(--font-ui);
|
|
|
|
| 6252 |
+ --diffs-bg-deletion-override: color-mix(in srgb, var(--danger) 12%, var(--bg));
|
| 6253 |
+ --diffs-bg-addition-emphasis-override: color-mix(in srgb, var(--success) 26%, transparent);
|
| 6254 |
+ --diffs-bg-deletion-emphasis-override: color-mix(in srgb, var(--danger) 26%, transparent);
|
| 6255 |
+
+ /* Selected lines (a range to comment on) as a highlighted row is: a tint of the ink, not the
|
| 6256 |
+
+ library's 65% of the "modified" colour, which turned a selection and its comment's row grey. */
|
| 6257 |
+
+ --diffs-bg-selection-override: color-mix(in srgb, var(--text-strong) 8%, var(--code-bg));
|
| 6258 |
+
+ --diffs-bg-selection-number-override: color-mix(in srgb, var(--text-strong) 12%, var(--code-bg));
|
| 6259 |
+
+}
|
| 6260 |
+
+.code-diff,
|
| 6261 |
+
+.code-file {
|
| 6262 |
+ min-width: 0;
|
| 6263 |
+ padding-block: 6px;
|
| 6264 |
+ background: var(--code-bg);
|
|
|
|
| 6267 |
+/* The background goes on the viewer's host itself: its theme sets these two there (:host), which
|
| 6268 |
+ beats a value inherited from the wrapper; a document rule on the host beats the :host rule. */
|
| 6269 |
+.code-diff diffs-container,
|
| 6270 |
+
+.code-file diffs-container,
|
| 6271 |
+
+.changes-diff-scroll diffs-container {
|
| 6272 |
+ --diffs-light-bg: var(--code-bg);
|
| 6273 |
+ --diffs-dark-bg: var(--code-bg);
|
| 6274 |
+}
|
|
|
|
| 8607 |
font-family: var(--font-mono);
|
| 8608 |
diff --git a/app/shell.css b/app/shell.css
|
| 8609 |
new file mode 100644
|
| 8610 |
+
index 0000000..a2e91d5
|
| 8611 |
--- /dev/null
|
| 8612 |
+++ b/app/shell.css
|
| 8613 |
+
@@ -0,0 +1,767 @@
|
| 8614 |
+/* The app's frame, as Claude Code Desktop's: the conversation's header (the
|
| 8615 |
+ title and its menu; a button per pane on the right), the tiles (the chat
|
| 8616 |
+ and the panes it opened: Terminal, Changes, Browser, Files) and the Changes
|
|
|
|
| 9096 |
+.changes-file {
|
| 9097 |
+ display: flex;
|
| 9098 |
+ align-items: baseline;
|
|
|
|
| 9099 |
+ gap: 6px;
|
| 9100 |
+ width: 100%;
|
| 9101 |
+ min-height: var(--size-row);
|
|
|
|
| 9106 |
+ color: var(--text);
|
| 9107 |
+ font: inherit;
|
| 9108 |
+ font-size: 12.5px;
|
| 9109 |
+
+ line-height: var(--size-row); /* after the font shorthand, which resets it */
|
| 9110 |
+ text-align: left;
|
| 9111 |
+ cursor: pointer;
|
| 9112 |
+}
|
|
|
|
| 9120 |
+.changes-file-status.is-modified, .changes-file-status.is-renamed { color: var(--warning); }
|
| 9121 |
+.changes-file-status.is-added, .changes-file-status.is-untracked { color: var(--success); }
|
| 9122 |
+.changes-file-status.is-deleted, .changes-file-status.is-conflict { color: var(--danger); }
|
| 9123 |
+
+/* The selected file's diff: the code's surface edge to edge under the list, its path, lines
|
| 9124 |
+
+ and tip on it, as the Files pane shows a diff. */
|
| 9125 |
+
+.changes-diff { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }
|
| 9126 |
+.changes-diff-head {
|
| 9127 |
+ display: flex;
|
| 9128 |
+ flex-shrink: 0;
|
|
|
|
| 9132 |
+ padding: 0 8px 0 12px;
|
| 9133 |
+}
|
| 9134 |
+.changes-diff-path { flex: 1 1 auto; min-width: 0; overflow: hidden; color: var(--text-muted); font-family: var(--font-mono); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
| 9135 |
+
+.changes-diff-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 2px 0 12px; background: var(--code-bg); }
|
| 9136 |
+.changes-diff-tip { flex-shrink: 0; padding: 6px 12px; border-top: 1px solid var(--line); color: var(--text-dim); font-size: 12px; }
|
| 9137 |
+@container (max-width: 720px) {
|
| 9138 |
+ .changes-body { flex-direction: column; }
|
|
|
|
| 32177 |
+export { CodeFile } from "./CodeFile";
|
| 32178 |
diff --git a/components/highlighting.test.mjs b/components/highlighting.test.mjs
|
| 32179 |
new file mode 100644
|
| 32180 |
+
index 0000000..f69de58
|
| 32181 |
--- /dev/null
|
| 32182 |
+++ b/components/highlighting.test.mjs
|
| 32183 |
+
@@ -0,0 +1,43 @@
|
| 32184 |
+import assert from "node:assert/strict";
|
| 32185 |
+import test from "node:test";
|
| 32186 |
+import { createJiti } from "jiti";
|
|
|
|
| 32209 |
+ assert.match(UNSAFE_CSS, /font-weight: calc\(var\(--font-mono-weight, 400\) \+ 200\)/);
|
| 32210 |
+ assert.doesNotMatch(UNSAFE_CSS, /#[0-9a-f]{3,6}\b/i);
|
| 32211 |
+});
|
| 32212 |
+
+
|
| 32213 |
+
+test("every viewer of the library sits in Pi Web's diff theme: no library background shows", async () => {
|
| 32214 |
+
+ const { readFileSync } = await import("node:fs");
|
| 32215 |
+
+ const globals = readFileSync(new URL("../app/globals.css", import.meta.url), "utf8");
|
| 32216 |
+
+ // The variables' rule and the rule on the viewer's host, each a list of the viewers' wrappers.
|
| 32217 |
+
+ const variables = globals.match(/((?:\.[\w-]+,\n)*\.[\w-]+) \{\n --code-bg: var\(--bg\);/)?.[1].split(",\n") ?? [];
|
| 32218 |
+
+ const hosts = globals.match(/((?:\.[\w-]+ diffs-container,\n)*\.[\w-]+ diffs-container) \{\n --diffs-light-bg: var\(--code-bg\);/)?.[1].split(",\n").map((s) => s.replace(" diffs-container", "")) ?? [];
|
| 32219 |
+
+ for (const [file, wrapper] of [["./CodeDiff.tsx", ".code-diff"], ["./CodeFile.tsx", ".code-file"], ["./ChangesPane.tsx", ".changes-diff-scroll"]]) {
|
| 32220 |
+
+ const source = readFileSync(new URL(file, import.meta.url), "utf8");
|
| 32221 |
+
+ assert.ok(source.includes(wrapper.slice(1)), `${file} renders its viewer in ${wrapper}`);
|
| 32222 |
+
+ assert.ok(variables.includes(wrapper), `${wrapper} takes the theme's colours (${variables.join(" ")})`);
|
| 32223 |
+
+ assert.ok(hosts.includes(wrapper), `${wrapper}'s viewer takes the code surface as its background`);
|
| 32224 |
+
+ }
|
| 32225 |
+
+ assert.match(globals, /--diffs-bg-selection-override: color-mix\(in srgb, var\(--text-strong\) 8%, var\(--code-bg\)\);/, "a selection is a light tint");
|
| 32226 |
+
+});
|
| 32227 |
diff --git a/components/highlighting.ts b/components/highlighting.ts
|
| 32228 |
new file mode 100644
|
| 32229 |
index 0000000..773b858
|
|
|
|
| 32459 |
-}
|
| 32460 |
diff --git a/components/ui/baselines.test.mjs b/components/ui/baselines.test.mjs
|
| 32461 |
new file mode 100644
|
| 32462 |
+
index 0000000..b01f48b
|
| 32463 |
--- /dev/null
|
| 32464 |
+++ b/components/ui/baselines.test.mjs
|
| 32465 |
+
@@ -0,0 +1,52 @@
|
| 32466 |
+import assert from "node:assert/strict";
|
| 32467 |
+import { readFileSync } from "node:fs";
|
| 32468 |
+import test from "node:test";
|
|
|
|
| 32498 |
+ const body = rule(selector);
|
| 32499 |
+ assert.match(body, /align-items: baseline/, selector);
|
| 32500 |
+ assert.ok(body.includes(`line-height: ${line}`), `${selector}: line box of ${line}`);
|
| 32501 |
+
+ // The font shorthand resets line-height: a later one would undo the row's line box (the
|
| 32502 |
+
+ // Changes list's names once sat high in their rows, their icons centred).
|
| 32503 |
+
+ const font = body.lastIndexOf("font: "), height = body.lastIndexOf(`line-height: ${line}`);
|
| 32504 |
+
+ assert.ok(font < height, `${selector}: its line box comes after its font shorthand`);
|
| 32505 |
+ }
|
| 32506 |
+ assert.match(rule(".tool-call-head"), /align-items: baseline/);
|
| 32507 |
+ assert.match(css, /\.tool-call-head > svg,\n\.tool-call-row > :not\(\.tool-call-head, \.tool-call-meta\) \{ align-self: center; \}/);
|