Skip to content

Commit 15e00f4

Browse files
committed
pnpm + ptable migration
1 parent 97d77e2 commit 15e00f4

9 files changed

Lines changed: 14224 additions & 22453 deletions

File tree

package-lock.json

Lines changed: 0 additions & 22343 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"framer-motion": "^12.23.19",
1818
"gl-matrix": "^3.4.4",
1919
"lodash.debounce": "^4.0.8",
20-
"matsci-parse": "^0.0.2",
20+
"matsci-parse": "^0.5.2",
21+
"mc-periodic-table": "^0.0.2",
2122
"mc-react-header": "^0.4.5",
2223
"mc-react-library": "^0.5.0",
2324
"mc-react-structure-visualizer": "^0.8.4",

pnpm-lock.yaml

Lines changed: 14009 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
allowBuilds:
2+
core-js: true
3+
core-js-pure: true
4+
esbuild: true

src/components/OptimadeClient/OptimadeFilters/OptimadePTable/elements.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Simple periodic table data up to 118
22
// Each element has atomic number, symbol, row, and column (group)
33
export const elements = [
4+
{},
45
// Period 1
56
{ num: 1, sym: "H", row: 1, col: 1, group: "group1" },
67
{ num: 2, sym: "He", row: 1, col: 18, group: "group18" },
Lines changed: 72 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,52 @@
1-
import React, { useEffect, useState } from "react";
2-
import { elements as allElements } from "./elements";
1+
import React, { useEffect, useState, useMemo } from "react";
2+
import { symbols, names } from "mc-periodic-table";
33

44
import HelpIcon from "../../../common/HelpIcon";
5-
6-
const defaultColors = {
7-
group1: "bg-[#d7bbbb]",
8-
group2: "bg-[#d7cdbb]",
9-
group17: "bg-[#d7d9c2]",
10-
group18: "bg-[#d0d5ee]",
11-
transition: "bg-[#c4d0d8]",
12-
lanthanide: "bg-[#e5cbee]",
13-
actinide: "bg-[#aebcee]",
14-
metalloid: "bg-[#cdd9c2]",
15-
postTransition: "bg-[#c2c8d9]",
16-
mainGroup: "bg-[#d9c2ce]",
17-
default: "bg-gray-200",
18-
};
5+
import { PTableWrapper } from "../../../common/PTableWrapper";
196

207
export default function PTable({
218
providerUrl = null,
229
selected = {},
2310
onSelectionChange,
24-
colors = defaultColors,
25-
selectedClassName = "bg-green-400 border border-green-700 text-white scale-105",
26-
deselectedClassName = "bg-red-400 border border-red-700 text-white scale-105",
27-
defaultBorderClassName = "border border-slate-700",
28-
hoverClassName = "transform transition-transform duration-100 hover:scale-105 hover:z-10 hover:cursor-pointer",
2911
}) {
30-
const [elements, setElements] = useState(allElements);
3112
const [cachedPTable, setCachedPTable] = useState(null);
3213
const [lastModified, setLastModified] = useState(null);
3314

34-
// Load cached PTable once on mount
15+
// ----------------------------
16+
// cache loading
17+
// ----------------------------
3518
useEffect(() => {
3619
const loadCache = async () => {
3720
const urls = [
3821
"./cachedPTable.json",
3922
"https://raw.githubusercontent.com/materialscloud-org/tools-optimadeclient-react/main/public/cachedPTable.json",
4023
];
24+
4125
let json = null;
26+
4227
for (const url of urls) {
4328
try {
4429
const res = await fetch(url);
45-
if (!res.ok)
46-
throw new Error(`Failed to load cached PTable from ${url}`);
30+
if (!res.ok) throw new Error(`Failed ${url}`);
4731
json = await res.json();
48-
console.log(`Loaded cached PTable from ${url}`);
4932
break;
50-
} catch (err) {
51-
console.warn(err.message);
33+
} catch (e) {
34+
console.warn(e.message);
5235
}
5336
}
5437

55-
if (!json) {
56-
console.error("Failed to load cached PTable from all sources");
57-
return;
58-
}
38+
if (!json) return;
5939

60-
// Use lastUpdated for UI
6140
if (json.lastUpdated) {
6241
setLastModified(new Date(json.lastUpdated).toLocaleDateString());
6342
}
6443

65-
// Convert to lookup map
6644
const map = {};
6745
json.data.forEach((entry) => {
6846
if (!entry.providerUrl) return;
6947

7048
const key = entry.providerUrl.replace(/\/+$/, "");
71-
// Check if `ptable` exists, otherwise check flattened object
49+
7250
const ptable =
7351
entry.ptable ??
7452
Object.fromEntries(
@@ -79,93 +57,81 @@ export default function PTable({
7957

8058
map[key] = ptable;
8159
});
60+
8261
setCachedPTable(map);
8362
};
8463

8564
loadCache();
8665
}, []);
8766

88-
// Update elements when providerUrl changes
89-
useEffect(() => {
90-
if (!providerUrl || !cachedPTable) return;
67+
// ----------------------------
68+
// convert selected symbols → atomic state
69+
// ----------------------------
70+
const selectionState = useMemo(() => {
71+
const atomic = {};
72+
for (const [sym, value] of Object.entries(selected)) {
73+
const idx = symbols.indexOf(sym);
74+
if (idx > 0) atomic[idx] = value;
75+
}
76+
return atomic;
77+
}, [selected]);
78+
79+
// ----------------------------
80+
// handle updates from web component
81+
// ----------------------------
82+
const handleChange = (atomicState) => {
83+
const mapped = {};
84+
85+
for (const [atomic, value] of Object.entries(atomicState)) {
86+
const sym = symbols[Number(atomic)];
87+
if (!sym) continue;
88+
mapped[sym] = value;
89+
}
90+
91+
onSelectionChange?.(mapped);
92+
};
9193

92-
const ptable = cachedPTable[providerUrl];
94+
// ----------------------------
95+
// noHighlight from cache (IMPORTANT FIX)
96+
// ----------------------------
97+
const noHighlightArray = useMemo(() => {
98+
if (!providerUrl || !cachedPTable) return [];
9399

94-
const updatedElements = allElements.map((el) => {
95-
// Case 1: provider not in cache everything full color
96-
if (!ptable) return { ...el, present: true };
100+
const ptable = cachedPTable[providerUrl];
101+
if (!ptable) return [];
97102

98-
// Case 2: element in cache use cached value
99-
if (el.sym in ptable) return { ...el, present: ptable[el.sym] };
103+
const out = [];
100104

101-
// Case 3: element missing in provider full color
102-
return { ...el, present: true };
103-
});
105+
for (let i = 1; i < symbols.length; i++) {
106+
const sym = symbols[i];
107+
if (ptable[sym] === false) out.push(i);
108+
}
104109

105-
setElements(updatedElements);
110+
return out;
106111
}, [providerUrl, cachedPTable]);
107112

108-
const toggle = (sym) => {
109-
if (!onSelectionChange) return;
110-
const newState = ((selected[sym] ?? 0) + 1) % 3;
111-
onSelectionChange({ [sym]: newState });
112-
};
113-
114-
const getColorClass = (el) => {
115-
const state = selected[el.sym] ?? 0;
116-
const baseColor = colors[el.group] ?? colors.default;
117-
118-
if (state === 1) return selectedClassName;
119-
if (state === 2) return deselectedClassName;
120-
121-
// Only grey out elements explicitly marked as absent (false)
122-
const opacityClass = el.present === false ? "opacity-30" : "";
123-
124-
return `${baseColor} ${defaultBorderClassName} ${opacityClass}`;
125-
};
113+
const noInteractArray = [];
126114

115+
// ----------------------------
116+
// render
117+
// ----------------------------
127118
return (
128-
<div className="w-full max-w-full mx-auto px-0 md:px-2">
129-
<div className="@container">
130-
<div className="flex justify-end pb-2 pr-1.5">
131-
<HelpIcon
132-
popover={`All OPTIMADE provider databases have been prefiltered, with unavailable structures greyed out. Last updated: ${lastModified}.`}
133-
placement="left"
134-
color="rgb(40,40,40)"
135-
/>
136-
</div>
137-
<div
138-
className="grid @gap-0.5 @sm:gap-1 w-full"
139-
style={{ gridTemplateColumns: "repeat(18, minmax(0, 1fr))" }}
140-
>
141-
{elements.map((el) => (
142-
<div
143-
key={el.sym}
144-
style={{ gridColumn: el.col, gridRow: el.row }}
145-
className="relative w-full"
146-
>
147-
<div className="w-full aspect-square">
148-
<button
149-
onClick={() => toggle(el.sym)}
150-
className={`flex flex-col justify-center items-center w-full h-full rounded-sm ${hoverClassName} ${getColorClass(
151-
el,
152-
)}`}
153-
>
154-
<span className="text-[0px] opacity-0 @sm:text-[0.3rem] @sm:opacity-100 @md:text-[0.5rem] @lg:text-[0.7rem] text-gray-700 leading-tight">
155-
{el.num}
156-
</span>
157-
<span
158-
className="text-[0.55rem] font-medium leading-none"
159-
style={{ fontSize: "clamp(0.55rem, 2.5vw, 1.25rem)" }}
160-
>
161-
{el.sym}
162-
</span>
163-
</button>
164-
</div>
165-
</div>
166-
))}
167-
</div>
119+
<div className="@container">
120+
<div className="flex justify-end pb-2 pr-2.5">
121+
<HelpIcon
122+
popover={`All OPTIMADE provider databases have been prefiltered. Last updated: ${lastModified}.`}
123+
placement="left"
124+
color="rgb(40,40,40)"
125+
/>
168126
</div>
127+
128+
<PTableWrapper
129+
noInteractArray={noInteractArray}
130+
noHighlightArray={noHighlightArray}
131+
selected={selectionState}
132+
onChange={handleChange}
133+
zoomLevel={1050}
134+
/>
169135
</div>
170136
);
171137
}

src/components/OptimadeClient/OptimadeFilters/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default function OptimadeFilters({ queryUrl, initialFilter, onSubmit }) {
2121
[1, 1000],
2222
selectedElements,
2323
numAtomsRange,
24-
numSitesRange
24+
numSitesRange,
2525
);
2626

2727
const filterString = manualMode ? manualQuery : generatedQuery;

src/components/OptimadeClient/index.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function OptimadeClient({ hideProviderList }) {
5151
const [selectedResult, setSelectedResult] = useState(null);
5252

5353
return (
54-
<div className="min-h-screen max-w-5xl mx-auto bg-white mb-4 shadow-md rounded-xs">
54+
<div className="min-h-screen max-w-6xl mx-auto bg-white mb-4 shadow-md rounded-xs">
5555
<div className="flex flex-col items-center w-full px-2 md:px-4 py-2">
5656
<OptimadeHeader />
5757
<div className="p-2 w-full">
@@ -68,7 +68,6 @@ export function OptimadeClient({ hideProviderList }) {
6868
dbParam={dbParam}
6969
updateUrlParams={updateUrlParams}
7070
/>
71-
7271
<ResultViewer selectedResult={selectedResult} />
7372
</div>
7473
</div>

0 commit comments

Comments
 (0)