Skip to content

Commit 9e805f9

Browse files
authored
Merge branch 'main' into build-website-workflow
2 parents 265c19d + e09d2df commit 9e805f9

File tree

8 files changed

+471
-113
lines changed

8 files changed

+471
-113
lines changed

packages/feedback-components/src/extractions/index.ts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Entity, EntityExt, Highlight, EntityType } from "./types";
55
import { CSSProperties } from "react";
66
import { asChromaColor } from "@macrostrat/color-utils";
77
import hyper from "@macrostrat/hyper";
8+
import { useDarkMode } from "@macrostrat/ui-components";
89

910
export type { Entity, EntityExt };
1011

@@ -25,7 +26,7 @@ export function buildHighlights(
2526
start: entity.indices[0],
2627
end: entity.indices[1],
2728
text: entity.name,
28-
backgroundColor: entity.type?.color ?? "rgb(107, 255, 91)",
29+
backgroundColor: entity.type?.color,
2930
tag: entity.type?.name ?? "lith",
3031
id: entity.id,
3132
parents,
@@ -49,7 +50,7 @@ export function getTagStyle(
4950
baseColor: string,
5051
options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean }
5152
): CSSProperties {
52-
const _baseColor = asChromaColor(baseColor ?? "#ddd");
53+
const _baseColor = asChromaColor(baseColor ?? "#fff");
5354
const { highlighted = true, inDarkMode = false, active = false } = options;
5455

5556
let mixAmount = highlighted ? 0.8 : 0.5;
@@ -62,19 +63,28 @@ export function getTagStyle(
6263

6364
const mixTarget = inDarkMode ? "white" : "black";
6465

65-
const color = _baseColor.mix(mixTarget, mixAmount).css();
66+
const color = _baseColor.mix(mixTarget, mixAmount).hex();
6667
const borderColor = highlighted
67-
? _baseColor.mix(mixTarget, mixAmount / 2).css()
68+
? _baseColor.mix(mixTarget, mixAmount / 1.1).hex()
6869
: "transparent";
6970

71+
const backgroundColor = active ?
72+
_baseColor.alpha(backgroundAlpha).hex() :
73+
normalizeColor(_baseColor.alpha(backgroundAlpha).hex())
74+
75+
if(backgroundColor.includes("56cc49")) {
76+
console.warn("base color", baseColor, "normalized to", backgroundColor);
77+
}
78+
7079
return {
7180
color,
72-
backgroundColor: _baseColor.alpha(backgroundAlpha).css(),
81+
backgroundColor,
7382
boxSizing: "border-box",
7483
borderStyle: "solid",
7584
borderColor,
76-
borderWidth: "1px",
85+
borderWidth: "1.5px",
7786
fontWeight: active ? "bold" : "normal",
87+
fontSize: "0.9em",
7888
};
7989
}
8090

@@ -90,7 +100,7 @@ function enhanceEntity(
90100
}
91101

92102
function addColor(entityType: EntityType, match = false) {
93-
const color = asChromaColor(entityType.color ?? "#ddd").brighten(
103+
const color = asChromaColor(entityType.color ?? "#fff").brighten(
94104
match ? 1 : 2
95105
);
96106

@@ -149,7 +159,7 @@ export function EntityTag({
149159
"entity"
150160
);
151161

152-
const style = getTagStyle(type?.color ?? "#aaaaaa", { highlighted, active });
162+
const style = getTagStyle(type?.color, { highlighted, active });
153163

154164
let _matchLink = null;
155165
if (match != null && matchComponent != null) {
@@ -218,3 +228,29 @@ function HighlightedText(props: { text: string; highlights: Highlight[] }) {
218228
parts.push(text.slice(start));
219229
return h("span", parts);
220230
}
231+
232+
function normalizeColor(hex8) {
233+
const background = useDarkMode().isEnabled ? "#000000" : "#ffffff";
234+
235+
const r = parseInt(hex8.slice(1, 3), 16);
236+
const g = parseInt(hex8.slice(3, 5), 16);
237+
const b = parseInt(hex8.slice(5, 7), 16);
238+
const a = parseInt(hex8.slice(7, 9), 16) / 255;
239+
240+
const bgR = parseInt(background.slice(1, 3), 16);
241+
const bgG = parseInt(background.slice(3, 5), 16);
242+
const bgB = parseInt(background.slice(5, 7), 16);
243+
244+
const blend = (fg, bg) => Math.round((1 - a) * bg + a * fg);
245+
246+
const blendedR = blend(r, bgR);
247+
const blendedG = blend(g, bgG);
248+
const blendedB = blend(b, bgB);
249+
250+
return (
251+
"#" +
252+
blendedR.toString(16).padStart(2, "0") +
253+
blendedG.toString(16).padStart(2, "0") +
254+
blendedB.toString(16).padStart(2, "0")
255+
);
256+
}

packages/feedback-components/src/feedback/edit-state.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ export interface EntityOutput {
264264
name: string;
265265
match: any | null;
266266
reasoning: string | null;
267+
color: string | null;
268+
children: any[] | null;
267269
}
268270

269271
export interface GraphData {
@@ -284,15 +286,17 @@ export function treeToGraph(tree: TreeData[]): GraphData {
284286
continue;
285287
}
286288

287-
const { indices, id, name } = node;
289+
const { indices, id, name, type, children } = node;
288290

289291
const nodeData: EntityOutput = {
290292
id,
291-
type: node.type.id,
293+
type: type.id,
294+
color: type.color,
292295
name,
293296
txt_range: [indices],
294297
reasoning: null,
295298
match: node.match,
299+
children
296300
};
297301

298302
nodeMap.set(node.id, node);

packages/feedback-components/src/feedback/feedback.module.sass

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@
88
.node
99
cursor: pointer
1010

11+
circle
12+
cursor: pointer
13+
border: 1px solid black
1114

15+
.selected
16+
border: 1px solid white
17+
1218
.feedback-text
1319
margin-bottom: 2em
1420

@@ -17,7 +23,6 @@
1723
max-height: 600px
1824

1925
.control-panel
20-
max-width: 15em
2126
position: absolute
2227
top: 1em
2328
right: 1em
@@ -35,9 +40,27 @@
3540
.selection-tree
3641
margin: -1em 0
3742
padding: 1em 0
38-
width: 80% !important
39-
43+
width: 70% !important
44+
4045
.type-list
41-
display: flex
42-
flex-direction: column
43-
gap: .2em
46+
display: grid
47+
grid-auto-flow: column
48+
grid-template-rows: repeat(10, auto)
49+
gap: 0.2em
50+
margin-bottom: .5em
51+
52+
.type-tag
53+
padding: .2em .5em
54+
border-radius: .2em
55+
56+
.description
57+
max-width: 300px
58+
padding: .5em
59+
60+
mark
61+
border-radius: .2em
62+
cursor: pointer
63+
color: black !important
64+
65+
[role="treeitem"]
66+
width: auto !important

packages/feedback-components/src/feedback/graph.ts

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ import {
1212
forceCollide,
1313
} from "d3-force";
1414
import { useEffect, useState } from "react";
15-
import { Spinner } from "@blueprintjs/core";
15+
import { Spinner, Popover } from "@blueprintjs/core";
16+
import { ErrorBoundary } from "@macrostrat/ui-components";
17+
import { getTagStyle } from "../extractions";
1618

1719
export function GraphView(props: {
1820
tree: TreeData[];
1921
width: number;
2022
height: number;
23+
dispatch: (action: any) => void;
24+
selectedNodes: number[];
2125
}) {
2226
// A graph view with react-flow
2327
// Get positions of nodes using force simulation
24-
const { tree, width, height } = props;
28+
const { tree, width, height, dispatch, selectedNodes } = props;
2529

2630
const [nodes, setNodes] = useState<SimulationNodeDatum[]>(null);
2731
const [links, setLinks] = useState<SimulationLinkDatum[]>(null);
@@ -66,33 +70,66 @@ export function GraphView(props: {
6670
return h(Spinner);
6771
}
6872

69-
console.log("Graph", nodes, links);
73+
console.log("Graph", nodes, links, selectedNodes);
7074

71-
return h("div.graph-view", { style: { width, height } }, [
72-
h("svg", { width, height }, [
75+
return h(ErrorBoundary,
76+
{
77+
description: "An error occurred while rendering the graph view."
78+
},
79+
h("div.graph-view", { style: { width, height } }, [
80+
h("svg", { width, height }, [
81+
h(
82+
"g.links",
83+
links.map((d) => {
84+
return h("line", {
85+
x1: d.source.x,
86+
y1: d.source.y,
87+
x2: d.target.x,
88+
y2: d.target.y,
89+
stroke: "black",
90+
});
91+
})
92+
),
7393
h(
7494
"g.nodes",
7595
nodes.map((d) => {
96+
const active = selectedNodes.includes(d.id);
97+
const stroke = active ? "white" : "black";
98+
const highlighted = isHighlighted(d.id, selectedNodes, nodes);
99+
const style = getTagStyle(d.color, { highlighted, active });
100+
76101
return h("circle", {
77102
cx: d.x,
78103
cy: d.y,
79104
r: 5,
80-
fill: "blue",
81-
});
105+
fill: style.backgroundColor || "blue",
106+
onClick: (e) => {
107+
e.stopPropagation();
108+
dispatch({
109+
type: "toggle-node-selected",
110+
payload: { ids: [d.id] },
111+
});
112+
},
113+
className: active ? "selected" : "",
114+
stroke,
115+
strokeWidth: 2,
116+
},
117+
h(
118+
"title",
119+
d.name || `Node ${d.id}`
120+
)
121+
);
82122
})
83123
),
84-
h(
85-
"g.links",
86-
links.map((d) => {
87-
return h("line", {
88-
x1: d.source.x,
89-
y1: d.source.y,
90-
x2: d.target.x,
91-
y2: d.target.y,
92-
stroke: "black",
93-
});
94-
})
95-
),
96-
]),
97-
]);
124+
])
125+
])
126+
);
127+
}
128+
129+
function isHighlighted(id: number, selectedNodes: number[], nodes: TreeData[]) {
130+
if (selectedNodes.length === 0) return true;
131+
return (
132+
selectedNodes.includes(id) ||
133+
nodes.some((node) => selectedNodes.includes(node.id) && node.children.some((child) => child.id === id))
134+
);
98135
}

0 commit comments

Comments
 (0)