lhasa-ligand-builder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +18 -0
- package/LICENSE +674 -0
- package/README.md +41 -0
- package/index.html +49 -0
- package/package.json +37 -0
- package/public/.gitkeep +0 -0
- package/public/Components-inchikey.ich +48167 -0
- package/public/icons/README +7 -0
- package/public/icons/dark/layla_3c.svg +82 -0
- package/public/icons/dark/layla_4c.svg +82 -0
- package/public/icons/dark/layla_5c.svg +82 -0
- package/public/icons/dark/layla_6arom.svg +89 -0
- package/public/icons/dark/layla_6c.svg +82 -0
- package/public/icons/dark/layla_7c.svg +82 -0
- package/public/icons/dark/layla_8c.svg +82 -0
- package/public/icons/dark/layla_charge_tool.svg +78 -0
- package/public/icons/dark/layla_delete_hydrogens_tool.svg +384 -0
- package/public/icons/dark/layla_double_bond.svg +78 -0
- package/public/icons/dark/layla_format_tool.svg +283 -0
- package/public/icons/dark/layla_geometry_tool.svg +105 -0
- package/public/icons/dark/layla_key.svg +76 -0
- package/public/icons/dark/layla_move_tool.svg +110 -0
- package/public/icons/dark/layla_single_bond.svg +73 -0
- package/public/icons/dark/layla_triple_bond.svg +87 -0
- package/public/icons/dark/lhasa_delete_tool.svg +401 -0
- package/public/icons/dark/lhasa_flip_x_tool.svg +106 -0
- package/public/icons/dark/lhasa_flip_y_tool.svg +106 -0
- package/public/icons/dark/lhasa_rotate_tool.svg +112 -0
- package/public/icons/icons/hicolor_apps_scalable_coot-layla.svg +105 -0
- package/public/icons/layla_3c.svg +82 -0
- package/public/icons/layla_4c.svg +82 -0
- package/public/icons/layla_5c.svg +82 -0
- package/public/icons/layla_6arom.svg +89 -0
- package/public/icons/layla_6c.svg +82 -0
- package/public/icons/layla_7c.svg +82 -0
- package/public/icons/layla_8c.svg +82 -0
- package/public/icons/layla_charge_tool.svg +78 -0
- package/public/icons/layla_delete_hydrogens_tool.svg +384 -0
- package/public/icons/layla_double_bond.svg +78 -0
- package/public/icons/layla_format_tool.svg +283 -0
- package/public/icons/layla_geometry_tool-dark.svg +105 -0
- package/public/icons/layla_geometry_tool.svg +105 -0
- package/public/icons/layla_key.svg +76 -0
- package/public/icons/layla_move_tool.svg +110 -0
- package/public/icons/layla_single_bond.svg +73 -0
- package/public/icons/layla_triple_bond.svg +87 -0
- package/public/icons/lhasa_delete_tool.svg +401 -0
- package/public/icons/lhasa_flip_x_tool.svg +106 -0
- package/public/icons/lhasa_flip_y_tool.svg +106 -0
- package/public/icons/lhasa_rotate_tool.svg +112 -0
- package/public/lhasa.js +2 -0
- package/public/lhasa.wasm +0 -0
- package/public/react.svg +1 -0
- package/src/Lhasa.tsx +1452 -0
- package/src/assets/.gitkeep +0 -0
- package/src/bansu_integration.tsx +315 -0
- package/src/customize_mui.scss +97 -0
- package/src/inchikey_database_parse.tsx +20 -0
- package/src/index.d.ts +11 -0
- package/src/index.scss +352 -0
- package/src/main.tsx +79 -0
- package/src/qed_property_infobox.tsx +14 -0
- package/src/types.d.ts +375 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.ts +55 -0
|
File without changes
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { Popover, Button, Tooltip, StyledEngineProvider, AccordionSummary, AccordionDetails, Accordion, Input, Switch, Checkbox, FormControlLabel } from "@mui/material";
|
|
2
|
+
// import Grid from '@mui/material/Grid2';
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
// import WebSocket from 'ws';
|
|
5
|
+
// import * as http from 'http';
|
|
6
|
+
|
|
7
|
+
// Do I really need that here?
|
|
8
|
+
import './index.scss';
|
|
9
|
+
import './customize_mui.scss';
|
|
10
|
+
|
|
11
|
+
class BansuPopupProps {
|
|
12
|
+
smiles!: string;
|
|
13
|
+
anchorEl?: HTMLElement | null;
|
|
14
|
+
bansu_endpoint!: string;
|
|
15
|
+
dark_mode!: boolean;
|
|
16
|
+
// internal_id:
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Do I want to use an enum?
|
|
20
|
+
// Or do I way to express the state with variables alone?
|
|
21
|
+
enum BansuPopupState {
|
|
22
|
+
UserConfig,
|
|
23
|
+
SpawningJob,
|
|
24
|
+
ConnectingOnWebsocket,
|
|
25
|
+
Queued,
|
|
26
|
+
Waiting,
|
|
27
|
+
Ready,
|
|
28
|
+
Error
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function BansuButton(props: BansuPopupProps) {
|
|
32
|
+
|
|
33
|
+
const [popoverOpened, setPopoverOpened] = useState<boolean>(false);
|
|
34
|
+
const [userConsent, setUserConsent] = useState<boolean>(false);
|
|
35
|
+
const [state, setState] = useState<BansuPopupState>(BansuPopupState.UserConfig);
|
|
36
|
+
const [bansuEndpoint, setBansuEndpoint] = useState<string>(props.bansu_endpoint);
|
|
37
|
+
const [jobId, setJobId] = useState<string | null>(null);
|
|
38
|
+
const [posInQueue, setPosInQueue] = useState<number | null>(null);
|
|
39
|
+
const [finishedJobOutput, setFinishedJobOutput] = useState<string | null>(null);
|
|
40
|
+
const [errorString, setErrorString] = useState<string | null>(null);
|
|
41
|
+
|
|
42
|
+
const [workerPromise, setWorkerPromise] = useState<null | Promise<void>>(null);
|
|
43
|
+
|
|
44
|
+
const resetState = () => {
|
|
45
|
+
setState(BansuPopupState.UserConfig);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const popoverContent = useCallback(() => {
|
|
49
|
+
if(!popoverOpened) {
|
|
50
|
+
return <></>;
|
|
51
|
+
}
|
|
52
|
+
switch(state) {
|
|
53
|
+
case BansuPopupState.UserConfig:
|
|
54
|
+
return <div className="vertical_panel">
|
|
55
|
+
Bansu is a server-side computational API which enables CIF generation via running Acedrg.
|
|
56
|
+
<div className="warning_box">
|
|
57
|
+
<h2>WARNING!</h2>
|
|
58
|
+
<b>Usage of non-local instances of Bansu implies that your data will travel across the web to a remote webserver.</b><br/>
|
|
59
|
+
<b>Make sure that you're using an HTTPS endpoint</b> for transport security.<br/>
|
|
60
|
+
While Bansu does not store logs containing chemical data, please note that<br/><b>by using a remote instance of Bansu you're trusting the instance's owner with your data.</b><br/>
|
|
61
|
+
<br/>
|
|
62
|
+
<FormControlLabel
|
|
63
|
+
label="I understand and agree to proceed"
|
|
64
|
+
control={
|
|
65
|
+
<Checkbox
|
|
66
|
+
style={{marginLeft: '5px'}}
|
|
67
|
+
checked={userConsent}
|
|
68
|
+
onChange={() => setUserConsent(!userConsent)}
|
|
69
|
+
/>}
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
<b>Bansu job configuration</b>
|
|
73
|
+
<div className="horizontal_container_centered">
|
|
74
|
+
Bansu instance
|
|
75
|
+
<Input defaultValue={bansuEndpoint} placeholder={props.bansu_endpoint} onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
76
|
+
if(event.target.value !== "") {
|
|
77
|
+
setBansuEndpoint(event.target.value);
|
|
78
|
+
} else {
|
|
79
|
+
setBansuEndpoint(props.bansu_endpoint);
|
|
80
|
+
}
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
Commandline flags
|
|
85
|
+
<div className="horizontal_container_centered">
|
|
86
|
+
{/* -z
|
|
87
|
+
<Switch /> */}
|
|
88
|
+
<i>TODO</i>
|
|
89
|
+
</div>
|
|
90
|
+
<div className="horizontal_container_centered children_expanded">
|
|
91
|
+
<Button
|
|
92
|
+
onClick={() => setPopoverOpened(false)}
|
|
93
|
+
variant="contained"
|
|
94
|
+
>
|
|
95
|
+
Cancel
|
|
96
|
+
</Button>
|
|
97
|
+
<Button
|
|
98
|
+
onClick={() => setState(BansuPopupState.SpawningJob)}
|
|
99
|
+
variant="contained"
|
|
100
|
+
disabled={!userConsent}
|
|
101
|
+
>
|
|
102
|
+
Spawn Bansu job
|
|
103
|
+
</Button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>;
|
|
106
|
+
case BansuPopupState.SpawningJob:
|
|
107
|
+
return <div className="vertical_panel">
|
|
108
|
+
Spawning Bansu job...
|
|
109
|
+
<small>Bansu instance <i>{bansuEndpoint}</i></small>
|
|
110
|
+
</div>;
|
|
111
|
+
case BansuPopupState.ConnectingOnWebsocket:
|
|
112
|
+
return <div className="vertical_panel">
|
|
113
|
+
Estabilishing event listener connection...
|
|
114
|
+
<small>Bansu instance <i>{bansuEndpoint}</i></small>
|
|
115
|
+
<small>Job id: {jobId}</small>
|
|
116
|
+
</div>;
|
|
117
|
+
case BansuPopupState.Queued:
|
|
118
|
+
return <div className="vertical_panel">
|
|
119
|
+
Job has been queued.
|
|
120
|
+
Waiting...
|
|
121
|
+
<small>Bansu instance <i>{bansuEndpoint}</i></small>
|
|
122
|
+
<small>Job id: {jobId}</small>
|
|
123
|
+
<small>Position in queue: {posInQueue}</small>
|
|
124
|
+
</div>;
|
|
125
|
+
case BansuPopupState.Waiting:
|
|
126
|
+
return <div className="vertical_panel">
|
|
127
|
+
Waiting for Bansu job to complete...
|
|
128
|
+
<small>Bansu instance <i>{bansuEndpoint}</i></small>
|
|
129
|
+
<small>Job id: {jobId}</small>
|
|
130
|
+
</div>;
|
|
131
|
+
case BansuPopupState.Ready:
|
|
132
|
+
return <div className="vertical_panel">
|
|
133
|
+
Ready
|
|
134
|
+
<small>Bansu instance <i>{bansuEndpoint}</i></small>
|
|
135
|
+
<small>Job id: {jobId}</small>
|
|
136
|
+
<Accordion>
|
|
137
|
+
<AccordionSummary>
|
|
138
|
+
Job output
|
|
139
|
+
</AccordionSummary>
|
|
140
|
+
<AccordionDetails
|
|
141
|
+
style={{maxWidth: '300px', wordBreak: 'break-word'}}
|
|
142
|
+
>
|
|
143
|
+
{finishedJobOutput}
|
|
144
|
+
</AccordionDetails>
|
|
145
|
+
</Accordion>
|
|
146
|
+
<div className="horizontal_container_centered children_expanded">
|
|
147
|
+
<Button
|
|
148
|
+
onClick={() => setPopoverOpened(false)}
|
|
149
|
+
variant="contained"
|
|
150
|
+
>
|
|
151
|
+
Close
|
|
152
|
+
</Button>
|
|
153
|
+
<Button
|
|
154
|
+
onClick={(e) => window.open(`${bansuEndpoint}/get_cif/${jobId}`)}
|
|
155
|
+
// style={{flex: 'auto'}}
|
|
156
|
+
variant="contained"
|
|
157
|
+
>
|
|
158
|
+
Download CIF
|
|
159
|
+
</Button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>;
|
|
162
|
+
case BansuPopupState.Error:
|
|
163
|
+
return <div className="vertical_panel">
|
|
164
|
+
<span style={{color: 'red'}}>Error</span>
|
|
165
|
+
<span style={{color: 'darkred'}}>{errorString}</span>
|
|
166
|
+
<div className="horizontal_container_centered children_expanded">
|
|
167
|
+
<Button
|
|
168
|
+
onClick={() => resetState()}
|
|
169
|
+
variant="contained"
|
|
170
|
+
>
|
|
171
|
+
Retry
|
|
172
|
+
</Button>
|
|
173
|
+
<Button
|
|
174
|
+
onClick={() => setPopoverOpened(false)}
|
|
175
|
+
variant="contained"
|
|
176
|
+
>
|
|
177
|
+
Close
|
|
178
|
+
</Button>
|
|
179
|
+
</div>
|
|
180
|
+
</div>;
|
|
181
|
+
}
|
|
182
|
+
}, [state, popoverOpened, jobId, errorString, finishedJobOutput, posInQueue, userConsent]);
|
|
183
|
+
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
// return;
|
|
186
|
+
if(popoverOpened && state == BansuPopupState.SpawningJob) {
|
|
187
|
+
let promise = new Promise<void>(async () => {
|
|
188
|
+
setState(BansuPopupState.SpawningJob);
|
|
189
|
+
const postData = JSON.stringify({
|
|
190
|
+
'smiles': props.smiles,
|
|
191
|
+
'commandline_args': []
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const res = await fetch(`${bansuEndpoint}/run_acedrg`, {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
body: postData,
|
|
198
|
+
headers: {
|
|
199
|
+
'Content-Type': 'application/json',
|
|
200
|
+
},
|
|
201
|
+
// mode: 'no-cors'
|
|
202
|
+
});
|
|
203
|
+
const jsonData = await res.json();
|
|
204
|
+
console.log("Got json from /run_acedrg: ", jsonData);
|
|
205
|
+
if(jsonData.job_id === null) {
|
|
206
|
+
let emsg = `Server returned null job id / no job id. Error message is: ${jsonData.error_message}`;
|
|
207
|
+
console.error(emsg);
|
|
208
|
+
setErrorString(emsg);
|
|
209
|
+
setState(BansuPopupState.Error);
|
|
210
|
+
}
|
|
211
|
+
setJobId(jsonData.job_id);
|
|
212
|
+
setState(BansuPopupState.ConnectingOnWebsocket);
|
|
213
|
+
console.log("Establishing WebSocket connection.");
|
|
214
|
+
// Create WebSocket connection.
|
|
215
|
+
let colonSlashSlashPos = bansuEndpoint.indexOf("://");
|
|
216
|
+
let bansuEndpoint_noprotocol = bansuEndpoint;
|
|
217
|
+
let bansuProtocol = bansuEndpoint.substring(0, colonSlashSlashPos);
|
|
218
|
+
let websocketMode = "ws";
|
|
219
|
+
if(bansuProtocol == "https") {
|
|
220
|
+
websocketMode = "wss";
|
|
221
|
+
}
|
|
222
|
+
if (colonSlashSlashPos != -1) {
|
|
223
|
+
bansuEndpoint_noprotocol = bansuEndpoint.substring(colonSlashSlashPos + 3);
|
|
224
|
+
}
|
|
225
|
+
const socket = new WebSocket(`${websocketMode}://${bansuEndpoint_noprotocol}/ws/${jsonData.job_id}`);
|
|
226
|
+
|
|
227
|
+
// Connection opened
|
|
228
|
+
socket.addEventListener("open", (event) => {
|
|
229
|
+
console.log("Connection on WebSocket established.");
|
|
230
|
+
// setState(BansuPopupState.Waiting);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
socket.addEventListener("close", (event) => {
|
|
234
|
+
console.log("Connection on WebSocket closed.");
|
|
235
|
+
// process.exit(0);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
socket.addEventListener("error", (event) => {
|
|
239
|
+
console.error("Connection on WebSocket errored-out: ", event);
|
|
240
|
+
setErrorString(`WebSocket error: ${event}`);
|
|
241
|
+
setState(BansuPopupState.Error);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Listen for messages
|
|
245
|
+
socket.addEventListener("message", (event) => {
|
|
246
|
+
//console.debug("Websocket message from server ", event.data);
|
|
247
|
+
const json = JSON.parse(event.data);
|
|
248
|
+
console.debug("Got JSON from WS: ", json);
|
|
249
|
+
if(json.status == "Failed") {
|
|
250
|
+
setErrorString(`Job failed:\n Failure reason: ${json.failure_reason}\n ${json.error_message ? "Error message: " + json.error_message + "\n ": ""} Output:${JSON.stringify(json.job_output)}`);
|
|
251
|
+
setState(BansuPopupState.Error);
|
|
252
|
+
} else if(json.status == "Finished") {
|
|
253
|
+
setFinishedJobOutput(JSON.stringify(json.job_output));
|
|
254
|
+
setState(BansuPopupState.Ready);
|
|
255
|
+
} else if(json.status == "Pending") {
|
|
256
|
+
setState(BansuPopupState.Waiting);
|
|
257
|
+
} else if(json.status == "Queued") {
|
|
258
|
+
setPosInQueue(json.queue_position);
|
|
259
|
+
setState(BansuPopupState.Queued);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
} catch(exception) {
|
|
264
|
+
console.error(`Problem with HTTP request: ${exception}`);
|
|
265
|
+
setErrorString(`${exception}`);
|
|
266
|
+
setState(BansuPopupState.Error);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
setWorkerPromise(promise);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return () => {
|
|
273
|
+
// todo: cleanup
|
|
274
|
+
// if(workerPromise) {
|
|
275
|
+
// workerPromise
|
|
276
|
+
// }
|
|
277
|
+
};
|
|
278
|
+
}, [state, popoverOpened]);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<StyledEngineProvider injectFirst>
|
|
282
|
+
<Tooltip
|
|
283
|
+
title={"Generate CIF via Bansu (runs Acedrg on a server)."}
|
|
284
|
+
enterDelay={1000}
|
|
285
|
+
enterNextDelay={1000}
|
|
286
|
+
disableInteractive
|
|
287
|
+
>
|
|
288
|
+
<Button
|
|
289
|
+
onClick={() => {
|
|
290
|
+
resetState();
|
|
291
|
+
setPopoverOpened(true);
|
|
292
|
+
}}
|
|
293
|
+
variant="contained"
|
|
294
|
+
>
|
|
295
|
+
Generate CIF
|
|
296
|
+
</Button>
|
|
297
|
+
</Tooltip>
|
|
298
|
+
<Popover
|
|
299
|
+
open={popoverOpened}
|
|
300
|
+
anchorEl={props.anchorEl}
|
|
301
|
+
anchorOrigin={{ vertical: 'center', horizontal: 'center'}}
|
|
302
|
+
transformOrigin={{ vertical: 'center', horizontal: 'center'}}
|
|
303
|
+
>
|
|
304
|
+
<div className={"vertical_popup lhasa_editor LhasaMuiStyling" + (props.dark_mode ? " lhasa_dark_mode" : "")} style={{maxWidth: '400px', maxHeight: '400px'}}>
|
|
305
|
+
<div className="vertical_popup_title">
|
|
306
|
+
CIF generation via Bansu
|
|
307
|
+
</div>
|
|
308
|
+
<div style={{alignSelf: "normal", overflow: 'auto'}}>
|
|
309
|
+
{popoverContent()}
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
</Popover>
|
|
313
|
+
</StyledEngineProvider>
|
|
314
|
+
);
|
|
315
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
@use 'index.scss';
|
|
2
|
+
|
|
3
|
+
@mixin normalize_text {
|
|
4
|
+
font-size: index.$lhasa_font_size;
|
|
5
|
+
line-height: normal;
|
|
6
|
+
text-transform: none;
|
|
7
|
+
letter-spacing: normal;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@mixin normalize_padding {
|
|
11
|
+
padding-right: index.$lhasa_base_padding;
|
|
12
|
+
padding-left: index.$lhasa_base_padding;
|
|
13
|
+
padding-top: index.$lhasa_padding_minor;
|
|
14
|
+
padding-bottom: index.$lhasa_padding_minor;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// This is a dummy
|
|
18
|
+
.LhasaMuiStyling {
|
|
19
|
+
text-align: left;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.LhasaMuiStyling .MuiAccordion-root {
|
|
23
|
+
background-color: index.$lhasa_background_color;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiAccordion-root {
|
|
27
|
+
background-color: index.$lhasa_background_color_dark;
|
|
28
|
+
color: index.$lhasa_text_color_dark;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.LhasaMuiStyling .MuiFormGroup-root {
|
|
32
|
+
margin-left: index.$lhasa_base_padding;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.LhasaMuiStyling .MuiButtonBase-root {
|
|
36
|
+
@include normalize_text;
|
|
37
|
+
@include normalize_padding;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiButtonBase-root {
|
|
41
|
+
color: index.$lhasa_text_color_dark;
|
|
42
|
+
border-color: index.$lhasa_border_color_dark;
|
|
43
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiPaper-root {
|
|
47
|
+
color: index.$lhasa_text_color_dark;
|
|
48
|
+
background-color: index.$lhasa_background_color_dark;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiInputLabel-root {
|
|
52
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
53
|
+
color: index.$lhasa_text_color_dark;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// .LhasaMuiStyling.lhasa_dark_mode .MuiNotchedOutlined-root {
|
|
57
|
+
// // background-color: index.$lhasa_background_color_dark;
|
|
58
|
+
// border-color: index.$lhasa_border_color_dark
|
|
59
|
+
// }
|
|
60
|
+
|
|
61
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiOutlinedInput-notchedOutline {
|
|
62
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
63
|
+
border-color: index.$lhasa_border_color_dark
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// .LhasaMuiStyling.lhasa_dark_mode .MuiPopover-root {
|
|
67
|
+
// color: index.$lhasa_text_color_dark;
|
|
68
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
// .LhasaMuiStyling.lhasa_dark_mode .MuiPopover-paper {
|
|
72
|
+
// color: index.$lhasa_text_color_dark;
|
|
73
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
74
|
+
// }
|
|
75
|
+
|
|
76
|
+
// .LhasaMuiStyling.lhasa_dark_mode .MuiMenu-paper {
|
|
77
|
+
// color: index.$lhasa_text_color_dark;
|
|
78
|
+
// background-color: index.$lhasa_background_color_dark;
|
|
79
|
+
// }
|
|
80
|
+
|
|
81
|
+
.LhasaMuiStyling .MuiTypography-root {
|
|
82
|
+
@include normalize_text;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
.LhasaMuiStyling.lhasa_dark_mode .MuiTypography-root {
|
|
87
|
+
color: index.$lhasa_text_color_dark;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.LhasaMuiStyling .MuiSwitch-thumb {
|
|
91
|
+
margin-left: index.$lhasa_base_padding;
|
|
92
|
+
margin-top: index.$lhasa_base_padding * 2;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// // .LhasaMuiStyling .MuiSwitch-root {
|
|
96
|
+
|
|
97
|
+
// }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
export function parseInchikeyDatabase(rawData: string): Map<string, [string, string]> {
|
|
3
|
+
const inchiMap = new Map<string, [string, string]>();
|
|
4
|
+
for (const line of rawData.split('\n')) {
|
|
5
|
+
if(line.length === 0) continue;
|
|
6
|
+
if(line.startsWith('#')) continue; // Skip comment lines
|
|
7
|
+
const segments = line.split('\t');
|
|
8
|
+
if (segments.length != 3) {
|
|
9
|
+
throw new Error("Unexpected number of segments in InchiKey database line: " + line);
|
|
10
|
+
}
|
|
11
|
+
// console.log(segments);
|
|
12
|
+
const inchiKey = segments[0];
|
|
13
|
+
const monomer_id = segments[1];
|
|
14
|
+
const chem_name = segments[2];
|
|
15
|
+
// console.log(inchiKey);
|
|
16
|
+
inchiMap.set(inchiKey, [monomer_id, chem_name]);
|
|
17
|
+
}
|
|
18
|
+
// console.log(inchiMap);
|
|
19
|
+
return inchiMap;
|
|
20
|
+
}
|