simonduerr commited on
Commit
a7f5d18
1 Parent(s): 14c03a8

Upload folder using huggingface_hub

Browse files
Dockerfile CHANGED
@@ -7,10 +7,10 @@ COPY --link --chown=1000 . .
7
 
8
  RUN mkdir -p /tmp/cache/
9
  RUN chmod a+rwx -R /tmp/cache/
10
- ENV TRANSFORMERS_CACHE=/tmp/cache/
11
 
12
  RUN pip install --no-cache-dir -r requirements.txt
13
 
14
  ENV PYTHONUNBUFFERED=1 GRADIO_ALLOW_FLAGGING=never GRADIO_NUM_PORTS=1 GRADIO_SERVER_NAME=0.0.0.0 GRADIO_SERVER_PORT=7860 SYSTEM=spaces
15
 
16
- CMD ["python", "app.py"]
 
7
 
8
  RUN mkdir -p /tmp/cache/
9
  RUN chmod a+rwx -R /tmp/cache/
10
+ ENV TRANSFORMERS_CACHE=/tmp/cache/
11
 
12
  RUN pip install --no-cache-dir -r requirements.txt
13
 
14
  ENV PYTHONUNBUFFERED=1 GRADIO_ALLOW_FLAGGING=never GRADIO_NUM_PORTS=1 GRADIO_SERVER_NAME=0.0.0.0 GRADIO_SERVER_PORT=7860 SYSTEM=spaces
15
 
16
+ CMD ["python", "space.py"]
README.md CHANGED
@@ -2,8 +2,8 @@
2
  ---
3
  tags: [gradio-custom-component,machine learning,reproducibility,visualization,gradio,gradio-template-File,protein]
4
  title: gradio_molecule3d V0.0.3
5
- colorFrom: gray
6
- colorTo: gray
7
  sdk: docker
8
  pinned: false
9
  license: apache-2.0
@@ -12,6 +12,6 @@ license: apache-2.0
12
 
13
  # Name: gradio_molecule3d
14
 
15
- Description: Molecule3D custom component to visualize pdb or sdf files
16
 
17
  Install with: pip install gradio_molecule3d
 
2
  ---
3
  tags: [gradio-custom-component,machine learning,reproducibility,visualization,gradio,gradio-template-File,protein]
4
  title: gradio_molecule3d V0.0.3
5
+ colorFrom: yellow
6
+ colorTo: pink
7
  sdk: docker
8
  pinned: false
9
  license: apache-2.0
 
12
 
13
  # Name: gradio_molecule3d
14
 
15
+ Description: Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
16
 
17
  Install with: pip install gradio_molecule3d
__pycache__/app.cpython-39.pyc CHANGED
Binary files a/__pycache__/app.cpython-39.pyc and b/__pycache__/app.cpython-39.pyc differ
 
app.py CHANGED
@@ -12,37 +12,30 @@ reps = [
12
  "model": 0,
13
  "chain": "",
14
  "resname": "",
15
- "style": "cartoon",
16
  "color": "whiteCarbon",
17
  "residue_range": "",
18
  "around": 0,
19
  "byres": False,
20
- "visible": False,
21
- },
22
  ]
23
 
 
 
24
  def predict(x):
25
  print("predict function", x)
 
26
  return x
27
 
28
- #doesn't work
29
- #demo = gr.Interface(
30
- # predict,
31
- # Molecule3D(label="Molecule3D", reps=reps), # interactive version of your component
32
- # Molecule3D(), # static version of your component
33
- # examples=[[example]], # uncomment this line to view the "example version" of your component
34
- # )
35
-
36
- #works
37
  with gr.Blocks() as demo:
38
- #gr.Markdown("# 3dmol.js Molecule Viewer")
39
- #inp = Molecule3D(label="Molecule3D", reps=reps)
40
- #gr.Markdown("Viewer disabled")
41
- inp = Molecule3D(label="Molecule3D", reps=reps, showviewer=False)
42
- out = Molecule3D(label="Molecule3D", reps=reps)
43
  gr.Markdown("""
44
  You can configure the default rendering of the molecule by adding a list of representations
45
- <code>
46
  reps = [
47
  {
48
  "model": 0,
@@ -55,11 +48,22 @@ with gr.Blocks() as demo:
55
  "byres": False,
56
  "visible": False,
57
  },
 
 
 
 
 
 
 
 
 
 
 
58
  ]
59
- </code>
60
  """)
61
- btn = gr.Button("Predict")
62
  btn.click(predict, inputs=inp, outputs=out)
63
 
64
- demo.launch()
65
- # blocks.launch()
 
 
12
  "model": 0,
13
  "chain": "",
14
  "resname": "",
15
+ "style": "stick",
16
  "color": "whiteCarbon",
17
  "residue_range": "",
18
  "around": 0,
19
  "byres": False,
20
+ "visible": False
21
+ }
22
  ]
23
 
24
+
25
+
26
  def predict(x):
27
  print("predict function", x)
28
+ print(x.name)
29
  return x
30
 
 
 
 
 
 
 
 
 
 
31
  with gr.Blocks() as demo:
32
+ inp = Molecule3D(label="Molecule3D", reps=reps)
33
+ out = Molecule3D(label="Output", reps=reps)
34
+
35
+ btn = gr.Button("Predict")
 
36
  gr.Markdown("""
37
  You can configure the default rendering of the molecule by adding a list of representations
38
+ <pre>
39
  reps = [
40
  {
41
  "model": 0,
 
48
  "byres": False,
49
  "visible": False,
50
  },
51
+ {
52
+ "model": 0,
53
+ "chain": "A",
54
+ "resname": "HIS",
55
+ "style": "stick",
56
+ "color": "red",
57
+ "residue_range": "",
58
+ "around": 0,
59
+ "byres": False,
60
+ "visible": False,
61
+ }
62
  ]
63
+ </pre>
64
  """)
 
65
  btn.click(predict, inputs=inp, outputs=out)
66
 
67
+
68
+ if __name__ == '__main__':
69
+ demo.launch()
css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
requirements.txt CHANGED
@@ -1,2 +1 @@
1
- gradio_molecule3d-0.0.3-py3-none-any.whl
2
- gradio>=4.21.0
 
1
+ gradio_molecule3d==0.0.3
 
space.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading generic file (when used as an input) and or displaying generic files (output).', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': 'Literal["single", "multiple", "directory"]', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': 'Literal["filepath", "binary"]', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'float | None', 'default': 'None', 'description': "If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': "The output data received by the component from the user's function in the backend."}}, 'preprocess': {'return': {'type': 'bytes | NamedString | list[bytes | NamedString] | None', 'description': "The preprocessed input data sent to the user's function in the backend."}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the X button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_molecule3d`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
+ </div>
26
+
27
+ Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_molecule3d
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+
42
+ import gradio as gr
43
+ from gradio_molecule3d import Molecule3D
44
+
45
+ import os
46
+
47
+ example = Molecule3D().example_inputs()
48
+
49
+
50
+ reps = [
51
+ {
52
+ "model": 0,
53
+ "chain": "",
54
+ "resname": "",
55
+ "style": "stick",
56
+ "color": "whiteCarbon",
57
+ "residue_range": "",
58
+ "around": 0,
59
+ "byres": False,
60
+ "visible": False
61
+ }
62
+ ]
63
+
64
+
65
+
66
+ def predict(x):
67
+ print("predict function", x)
68
+ print(x.name)
69
+ return x
70
+
71
+ with gr.Blocks() as demo:
72
+ inp = Molecule3D(label="Molecule3D", reps=reps)
73
+ out = Molecule3D(label="Output", reps=reps)
74
+
75
+ btn = gr.Button("Predict")
76
+ gr.Markdown(\"\"\"
77
+ You can configure the default rendering of the molecule by adding a list of representations
78
+ <pre>
79
+ reps = [
80
+ {
81
+ "model": 0,
82
+ "chain": "",
83
+ "resname": "",
84
+ "style": "cartoon",
85
+ "color": "whiteCarbon",
86
+ "residue_range": "",
87
+ "around": 0,
88
+ "byres": False,
89
+ "visible": False,
90
+ },
91
+ {
92
+ "model": 0,
93
+ "chain": "A",
94
+ "resname": "HIS",
95
+ "style": "stick",
96
+ "color": "red",
97
+ "residue_range": "",
98
+ "around": 0,
99
+ "byres": False,
100
+ "visible": False,
101
+ }
102
+ ]
103
+ </pre>
104
+ \"\"\")
105
+ btn.click(predict, inputs=inp, outputs=out)
106
+
107
+
108
+ if __name__ == '__main__':
109
+ demo.launch()
110
+
111
+ ```
112
+ """, elem_classes=["md-custom"], header_links=True)
113
+
114
+
115
+ gr.Markdown("""
116
+ ## `Molecule3D`
117
+
118
+ ### Initialization
119
+ """, elem_classes=["md-custom"], header_links=True)
120
+
121
+ gr.ParamViewer(value=_docs["Molecule3D"]["members"]["__init__"], linkify=[])
122
+
123
+
124
+ gr.Markdown("### Events")
125
+ gr.ParamViewer(value=_docs["Molecule3D"]["events"], linkify=['Event'])
126
+
127
+
128
+
129
+
130
+ gr.Markdown("""
131
+
132
+ ### User function
133
+
134
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
135
+
136
+ - When used as an Input, the component only impacts the input signature of the user function.
137
+ - When used as an output, the component only impacts the return signature of the user function.
138
+
139
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
140
+
141
+ - **As input:** Is passed, the preprocessed input data sent to the user's function in the backend.
142
+ - **As output:** Should return, the output data received by the component from the user's function in the backend.
143
+
144
+ ```python
145
+ def predict(
146
+ value: bytes | NamedString | list[bytes | NamedString] | None
147
+ ) -> str | list[str] | None:
148
+ return value
149
+ ```
150
+ """, elem_classes=["md-custom", "Molecule3D-user-fn"], header_links=True)
151
+
152
+
153
+
154
+
155
+ demo.load(None, js=r"""function() {
156
+ const refs = {};
157
+ const user_fn_refs = {
158
+ Molecule3D: [], };
159
+ requestAnimationFrame(() => {
160
+
161
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
162
+ if (refs.length > 0) {
163
+ const el = document.querySelector(`.${key}-user-fn`);
164
+ if (!el) return;
165
+ refs.forEach(ref => {
166
+ el.innerHTML = el.innerHTML.replace(
167
+ new RegExp("\\b"+ref+"\\b", "g"),
168
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
169
+ );
170
+ })
171
+ }
172
+ })
173
+
174
+ Object.entries(refs).forEach(([key, refs]) => {
175
+ if (refs.length > 0) {
176
+ const el = document.querySelector(`.${key}`);
177
+ if (!el) return;
178
+ refs.forEach(ref => {
179
+ el.innerHTML = el.innerHTML.replace(
180
+ new RegExp("\\b"+ref+"\\b", "g"),
181
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
182
+ );
183
+ })
184
+ }
185
+ })
186
+ })
187
+ }
188
+
189
+ """)
190
+
191
+ demo.launch()
src/README.md CHANGED
@@ -1,16 +1,397 @@
1
 
2
- # gradio_molecule3d
3
- A Custom Gradio component to visualize molecules in pdb, sdf or mol2 format.
4
 
 
5
 
6
- Developed by Simon Dürr.
7
 
8
- If you use this component for academic work please cite:
9
- 3Dmol.js: molecular visualization with WebGL , Nicholas Rego, David Koes, Bioinformatics, Volume 31, Issue 8, April 2015, Pages 1322–1324, https://doi.org/10.1093/bioinformatics/btu829
 
10
 
11
- ## How to use
12
 
13
  ```python
 
14
  import gradio as gr
15
  from gradio_molecule3d import Molecule3D
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
+ # `gradio_molecule3d`
3
+ <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
4
 
5
+ Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
6
 
7
+ ## Installation
8
 
9
+ ```bash
10
+ pip install gradio_molecule3d
11
+ ```
12
 
13
+ ## Usage
14
 
15
  ```python
16
+
17
  import gradio as gr
18
  from gradio_molecule3d import Molecule3D
19
+
20
+ import os
21
+
22
+ example = Molecule3D().example_inputs()
23
+
24
+
25
+ reps = [
26
+ {
27
+ "model": 0,
28
+ "chain": "",
29
+ "resname": "",
30
+ "style": "stick",
31
+ "color": "whiteCarbon",
32
+ "residue_range": "",
33
+ "around": 0,
34
+ "byres": False,
35
+ "visible": False
36
+ }
37
+ ]
38
+
39
+
40
+
41
+ def predict(x):
42
+ print("predict function", x)
43
+ print(x.name)
44
+ return x
45
+
46
+ with gr.Blocks() as demo:
47
+ inp = Molecule3D(label="Molecule3D", reps=reps)
48
+ out = Molecule3D(label="Output", reps=reps)
49
+
50
+ btn = gr.Button("Predict")
51
+ gr.Markdown("""
52
+ You can configure the default rendering of the molecule by adding a list of representations
53
+ <pre>
54
+ reps = [
55
+ {
56
+ "model": 0,
57
+ "chain": "",
58
+ "resname": "",
59
+ "style": "cartoon",
60
+ "color": "whiteCarbon",
61
+ "residue_range": "",
62
+ "around": 0,
63
+ "byres": False,
64
+ "visible": False,
65
+ },
66
+ {
67
+ "model": 0,
68
+ "chain": "A",
69
+ "resname": "HIS",
70
+ "style": "stick",
71
+ "color": "red",
72
+ "residue_range": "",
73
+ "around": 0,
74
+ "byres": False,
75
+ "visible": False,
76
+ }
77
+ ]
78
+ </pre>
79
+ """)
80
+ btn.click(predict, inputs=inp, outputs=out)
81
+
82
+
83
+ if __name__ == '__main__':
84
+ demo.launch()
85
+
86
+ ```
87
+
88
+ ## `Molecule3D`
89
+
90
+ ### Initialization
91
+
92
+ <table>
93
+ <thead>
94
+ <tr>
95
+ <th align="left">name</th>
96
+ <th align="left" style="width: 25%;">type</th>
97
+ <th align="left">default</th>
98
+ <th align="left">description</th>
99
+ </tr>
100
+ </thead>
101
+ <tbody>
102
+ <tr>
103
+ <td align="left"><code>value</code></td>
104
+ <td align="left" style="width: 25%;">
105
+
106
+ ```python
107
+ str | list[str] | Callable | None
108
+ ```
109
+
110
+ </td>
111
+ <td align="left"><code>None</code></td>
112
+ <td align="left">Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.</td>
113
+ </tr>
114
+
115
+ <tr>
116
+ <td align="left"><code>reps</code></td>
117
+ <td align="left" style="width: 25%;">
118
+
119
+ ```python
120
+ Any | None
121
+ ```
122
+
123
+ </td>
124
+ <td align="left"><code>[]</code></td>
125
+ <td align="left">None</td>
126
+ </tr>
127
+
128
+ <tr>
129
+ <td align="left"><code>config</code></td>
130
+ <td align="left" style="width: 25%;">
131
+
132
+ ```python
133
+ Any | None
134
+ ```
135
+
136
+ </td>
137
+ <td align="left"><code>{
138
+ "backgroundColor": "white",
139
+ "orthographic": False,
140
+ "disableFog": False,
141
+ }</code></td>
142
+ <td align="left">dictionary of config options</td>
143
+ </tr>
144
+
145
+ <tr>
146
+ <td align="left"><code>confidenceLabel</code></td>
147
+ <td align="left" style="width: 25%;">
148
+
149
+ ```python
150
+ str | None
151
+ ```
152
+
153
+ </td>
154
+ <td align="left"><code>"pLDDT"</code></td>
155
+ <td align="left">label for confidence values stored in the bfactor column of a pdb file</td>
156
+ </tr>
157
+
158
+ <tr>
159
+ <td align="left"><code>file_count</code></td>
160
+ <td align="left" style="width: 25%;">
161
+
162
+ ```python
163
+ Literal["single", "multiple", "directory"]
164
+ ```
165
+
166
+ </td>
167
+ <td align="left"><code>"single"</code></td>
168
+ <td align="left">if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".</td>
169
+ </tr>
170
+
171
+ <tr>
172
+ <td align="left"><code>file_types</code></td>
173
+ <td align="left" style="width: 25%;">
174
+
175
+ ```python
176
+ list[str] | None
177
+ ```
178
+
179
+ </td>
180
+ <td align="left"><code>None</code></td>
181
+ <td align="left">List of file extensions or types of files to be uploaded (e.g. ['image', '.json', '.mp4']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.</td>
182
+ </tr>
183
+
184
+ <tr>
185
+ <td align="left"><code>type</code></td>
186
+ <td align="left" style="width: 25%;">
187
+
188
+ ```python
189
+ Literal["filepath", "binary"]
190
+ ```
191
+
192
+ </td>
193
+ <td align="left"><code>"filepath"</code></td>
194
+ <td align="left">Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.</td>
195
+ </tr>
196
+
197
+ <tr>
198
+ <td align="left"><code>label</code></td>
199
+ <td align="left" style="width: 25%;">
200
+
201
+ ```python
202
+ str | None
203
+ ```
204
+
205
+ </td>
206
+ <td align="left"><code>None</code></td>
207
+ <td align="left">The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.</td>
208
+ </tr>
209
+
210
+ <tr>
211
+ <td align="left"><code>every</code></td>
212
+ <td align="left" style="width: 25%;">
213
+
214
+ ```python
215
+ float | None
216
  ```
217
+
218
+ </td>
219
+ <td align="left"><code>None</code></td>
220
+ <td align="left">If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.</td>
221
+ </tr>
222
+
223
+ <tr>
224
+ <td align="left"><code>show_label</code></td>
225
+ <td align="left" style="width: 25%;">
226
+
227
+ ```python
228
+ bool | None
229
+ ```
230
+
231
+ </td>
232
+ <td align="left"><code>None</code></td>
233
+ <td align="left">if True, will display label.</td>
234
+ </tr>
235
+
236
+ <tr>
237
+ <td align="left"><code>container</code></td>
238
+ <td align="left" style="width: 25%;">
239
+
240
+ ```python
241
+ bool
242
+ ```
243
+
244
+ </td>
245
+ <td align="left"><code>True</code></td>
246
+ <td align="left">If True, will place the component in a container - providing some extra padding around the border.</td>
247
+ </tr>
248
+
249
+ <tr>
250
+ <td align="left"><code>scale</code></td>
251
+ <td align="left" style="width: 25%;">
252
+
253
+ ```python
254
+ int | None
255
+ ```
256
+
257
+ </td>
258
+ <td align="left"><code>None</code></td>
259
+ <td align="left">relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.</td>
260
+ </tr>
261
+
262
+ <tr>
263
+ <td align="left"><code>min_width</code></td>
264
+ <td align="left" style="width: 25%;">
265
+
266
+ ```python
267
+ int
268
+ ```
269
+
270
+ </td>
271
+ <td align="left"><code>160</code></td>
272
+ <td align="left">minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.</td>
273
+ </tr>
274
+
275
+ <tr>
276
+ <td align="left"><code>height</code></td>
277
+ <td align="left" style="width: 25%;">
278
+
279
+ ```python
280
+ int | float | None
281
+ ```
282
+
283
+ </td>
284
+ <td align="left"><code>None</code></td>
285
+ <td align="left">The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.</td>
286
+ </tr>
287
+
288
+ <tr>
289
+ <td align="left"><code>interactive</code></td>
290
+ <td align="left" style="width: 25%;">
291
+
292
+ ```python
293
+ bool | None
294
+ ```
295
+
296
+ </td>
297
+ <td align="left"><code>None</code></td>
298
+ <td align="left">if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.</td>
299
+ </tr>
300
+
301
+ <tr>
302
+ <td align="left"><code>visible</code></td>
303
+ <td align="left" style="width: 25%;">
304
+
305
+ ```python
306
+ bool
307
+ ```
308
+
309
+ </td>
310
+ <td align="left"><code>True</code></td>
311
+ <td align="left">If False, component will be hidden.</td>
312
+ </tr>
313
+
314
+ <tr>
315
+ <td align="left"><code>elem_id</code></td>
316
+ <td align="left" style="width: 25%;">
317
+
318
+ ```python
319
+ str | None
320
+ ```
321
+
322
+ </td>
323
+ <td align="left"><code>None</code></td>
324
+ <td align="left">An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
325
+ </tr>
326
+
327
+ <tr>
328
+ <td align="left"><code>elem_classes</code></td>
329
+ <td align="left" style="width: 25%;">
330
+
331
+ ```python
332
+ list[str] | str | None
333
+ ```
334
+
335
+ </td>
336
+ <td align="left"><code>None</code></td>
337
+ <td align="left">An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
338
+ </tr>
339
+
340
+ <tr>
341
+ <td align="left"><code>render</code></td>
342
+ <td align="left" style="width: 25%;">
343
+
344
+ ```python
345
+ bool
346
+ ```
347
+
348
+ </td>
349
+ <td align="left"><code>True</code></td>
350
+ <td align="left">If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
351
+ </tr>
352
+
353
+ <tr>
354
+ <td align="left"><code>showviewer</code></td>
355
+ <td align="left" style="width: 25%;">
356
+
357
+ ```python
358
+ bool
359
+ ```
360
+
361
+ </td>
362
+ <td align="left"><code>True</code></td>
363
+ <td align="left">If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.</td>
364
+ </tr>
365
+ </tbody></table>
366
+
367
+
368
+ ### Events
369
+
370
+ | name | description |
371
+ |:-----|:------------|
372
+ | `change` | Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
373
+ | `select` | Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data |
374
+ | `clear` | This listener is triggered when the user clears the Molecule3D using the X button for the component. |
375
+ | `upload` | This listener is triggered when the user uploads a file into the Molecule3D. |
376
+
377
+
378
+
379
+ ### User function
380
+
381
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
382
+
383
+ - When used as an Input, the component only impacts the input signature of the user function.
384
+ - When used as an output, the component only impacts the return signature of the user function.
385
+
386
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
387
+
388
+ - **As output:** Is passed, the preprocessed input data sent to the user's function in the backend.
389
+ - **As input:** Should return, the output data received by the component from the user's function in the backend.
390
+
391
+ ```python
392
+ def predict(
393
+ value: bytes | NamedString | list[bytes | NamedString] | None
394
+ ) -> str | list[str] | None:
395
+ return value
396
+ ```
397
+
src/backend/gradio_molecule3d/molecule3d.py CHANGED
@@ -153,7 +153,6 @@ class Molecule3D(Component):
153
  def preprocess(
154
  self, payload: ListFiles | FileData | None
155
  ) -> bytes | NamedString | list[bytes | NamedString] | None:
156
- print("preprocess", payload)
157
  if payload is None:
158
  return None
159
  if self.file_count == "single":
@@ -168,7 +167,6 @@ class Molecule3D(Component):
168
  return [self._process_single_file(payload)]
169
 
170
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
171
- print("postprocess",value)
172
  if value is None:
173
  return None
174
 
 
153
  def preprocess(
154
  self, payload: ListFiles | FileData | None
155
  ) -> bytes | NamedString | list[bytes | NamedString] | None:
 
156
  if payload is None:
157
  return None
158
  if self.file_count == "single":
 
167
  return [self._process_single_file(payload)]
168
 
169
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
 
170
  if value is None:
171
  return None
172
 
src/backend/gradio_molecule3d/molecule3d.pyi CHANGED
@@ -154,7 +154,6 @@ class Molecule3D(Component):
154
  def preprocess(
155
  self, payload: ListFiles | FileData | None
156
  ) -> bytes | NamedString | list[bytes | NamedString] | None:
157
- print("preprocess", payload)
158
  if payload is None:
159
  return None
160
  if self.file_count == "single":
@@ -169,7 +168,6 @@ class Molecule3D(Component):
169
  return [self._process_single_file(payload)]
170
 
171
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
172
- print("postprocess",value)
173
  if value is None:
174
  return None
175
 
 
154
  def preprocess(
155
  self, payload: ListFiles | FileData | None
156
  ) -> bytes | NamedString | list[bytes | NamedString] | None:
 
157
  if payload is None:
158
  return None
159
  if self.file_count == "single":
 
168
  return [self._process_single_file(payload)]
169
 
170
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
 
171
  if value is None:
172
  return None
173
 
src/backend/gradio_molecule3d/templates/component/index.js CHANGED
@@ -25018,7 +25018,7 @@ const _3Dmol = /* @__PURE__ */ getDefaultExportFromCjs(_3DmolExports), Molecular
25018
  text: text$3,
25019
  toggle_class: toggle_class$5,
25020
  transition_in: transition_in$7
25021
- } = window.__gradio__svelte__internal, { onMount: onMount$1 } = window.__gradio__svelte__internal;
25022
  function get_each_context$2(t, e, r) {
25023
  const n = t.slice();
25024
  return n[53] = e[r], n[54] = e, n[55] = r, n;
@@ -26251,12 +26251,13 @@ function instance$9(t, e, r) {
26251
  }), a.render());
26252
  }
26253
  onMount$1(() => {
 
26254
  let pe = { ..._, cartoonQuality: 7 };
26255
  r(20, a = n.createViewer(f, pe));
26256
  let de = [];
26257
  y.forEach((ce) => {
26258
  de.some((Ae) => Ae.model === ce.model && Ae.chain === ce.chain && Ae.resname === ce.resname && Ae.style === ce.style && Ae.color === ce.color && Ae.residue_range === ce.residue_range && Ae.around === ce.around && Ae.byres === ce.byres && Ae.sidechain === ce.sidechain) || de.push(ce);
26259
- }), r(1, y = de), b.length > 0 && b.forEach((ce) => {
26260
  ce.asFrames ? a.addModelsAsFrames(ce.data, ce.format) : a.addModel(ce.data, ce.format);
26261
  }), g(y), a.zoomTo(), a.render(), a.zoom(0.8, 2e3), y.forEach((ce) => {
26262
  ce.color === "alphafold" && r(11, T = !0);
@@ -32692,7 +32693,7 @@ function create_fragment$5(t) {
32692
  "placeholder",
32693
  /*placeholder*/
32694
  t[2]
32695
- ), attr$4(n, "class", "wfull inp svelte-18kpwjt"), b.__value = "pdb_assym", set_input_value(b, b.__value), h.__value = "pdb_bioass", set_input_value(h, h.__value), _.__value = "af", set_input_value(_, _.__value), E.__value = "esm", set_input_value(E, E.__value), attr$4(u, "name", ""), attr$4(u, "id", ""), attr$4(u, "class", "select svelte-18kpwjt"), attr$4(r, "class", "flex input wfull svelte-18kpwjt"), attr$4(S, "class", "btn text-center svelte-18kpwjt"), attr$4(e, "class", "flex mt-2 svelte-18kpwjt"), attr$4(s, "class", "or py svelte-18kpwjt");
32696
  },
32697
  m(g, M) {
32698
  insert$5(g, e, M), append$4(e, r), append$4(r, n), set_input_value(
@@ -32763,7 +32764,7 @@ function instance$5(t, e, r) {
32763
  async function h(p) {
32764
  await tick$2();
32765
  const v = Math.random().toString(36).substring(2, 15);
32766
- console.log("file to upload", p), n = await upload([p], b, v, u), console.log("uploaded files", n[0]), f("load", n[0]);
32767
  }
32768
  let _ = !1;
32769
  async function E(p, v) {
@@ -32792,7 +32793,7 @@ function instance$5(t, e, r) {
32792
  if (r(1, _ = !1), T.status == 200)
32793
  return T.blob();
32794
  f("notfound");
32795
- }).then((T) => new File([T], p + g, { type: "text/plain" }));
32796
  } catch {
32797
  r(1, _ = !1), f("notfound");
32798
  }
@@ -32817,7 +32818,7 @@ function instance$5(t, e, r) {
32817
  esm: "Enter MGnify protein identifier"
32818
  };
32819
  function s(p) {
32820
- p.key === "Enter" && (console.log("Enter pressed"), console.log(y), console.log(c), E(y, c));
32821
  }
32822
  function o() {
32823
  y = this.value, r(3, y);
@@ -32874,7 +32875,7 @@ function create_else_block$2(t) {
32874
  let e, r, n, f, u;
32875
  e = new FileRetrieval({ props: { root: (
32876
  /*root*/
32877
- t[5]
32878
  ) } }), e.$on(
32879
  "load",
32880
  /*handle_upload*/
@@ -32894,11 +32895,11 @@ function create_else_block$2(t) {
32894
  ),
32895
  file_count: (
32896
  /*file_count*/
32897
- t[3]
32898
  ),
32899
  root: (
32900
  /*root*/
32901
- t[5]
32902
  ),
32903
  $$slots: { default: [create_default_slot$1] },
32904
  $$scope: { ctx: t }
@@ -32920,16 +32921,16 @@ function create_else_block$2(t) {
32920
  p(_, E) {
32921
  const c = {};
32922
  E & /*root*/
32923
- 32 && (c.root = /*root*/
32924
- _[5]), e.$set(c);
32925
  const S = {};
32926
  E & /*accept_file_types*/
32927
  16384 && (S.filetype = /*accept_file_types*/
32928
  _[14]), E & /*file_count*/
32929
- 8 && (S.file_count = /*file_count*/
32930
- _[3]), E & /*root*/
32931
- 32 && (S.root = /*root*/
32932
- _[5]), E & /*$$scope*/
32933
  8388608 && (S.$$scope = { dirty: E, ctx: _ }), !f && E & /*dragging*/
32934
  8192 && (f = !0, S.dragging = /*dragging*/
32935
  _[13], add_flush_callback(() => f = !1)), n.$set(S);
@@ -32951,7 +32952,7 @@ function create_if_block$2(t) {
32951
  e = new ModifyUpload({
32952
  props: { i18n: (
32953
  /*i18n*/
32954
- t[7]
32955
  ), absolute: !0 }
32956
  }), e.$on(
32957
  "clear",
@@ -32961,11 +32962,11 @@ function create_if_block$2(t) {
32961
  props: {
32962
  i18n: (
32963
  /*i18n*/
32964
- t[7]
32965
  ),
32966
  selectable: (
32967
  /*selectable*/
32968
- t[4]
32969
  ),
32970
  value: (
32971
  /*value*/
@@ -32973,7 +32974,7 @@ function create_if_block$2(t) {
32973
  ),
32974
  height: (
32975
  /*height*/
32976
- t[6]
32977
  )
32978
  }
32979
  }), n.$on(
@@ -32983,7 +32984,7 @@ function create_if_block$2(t) {
32983
  );
32984
  let h = (
32985
  /*moldata*/
32986
- t[11] != null && /*molviewer*/
32987
  t[12] && create_if_block_1$2(t)
32988
  );
32989
  return {
@@ -32996,21 +32997,21 @@ function create_if_block$2(t) {
32996
  p(_, E) {
32997
  const c = {};
32998
  E & /*i18n*/
32999
- 128 && (c.i18n = /*i18n*/
33000
- _[7]), e.$set(c);
33001
  const S = {};
33002
  E & /*i18n*/
33003
- 128 && (S.i18n = /*i18n*/
33004
- _[7]), E & /*selectable*/
33005
- 16 && (S.selectable = /*selectable*/
33006
- _[4]), E & /*value*/
33007
  1 && (S.value = /*value*/
33008
  _[0]), E & /*height*/
33009
- 64 && (S.height = /*height*/
33010
- _[6]), n.$set(S), /*moldata*/
33011
- _[11] != null && /*molviewer*/
33012
  _[12] ? h ? (h.p(_, E), E & /*moldata, molviewer*/
33013
- 6144 && transition_in$2(h, 1)) : (h = create_if_block_1$2(_), h.c(), transition_in$2(h, 1), h.m(u.parentNode, u)) : h && (group_outros$2(), transition_out$2(h, 1, 1, () => {
33014
  h = null;
33015
  }), check_outros$2());
33016
  },
@@ -33082,19 +33083,19 @@ function create_if_block_1$2(t) {
33082
  props: {
33083
  moldata: (
33084
  /*moldata*/
33085
- t[11]
33086
  ),
33087
  config: (
33088
  /*config*/
33089
- t[8]
33090
  ),
33091
  confidenceLabel: (
33092
  /*confidenceLabel*/
33093
- t[9]
33094
  ),
33095
  representations: (
33096
  /*representations*/
33097
- t[10]
33098
  )
33099
  }
33100
  }), {
@@ -33107,14 +33108,14 @@ function create_if_block_1$2(t) {
33107
  p(n, f) {
33108
  const u = {};
33109
  f & /*moldata*/
33110
- 2048 && (u.moldata = /*moldata*/
33111
- n[11]), f & /*config*/
33112
- 256 && (u.config = /*config*/
33113
- n[8]), f & /*confidenceLabel*/
33114
- 512 && (u.confidenceLabel = /*confidenceLabel*/
33115
- n[9]), f & /*representations*/
33116
- 1024 && (u.representations = /*representations*/
33117
- n[10]), e.$set(u);
33118
  },
33119
  i(n) {
33120
  r || (transition_in$2(e.$$.fragment, n), r = !0);
@@ -33133,7 +33134,7 @@ function create_fragment$4(t) {
33133
  props: {
33134
  show_label: (
33135
  /*show_label*/
33136
- t[2]
33137
  ),
33138
  Icon: File$1,
33139
  float: (
@@ -33142,7 +33143,7 @@ function create_fragment$4(t) {
33142
  ),
33143
  label: (
33144
  /*label*/
33145
- t[1] || "File"
33146
  )
33147
  }
33148
  });
@@ -33163,12 +33164,12 @@ function create_fragment$4(t) {
33163
  p(c, [S]) {
33164
  const y = {};
33165
  S & /*show_label*/
33166
- 4 && (y.show_label = /*show_label*/
33167
- c[2]), S & /*value*/
33168
  1 && (y.float = /*value*/
33169
  c[0] === null), S & /*label*/
33170
- 2 && (y.label = /*label*/
33171
- c[1] || "File"), e.$set(y);
33172
  let w = n;
33173
  n = E(c), n === w ? _[n].p(c, S) : (group_outros$2(), transition_out$2(_[w], 1, 1, () => {
33174
  _[w] = null;
@@ -33188,10 +33189,10 @@ function create_fragment$4(t) {
33188
  function instance$4(t, e, r) {
33189
  let { $$slots: n = {}, $$scope: f } = e, { value: u } = e, { label: b } = e, { show_label: h = !0 } = e, { file_count: _ = "single" } = e, { file_types: E = null } = e, { selectable: c = !1 } = e, { root: S } = e, { height: y = void 0 } = e, { i18n: w } = e, { config: L = {} } = e, { confidenceLabel: s = "" } = e, { representations: o = [] } = e, { moldata: A = null } = e, { molviewer: p = !1 } = e;
33190
  async function v({ detail: I }) {
33191
- r(0, u = I), await tick$1(), l("change", u), l("upload", I);
33192
  }
33193
  function a() {
33194
- r(0, u = null), l("change", null), l("clear");
33195
  }
33196
  const l = createEventDispatcher();
33197
  let g;
@@ -33205,12 +33206,13 @@ function instance$4(t, e, r) {
33205
  M = I, r(13, M);
33206
  }
33207
  return t.$$set = (I) => {
33208
- "value" in I && r(0, u = I.value), "label" in I && r(1, b = I.label), "show_label" in I && r(2, h = I.show_label), "file_count" in I && r(3, _ = I.file_count), "file_types" in I && r(18, E = I.file_types), "selectable" in I && r(4, c = I.selectable), "root" in I && r(5, S = I.root), "height" in I && r(6, y = I.height), "i18n" in I && r(7, w = I.i18n), "config" in I && r(8, L = I.config), "confidenceLabel" in I && r(9, s = I.confidenceLabel), "representations" in I && r(10, o = I.representations), "moldata" in I && r(11, A = I.moldata), "molviewer" in I && r(12, p = I.molviewer), "$$scope" in I && r(23, f = I.$$scope);
33209
  }, t.$$.update = () => {
33210
  t.$$.dirty & /*dragging*/
33211
  8192 && l("drag", M);
33212
  }, [
33213
  u,
 
33214
  b,
33215
  h,
33216
  _,
@@ -33221,7 +33223,6 @@ function instance$4(t, e, r) {
33221
  L,
33222
  s,
33223
  o,
33224
- A,
33225
  p,
33226
  M,
33227
  g,
@@ -33240,18 +33241,18 @@ class FileUpload extends SvelteComponent$4 {
33240
  constructor(e) {
33241
  super(), init$4(this, e, instance$4, create_fragment$4, safe_not_equal$4, {
33242
  value: 0,
33243
- label: 1,
33244
- show_label: 2,
33245
- file_count: 3,
33246
  file_types: 18,
33247
- selectable: 4,
33248
- root: 5,
33249
- height: 6,
33250
- i18n: 7,
33251
- config: 8,
33252
- confidenceLabel: 9,
33253
- representations: 10,
33254
- moldata: 11,
33255
  molviewer: 12
33256
  });
33257
  }
@@ -34697,7 +34698,7 @@ function create_if_block(t) {
34697
  e = element("div"), r = svg_element("svg"), n = svg_element("path"), f = space(), u = element("span"), u.textContent = "Error in the representations", b = space(), h = element("div"), _ = element("span"), _.textContent = "Couldn't display Molecule. Fix the following problems:", E = space(), c = element("ul");
34698
  for (let w = 0; w < y.length; w += 1)
34699
  y[w].c();
34700
- attr(n, "stroke-linecap", "round"), attr(n, "stroke-linejoin", "round"), attr(n, "d", "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"), attr(r, "class", "flex-shrink-0 inline w-4 h-4 mr-3 mt-[2px] svelte-1j3z0by"), attr(r, "xmlns", "http://www.w3.org/2000/svg"), attr(r, "fill", "none"), attr(r, "viewBox", "0 0 24 24"), attr(r, "stroke-width", "1.5"), attr(r, "stroke", "currentColor"), attr(u, "class", "sr-only svelte-1j3z0by"), attr(_, "class", "font-medium svelte-1j3z0by"), attr(c, "class", "mt-1.5 ml-4 list-disc list-inside svelte-1j3z0by"), attr(e, "class", "flex m-2 p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 svelte-1j3z0by"), attr(e, "role", "alert");
34701
  },
34702
  m(w, L) {
34703
  insert(w, e, L), append(e, r), append(r, n), append(e, f), append(e, u), append(e, b), append(e, h), append(h, _), append(h, E), append(h, c);
@@ -34960,7 +34961,7 @@ function instance(t, e, r) {
34960
  around: { type: Number, default: 0 },
34961
  byres: { type: Boolean, default: !1 },
34962
  visible: { type: Boolean, default: !0 }
34963
- }, I = null, B = ["pdb", "sdf", "mol2"], P = [];
34964
  async function z(X) {
34965
  if (X == null)
34966
  return [];
@@ -34985,12 +34986,12 @@ function instance(t, e, r) {
34985
  if (!B.includes(oe))
34986
  P.push(`Invalid file extension for ${X.orig_name}. Expected one of ${B.join(", ")}, got ${oe}`), r(20, I = null);
34987
  else {
34988
- let te = await fetchFileContent(X.url);
34989
- console.log("t", te), r(20, I = [
34990
  {
34991
  data: te,
34992
  name: X.orig_name,
34993
- format: "pdb",
34994
  asFrames: !1
34995
  }
34996
  ]);
@@ -35006,7 +35007,7 @@ function instance(t, e, r) {
35006
  "elem_id" in X && r(1, n = X.elem_id), "elem_classes" in X && r(2, f = X.elem_classes), "visible" in X && r(3, u = X.visible), "value" in X && r(0, b = X.value), "interactive" in X && r(4, h = X.interactive), "root" in X && r(5, _ = X.root), "label" in X && r(6, E = X.label), "show_label" in X && r(7, c = X.show_label), "height" in X && r(8, S = X.height), "reps" in X && r(24, y = X.reps), "config" in X && r(9, w = X.config), "confidenceLabel" in X && r(10, L = X.confidenceLabel), "showviewer" in X && r(11, s = X.showviewer), "_selectable" in X && r(12, o = X._selectable), "loading_status" in X && r(13, A = X.loading_status), "container" in X && r(14, p = X.container), "scale" in X && r(15, v = X.scale), "min_width" in X && r(16, a = X.min_width), "gradio" in X && r(17, l = X.gradio), "file_count" in X && r(18, g = X.file_count), "file_types" in X && r(19, M = X.file_types);
35007
  }, t.$$.update = () => {
35008
  t.$$.dirty[0] & /*old_value, value, gradio*/
35009
- 33685505 && JSON.stringify(C) !== JSON.stringify(b) && (l.dispatch("change"), r(25, C = b), console.log("value change", b)), t.$$.dirty[0] & /*moldata*/
35010
  1048576 && r(26, k = I ? I.length : 0), t.$$.dirty[0] & /*reps, errors, lenMoldata*/
35011
  85983232 && (y.forEach((X) => {
35012
  for (const [oe, te] of Object.entries(D))
 
25018
  text: text$3,
25019
  toggle_class: toggle_class$5,
25020
  transition_in: transition_in$7
25021
+ } = window.__gradio__svelte__internal, { onMount: onMount$1, onDestroy: onDestroy$1 } = window.__gradio__svelte__internal;
25022
  function get_each_context$2(t, e, r) {
25023
  const n = t.slice();
25024
  return n[53] = e[r], n[54] = e, n[55] = r, n;
 
26251
  }), a.render());
26252
  }
26253
  onMount$1(() => {
26254
+ console.log("MolecularViewer Mounted");
26255
  let pe = { ..._, cartoonQuality: 7 };
26256
  r(20, a = n.createViewer(f, pe));
26257
  let de = [];
26258
  y.forEach((ce) => {
26259
  de.some((Ae) => Ae.model === ce.model && Ae.chain === ce.chain && Ae.resname === ce.resname && Ae.style === ce.style && Ae.color === ce.color && Ae.residue_range === ce.residue_range && Ae.around === ce.around && Ae.byres === ce.byres && Ae.sidechain === ce.sidechain) || de.push(ce);
26260
+ }), r(1, y = de), console.log(b), b.length > 0 && b.forEach((ce) => {
26261
  ce.asFrames ? a.addModelsAsFrames(ce.data, ce.format) : a.addModel(ce.data, ce.format);
26262
  }), g(y), a.zoomTo(), a.render(), a.zoom(0.8, 2e3), y.forEach((ce) => {
26263
  ce.color === "alphafold" && r(11, T = !0);
 
32693
  "placeholder",
32694
  /*placeholder*/
32695
  t[2]
32696
+ ), attr$4(n, "class", "wfull inp svelte-1nnwgsd"), b.__value = "pdb_assym", set_input_value(b, b.__value), h.__value = "pdb_bioass", set_input_value(h, h.__value), _.__value = "af", set_input_value(_, _.__value), E.__value = "esm", set_input_value(E, E.__value), attr$4(u, "name", ""), attr$4(u, "id", ""), attr$4(u, "class", "select svelte-1nnwgsd"), attr$4(r, "class", "flex input wfull svelte-1nnwgsd"), attr$4(S, "class", "btn text-center svelte-1nnwgsd"), attr$4(e, "class", "flex mt-2 svelte-1nnwgsd"), attr$4(s, "class", "or py svelte-1nnwgsd");
32697
  },
32698
  m(g, M) {
32699
  insert$5(g, e, M), append$4(e, r), append$4(r, n), set_input_value(
 
32764
  async function h(p) {
32765
  await tick$2();
32766
  const v = Math.random().toString(36).substring(2, 15);
32767
+ n = await upload([p], b, v, u), f("load", n[0]);
32768
  }
32769
  let _ = !1;
32770
  async function E(p, v) {
 
32793
  if (r(1, _ = !1), T.status == 200)
32794
  return T.blob();
32795
  f("notfound");
32796
+ }).then((T) => new File([T], p + ".pdb", { type: "text/plain" }));
32797
  } catch {
32798
  r(1, _ = !1), f("notfound");
32799
  }
 
32818
  esm: "Enter MGnify protein identifier"
32819
  };
32820
  function s(p) {
32821
+ p.key === "Enter" && E(y, c);
32822
  }
32823
  function o() {
32824
  y = this.value, r(3, y);
 
32875
  let e, r, n, f, u;
32876
  e = new FileRetrieval({ props: { root: (
32877
  /*root*/
32878
+ t[6]
32879
  ) } }), e.$on(
32880
  "load",
32881
  /*handle_upload*/
 
32895
  ),
32896
  file_count: (
32897
  /*file_count*/
32898
+ t[4]
32899
  ),
32900
  root: (
32901
  /*root*/
32902
+ t[6]
32903
  ),
32904
  $$slots: { default: [create_default_slot$1] },
32905
  $$scope: { ctx: t }
 
32921
  p(_, E) {
32922
  const c = {};
32923
  E & /*root*/
32924
+ 64 && (c.root = /*root*/
32925
+ _[6]), e.$set(c);
32926
  const S = {};
32927
  E & /*accept_file_types*/
32928
  16384 && (S.filetype = /*accept_file_types*/
32929
  _[14]), E & /*file_count*/
32930
+ 16 && (S.file_count = /*file_count*/
32931
+ _[4]), E & /*root*/
32932
+ 64 && (S.root = /*root*/
32933
+ _[6]), E & /*$$scope*/
32934
  8388608 && (S.$$scope = { dirty: E, ctx: _ }), !f && E & /*dragging*/
32935
  8192 && (f = !0, S.dragging = /*dragging*/
32936
  _[13], add_flush_callback(() => f = !1)), n.$set(S);
 
32952
  e = new ModifyUpload({
32953
  props: { i18n: (
32954
  /*i18n*/
32955
+ t[8]
32956
  ), absolute: !0 }
32957
  }), e.$on(
32958
  "clear",
 
32962
  props: {
32963
  i18n: (
32964
  /*i18n*/
32965
+ t[8]
32966
  ),
32967
  selectable: (
32968
  /*selectable*/
32969
+ t[5]
32970
  ),
32971
  value: (
32972
  /*value*/
 
32974
  ),
32975
  height: (
32976
  /*height*/
32977
+ t[7]
32978
  )
32979
  }
32980
  }), n.$on(
 
32984
  );
32985
  let h = (
32986
  /*moldata*/
32987
+ t[1] != null && /*molviewer*/
32988
  t[12] && create_if_block_1$2(t)
32989
  );
32990
  return {
 
32997
  p(_, E) {
32998
  const c = {};
32999
  E & /*i18n*/
33000
+ 256 && (c.i18n = /*i18n*/
33001
+ _[8]), e.$set(c);
33002
  const S = {};
33003
  E & /*i18n*/
33004
+ 256 && (S.i18n = /*i18n*/
33005
+ _[8]), E & /*selectable*/
33006
+ 32 && (S.selectable = /*selectable*/
33007
+ _[5]), E & /*value*/
33008
  1 && (S.value = /*value*/
33009
  _[0]), E & /*height*/
33010
+ 128 && (S.height = /*height*/
33011
+ _[7]), n.$set(S), /*moldata*/
33012
+ _[1] != null && /*molviewer*/
33013
  _[12] ? h ? (h.p(_, E), E & /*moldata, molviewer*/
33014
+ 4098 && transition_in$2(h, 1)) : (h = create_if_block_1$2(_), h.c(), transition_in$2(h, 1), h.m(u.parentNode, u)) : h && (group_outros$2(), transition_out$2(h, 1, 1, () => {
33015
  h = null;
33016
  }), check_outros$2());
33017
  },
 
33083
  props: {
33084
  moldata: (
33085
  /*moldata*/
33086
+ t[1]
33087
  ),
33088
  config: (
33089
  /*config*/
33090
+ t[9]
33091
  ),
33092
  confidenceLabel: (
33093
  /*confidenceLabel*/
33094
+ t[10]
33095
  ),
33096
  representations: (
33097
  /*representations*/
33098
+ t[11]
33099
  )
33100
  }
33101
  }), {
 
33108
  p(n, f) {
33109
  const u = {};
33110
  f & /*moldata*/
33111
+ 2 && (u.moldata = /*moldata*/
33112
+ n[1]), f & /*config*/
33113
+ 512 && (u.config = /*config*/
33114
+ n[9]), f & /*confidenceLabel*/
33115
+ 1024 && (u.confidenceLabel = /*confidenceLabel*/
33116
+ n[10]), f & /*representations*/
33117
+ 2048 && (u.representations = /*representations*/
33118
+ n[11]), e.$set(u);
33119
  },
33120
  i(n) {
33121
  r || (transition_in$2(e.$$.fragment, n), r = !0);
 
33134
  props: {
33135
  show_label: (
33136
  /*show_label*/
33137
+ t[3]
33138
  ),
33139
  Icon: File$1,
33140
  float: (
 
33143
  ),
33144
  label: (
33145
  /*label*/
33146
+ t[2] || "File"
33147
  )
33148
  }
33149
  });
 
33164
  p(c, [S]) {
33165
  const y = {};
33166
  S & /*show_label*/
33167
+ 8 && (y.show_label = /*show_label*/
33168
+ c[3]), S & /*value*/
33169
  1 && (y.float = /*value*/
33170
  c[0] === null), S & /*label*/
33171
+ 4 && (y.label = /*label*/
33172
+ c[2] || "File"), e.$set(y);
33173
  let w = n;
33174
  n = E(c), n === w ? _[n].p(c, S) : (group_outros$2(), transition_out$2(_[w], 1, 1, () => {
33175
  _[w] = null;
 
33189
  function instance$4(t, e, r) {
33190
  let { $$slots: n = {}, $$scope: f } = e, { value: u } = e, { label: b } = e, { show_label: h = !0 } = e, { file_count: _ = "single" } = e, { file_types: E = null } = e, { selectable: c = !1 } = e, { root: S } = e, { height: y = void 0 } = e, { i18n: w } = e, { config: L = {} } = e, { confidenceLabel: s = "" } = e, { representations: o = [] } = e, { moldata: A = null } = e, { molviewer: p = !1 } = e;
33191
  async function v({ detail: I }) {
33192
+ r(0, u = I), await tick$1(), l("change", u), l("upload", I), console.log("upload", I);
33193
  }
33194
  function a() {
33195
+ r(0, u = null), r(1, A = null), l("change", null), l("clear");
33196
  }
33197
  const l = createEventDispatcher();
33198
  let g;
 
33206
  M = I, r(13, M);
33207
  }
33208
  return t.$$set = (I) => {
33209
+ "value" in I && r(0, u = I.value), "label" in I && r(2, b = I.label), "show_label" in I && r(3, h = I.show_label), "file_count" in I && r(4, _ = I.file_count), "file_types" in I && r(18, E = I.file_types), "selectable" in I && r(5, c = I.selectable), "root" in I && r(6, S = I.root), "height" in I && r(7, y = I.height), "i18n" in I && r(8, w = I.i18n), "config" in I && r(9, L = I.config), "confidenceLabel" in I && r(10, s = I.confidenceLabel), "representations" in I && r(11, o = I.representations), "moldata" in I && r(1, A = I.moldata), "molviewer" in I && r(12, p = I.molviewer), "$$scope" in I && r(23, f = I.$$scope);
33210
  }, t.$$.update = () => {
33211
  t.$$.dirty & /*dragging*/
33212
  8192 && l("drag", M);
33213
  }, [
33214
  u,
33215
+ A,
33216
  b,
33217
  h,
33218
  _,
 
33223
  L,
33224
  s,
33225
  o,
 
33226
  p,
33227
  M,
33228
  g,
 
33241
  constructor(e) {
33242
  super(), init$4(this, e, instance$4, create_fragment$4, safe_not_equal$4, {
33243
  value: 0,
33244
+ label: 2,
33245
+ show_label: 3,
33246
+ file_count: 4,
33247
  file_types: 18,
33248
+ selectable: 5,
33249
+ root: 6,
33250
+ height: 7,
33251
+ i18n: 8,
33252
+ config: 9,
33253
+ confidenceLabel: 10,
33254
+ representations: 11,
33255
+ moldata: 1,
33256
  molviewer: 12
33257
  });
33258
  }
 
34698
  e = element("div"), r = svg_element("svg"), n = svg_element("path"), f = space(), u = element("span"), u.textContent = "Error in the representations", b = space(), h = element("div"), _ = element("span"), _.textContent = "Couldn't display Molecule. Fix the following problems:", E = space(), c = element("ul");
34699
  for (let w = 0; w < y.length; w += 1)
34700
  y[w].c();
34701
+ attr(n, "stroke-linecap", "round"), attr(n, "stroke-linejoin", "round"), attr(n, "d", "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"), attr(r, "class", "flex-shrink-0 inline w-4 h-4 mr-3 mt-[2px] svelte-1xezsv6"), attr(r, "xmlns", "http://www.w3.org/2000/svg"), attr(r, "fill", "none"), attr(r, "viewBox", "0 0 24 24"), attr(r, "stroke-width", "1.5"), attr(r, "stroke", "currentColor"), attr(u, "class", "sr-only svelte-1xezsv6"), attr(_, "class", "font-medium svelte-1xezsv6"), attr(c, "class", "mt-1.5 ml-4 list-disc list-inside svelte-1xezsv6"), attr(e, "class", "flex m-2 p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 svelte-1xezsv6"), attr(e, "role", "alert");
34702
  },
34703
  m(w, L) {
34704
  insert(w, e, L), append(e, r), append(r, n), append(e, f), append(e, u), append(e, b), append(e, h), append(h, _), append(h, E), append(h, c);
 
34961
  around: { type: Number, default: 0 },
34962
  byres: { type: Boolean, default: !1 },
34963
  visible: { type: Boolean, default: !0 }
34964
+ }, I = null, B = ["pdb", "sdf", "mol2", "pdb1"], P = [];
34965
  async function z(X) {
34966
  if (X == null)
34967
  return [];
 
34986
  if (!B.includes(oe))
34987
  P.push(`Invalid file extension for ${X.orig_name}. Expected one of ${B.join(", ")}, got ${oe}`), r(20, I = null);
34988
  else {
34989
+ let te = await fetchFileContent(X.url), ve = X.orig_name.split(".").pop();
34990
+ ve === "pdb1" && (ve = "pdb"), r(20, I = [
34991
  {
34992
  data: te,
34993
  name: X.orig_name,
34994
+ format: ve,
34995
  asFrames: !1
34996
  }
34997
  ]);
 
35007
  "elem_id" in X && r(1, n = X.elem_id), "elem_classes" in X && r(2, f = X.elem_classes), "visible" in X && r(3, u = X.visible), "value" in X && r(0, b = X.value), "interactive" in X && r(4, h = X.interactive), "root" in X && r(5, _ = X.root), "label" in X && r(6, E = X.label), "show_label" in X && r(7, c = X.show_label), "height" in X && r(8, S = X.height), "reps" in X && r(24, y = X.reps), "config" in X && r(9, w = X.config), "confidenceLabel" in X && r(10, L = X.confidenceLabel), "showviewer" in X && r(11, s = X.showviewer), "_selectable" in X && r(12, o = X._selectable), "loading_status" in X && r(13, A = X.loading_status), "container" in X && r(14, p = X.container), "scale" in X && r(15, v = X.scale), "min_width" in X && r(16, a = X.min_width), "gradio" in X && r(17, l = X.gradio), "file_count" in X && r(18, g = X.file_count), "file_types" in X && r(19, M = X.file_types);
35008
  }, t.$$.update = () => {
35009
  t.$$.dirty[0] & /*old_value, value, gradio*/
35010
+ 33685505 && JSON.stringify(C) !== JSON.stringify(b) && (l.dispatch("change"), r(25, C = b), console.log("value change", b), r(20, I = null), z(b)), t.$$.dirty[0] & /*moldata*/
35011
  1048576 && r(26, k = I ? I.length : 0), t.$$.dirty[0] & /*reps, errors, lenMoldata*/
35012
  85983232 && (y.forEach((X) => {
35013
  for (const [oe, te] of Object.entries(D))
src/backend/gradio_molecule3d/templates/component/style.css CHANGED
@@ -1 +1 @@
1
- .block.svelte-1t38q2d{position:relative;margin:0;box-shadow:var(--block-shadow);border-width:var(--block-border-width);border-color:var(--block-border-color);border-radius:var(--block-radius);background:var(--block-background-fill);width:100%;line-height:var(--line-sm)}.block.border_focus.svelte-1t38q2d{border-color:var(--color-accent)}.padded.svelte-1t38q2d{padding:var(--block-padding)}.hidden.svelte-1t38q2d{display:none}.hide-container.svelte-1t38q2d{margin:0;box-shadow:none;--block-border-width:0;background:transparent;padding:0;overflow:visible}div.svelte-1hnfib2{margin-bottom:var(--spacing-lg);color:var(--block-info-text-color);font-weight:var(--block-info-text-weight);font-size:var(--block-info-text-size);line-height:var(--line-sm)}span.has-info.svelte-22c38v{margin-bottom:var(--spacing-xs)}span.svelte-22c38v:not(.has-info){margin-bottom:var(--spacing-lg)}span.svelte-22c38v{display:inline-block;position:relative;z-index:var(--layer-4);border:solid var(--block-title-border-width) var(--block-title-border-color);border-radius:var(--block-title-radius);background:var(--block-title-background-fill);padding:var(--block-title-padding);color:var(--block-title-text-color);font-weight:var(--block-title-text-weight);font-size:var(--block-title-text-size);line-height:var(--line-sm)}.hide.svelte-22c38v{margin:0;height:0}label.svelte-9gxdi0{display:inline-flex;align-items:center;z-index:var(--layer-2);box-shadow:var(--block-label-shadow);border:var(--block-label-border-width) solid var(--border-color-primary);border-top:none;border-left:none;border-radius:var(--block-label-radius);background:var(--block-label-background-fill);padding:var(--block-label-padding);pointer-events:none;color:var(--block-label-text-color);font-weight:var(--block-label-text-weight);font-size:var(--block-label-text-size);line-height:var(--line-sm)}.gr-group label.svelte-9gxdi0{border-top-left-radius:0}label.float.svelte-9gxdi0{position:absolute;top:var(--block-label-margin);left:var(--block-label-margin)}label.svelte-9gxdi0:not(.float){position:static;margin-top:var(--block-label-margin);margin-left:var(--block-label-margin)}.hide.svelte-9gxdi0{height:0}span.svelte-9gxdi0{opacity:.8;margin-right:var(--size-2);width:calc(var(--block-label-text-size) - 1px);height:calc(var(--block-label-text-size) - 1px)}.hide-label.svelte-9gxdi0{box-shadow:none;border-width:0;background:transparent;overflow:visible}button.svelte-xtz2g8{display:flex;justify-content:center;align-items:center;gap:1px;z-index:var(--layer-2);border-radius:var(--radius-sm);color:var(--block-label-text-color);border:1px solid transparent}.padded.svelte-xtz2g8{padding:2px;background:var(--background-fill-primary);box-shadow:var(--shadow-drop);border:1px solid var(--button-secondary-border-color)}button.svelte-xtz2g8:hover{cursor:pointer;color:var(--color-accent)}.padded.svelte-xtz2g8:hover{border:2px solid var(--button-secondary-border-color-hover);padding:1px;color:var(--block-label-text-color)}span.svelte-xtz2g8{padding:0 1px;font-size:10px}div.svelte-xtz2g8{padding:2px;display:flex;align-items:flex-end}.small.svelte-xtz2g8{width:14px;height:14px}.large.svelte-xtz2g8{width:22px;height:22px}.pending.svelte-xtz2g8{animation:svelte-xtz2g8-flash .5s infinite}@keyframes svelte-xtz2g8-flash{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.empty.svelte-3w3rth{display:flex;justify-content:center;align-items:center;margin-top:calc(0px - var(--size-6));height:var(--size-full)}.icon.svelte-3w3rth{opacity:.5;height:var(--size-5);color:var(--body-text-color)}.small.svelte-3w3rth{min-height:calc(var(--size-32) - 20px)}.large.svelte-3w3rth{min-height:calc(var(--size-64) - 20px)}.unpadded_box.svelte-3w3rth{margin-top:0}.small_parent.svelte-3w3rth{min-height:100%!important}.dropdown-arrow.svelte-145leq6{fill:currentColor}.wrap.svelte-kzcjhc{display:flex;flex-direction:column;justify-content:center;align-items:center;min-height:var(--size-60);color:var(--block-label-text-color);line-height:var(--line-md);height:100%;padding-top:var(--size-3)}.or.svelte-kzcjhc{color:var(--body-text-color-subdued);display:flex}.icon-wrap.svelte-kzcjhc{width:30px;margin-bottom:var(--spacing-lg)}@media (--screen-md){.wrap.svelte-kzcjhc{font-size:var(--text-lg)}}.hovered.svelte-kzcjhc{color:var(--color-accent)}div.svelte-1nba87b{border-top:1px solid transparent;display:flex;max-height:100%;justify-content:center;gap:var(--spacing-sm);height:auto;align-items:flex-end;box-shadow:var(--shadow-drop);padding:var(--spacing-xl) 0;color:var(--block-label-text-color);flex-shrink:0;width:95%}.show_border.svelte-1nba87b{border-top:1px solid var(--block-border-color);margin-top:var(--spacing-xxl)}td.svelte-usqupg.svelte-usqupg{width:45%}td.svelte-usqupg.svelte-usqupg:last-child{width:10%;text-align:right}.file-preview-holder.svelte-usqupg.svelte-usqupg{overflow-x:auto;overflow-y:auto}.file-preview.svelte-usqupg.svelte-usqupg{width:var(--size-full);max-height:var(--size-60);overflow-y:auto;margin-top:var(--size-1);color:var(--body-text-color)}.file.svelte-usqupg.svelte-usqupg{width:var(--size-full)}.file.svelte-usqupg>.svelte-usqupg{padding:var(--size-1) var(--size-2-5)}.download.svelte-usqupg.svelte-usqupg:hover{text-decoration:underline}.download.svelte-usqupg>a.svelte-usqupg{color:var(--link-text-color)}.download.svelte-usqupg>a.svelte-usqupg:hover{color:var(--link-text-color-hover)}.download.svelte-usqupg>a.svelte-usqupg:visited{color:var(--link-text-color-visited)}.download.svelte-usqupg>a.svelte-usqupg:active{color:var(--link-text-color-active)}.selectable.svelte-usqupg.svelte-usqupg{cursor:pointer}tbody.svelte-usqupg>tr.svelte-usqupg:nth-child(2n){background:var(--block-background-fill)}tbody.svelte-usqupg>tr.svelte-usqupg:nth-child(odd){background:var(--table-odd-background-fill)}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-content:""}h5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:inherit;font-weight:inherit}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,select.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,select.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{text-transform:none}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,[type=button].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{-webkit-appearance:button;background-color:transparent;background-image:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:-moz-focusring{outline:auto}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:-moz-ui-invalid{box-shadow:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-inner-spin-button,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-outer-spin-button{height:auto}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-search-decoration{-webkit-appearance:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}h5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin:0}input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-moz-placeholder{opacity:1;color:#9ca3af}input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::placeholder{opacity:1;color:#9ca3af}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{cursor:pointer}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:disabled{cursor:default}svg.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:block;vertical-align:middle}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.absolute.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:absolute}.relative.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:relative}.bottom-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{bottom:0}.left-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{left:0}.right-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{right:0}.right-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{right:.625rem}.top-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:0}.top-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:.625rem}.z-10.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{z-index:10}.z-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{z-index:50}.my-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-top:.5rem;margin-bottom:.5rem}.mb-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-bottom:.5rem}.mb-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-bottom:1rem}.mr-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-right:.5rem}.ml-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-left:.5rem}.mr-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-right:1.25rem}.mt-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-top:.5rem}.block.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:block}.flex.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:flex}.inline-flex.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:inline-flex}.h-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:.5rem}.h-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1.25rem}.h-6.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1.5rem}.h-8.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:2rem}.h-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:100%}.w-1\/2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:50%}.w-1\/3.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:33.333333%}.w-11.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:2.75rem}.w-2\/3.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:66.666667%}.w-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:1.25rem}.w-8.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:2rem}.w-80.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:20rem}.w-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:100%}.rotate-90.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.appearance-none.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-col.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{flex-direction:column}.flex-wrap.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{flex-wrap:wrap}.items-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{align-items:center}.justify-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{justify-content:center}.gap-px.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{gap:1px}.space-x-1.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.divide-x.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-divide-x-reverse:0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-y.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.overflow-hidden.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{overflow:hidden}.overflow-y-auto.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{overflow-y:auto}.rounded-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:9999px}.rounded-lg.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:.5rem}.border.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-width:1px}.border-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-width:4px}.border-b.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-bottom-width:1px}.border-l.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-left-width:1px}.border-t.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-top-width:1px}.border-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(156 163 175 / var(--tw-border-opacity))}.border-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.bg-black.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-blue-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-cyan-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(8 145 178 / var(--tw-bg-opacity))}.bg-gray-100.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-green-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.bg-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(234 88 12 / var(--tw-bg-opacity))}.bg-red-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-transparent.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{background-color:transparent}.bg-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.25rem}.p-1\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.375rem}.p-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.5rem}.p-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.625rem}.p-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:1rem}.px-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-left:1rem;padding-right:1rem}.py-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:.5rem;padding-bottom:.5rem}.py-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:1rem;padding-bottom:1rem}.text-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{text-align:center}.text-base.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:1rem;line-height:1.5rem}.font-semibold.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-weight:600}.text-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity))}.transition-transform.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.sr-only.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{clip:rect(0,0,0,0);position:absolute;margin:-1px;border-width:0;padding:0;width:1px;height:1px;overflow:hidden;white-space:nowrap}.after\:absolute.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);position:absolute}.after\:left-\[2px\].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);left:2px}.after\:top-0\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);top:.125rem}.after\:h-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);height:1.25rem}.after\:w-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);width:1.25rem}.after\:rounded-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);border-radius:9999px}.after\:border.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);border-width:1px}.after\:border-gray-300.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.after\:bg-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-content:"";content:var(--tw-content)}.hover\:bg-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:text-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:border-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-border-opacity:1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:ring-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246 / var(--tw-ring-opacity))}.peer.svelte-1skivl7:checked~.peer-checked\:bg-orange-400.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(251 146 60 / var(--tw-bg-opacity))}.peer.svelte-1skivl7:checked~.peer-checked\:after\:translate-x-full.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer.svelte-1skivl7:checked~.peer-checked\:after\:border-white.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-border-opacity:1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.peer.svelte-1skivl7:focus~.peer-focus\:ring-4.svelte-1skivl7.svelte-1skivl7{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.peer.svelte-1skivl7:focus~.peer-focus\:ring-orange-300.svelte-1skivl7.svelte-1skivl7{--tw-ring-opacity:1;--tw-ring-color:rgb(253 186 116 / var(--tw-ring-opacity))}@media (prefers-color-scheme: dark){.dark\:border-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:bg-gray-800.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:text-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:hover\:bg-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.dark\:hover\:text-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:focus\:border-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-border-opacity:1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246 / var(--tw-ring-opacity))}.peer.svelte-1skivl7:focus~.dark\:peer-focus\:ring-orange-800.svelte-1skivl7.svelte-1skivl7{--tw-ring-opacity:1;--tw-ring-color:rgb(154 52 18 / var(--tw-ring-opacity))}}.minh.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:600px}.-top-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:-.25rem}.left-6.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{left:1.5rem}.h-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1rem}.w-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:1rem}.w-max.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:max-content}.cursor-pointer.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{cursor:pointer}.rounded.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:.25rem}.bg-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(17 24 39 / var(--tw-bg-opacity))}.fill-current.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{fill:currentColor}.px-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-left:.5rem;padding-right:.5rem}.py-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:.25rem;padding-bottom:.25rem}.text-sm.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:.875rem;line-height:1.25rem}.font-medium.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-weight:500}.text-gray-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(249 250 251 / var(--tw-text-opacity))}.text-gray-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.opacity-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{opacity:0}.opacity-100.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{opacity:1}.shadow.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-shadow:0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.transition-opacity.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:text-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity))}button.svelte-18dlsnh{cursor:pointer;width:var(--size-full);height:var(--size-full)}.hidden.svelte-18dlsnh{display:none;height:0;position:absolute}.center.svelte-18dlsnh{display:flex;justify-content:center}.flex.svelte-18dlsnh{display:flex;justify-content:center;align-items:center}input.svelte-18dlsnh{display:none}div.svelte-1wj0ocy{display:flex;top:var(--size-2);right:var(--size-2);justify-content:flex-end;gap:var(--spacing-sm);z-index:var(--layer-1)}.not-absolute.svelte-1wj0ocy{margin:var(--size-1)}.py.svelte-18kpwjt{padding:10px 0}.btn.svelte-18kpwjt{margin:0 5px;padding:3px 15px;border:var(--button-border-width) solid var(--button-secondary-border-color);background:var(--button-secondary-background-fill);color:var(--button-secondary-text-color);border-radius:var(--button-large-radius);padding:var(--button-large-padding);font-weight:var(--button-large-text-weight);font-size:var(--button-large-text-size);cursor:pointer}.btn.svelte-18kpwjt:hover{border-color:var(--button-secondary-border-color-hover);background:var(--button-secondary-background-fill-hover);color:var(--button-secondary-text-color-hover);box-shadow:var(--button-shadow-hover)}.or.svelte-18kpwjt{color:var(--body-text-color-subdued);text-align:center;display:block}.wfull.svelte-18kpwjt{width:100%}.mt-2.svelte-18kpwjt{margin-top:2rem}.input.svelte-18kpwjt{box-shadow:var(--input-shadow);background:var(--input-background-fill);border:var(--input-border-width) solid var(--input-border-color);border-radius:var(--input-radius);margin:0 5px}.select.svelte-18kpwjt{outline:none;border:none}.flex.svelte-18kpwjt{display:flex;justify-content:space-between}.inp.svelte-18kpwjt{width:100%;border:0 #fff!important;outline:none!important}.inp.svelte-18kpwjt:focus,.inp.svelte-18kpwjt:hover{border:0!important;outline:none!important}.text-center.svelte-18kpwjt{text-align:center}svg.svelte-43sxxs.svelte-43sxxs{width:var(--size-20);height:var(--size-20)}svg.svelte-43sxxs path.svelte-43sxxs{fill:var(--loader-color)}div.svelte-43sxxs.svelte-43sxxs{z-index:var(--layer-2)}.margin.svelte-43sxxs.svelte-43sxxs{margin:var(--size-4)}.wrap.svelte-14miwb5.svelte-14miwb5{display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:var(--layer-5);transition:opacity .1s ease-in-out;border-radius:var(--block-radius);background:var(--block-background-fill);padding:0 var(--size-6);max-height:var(--size-screen-h);overflow:hidden;pointer-events:none}.wrap.center.svelte-14miwb5.svelte-14miwb5{top:0;right:0;left:0}.wrap.default.svelte-14miwb5.svelte-14miwb5{top:0;right:0;bottom:0;left:0}.hide.svelte-14miwb5.svelte-14miwb5{opacity:0;pointer-events:none}.generating.svelte-14miwb5.svelte-14miwb5{animation:svelte-14miwb5-pulse 2s cubic-bezier(.4,0,.6,1) infinite;border:2px solid var(--color-accent);background:transparent}.translucent.svelte-14miwb5.svelte-14miwb5{background:none}@keyframes svelte-14miwb5-pulse{0%,to{opacity:1}50%{opacity:.5}}.loading.svelte-14miwb5.svelte-14miwb5{z-index:var(--layer-2);color:var(--body-text-color)}.eta-bar.svelte-14miwb5.svelte-14miwb5{position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:left;opacity:.8;z-index:var(--layer-1);transition:10ms;background:var(--background-fill-secondary)}.progress-bar-wrap.svelte-14miwb5.svelte-14miwb5{border:1px solid var(--border-color-primary);background:var(--background-fill-primary);width:55.5%;height:var(--size-4)}.progress-bar.svelte-14miwb5.svelte-14miwb5{transform-origin:left;background-color:var(--loader-color);width:var(--size-full);height:var(--size-full)}.progress-level.svelte-14miwb5.svelte-14miwb5{display:flex;flex-direction:column;align-items:center;gap:1;z-index:var(--layer-2);width:var(--size-full)}.progress-level-inner.svelte-14miwb5.svelte-14miwb5{margin:var(--size-2) auto;color:var(--body-text-color);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text.svelte-14miwb5.svelte-14miwb5{position:absolute;top:0;right:0;z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text-center.svelte-14miwb5.svelte-14miwb5{display:flex;position:absolute;top:0;right:0;justify-content:center;align-items:center;transform:translateY(var(--size-6));z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono);text-align:center}.error.svelte-14miwb5.svelte-14miwb5{box-shadow:var(--shadow-drop);border:solid 1px var(--error-border-color);border-radius:var(--radius-full);background:var(--error-background-fill);padding-right:var(--size-4);padding-left:var(--size-4);color:var(--error-text-color);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--line-lg);font-family:var(--font)}.minimal.svelte-14miwb5 .progress-text.svelte-14miwb5{background:var(--block-background-fill)}.border.svelte-14miwb5.svelte-14miwb5{border:1px solid var(--border-color-primary)}.toast-body.svelte-solcu7{display:flex;position:relative;right:0;left:0;align-items:center;margin:var(--size-6) var(--size-4);margin:auto;border-radius:var(--container-radius);overflow:hidden;pointer-events:auto}.toast-body.error.svelte-solcu7{border:1px solid var(--color-red-700);background:var(--color-red-50)}.dark .toast-body.error.svelte-solcu7{border:1px solid var(--color-red-500);background-color:var(--color-grey-950)}.toast-body.warning.svelte-solcu7{border:1px solid var(--color-yellow-700);background:var(--color-yellow-50)}.dark .toast-body.warning.svelte-solcu7{border:1px solid var(--color-yellow-500);background-color:var(--color-grey-950)}.toast-body.info.svelte-solcu7{border:1px solid var(--color-grey-700);background:var(--color-grey-50)}.dark .toast-body.info.svelte-solcu7{border:1px solid var(--color-grey-500);background-color:var(--color-grey-950)}.toast-title.svelte-solcu7{display:flex;align-items:center;font-weight:var(--weight-bold);font-size:var(--text-lg);line-height:var(--line-sm);text-transform:capitalize}.toast-title.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-title.error.svelte-solcu7{color:var(--color-red-50)}.toast-title.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-title.warning.svelte-solcu7{color:var(--color-yellow-50)}.toast-title.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-title.info.svelte-solcu7{color:var(--color-grey-50)}.toast-close.svelte-solcu7{margin:0 var(--size-3);border-radius:var(--size-3);padding:0px var(--size-1-5);font-size:var(--size-5);line-height:var(--size-5)}.toast-close.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-close.error.svelte-solcu7{color:var(--color-red-500)}.toast-close.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-close.warning.svelte-solcu7{color:var(--color-yellow-500)}.toast-close.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-close.info.svelte-solcu7{color:var(--color-grey-500)}.toast-text.svelte-solcu7{font-size:var(--text-lg)}.toast-text.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-text.error.svelte-solcu7{color:var(--color-red-50)}.toast-text.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-text.warning.svelte-solcu7{color:var(--color-yellow-50)}.toast-text.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-text.info.svelte-solcu7{color:var(--color-grey-50)}.toast-details.svelte-solcu7{margin:var(--size-3) var(--size-3) var(--size-3) 0;width:100%}.toast-icon.svelte-solcu7{display:flex;position:absolute;position:relative;flex-shrink:0;justify-content:center;align-items:center;margin:var(--size-2);border-radius:var(--radius-full);padding:var(--size-1);padding-left:calc(var(--size-1) - 1px);width:35px;height:35px}.toast-icon.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-icon.error.svelte-solcu7{color:var(--color-red-500)}.toast-icon.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-icon.warning.svelte-solcu7{color:var(--color-yellow-500)}.toast-icon.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-icon.info.svelte-solcu7{color:var(--color-grey-500)}@keyframes svelte-solcu7-countdown{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.timer.svelte-solcu7{position:absolute;bottom:0;left:0;transform-origin:0 0;animation:svelte-solcu7-countdown 10s linear forwards;width:100%;height:var(--size-1)}.timer.error.svelte-solcu7{background:var(--color-red-700)}.dark .timer.error.svelte-solcu7{background:var(--color-red-500)}.timer.warning.svelte-solcu7{background:var(--color-yellow-700)}.dark .timer.warning.svelte-solcu7{background:var(--color-yellow-500)}.timer.info.svelte-solcu7{background:var(--color-grey-700)}.dark .timer.info.svelte-solcu7{background:var(--color-grey-500)}.toast-wrap.svelte-gatr8h{display:flex;position:fixed;top:var(--size-4);right:var(--size-4);flex-direction:column;align-items:end;gap:var(--size-2);z-index:var(--layer-top);width:calc(100% - var(--size-8))}@media (--screen-sm){.toast-wrap.svelte-gatr8h{width:calc(var(--size-96) + var(--size-10))}}div.svelte-1hgn91n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gallery.svelte-1hgn91n{display:flex;align-items:center;cursor:pointer;padding:var(--size-1) var(--size-2);text-align:left}.sr-only.svelte-1j3z0by{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.mb-4.svelte-1j3z0by{margin-bottom:1rem}.ml-4.svelte-1j3z0by{margin-left:1rem}.mr-3.svelte-1j3z0by{margin-right:.75rem}.mt-1\.5.svelte-1j3z0by{margin-top:.375rem}.mt-\[2px\].svelte-1j3z0by{margin-top:2px}.inline.svelte-1j3z0by{display:inline}.flex.svelte-1j3z0by{display:flex}.h-4.svelte-1j3z0by{height:1rem}.w-4.svelte-1j3z0by{width:1rem}.flex-shrink-0.svelte-1j3z0by{flex-shrink:0}.list-inside.svelte-1j3z0by{list-style-position:inside}.list-disc.svelte-1j3z0by{list-style-type:disc}.rounded-lg.svelte-1j3z0by{border-radius:.5rem}.bg-red-50.svelte-1j3z0by{--tw-bg-opacity:1;background-color:rgb(254 242 242 / var(--tw-bg-opacity))}.m-2.svelte-1j3z0by{margin:.5rem}.p-4.svelte-1j3z0by{padding:1rem}.text-sm.svelte-1j3z0by{font-size:.875rem;line-height:1.25rem}.font-medium.svelte-1j3z0by{font-weight:500}.text-red-800.svelte-1j3z0by{--tw-text-opacity:1;color:rgb(153 27 27 / var(--tw-text-opacity))}@media (prefers-color-scheme: dark){.dark\:bg-gray-800.svelte-1j3z0by{--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:text-red-400.svelte-1j3z0by{--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity))}}
 
1
+ .block.svelte-1t38q2d{position:relative;margin:0;box-shadow:var(--block-shadow);border-width:var(--block-border-width);border-color:var(--block-border-color);border-radius:var(--block-radius);background:var(--block-background-fill);width:100%;line-height:var(--line-sm)}.block.border_focus.svelte-1t38q2d{border-color:var(--color-accent)}.padded.svelte-1t38q2d{padding:var(--block-padding)}.hidden.svelte-1t38q2d{display:none}.hide-container.svelte-1t38q2d{margin:0;box-shadow:none;--block-border-width:0;background:transparent;padding:0;overflow:visible}div.svelte-1hnfib2{margin-bottom:var(--spacing-lg);color:var(--block-info-text-color);font-weight:var(--block-info-text-weight);font-size:var(--block-info-text-size);line-height:var(--line-sm)}span.has-info.svelte-22c38v{margin-bottom:var(--spacing-xs)}span.svelte-22c38v:not(.has-info){margin-bottom:var(--spacing-lg)}span.svelte-22c38v{display:inline-block;position:relative;z-index:var(--layer-4);border:solid var(--block-title-border-width) var(--block-title-border-color);border-radius:var(--block-title-radius);background:var(--block-title-background-fill);padding:var(--block-title-padding);color:var(--block-title-text-color);font-weight:var(--block-title-text-weight);font-size:var(--block-title-text-size);line-height:var(--line-sm)}.hide.svelte-22c38v{margin:0;height:0}label.svelte-9gxdi0{display:inline-flex;align-items:center;z-index:var(--layer-2);box-shadow:var(--block-label-shadow);border:var(--block-label-border-width) solid var(--border-color-primary);border-top:none;border-left:none;border-radius:var(--block-label-radius);background:var(--block-label-background-fill);padding:var(--block-label-padding);pointer-events:none;color:var(--block-label-text-color);font-weight:var(--block-label-text-weight);font-size:var(--block-label-text-size);line-height:var(--line-sm)}.gr-group label.svelte-9gxdi0{border-top-left-radius:0}label.float.svelte-9gxdi0{position:absolute;top:var(--block-label-margin);left:var(--block-label-margin)}label.svelte-9gxdi0:not(.float){position:static;margin-top:var(--block-label-margin);margin-left:var(--block-label-margin)}.hide.svelte-9gxdi0{height:0}span.svelte-9gxdi0{opacity:.8;margin-right:var(--size-2);width:calc(var(--block-label-text-size) - 1px);height:calc(var(--block-label-text-size) - 1px)}.hide-label.svelte-9gxdi0{box-shadow:none;border-width:0;background:transparent;overflow:visible}button.svelte-xtz2g8{display:flex;justify-content:center;align-items:center;gap:1px;z-index:var(--layer-2);border-radius:var(--radius-sm);color:var(--block-label-text-color);border:1px solid transparent}.padded.svelte-xtz2g8{padding:2px;background:var(--background-fill-primary);box-shadow:var(--shadow-drop);border:1px solid var(--button-secondary-border-color)}button.svelte-xtz2g8:hover{cursor:pointer;color:var(--color-accent)}.padded.svelte-xtz2g8:hover{border:2px solid var(--button-secondary-border-color-hover);padding:1px;color:var(--block-label-text-color)}span.svelte-xtz2g8{padding:0 1px;font-size:10px}div.svelte-xtz2g8{padding:2px;display:flex;align-items:flex-end}.small.svelte-xtz2g8{width:14px;height:14px}.large.svelte-xtz2g8{width:22px;height:22px}.pending.svelte-xtz2g8{animation:svelte-xtz2g8-flash .5s infinite}@keyframes svelte-xtz2g8-flash{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.empty.svelte-3w3rth{display:flex;justify-content:center;align-items:center;margin-top:calc(0px - var(--size-6));height:var(--size-full)}.icon.svelte-3w3rth{opacity:.5;height:var(--size-5);color:var(--body-text-color)}.small.svelte-3w3rth{min-height:calc(var(--size-32) - 20px)}.large.svelte-3w3rth{min-height:calc(var(--size-64) - 20px)}.unpadded_box.svelte-3w3rth{margin-top:0}.small_parent.svelte-3w3rth{min-height:100%!important}.dropdown-arrow.svelte-145leq6{fill:currentColor}.wrap.svelte-kzcjhc{display:flex;flex-direction:column;justify-content:center;align-items:center;min-height:var(--size-60);color:var(--block-label-text-color);line-height:var(--line-md);height:100%;padding-top:var(--size-3)}.or.svelte-kzcjhc{color:var(--body-text-color-subdued);display:flex}.icon-wrap.svelte-kzcjhc{width:30px;margin-bottom:var(--spacing-lg)}@media (--screen-md){.wrap.svelte-kzcjhc{font-size:var(--text-lg)}}.hovered.svelte-kzcjhc{color:var(--color-accent)}div.svelte-1nba87b{border-top:1px solid transparent;display:flex;max-height:100%;justify-content:center;gap:var(--spacing-sm);height:auto;align-items:flex-end;box-shadow:var(--shadow-drop);padding:var(--spacing-xl) 0;color:var(--block-label-text-color);flex-shrink:0;width:95%}.show_border.svelte-1nba87b{border-top:1px solid var(--block-border-color);margin-top:var(--spacing-xxl)}td.svelte-usqupg.svelte-usqupg{width:45%}td.svelte-usqupg.svelte-usqupg:last-child{width:10%;text-align:right}.file-preview-holder.svelte-usqupg.svelte-usqupg{overflow-x:auto;overflow-y:auto}.file-preview.svelte-usqupg.svelte-usqupg{width:var(--size-full);max-height:var(--size-60);overflow-y:auto;margin-top:var(--size-1);color:var(--body-text-color)}.file.svelte-usqupg.svelte-usqupg{width:var(--size-full)}.file.svelte-usqupg>.svelte-usqupg{padding:var(--size-1) var(--size-2-5)}.download.svelte-usqupg.svelte-usqupg:hover{text-decoration:underline}.download.svelte-usqupg>a.svelte-usqupg{color:var(--link-text-color)}.download.svelte-usqupg>a.svelte-usqupg:hover{color:var(--link-text-color-hover)}.download.svelte-usqupg>a.svelte-usqupg:visited{color:var(--link-text-color-visited)}.download.svelte-usqupg>a.svelte-usqupg:active{color:var(--link-text-color-active)}.selectable.svelte-usqupg.svelte-usqupg{cursor:pointer}tbody.svelte-usqupg>tr.svelte-usqupg:nth-child(2n){background:var(--block-background-fill)}tbody.svelte-usqupg>tr.svelte-usqupg:nth-child(odd){background:var(--table-odd-background-fill)}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-content:""}h5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:inherit;font-weight:inherit}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,select.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,select.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{text-transform:none}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,[type=button].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{-webkit-appearance:button;background-color:transparent;background-image:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:-moz-focusring{outline:auto}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:-moz-ui-invalid{box-shadow:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-inner-spin-button,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-outer-spin-button{height:auto}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-search-decoration{-webkit-appearance:none}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}h5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin:0}input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-moz-placeholder{opacity:1;color:#9ca3af}input.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::placeholder{opacity:1;color:#9ca3af}button.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{cursor:pointer}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:disabled{cursor:default}svg.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:block;vertical-align:middle}.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:before,.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.absolute.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:absolute}.relative.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{position:relative}.bottom-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{bottom:0}.left-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{left:0}.right-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{right:0}.right-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{right:.625rem}.top-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:0}.top-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:.625rem}.z-10.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{z-index:10}.z-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{z-index:50}.my-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-top:.5rem;margin-bottom:.5rem}.mb-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-bottom:.5rem}.mb-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-bottom:1rem}.mr-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-right:.5rem}.ml-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-left:.5rem}.mr-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-right:1.25rem}.mt-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{margin-top:.5rem}.block.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:block}.flex.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:flex}.inline-flex.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{display:inline-flex}.h-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:.5rem}.h-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1.25rem}.h-6.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1.5rem}.h-8.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:2rem}.h-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:100%}.w-1\/2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:50%}.w-1\/3.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:33.333333%}.w-11.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:2.75rem}.w-2\/3.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:66.666667%}.w-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:1.25rem}.w-8.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:2rem}.w-80.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:20rem}.w-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:100%}.rotate-90.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.appearance-none.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-col.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{flex-direction:column}.flex-wrap.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{flex-wrap:wrap}.items-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{align-items:center}.justify-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{justify-content:center}.gap-px.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{gap:1px}.space-x-1.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.divide-x.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-divide-x-reverse:0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-y.svelte-1skivl7>.svelte-1skivl7:not([hidden])~.svelte-1skivl7:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.overflow-hidden.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{overflow:hidden}.overflow-y-auto.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{overflow-y:auto}.rounded-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:9999px}.rounded-lg.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:.5rem}.border.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-width:1px}.border-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-width:4px}.border-b.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-bottom-width:1px}.border-l.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-left-width:1px}.border-t.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-top-width:1px}.border-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(156 163 175 / var(--tw-border-opacity))}.border-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.bg-black.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-blue-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-cyan-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(8 145 178 / var(--tw-bg-opacity))}.bg-gray-100.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-green-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.bg-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(234 88 12 / var(--tw-bg-opacity))}.bg-red-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-transparent.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{background-color:transparent}.bg-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.25rem}.p-1\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.375rem}.p-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.5rem}.p-2\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:.625rem}.p-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding:1rem}.px-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-left:1rem;padding-right:1rem}.py-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:.5rem;padding-bottom:.5rem}.py-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:1rem;padding-bottom:1rem}.text-center.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{text-align:center}.text-base.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:1rem;line-height:1.5rem}.font-semibold.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-weight:600}.text-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity))}.transition-transform.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.sr-only.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{clip:rect(0,0,0,0);position:absolute;margin:-1px;border-width:0;padding:0;width:1px;height:1px;overflow:hidden;white-space:nowrap}.after\:absolute.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);position:absolute}.after\:left-\[2px\].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);left:2px}.after\:top-0\.5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);top:.125rem}.after\:h-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);height:1.25rem}.after\:w-5.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);width:1.25rem}.after\:rounded-full.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);border-radius:9999px}.after\:border.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);border-width:1px}.after\:border-gray-300.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.after\:bg-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\].svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:after{--tw-content:"";content:var(--tw-content)}.hover\:bg-gray-200.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:text-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:border-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-border-opacity:1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:ring-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246 / var(--tw-ring-opacity))}.peer.svelte-1skivl7:checked~.peer-checked\:bg-orange-400.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(251 146 60 / var(--tw-bg-opacity))}.peer.svelte-1skivl7:checked~.peer-checked\:after\:translate-x-full.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer.svelte-1skivl7:checked~.peer-checked\:after\:border-white.svelte-1skivl7.svelte-1skivl7:after{content:var(--tw-content);--tw-border-opacity:1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.peer.svelte-1skivl7:focus~.peer-focus\:ring-4.svelte-1skivl7.svelte-1skivl7{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.peer.svelte-1skivl7:focus~.peer-focus\:ring-orange-300.svelte-1skivl7.svelte-1skivl7{--tw-ring-opacity:1;--tw-ring-color:rgb(253 186 116 / var(--tw-ring-opacity))}@media (prefers-color-scheme: dark){.dark\:border-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-border-opacity:1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:bg-gray-800.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:text-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7::placeholder{--tw-placeholder-opacity:1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:hover\:bg-gray-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.dark\:hover\:text-white.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:focus\:border-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-border-opacity:1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246 / var(--tw-ring-opacity))}.peer.svelte-1skivl7:focus~.dark\:peer-focus\:ring-orange-800.svelte-1skivl7.svelte-1skivl7{--tw-ring-opacity:1;--tw-ring-color:rgb(154 52 18 / var(--tw-ring-opacity))}}.minh.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:600px}.-top-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{top:-.25rem}.left-6.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{left:1.5rem}.h-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{height:1rem}.w-4.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:1rem}.w-max.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{width:max-content}.cursor-pointer.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{cursor:pointer}.rounded.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{border-radius:.25rem}.bg-gray-900.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-bg-opacity:1;background-color:rgb(17 24 39 / var(--tw-bg-opacity))}.fill-current.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{fill:currentColor}.px-2.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-left:.5rem;padding-right:.5rem}.py-1.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{padding-top:.25rem;padding-bottom:.25rem}.text-sm.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-size:.875rem;line-height:1.25rem}.font-medium.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{font-weight:500}.text-gray-50.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(249 250 251 / var(--tw-text-opacity))}.text-gray-500.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.opacity-0.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{opacity:0}.opacity-100.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{opacity:1}.shadow.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{--tw-shadow:0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.transition-opacity.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:text-orange-600.svelte-1skivl7.svelte-1skivl7.svelte-1skivl7:hover{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity))}button.svelte-18dlsnh{cursor:pointer;width:var(--size-full);height:var(--size-full)}.hidden.svelte-18dlsnh{display:none;height:0;position:absolute}.center.svelte-18dlsnh{display:flex;justify-content:center}.flex.svelte-18dlsnh{display:flex;justify-content:center;align-items:center}input.svelte-18dlsnh{display:none}div.svelte-1wj0ocy{display:flex;top:var(--size-2);right:var(--size-2);justify-content:flex-end;gap:var(--spacing-sm);z-index:var(--layer-1)}.not-absolute.svelte-1wj0ocy{margin:var(--size-1)}.py.svelte-1nnwgsd{padding:10px 0}.btn.svelte-1nnwgsd{margin:0 5px;padding:3px 15px;border:var(--button-border-width) solid var(--button-secondary-border-color);background:var(--button-secondary-background-fill);color:var(--button-secondary-text-color);border-radius:var(--button-large-radius);padding:var(--button-large-padding);font-weight:var(--button-large-text-weight);font-size:var(--button-large-text-size);cursor:pointer}.btn.svelte-1nnwgsd:hover{border-color:var(--button-secondary-border-color-hover);background:var(--button-secondary-background-fill-hover);color:var(--button-secondary-text-color-hover);box-shadow:var(--button-shadow-hover)}.or.svelte-1nnwgsd{color:var(--body-text-color-subdued);text-align:center;display:block}.wfull.svelte-1nnwgsd{width:100%}.mt-2.svelte-1nnwgsd{margin-top:2rem}.input.svelte-1nnwgsd{box-shadow:var(--input-shadow);background:var(--input-background-fill);border:var(--input-border-width) solid var(--input-border-color);border-radius:var(--input-radius);margin:0 5px}.select.svelte-1nnwgsd{outline:none;border:none}.flex.svelte-1nnwgsd{display:flex;justify-content:space-between}.inp.svelte-1nnwgsd{width:100%;border:0 #fff!important;outline:none!important}.inp.svelte-1nnwgsd:focus,.inp.svelte-1nnwgsd:hover{border:0!important;outline:none!important}.text-center.svelte-1nnwgsd{text-align:center}svg.svelte-43sxxs.svelte-43sxxs{width:var(--size-20);height:var(--size-20)}svg.svelte-43sxxs path.svelte-43sxxs{fill:var(--loader-color)}div.svelte-43sxxs.svelte-43sxxs{z-index:var(--layer-2)}.margin.svelte-43sxxs.svelte-43sxxs{margin:var(--size-4)}.wrap.svelte-14miwb5.svelte-14miwb5{display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:var(--layer-5);transition:opacity .1s ease-in-out;border-radius:var(--block-radius);background:var(--block-background-fill);padding:0 var(--size-6);max-height:var(--size-screen-h);overflow:hidden;pointer-events:none}.wrap.center.svelte-14miwb5.svelte-14miwb5{top:0;right:0;left:0}.wrap.default.svelte-14miwb5.svelte-14miwb5{top:0;right:0;bottom:0;left:0}.hide.svelte-14miwb5.svelte-14miwb5{opacity:0;pointer-events:none}.generating.svelte-14miwb5.svelte-14miwb5{animation:svelte-14miwb5-pulse 2s cubic-bezier(.4,0,.6,1) infinite;border:2px solid var(--color-accent);background:transparent}.translucent.svelte-14miwb5.svelte-14miwb5{background:none}@keyframes svelte-14miwb5-pulse{0%,to{opacity:1}50%{opacity:.5}}.loading.svelte-14miwb5.svelte-14miwb5{z-index:var(--layer-2);color:var(--body-text-color)}.eta-bar.svelte-14miwb5.svelte-14miwb5{position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:left;opacity:.8;z-index:var(--layer-1);transition:10ms;background:var(--background-fill-secondary)}.progress-bar-wrap.svelte-14miwb5.svelte-14miwb5{border:1px solid var(--border-color-primary);background:var(--background-fill-primary);width:55.5%;height:var(--size-4)}.progress-bar.svelte-14miwb5.svelte-14miwb5{transform-origin:left;background-color:var(--loader-color);width:var(--size-full);height:var(--size-full)}.progress-level.svelte-14miwb5.svelte-14miwb5{display:flex;flex-direction:column;align-items:center;gap:1;z-index:var(--layer-2);width:var(--size-full)}.progress-level-inner.svelte-14miwb5.svelte-14miwb5{margin:var(--size-2) auto;color:var(--body-text-color);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text.svelte-14miwb5.svelte-14miwb5{position:absolute;top:0;right:0;z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text-center.svelte-14miwb5.svelte-14miwb5{display:flex;position:absolute;top:0;right:0;justify-content:center;align-items:center;transform:translateY(var(--size-6));z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono);text-align:center}.error.svelte-14miwb5.svelte-14miwb5{box-shadow:var(--shadow-drop);border:solid 1px var(--error-border-color);border-radius:var(--radius-full);background:var(--error-background-fill);padding-right:var(--size-4);padding-left:var(--size-4);color:var(--error-text-color);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--line-lg);font-family:var(--font)}.minimal.svelte-14miwb5 .progress-text.svelte-14miwb5{background:var(--block-background-fill)}.border.svelte-14miwb5.svelte-14miwb5{border:1px solid var(--border-color-primary)}.toast-body.svelte-solcu7{display:flex;position:relative;right:0;left:0;align-items:center;margin:var(--size-6) var(--size-4);margin:auto;border-radius:var(--container-radius);overflow:hidden;pointer-events:auto}.toast-body.error.svelte-solcu7{border:1px solid var(--color-red-700);background:var(--color-red-50)}.dark .toast-body.error.svelte-solcu7{border:1px solid var(--color-red-500);background-color:var(--color-grey-950)}.toast-body.warning.svelte-solcu7{border:1px solid var(--color-yellow-700);background:var(--color-yellow-50)}.dark .toast-body.warning.svelte-solcu7{border:1px solid var(--color-yellow-500);background-color:var(--color-grey-950)}.toast-body.info.svelte-solcu7{border:1px solid var(--color-grey-700);background:var(--color-grey-50)}.dark .toast-body.info.svelte-solcu7{border:1px solid var(--color-grey-500);background-color:var(--color-grey-950)}.toast-title.svelte-solcu7{display:flex;align-items:center;font-weight:var(--weight-bold);font-size:var(--text-lg);line-height:var(--line-sm);text-transform:capitalize}.toast-title.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-title.error.svelte-solcu7{color:var(--color-red-50)}.toast-title.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-title.warning.svelte-solcu7{color:var(--color-yellow-50)}.toast-title.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-title.info.svelte-solcu7{color:var(--color-grey-50)}.toast-close.svelte-solcu7{margin:0 var(--size-3);border-radius:var(--size-3);padding:0px var(--size-1-5);font-size:var(--size-5);line-height:var(--size-5)}.toast-close.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-close.error.svelte-solcu7{color:var(--color-red-500)}.toast-close.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-close.warning.svelte-solcu7{color:var(--color-yellow-500)}.toast-close.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-close.info.svelte-solcu7{color:var(--color-grey-500)}.toast-text.svelte-solcu7{font-size:var(--text-lg)}.toast-text.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-text.error.svelte-solcu7{color:var(--color-red-50)}.toast-text.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-text.warning.svelte-solcu7{color:var(--color-yellow-50)}.toast-text.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-text.info.svelte-solcu7{color:var(--color-grey-50)}.toast-details.svelte-solcu7{margin:var(--size-3) var(--size-3) var(--size-3) 0;width:100%}.toast-icon.svelte-solcu7{display:flex;position:absolute;position:relative;flex-shrink:0;justify-content:center;align-items:center;margin:var(--size-2);border-radius:var(--radius-full);padding:var(--size-1);padding-left:calc(var(--size-1) - 1px);width:35px;height:35px}.toast-icon.error.svelte-solcu7{color:var(--color-red-700)}.dark .toast-icon.error.svelte-solcu7{color:var(--color-red-500)}.toast-icon.warning.svelte-solcu7{color:var(--color-yellow-700)}.dark .toast-icon.warning.svelte-solcu7{color:var(--color-yellow-500)}.toast-icon.info.svelte-solcu7{color:var(--color-grey-700)}.dark .toast-icon.info.svelte-solcu7{color:var(--color-grey-500)}@keyframes svelte-solcu7-countdown{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.timer.svelte-solcu7{position:absolute;bottom:0;left:0;transform-origin:0 0;animation:svelte-solcu7-countdown 10s linear forwards;width:100%;height:var(--size-1)}.timer.error.svelte-solcu7{background:var(--color-red-700)}.dark .timer.error.svelte-solcu7{background:var(--color-red-500)}.timer.warning.svelte-solcu7{background:var(--color-yellow-700)}.dark .timer.warning.svelte-solcu7{background:var(--color-yellow-500)}.timer.info.svelte-solcu7{background:var(--color-grey-700)}.dark .timer.info.svelte-solcu7{background:var(--color-grey-500)}.toast-wrap.svelte-gatr8h{display:flex;position:fixed;top:var(--size-4);right:var(--size-4);flex-direction:column;align-items:end;gap:var(--size-2);z-index:var(--layer-top);width:calc(100% - var(--size-8))}@media (--screen-sm){.toast-wrap.svelte-gatr8h{width:calc(var(--size-96) + var(--size-10))}}div.svelte-1hgn91n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gallery.svelte-1hgn91n{display:flex;align-items:center;cursor:pointer;padding:var(--size-1) var(--size-2);text-align:left}.sr-only.svelte-1xezsv6{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.mb-4.svelte-1xezsv6{margin-bottom:1rem}.ml-4.svelte-1xezsv6{margin-left:1rem}.mr-3.svelte-1xezsv6{margin-right:.75rem}.mt-1\.5.svelte-1xezsv6{margin-top:.375rem}.mt-\[2px\].svelte-1xezsv6{margin-top:2px}.inline.svelte-1xezsv6{display:inline}.flex.svelte-1xezsv6{display:flex}.h-4.svelte-1xezsv6{height:1rem}.w-4.svelte-1xezsv6{width:1rem}.flex-shrink-0.svelte-1xezsv6{flex-shrink:0}.list-inside.svelte-1xezsv6{list-style-position:inside}.list-disc.svelte-1xezsv6{list-style-type:disc}.rounded-lg.svelte-1xezsv6{border-radius:.5rem}.bg-red-50.svelte-1xezsv6{--tw-bg-opacity:1;background-color:rgb(254 242 242 / var(--tw-bg-opacity))}.m-2.svelte-1xezsv6{margin:.5rem}.p-4.svelte-1xezsv6{padding:1rem}.text-sm.svelte-1xezsv6{font-size:.875rem;line-height:1.25rem}.font-medium.svelte-1xezsv6{font-weight:500}.text-red-800.svelte-1xezsv6{--tw-text-opacity:1;color:rgb(153 27 27 / var(--tw-text-opacity))}@media (prefers-color-scheme: dark){.dark\:bg-gray-800.svelte-1xezsv6{--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:text-red-400.svelte-1xezsv6{--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity))}}
src/demo/app.py CHANGED
@@ -12,34 +12,58 @@ reps = [
12
  "model": 0,
13
  "chain": "",
14
  "resname": "",
15
- "style": "cartoon",
16
  "color": "whiteCarbon",
17
  "residue_range": "",
18
  "around": 0,
19
  "byres": False,
20
- "visible": False,
21
- },
22
  ]
23
 
 
 
24
  def predict(x):
25
  print("predict function", x)
 
26
  return x
27
 
28
- #doesn't work
29
- demo = gr.Interface(
30
- predict,
31
- Molecule3D(label="Molecule3D", reps=reps), # interactive version of your component
32
- Molecule3D(reps=reps), # static version of your component
33
- #examples=[[example]], # uncomment this line to view the "example version" of your component
34
- )
35
-
36
- #works
37
- # with gr.Blocks() as demo:
38
- # inp = Molecule3D("demo/1pga.pdb",label="Molecule3D", reps=reps)
39
- # inp = Molecule3D("demo/1pga.pdb",label="Molecule3D", reps=reps, showviewer=False)
40
- # out = Molecule3D(label="Molecule3D", reps=reps)
41
- # btn = gr.Button("Predict")
42
- # btn.click(predict, inputs=inp, outputs=out)
43
-
44
- if __name__ == "__main__":
45
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  "model": 0,
13
  "chain": "",
14
  "resname": "",
15
+ "style": "stick",
16
  "color": "whiteCarbon",
17
  "residue_range": "",
18
  "around": 0,
19
  "byres": False,
20
+ "visible": False
21
+ }
22
  ]
23
 
24
+
25
+
26
  def predict(x):
27
  print("predict function", x)
28
+ print(x.name)
29
  return x
30
 
31
+ with gr.Blocks() as demo:
32
+ inp = Molecule3D(label="Molecule3D", reps=reps)
33
+ out = Molecule3D(label="Output", reps=reps)
34
+
35
+ btn = gr.Button("Predict")
36
+ gr.Markdown("""
37
+ You can configure the default rendering of the molecule by adding a list of representations
38
+ <pre>
39
+ reps = [
40
+ {
41
+ "model": 0,
42
+ "chain": "",
43
+ "resname": "",
44
+ "style": "cartoon",
45
+ "color": "whiteCarbon",
46
+ "residue_range": "",
47
+ "around": 0,
48
+ "byres": False,
49
+ "visible": False,
50
+ },
51
+ {
52
+ "model": 0,
53
+ "chain": "A",
54
+ "resname": "HIS",
55
+ "style": "stick",
56
+ "color": "red",
57
+ "residue_range": "",
58
+ "around": 0,
59
+ "byres": False,
60
+ "visible": False,
61
+ }
62
+ ]
63
+ </pre>
64
+ """)
65
+ btn.click(predict, inputs=inp, outputs=out)
66
+
67
+
68
+ if __name__ == '__main__':
69
+ demo.launch()
src/demo/css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
src/demo/space.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading generic file (when used as an input) and or displaying generic files (output).', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': 'Literal["single", "multiple", "directory"]', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': 'Literal["filepath", "binary"]', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'float | None', 'default': 'None', 'description': "If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': "The output data received by the component from the user's function in the backend."}}, 'preprocess': {'return': {'type': 'bytes | NamedString | list[bytes | NamedString] | None', 'description': "The preprocessed input data sent to the user's function in the backend."}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the X button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_molecule3d`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
+ </div>
26
+
27
+ Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_molecule3d
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+
42
+ import gradio as gr
43
+ from gradio_molecule3d import Molecule3D
44
+
45
+ import os
46
+
47
+ example = Molecule3D().example_inputs()
48
+
49
+
50
+ reps = [
51
+ {
52
+ "model": 0,
53
+ "chain": "",
54
+ "resname": "",
55
+ "style": "stick",
56
+ "color": "whiteCarbon",
57
+ "residue_range": "",
58
+ "around": 0,
59
+ "byres": False,
60
+ "visible": False
61
+ }
62
+ ]
63
+
64
+
65
+
66
+ def predict(x):
67
+ print("predict function", x)
68
+ print(x.name)
69
+ return x
70
+
71
+ with gr.Blocks() as demo:
72
+ inp = Molecule3D(label="Molecule3D", reps=reps)
73
+ out = Molecule3D(label="Output", reps=reps)
74
+
75
+ btn = gr.Button("Predict")
76
+ gr.Markdown(\"\"\"
77
+ You can configure the default rendering of the molecule by adding a list of representations
78
+ <pre>
79
+ reps = [
80
+ {
81
+ "model": 0,
82
+ "chain": "",
83
+ "resname": "",
84
+ "style": "cartoon",
85
+ "color": "whiteCarbon",
86
+ "residue_range": "",
87
+ "around": 0,
88
+ "byres": False,
89
+ "visible": False,
90
+ },
91
+ {
92
+ "model": 0,
93
+ "chain": "A",
94
+ "resname": "HIS",
95
+ "style": "stick",
96
+ "color": "red",
97
+ "residue_range": "",
98
+ "around": 0,
99
+ "byres": False,
100
+ "visible": False,
101
+ }
102
+ ]
103
+ </pre>
104
+ \"\"\")
105
+ btn.click(predict, inputs=inp, outputs=out)
106
+
107
+
108
+ if __name__ == '__main__':
109
+ demo.launch()
110
+
111
+ ```
112
+ """, elem_classes=["md-custom"], header_links=True)
113
+
114
+
115
+ gr.Markdown("""
116
+ ## `Molecule3D`
117
+
118
+ ### Initialization
119
+ """, elem_classes=["md-custom"], header_links=True)
120
+
121
+ gr.ParamViewer(value=_docs["Molecule3D"]["members"]["__init__"], linkify=[])
122
+
123
+
124
+ gr.Markdown("### Events")
125
+ gr.ParamViewer(value=_docs["Molecule3D"]["events"], linkify=['Event'])
126
+
127
+
128
+
129
+
130
+ gr.Markdown("""
131
+
132
+ ### User function
133
+
134
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
135
+
136
+ - When used as an Input, the component only impacts the input signature of the user function.
137
+ - When used as an output, the component only impacts the return signature of the user function.
138
+
139
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
140
+
141
+ - **As input:** Is passed, the preprocessed input data sent to the user's function in the backend.
142
+ - **As output:** Should return, the output data received by the component from the user's function in the backend.
143
+
144
+ ```python
145
+ def predict(
146
+ value: bytes | NamedString | list[bytes | NamedString] | None
147
+ ) -> str | list[str] | None:
148
+ return value
149
+ ```
150
+ """, elem_classes=["md-custom", "Molecule3D-user-fn"], header_links=True)
151
+
152
+
153
+
154
+
155
+ demo.load(None, js=r"""function() {
156
+ const refs = {};
157
+ const user_fn_refs = {
158
+ Molecule3D: [], };
159
+ requestAnimationFrame(() => {
160
+
161
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
162
+ if (refs.length > 0) {
163
+ const el = document.querySelector(`.${key}-user-fn`);
164
+ if (!el) return;
165
+ refs.forEach(ref => {
166
+ el.innerHTML = el.innerHTML.replace(
167
+ new RegExp("\\b"+ref+"\\b", "g"),
168
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
169
+ );
170
+ })
171
+ }
172
+ })
173
+
174
+ Object.entries(refs).forEach(([key, refs]) => {
175
+ if (refs.length > 0) {
176
+ const el = document.querySelector(`.${key}`);
177
+ if (!el) return;
178
+ refs.forEach(ref => {
179
+ el.innerHTML = el.innerHTML.replace(
180
+ new RegExp("\\b"+ref+"\\b", "g"),
181
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
182
+ );
183
+ })
184
+ }
185
+ })
186
+ })
187
+ }
188
+
189
+ """)
190
+
191
+ demo.launch()
src/frontend/Index.svelte CHANGED
@@ -11,30 +11,24 @@
11
  import type { Gradio, SelectData } from "@gradio/utils";
12
  import File from "./shared/File.svelte";
13
  import FileUpload from "./shared/FileUpload.svelte";
14
-
15
  import { type FileData } from "@gradio/client";
16
  import { Block, UploadText } from "@gradio/atoms";
17
-
18
  import { StatusTracker } from "@gradio/statustracker";
19
  import type { LoadingStatus } from "@gradio/statustracker";
20
-
21
  export let elem_id = "";
22
  export let elem_classes: string[] = [];
23
  export let visible = true;
24
  export let value: null | FileData | FileData[];
25
-
26
  export let interactive: boolean;
27
  export let root: string;
28
  export let label: string;
29
  export let show_label: boolean;
30
  export let height: number | undefined = undefined;
31
-
32
  //Molecule3D specific arguments
33
  export let reps: any = [];
34
  export let config: any = {};
35
  export let confidenceLabel: string = "";
36
  export let showviewer: boolean = true;
37
-
38
  export let _selectable = false;
39
  export let loading_status: LoadingStatus;
40
  export let container = true;
@@ -49,17 +43,16 @@
49
  }>;
50
  export let file_count: string;
51
  export let file_types: string[] = ["file"];
52
-
53
  let old_value = value;
54
  $: if (JSON.stringify(old_value) !== JSON.stringify(value)) {
55
  gradio.dispatch("change");
56
  old_value = value;
57
  console.log("value change", value);
 
 
58
  }
59
-
60
  let dragging = false;
61
  let pending_upload = false;
62
-
63
  //check for missing keys in reps
64
  let keys_for_reps = {
65
  model: {
@@ -115,10 +108,8 @@
115
  default: true,
116
  },
117
  };
118
-
119
  let moldata = null;
120
-
121
- let allowed_extensions = ["pdb", "sdf", "mol2"];
122
  async function fetchFileContent(url) {
123
  const response = await fetch(url);
124
  const content = await response.text();
@@ -126,14 +117,12 @@
126
  }
127
  let promise = null;
128
  let errors = [];
129
-
130
  async function retrieveContent(value) {
131
  if (value == null) {
132
  return [];
133
  } else if (Array.isArray(value)) {
134
  let tempMoldata = [];
135
  // get file extension
136
-
137
  for (const element of value) {
138
  let ext = element.orig_name.split(".").pop();
139
  if (!allowed_extensions.includes(ext)) {
@@ -164,9 +153,12 @@
164
  moldata = null;
165
  } else {
166
  let t = await fetchFileContent(value.url);
167
- console.log("t", t);
 
 
 
168
  moldata = [
169
- { data: t, name: value.orig_name, format: "pdb", asFrames: false },
170
  ];
171
  }
172
  } else {
@@ -175,10 +167,8 @@
175
  // value is object
176
  }
177
  // go through each rep, do a type check and add missing keys to the rep
178
-
179
  let lenMoldata = 0;
180
  $: lenMoldata = moldata ? moldata.length : 0;
181
-
182
  let representations = [];
183
  //first add all missing keys
184
  $: {
@@ -203,7 +193,6 @@
203
  }
204
  });
205
  }
206
-
207
  $: promise = retrieveContent(value);
208
  </script>
209
 
@@ -232,7 +221,7 @@
232
  <File
233
  on:select={({ detail }) => gradio.dispatch("select", detail)}
234
  selectable={_selectable}
235
- value={value}
236
  {label}
237
  {show_label}
238
  {height}
@@ -248,7 +237,7 @@
248
  <FileUpload
249
  {label}
250
  {show_label}
251
- value={value}
252
  {file_count}
253
  {file_types}
254
  selectable={_selectable}
@@ -325,63 +314,48 @@
325
  white-space: nowrap;
326
  border-width: 0;
327
  }
328
-
329
  .mb-4 {
330
  margin-bottom: 1rem;
331
  }
332
-
333
  .ml-4 {
334
  margin-left: 1rem;
335
  }
336
-
337
  .mr-3 {
338
  margin-right: 0.75rem;
339
  }
340
-
341
  .mt-1 {
342
  margin-top: 0.25rem;
343
  }
344
-
345
  .mt-1\.5 {
346
  margin-top: 0.375rem;
347
  }
348
-
349
  .mt-\[2px\] {
350
  margin-top: 2px;
351
  }
352
-
353
  .inline {
354
  display: inline;
355
  }
356
-
357
  .flex {
358
  display: flex;
359
  }
360
-
361
  .h-4 {
362
  height: 1rem;
363
  }
364
-
365
  .w-4 {
366
  width: 1rem;
367
  }
368
-
369
  .flex-shrink-0 {
370
  flex-shrink: 0;
371
  }
372
-
373
  .list-inside {
374
  list-style-position: inside;
375
  }
376
-
377
  .list-disc {
378
  list-style-type: disc;
379
  }
380
-
381
  .rounded-lg {
382
  border-radius: 0.5rem;
383
  }
384
-
385
  .bg-red-50 {
386
  --tw-bg-opacity: 1;
387
  background-color: rgb(254 242 242 / var(--tw-bg-opacity));
@@ -392,31 +366,25 @@
392
  .p-4 {
393
  padding: 1rem;
394
  }
395
-
396
  .text-sm {
397
  font-size: 0.875rem;
398
  line-height: 1.25rem;
399
  }
400
-
401
  .font-medium {
402
  font-weight: 500;
403
  }
404
-
405
  .lowercase {
406
  text-transform: lowercase;
407
  }
408
-
409
  .text-red-800 {
410
  --tw-text-opacity: 1;
411
  color: rgb(153 27 27 / var(--tw-text-opacity));
412
  }
413
-
414
  @media (prefers-color-scheme: dark) {
415
  .dark\:bg-gray-800 {
416
  --tw-bg-opacity: 1;
417
  background-color: rgb(31 41 55 / var(--tw-bg-opacity));
418
  }
419
-
420
  .dark\:text-red-400 {
421
  --tw-text-opacity: 1;
422
  color: rgb(248 113 113 / var(--tw-text-opacity));
 
11
  import type { Gradio, SelectData } from "@gradio/utils";
12
  import File from "./shared/File.svelte";
13
  import FileUpload from "./shared/FileUpload.svelte";
 
14
  import { type FileData } from "@gradio/client";
15
  import { Block, UploadText } from "@gradio/atoms";
 
16
  import { StatusTracker } from "@gradio/statustracker";
17
  import type { LoadingStatus } from "@gradio/statustracker";
 
18
  export let elem_id = "";
19
  export let elem_classes: string[] = [];
20
  export let visible = true;
21
  export let value: null | FileData | FileData[];
 
22
  export let interactive: boolean;
23
  export let root: string;
24
  export let label: string;
25
  export let show_label: boolean;
26
  export let height: number | undefined = undefined;
 
27
  //Molecule3D specific arguments
28
  export let reps: any = [];
29
  export let config: any = {};
30
  export let confidenceLabel: string = "";
31
  export let showviewer: boolean = true;
 
32
  export let _selectable = false;
33
  export let loading_status: LoadingStatus;
34
  export let container = true;
 
43
  }>;
44
  export let file_count: string;
45
  export let file_types: string[] = ["file"];
 
46
  let old_value = value;
47
  $: if (JSON.stringify(old_value) !== JSON.stringify(value)) {
48
  gradio.dispatch("change");
49
  old_value = value;
50
  console.log("value change", value);
51
+ moldata = null;
52
+ retrieveContent(value);
53
  }
 
54
  let dragging = false;
55
  let pending_upload = false;
 
56
  //check for missing keys in reps
57
  let keys_for_reps = {
58
  model: {
 
108
  default: true,
109
  },
110
  };
 
111
  let moldata = null;
112
+ let allowed_extensions = ["pdb", "sdf", "mol2", "pdb1"];
 
113
  async function fetchFileContent(url) {
114
  const response = await fetch(url);
115
  const content = await response.text();
 
117
  }
118
  let promise = null;
119
  let errors = [];
 
120
  async function retrieveContent(value) {
121
  if (value == null) {
122
  return [];
123
  } else if (Array.isArray(value)) {
124
  let tempMoldata = [];
125
  // get file extension
 
126
  for (const element of value) {
127
  let ext = element.orig_name.split(".").pop();
128
  if (!allowed_extensions.includes(ext)) {
 
153
  moldata = null;
154
  } else {
155
  let t = await fetchFileContent(value.url);
156
+ let ext = value.orig_name.split(".").pop();
157
+ if (ext === "pdb1") {
158
+ ext = "pdb";
159
+ }
160
  moldata = [
161
+ { data: t, name: value.orig_name, format: ext, asFrames: false },
162
  ];
163
  }
164
  } else {
 
167
  // value is object
168
  }
169
  // go through each rep, do a type check and add missing keys to the rep
 
170
  let lenMoldata = 0;
171
  $: lenMoldata = moldata ? moldata.length : 0;
 
172
  let representations = [];
173
  //first add all missing keys
174
  $: {
 
193
  }
194
  });
195
  }
 
196
  $: promise = retrieveContent(value);
197
  </script>
198
 
 
221
  <File
222
  on:select={({ detail }) => gradio.dispatch("select", detail)}
223
  selectable={_selectable}
224
+ {value}
225
  {label}
226
  {show_label}
227
  {height}
 
237
  <FileUpload
238
  {label}
239
  {show_label}
240
+ {value}
241
  {file_count}
242
  {file_types}
243
  selectable={_selectable}
 
314
  white-space: nowrap;
315
  border-width: 0;
316
  }
 
317
  .mb-4 {
318
  margin-bottom: 1rem;
319
  }
 
320
  .ml-4 {
321
  margin-left: 1rem;
322
  }
 
323
  .mr-3 {
324
  margin-right: 0.75rem;
325
  }
 
326
  .mt-1 {
327
  margin-top: 0.25rem;
328
  }
 
329
  .mt-1\.5 {
330
  margin-top: 0.375rem;
331
  }
 
332
  .mt-\[2px\] {
333
  margin-top: 2px;
334
  }
 
335
  .inline {
336
  display: inline;
337
  }
 
338
  .flex {
339
  display: flex;
340
  }
 
341
  .h-4 {
342
  height: 1rem;
343
  }
 
344
  .w-4 {
345
  width: 1rem;
346
  }
 
347
  .flex-shrink-0 {
348
  flex-shrink: 0;
349
  }
 
350
  .list-inside {
351
  list-style-position: inside;
352
  }
 
353
  .list-disc {
354
  list-style-type: disc;
355
  }
 
356
  .rounded-lg {
357
  border-radius: 0.5rem;
358
  }
 
359
  .bg-red-50 {
360
  --tw-bg-opacity: 1;
361
  background-color: rgb(254 242 242 / var(--tw-bg-opacity));
 
366
  .p-4 {
367
  padding: 1rem;
368
  }
 
369
  .text-sm {
370
  font-size: 0.875rem;
371
  line-height: 1.25rem;
372
  }
 
373
  .font-medium {
374
  font-weight: 500;
375
  }
 
376
  .lowercase {
377
  text-transform: lowercase;
378
  }
 
379
  .text-red-800 {
380
  --tw-text-opacity: 1;
381
  color: rgb(153 27 27 / var(--tw-text-opacity));
382
  }
 
383
  @media (prefers-color-scheme: dark) {
384
  .dark\:bg-gray-800 {
385
  --tw-bg-opacity: 1;
386
  background-color: rgb(31 41 55 / var(--tw-bg-opacity));
387
  }
 
388
  .dark\:text-red-400 {
389
  --tw-text-opacity: 1;
390
  color: rgb(248 113 113 / var(--tw-text-opacity));
src/frontend/package.json CHANGED
@@ -22,4 +22,4 @@
22
  "./example": "./Example.svelte",
23
  "./package.json": "./package.json"
24
  }
25
- }
 
22
  "./example": "./Example.svelte",
23
  "./package.json": "./package.json"
24
  }
25
+ }
src/frontend/shared/FileRetrieval.svelte CHANGED
@@ -1,33 +1,19 @@
1
  <script lang="ts">
2
  import { createEventDispatcher, tick, getContext } from "svelte";
3
 
4
- // import { upload_files as default_upload_files } from "@gradio/client";
5
-
6
- // import { blobToBase64, normalise_file } from "@gradio/upload";
7
- import {
8
- upload_files,
9
- upload,
10
- FileData,
11
- } from "@gradio/client";
12
-
13
  import LoadingSpinner from "./loading_spinner.svelte";
14
  let uploaded_files;
15
-
16
  const dispatch = createEventDispatcher();
17
-
18
  const upload_fn = getContext<typeof upload_files>("upload_files");
19
-
20
  export let root: string;
21
-
22
  async function handle_upload(file_data: FileData): Promise<void> {
23
  await tick();
24
  const upload_id = Math.random().toString(36).substring(2, 15);
25
  uploaded_files = await upload([file_data], root, upload_id, upload_fn);
26
  dispatch("load", uploaded_files[0]);
27
  }
28
-
29
  let loading = false;
30
-
31
  async function fetchFromDB(identifier, database): Promise<void> {
32
  let dbs = {
33
  pdb_assym: {
@@ -52,39 +38,37 @@
52
  let url = dbs[database]["url"];
53
  let ext = dbs[database]["ext"];
54
  // load the file and save blob
55
-
56
  // emulate file upload by fetching from the db and triggering upload
57
  // check if response status is 200, then return blob
58
-
59
  loading = true;
60
  let file = null;
61
  try {
62
- file = await fetch(url + identifier + ext).then((r) => {
63
- loading = false;
64
- if (r.status == 200) {
65
- return r.blob();
66
- } else {
67
- dispatch("notfound");
68
- }
69
- }).then((blob) => {
70
- return new File([blob], identifier + ext, { type: "text/plain" });
71
- })} catch (error) {
 
 
 
72
  loading = false;
73
  dispatch("notfound");
74
  }
75
-
76
  let file_data = new FileData({
77
- path: identifier + ".pdb",
78
- orig_name: identifier + ".pdb",
79
- blob: file,
80
- size: file.size,
81
- mime_type: file.type,
82
- is_stream: false,
83
- });
84
-
85
  await handle_upload(file_data);
86
  }
87
-
88
  let selectedValue = "pdb_assym";
89
  let placeholder = "";
90
  let textInput = "";
@@ -100,7 +84,6 @@
100
  // text: "Enter molecule in PDB or mol2 format",
101
  };
102
  $: placeholder = placeholders[selectedValue];
103
-
104
  function isEnterPressed(event) {
105
  if (event.key === "Enter") {
106
  fetchFromDB(textInput, selectedValue);
@@ -173,7 +156,6 @@
173
  .mt-2 {
174
  margin-top: 2rem;
175
  }
176
-
177
  .input {
178
  box-shadow: var(--input-shadow);
179
  background: var(--input-background-fill);
 
1
  <script lang="ts">
2
  import { createEventDispatcher, tick, getContext } from "svelte";
3
 
4
+ import { upload_files, upload, FileData } from "@gradio/client";
 
 
 
 
 
 
 
 
5
  import LoadingSpinner from "./loading_spinner.svelte";
6
  let uploaded_files;
 
7
  const dispatch = createEventDispatcher();
 
8
  const upload_fn = getContext<typeof upload_files>("upload_files");
 
9
  export let root: string;
 
10
  async function handle_upload(file_data: FileData): Promise<void> {
11
  await tick();
12
  const upload_id = Math.random().toString(36).substring(2, 15);
13
  uploaded_files = await upload([file_data], root, upload_id, upload_fn);
14
  dispatch("load", uploaded_files[0]);
15
  }
 
16
  let loading = false;
 
17
  async function fetchFromDB(identifier, database): Promise<void> {
18
  let dbs = {
19
  pdb_assym: {
 
38
  let url = dbs[database]["url"];
39
  let ext = dbs[database]["ext"];
40
  // load the file and save blob
 
41
  // emulate file upload by fetching from the db and triggering upload
42
  // check if response status is 200, then return blob
 
43
  loading = true;
44
  let file = null;
45
  try {
46
+ file = await fetch(url + identifier + ext)
47
+ .then((r) => {
48
+ loading = false;
49
+ if (r.status == 200) {
50
+ return r.blob();
51
+ } else {
52
+ dispatch("notfound");
53
+ }
54
+ })
55
+ .then((blob) => {
56
+ return new File([blob], identifier + ".pdb", { type: "text/plain" });
57
+ });
58
+ } catch (error) {
59
  loading = false;
60
  dispatch("notfound");
61
  }
 
62
  let file_data = new FileData({
63
+ path: identifier + ".pdb",
64
+ orig_name: identifier + ".pdb",
65
+ blob: file,
66
+ size: file.size,
67
+ mime_type: file.type,
68
+ is_stream: false,
69
+ });
 
70
  await handle_upload(file_data);
71
  }
 
72
  let selectedValue = "pdb_assym";
73
  let placeholder = "";
74
  let textInput = "";
 
84
  // text: "Enter molecule in PDB or mol2 format",
85
  };
86
  $: placeholder = placeholders[selectedValue];
 
87
  function isEnterPressed(event) {
88
  if (event.key === "Enter") {
89
  fetchFromDB(textInput, selectedValue);
 
156
  .mt-2 {
157
  margin-top: 2rem;
158
  }
 
159
  .input {
160
  box-shadow: var(--input-shadow);
161
  background: var(--input-background-fill);
src/frontend/shared/FileUpload.svelte CHANGED
@@ -34,10 +34,12 @@
34
  await tick();
35
  dispatch("change", value);
36
  dispatch("upload", detail);
 
37
  }
38
 
39
  function handle_clear(): void {
40
  value = null;
 
41
  dispatch("change", null);
42
  dispatch("clear");
43
  }
 
34
  await tick();
35
  dispatch("change", value);
36
  dispatch("upload", detail);
37
+ console.log("upload", detail);
38
  }
39
 
40
  function handle_clear(): void {
41
  value = null;
42
+ moldata = null;
43
  dispatch("change", null);
44
  dispatch("clear");
45
  }
src/frontend/shared/MolecularViewer.svelte CHANGED
@@ -2,7 +2,7 @@
2
  import * as mol from "3dmol/build/3Dmol.js";
3
  let TDmol = mol.default;
4
 
5
- import { onMount } from "svelte";
6
 
7
  // import RepresentationsIcon from "../static/RepresentationsIcon.svelte";
8
  // import JSZip from "jszip";
@@ -179,17 +179,8 @@
179
  }
180
  }
181
 
182
- // function downloadFiles() {
183
- // var zip = new JSZip();
184
- // moldata.forEach((element, i) => {
185
- // zip.file(element.name + "_" + i + "." + element.format, element.data);
186
- // });
187
- // zip.generateAsync({ type: "blob" }).then(function (content) {
188
- // saveAs(content, "files.zip");
189
- // });
190
- // }
191
-
192
  onMount(() => {
 
193
  let startingConfig = { ...config, cartoonQuality: 7 };
194
 
195
  view = TDmol.createViewer(viewer, startingConfig);
@@ -215,7 +206,7 @@
215
  }
216
  });
217
  representations = uniqueReps;
218
-
219
  if (moldata.length > 0) {
220
  moldata.forEach((element) => {
221
  if (element.asFrames) {
@@ -313,29 +304,6 @@
313
  <div class="bg-white w-full minh">
314
  <div class="overflow-hidden flex gap-px w-full h-full flex-wrap">
315
  <div class="gr-block gr-box relative w-full overflow-hidden">
316
- <!-- <div
317
- style=" "
318
- class="absolute z-50 top-0 left-0 bg-white rounded-br border-b border-r border-gray-200 p-1"
319
- >
320
- <span class=" flex items-center space-x-1 text-xs text-gray-500"
321
- ><svg
322
- xmlns="http://www.w3.org/2000/svg"
323
- width="100%"
324
- height="100%"
325
- viewBox="0 0 24 24"
326
- fill="none"
327
- stroke="currentColor"
328
- stroke-width="1.5"
329
- stroke-linecap="round"
330
- stroke-linejoin="round"
331
- class="feather feather-file h-3 w-3"
332
- ><path
333
- d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"
334
- /><polyline points="13 2 13 9 20 9" /></svg
335
- > <span>Molecule3D</span>
336
- </span>
337
- </div> -->
338
-
339
  <div
340
  class="absolute z-50 top-0 right-0 mr-2 flex flex-col divide-y border border-gray-200 mt-2 rounded items-center justify-center bg-white dark:bg-gray-800"
341
  >
 
2
  import * as mol from "3dmol/build/3Dmol.js";
3
  let TDmol = mol.default;
4
 
5
+ import { onMount, onDestroy } from "svelte";
6
 
7
  // import RepresentationsIcon from "../static/RepresentationsIcon.svelte";
8
  // import JSZip from "jszip";
 
179
  }
180
  }
181
 
 
 
 
 
 
 
 
 
 
 
182
  onMount(() => {
183
+ console.log("MolecularViewer Mounted");
184
  let startingConfig = { ...config, cartoonQuality: 7 };
185
 
186
  view = TDmol.createViewer(viewer, startingConfig);
 
206
  }
207
  });
208
  representations = uniqueReps;
209
+ console.log(moldata);
210
  if (moldata.length > 0) {
211
  moldata.forEach((element) => {
212
  if (element.asFrames) {
 
304
  <div class="bg-white w-full minh">
305
  <div class="overflow-hidden flex gap-px w-full h-full flex-wrap">
306
  <div class="gr-block gr-box relative w-full overflow-hidden">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  <div
308
  class="absolute z-50 top-0 right-0 mr-2 flex flex-col divide-y border border-gray-200 mt-2 rounded items-center justify-center bg-white dark:bg-gray-800"
309
  >
src/pyproject.toml CHANGED
@@ -9,7 +9,7 @@ build-backend = "hatchling.build"
9
  [project]
10
  name = "gradio_molecule3d"
11
  version = "0.0.3"
12
- description = "Molecule3D custom component to visualize pdb or sdf files"
13
  readme = "README.md"
14
  license = "MIT"
15
  requires-python = ">=3.8"
@@ -24,7 +24,7 @@ keywords = [
24
  "protein"
25
  ]
26
  # Add dependencies here
27
- dependencies = ["gradio>=4.21.0,<5.0"]
28
  classifiers = [
29
  'Development Status :: 3 - Alpha',
30
  'License :: OSI Approved :: Apache Software License',
@@ -44,7 +44,7 @@ classifiers = [
44
  dev = ["build", "twine"]
45
 
46
  [tool.hatch.build]
47
- artifacts = ["/backend/gradio_molecule3d/templates", "*.pyi", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates"]
48
 
49
  [tool.hatch.build.targets.wheel]
50
  packages = ["/backend/gradio_molecule3d"]
 
9
  [project]
10
  name = "gradio_molecule3d"
11
  version = "0.0.3"
12
+ description = "Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js"
13
  readme = "README.md"
14
  license = "MIT"
15
  requires-python = ">=3.8"
 
24
  "protein"
25
  ]
26
  # Add dependencies here
27
+ dependencies = ["gradio>=4.0,<5.0"]
28
  classifiers = [
29
  'Development Status :: 3 - Alpha',
30
  'License :: OSI Approved :: Apache Software License',
 
44
  dev = ["build", "twine"]
45
 
46
  [tool.hatch.build]
47
+ artifacts = ["/backend/gradio_molecule3d/templates", "*.pyi", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates"]
48
 
49
  [tool.hatch.build.targets.wheel]
50
  packages = ["/backend/gradio_molecule3d"]