Spaces:
Configuration error
Configuration error
Commit
Β·
7f30a93
1
Parent(s):
6e075ce
refactor frontend/backend π¨βπ»
Browse files- backend/src/resources/module.py +94 -22
- frontend/src/App.js +1 -1
- frontend/src/{Components β components}/Navagation/navbar.js +111 -41
- frontend/src/{Components β components}/Nodes/Custom.js +21 -12
- frontend/src/{Components β components}/ReactFlow/ReactFlowEnv.js +3 -5
- frontend/src/css/CustomNode.css +0 -46
- frontend/src/css/dist/output.css +73 -15
- frontend/src/css/iframe.css +0 -5
- frontend/src/helper/visual.js +31 -25
- frontend/tailwind.config.js +8 -0
- images/application_dark.png +2 -2
- images/application_light.png +2 -2
backend/src/resources/module.py
CHANGED
|
@@ -1,41 +1,77 @@
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
from inspect import getfile
|
| 3 |
-
|
| 4 |
import socket
|
| 5 |
import requests
|
| 6 |
-
|
| 7 |
class Dock:
|
| 8 |
|
| 9 |
def __init__(self) -> None:
|
| 10 |
self.port_map = dict()
|
| 11 |
for p in range(7860, 7880):
|
| 12 |
-
if not self.
|
| 13 |
self.port_map[p] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
def
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
for port, available in self.port_map.items():
|
| 24 |
if available == True:
|
|
|
|
|
|
|
| 25 |
return port
|
|
|
|
| 26 |
raise Exception(f'β π {bcolor.BOLD}{bcolor.UNDERLINE}{bcolor.FAIL}All visable ports are used up...Try close some ports {bcolor.ENDC}')
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
def InterLauncher(name, interface, listen=2000, **kwargs):
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
try:
|
|
|
|
| 34 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{listen}/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : "Not Applicable", "name" : name, "kwargs" : kwargs})
|
| 35 |
-
except Exception as e:
|
|
|
|
| 36 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
| 37 |
return
|
| 38 |
|
|
|
|
| 39 |
interface.launch(server_port=port,
|
| 40 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 41 |
inline= kwargs['inline'] if "inline" in kwargs else False,
|
|
@@ -58,6 +94,9 @@ def InterLauncher(name, interface, listen=2000, **kwargs):
|
|
| 58 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
| 59 |
|
| 60 |
try:
|
|
|
|
|
|
|
|
|
|
| 61 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ listen }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 62 |
except Exception as e:
|
| 63 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π \n {e}")
|
|
@@ -77,6 +116,7 @@ def tabularGradio(funcs, names=[], name="Tabular Temp Name", **kwargs):
|
|
| 77 |
# send this to the backend api for it to be read by the react frontend
|
| 78 |
if 'listen' in kwargs:
|
| 79 |
try:
|
|
|
|
| 80 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 81 |
except Exception as e:
|
| 82 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
|
@@ -116,14 +156,21 @@ def tabularGradio(funcs, names=[], name="Tabular Temp Name", **kwargs):
|
|
| 116 |
|
| 117 |
|
| 118 |
def register(inputs, outputs, examples=None, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
def register_gradio(func):
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
if type(outputs) is list:
|
| 124 |
assert len(outputs) >= 1, f"β {bcolor.BOLD}{bcolor.FAIL}you have no outputs π€¨... {str(type(outputs))} {bcolor.ENDC}"
|
| 125 |
|
| 126 |
-
fn_name = func.__name__
|
|
|
|
|
|
|
| 127 |
if 'self' in func.__code__.co_varnames and func.__code__.co_varnames[0] == 'self' and fn_name in dir(args[0]):
|
| 128 |
"""
|
| 129 |
given the decorator is on a class then
|
|
@@ -131,6 +178,7 @@ def register(inputs, outputs, examples=None, **kwargs):
|
|
| 131 |
if not already initialize.
|
| 132 |
"""
|
| 133 |
|
|
|
|
| 134 |
if type(inputs) is list:
|
| 135 |
assert len(inputs) == func.__code__.co_argcount - 1, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 136 |
|
|
@@ -138,8 +186,9 @@ def register(inputs, outputs, examples=None, **kwargs):
|
|
| 138 |
self = args[0]
|
| 139 |
self.registered_gradio_functons
|
| 140 |
except AttributeError:
|
| 141 |
-
self.registered_gradio_functons = dict()
|
| 142 |
|
|
|
|
| 143 |
if not fn_name in self.registered_gradio_functons:
|
| 144 |
self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
|
| 145 |
outputs=outputs,
|
|
@@ -156,13 +205,19 @@ def register(inputs, outputs, examples=None, **kwargs):
|
|
| 156 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 157 |
theme=kwargs['theme'] if "theme" in kwargs else 'default', )
|
| 158 |
|
|
|
|
|
|
|
| 159 |
if len(args[1:]) == (func.__code__.co_argcount - 1):
|
| 160 |
return func(*args, **wargs)
|
|
|
|
|
|
|
| 161 |
return None
|
| 162 |
else :
|
| 163 |
"""
|
| 164 |
the function is not a class function
|
| 165 |
"""
|
|
|
|
|
|
|
| 166 |
if type(inputs) is list:
|
| 167 |
assert len(inputs) == func.__code__.co_argcount, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 168 |
|
|
@@ -187,7 +242,7 @@ def register(inputs, outputs, examples=None, **kwargs):
|
|
| 187 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 188 |
theme='default',
|
| 189 |
)
|
| 190 |
-
decorator.__decorator__ = "__gradio__"
|
| 191 |
return decorator
|
| 192 |
return register_gradio
|
| 193 |
|
|
@@ -200,14 +255,23 @@ def GradioModule(cls):
|
|
| 200 |
self.interface = self.__compile()
|
| 201 |
|
| 202 |
def get_funcs_names(self):
|
|
|
|
|
|
|
|
|
|
| 203 |
assert self.get_registered_map() != None, "this is not possible..."
|
| 204 |
return [ name for name in self.get_registered_map().keys()]
|
| 205 |
|
| 206 |
def get_registered_map(self):
|
|
|
|
|
|
|
|
|
|
| 207 |
assert self.__cls__.registered_gradio_functons != None, "what happen!!!!"
|
| 208 |
return self.__cls__.registered_gradio_functons
|
| 209 |
|
| 210 |
def __get_funcs_attr(self):
|
|
|
|
|
|
|
|
|
|
| 211 |
for func in dir(self.__cls__):
|
| 212 |
fn = getattr(self.__cls__, func, None)
|
| 213 |
|
|
@@ -220,8 +284,8 @@ def GradioModule(cls):
|
|
| 220 |
within the class that are registeed
|
| 221 |
"""
|
| 222 |
demos, names = [], []
|
| 223 |
-
for func, param in self.get_registered_map().items():
|
| 224 |
-
names.append(func)
|
| 225 |
try:
|
| 226 |
demos.append(gr.Interface(fn=getattr(self.__cls__, func, None), **param))
|
| 227 |
except Exception as e :
|
|
@@ -232,6 +296,13 @@ def GradioModule(cls):
|
|
| 232 |
return gr.TabbedInterface(demos, names)
|
| 233 |
|
| 234 |
def launch(self, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
| 236 |
if 'listen' in kwargs:
|
| 237 |
try:
|
|
@@ -269,6 +340,7 @@ def GradioModule(cls):
|
|
| 269 |
|
| 270 |
return Decorator
|
| 271 |
|
|
|
|
| 272 |
class bcolor:
|
| 273 |
HEADER = '\033[95m'
|
| 274 |
OKBLUE = '\033[94m'
|
|
|
|
| 1 |
+
from signal import signal, SIGKILL
|
| 2 |
import gradio as gr
|
| 3 |
from inspect import getfile
|
|
|
|
| 4 |
import socket
|
| 5 |
import requests
|
| 6 |
+
import os
|
| 7 |
class Dock:
|
| 8 |
|
| 9 |
def __init__(self) -> None:
|
| 10 |
self.port_map = dict()
|
| 11 |
for p in range(7860, 7880):
|
| 12 |
+
if not self.port_is_connected(p):
|
| 13 |
self.port_map[p] = True
|
| 14 |
+
else:
|
| 15 |
+
self.port_map[p] = False
|
| 16 |
+
|
| 17 |
+
|
| 18 |
|
| 19 |
+
def port_is_connected(self, port : int) -> bool:
|
| 20 |
+
"""
|
| 21 |
+
@params:
|
| 22 |
+
- port : int
|
| 23 |
+
@return:
|
| 24 |
+
- boolean
|
| 25 |
+
check if the port is open with in our localhost
|
| 26 |
+
"""
|
| 27 |
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
| 28 |
+
return s.connect_ex(("localhost", port)) == 0
|
| 29 |
|
| 30 |
+
|
| 31 |
+
def determinePort(self) -> any:
|
| 32 |
+
"""
|
| 33 |
+
Take the port_map that was instantiate
|
| 34 |
+
in the __init__ and loop though all ports
|
| 35 |
+
and check if it the port is available
|
| 36 |
+
"""
|
| 37 |
for port, available in self.port_map.items():
|
| 38 |
if available == True:
|
| 39 |
+
if self.port_is_connected(port): # check if port is in use if so then go to the next one
|
| 40 |
+
continue
|
| 41 |
return port
|
| 42 |
+
|
| 43 |
raise Exception(f'β π {bcolor.BOLD}{bcolor.UNDERLINE}{bcolor.FAIL}All visable ports are used up...Try close some ports {bcolor.ENDC}')
|
| 44 |
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
DOCKER_LOCAL_HOST = '0.0.0.0'
|
| 50 |
+
DOCKER_PORT = Dock() # Determine the best possible port
|
| 51 |
|
| 52 |
def InterLauncher(name, interface, listen=2000, **kwargs):
|
| 53 |
+
"""
|
| 54 |
+
@params:
|
| 55 |
+
- name : string
|
| 56 |
+
- interface : gradio.Interface(...)
|
| 57 |
+
- listen : int
|
| 58 |
+
- **kwargs
|
| 59 |
+
|
| 60 |
+
Take any gradio interface object
|
| 61 |
+
that is created by the gradio
|
| 62 |
+
package and send it to the flaks api
|
| 63 |
+
"""
|
| 64 |
+
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort() # determine the next open port is no port is listed **kwargs
|
| 65 |
+
|
| 66 |
try:
|
| 67 |
+
# (POST) send the information of the gradio to the flask api
|
| 68 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{listen}/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : "Not Applicable", "name" : name, "kwargs" : kwargs})
|
| 69 |
+
except Exception as e:
|
| 70 |
+
# If there is an Exception then notify the user and end the method
|
| 71 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
| 72 |
return
|
| 73 |
|
| 74 |
+
# Launch the gradio application
|
| 75 |
interface.launch(server_port=port,
|
| 76 |
server_name=f"{DOCKER_LOCAL_HOST}",
|
| 77 |
inline= kwargs['inline'] if "inline" in kwargs else False,
|
|
|
|
| 94 |
quiet=kwargs['quiet'] if "quiet" in kwargs else False)
|
| 95 |
|
| 96 |
try:
|
| 97 |
+
# (POST) stop the interface if user hits ctrl+c
|
| 98 |
+
# send the information of the gradio to the flask
|
| 99 |
+
# api to remove it from the list within the flask api
|
| 100 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ listen }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 101 |
except Exception as e:
|
| 102 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe api either lost connection or was turned off...π \n {e}")
|
|
|
|
| 116 |
# send this to the backend api for it to be read by the react frontend
|
| 117 |
if 'listen' in kwargs:
|
| 118 |
try:
|
| 119 |
+
# (POST) send the information of the gradio to the flask api
|
| 120 |
requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
|
| 121 |
except Exception as e:
|
| 122 |
print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πThe listening api is either not up or you choose the wrong port.π \n {e}")
|
|
|
|
| 156 |
|
| 157 |
|
| 158 |
def register(inputs, outputs, examples=None, **kwargs):
|
| 159 |
+
"""
|
| 160 |
+
Decorator that is appended to a function either within a class or not
|
| 161 |
+
and output either an interface or inputs and outputs for later processing
|
| 162 |
+
to launch either to Gradio-Flow or just Gradio
|
| 163 |
+
"""
|
| 164 |
def register_gradio(func):
|
| 165 |
+
def decorator(*args, **wargs):
|
| 166 |
+
|
| 167 |
+
# if the output is a list then there should be equal or more then 1
|
| 168 |
if type(outputs) is list:
|
| 169 |
assert len(outputs) >= 1, f"β {bcolor.BOLD}{bcolor.FAIL}you have no outputs π€¨... {str(type(outputs))} {bcolor.ENDC}"
|
| 170 |
|
| 171 |
+
fn_name = func.__name__ # name of the function
|
| 172 |
+
|
| 173 |
+
# if there exist the self within the arguments and thats the first argument then this must be a class function
|
| 174 |
if 'self' in func.__code__.co_varnames and func.__code__.co_varnames[0] == 'self' and fn_name in dir(args[0]):
|
| 175 |
"""
|
| 176 |
given the decorator is on a class then
|
|
|
|
| 178 |
if not already initialize.
|
| 179 |
"""
|
| 180 |
|
| 181 |
+
# if the inputs is a list then inputs list should equal the arugments list
|
| 182 |
if type(inputs) is list:
|
| 183 |
assert len(inputs) == func.__code__.co_argcount - 1, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 184 |
|
|
|
|
| 186 |
self = args[0]
|
| 187 |
self.registered_gradio_functons
|
| 188 |
except AttributeError:
|
| 189 |
+
self.registered_gradio_functons = dict() # if registered_gradio_functons does not exist then create it
|
| 190 |
|
| 191 |
+
# if the function name is not within the registered_gradio_functons then register it within the registered_gradio_functons
|
| 192 |
if not fn_name in self.registered_gradio_functons:
|
| 193 |
self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
|
| 194 |
outputs=outputs,
|
|
|
|
| 205 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 206 |
theme=kwargs['theme'] if "theme" in kwargs else 'default', )
|
| 207 |
|
| 208 |
+
# if the argument are within the function when it's called then give me the output of the function
|
| 209 |
+
# giving the user the ability to use the function if necessary
|
| 210 |
if len(args[1:]) == (func.__code__.co_argcount - 1):
|
| 211 |
return func(*args, **wargs)
|
| 212 |
+
|
| 213 |
+
# return nothing if the arguments are not within it cause if the arguments do not exist it will give a error
|
| 214 |
return None
|
| 215 |
else :
|
| 216 |
"""
|
| 217 |
the function is not a class function
|
| 218 |
"""
|
| 219 |
+
|
| 220 |
+
# if the inputs is a list then inputs list should equal the arugments list
|
| 221 |
if type(inputs) is list:
|
| 222 |
assert len(inputs) == func.__code__.co_argcount, f"β {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
|
| 223 |
|
|
|
|
| 242 |
allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
|
| 243 |
theme='default',
|
| 244 |
)
|
| 245 |
+
decorator.__decorator__ = "__gradio__" # siginture to tell any function that need to know that function is a registed gradio application
|
| 246 |
return decorator
|
| 247 |
return register_gradio
|
| 248 |
|
|
|
|
| 255 |
self.interface = self.__compile()
|
| 256 |
|
| 257 |
def get_funcs_names(self):
|
| 258 |
+
"""
|
| 259 |
+
Get all name for each function
|
| 260 |
+
"""
|
| 261 |
assert self.get_registered_map() != None, "this is not possible..."
|
| 262 |
return [ name for name in self.get_registered_map().keys()]
|
| 263 |
|
| 264 |
def get_registered_map(self):
|
| 265 |
+
"""
|
| 266 |
+
Get all registered functions
|
| 267 |
+
"""
|
| 268 |
assert self.__cls__.registered_gradio_functons != None, "what happen!!!!"
|
| 269 |
return self.__cls__.registered_gradio_functons
|
| 270 |
|
| 271 |
def __get_funcs_attr(self):
|
| 272 |
+
"""
|
| 273 |
+
Get all the function that are registered
|
| 274 |
+
"""
|
| 275 |
for func in dir(self.__cls__):
|
| 276 |
fn = getattr(self.__cls__, func, None)
|
| 277 |
|
|
|
|
| 284 |
within the class that are registeed
|
| 285 |
"""
|
| 286 |
demos, names = [], []
|
| 287 |
+
for func, param in self.get_registered_map().items(): # loop though the registered function and append it to the TabularInterface
|
| 288 |
+
names.append(func)
|
| 289 |
try:
|
| 290 |
demos.append(gr.Interface(fn=getattr(self.__cls__, func, None), **param))
|
| 291 |
except Exception as e :
|
|
|
|
| 296 |
return gr.TabbedInterface(demos, names)
|
| 297 |
|
| 298 |
def launch(self, **kwargs):
|
| 299 |
+
"""
|
| 300 |
+
@params:
|
| 301 |
+
**kwargs
|
| 302 |
+
Take the tabular interface and send it to the api if
|
| 303 |
+
'listen' is within the kwargs and launch the gradio interface
|
| 304 |
+
then when the gradio stops then remove it from the api
|
| 305 |
+
"""
|
| 306 |
port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
|
| 307 |
if 'listen' in kwargs:
|
| 308 |
try:
|
|
|
|
| 340 |
|
| 341 |
return Decorator
|
| 342 |
|
| 343 |
+
# console colour changer
|
| 344 |
class bcolor:
|
| 345 |
HEADER = '\033[95m'
|
| 346 |
OKBLUE = '\033[94m'
|
frontend/src/App.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import ReactEnviorment from './
|
| 2 |
|
| 3 |
export default function App() {
|
| 4 |
return(
|
|
|
|
| 1 |
+
import ReactEnviorment from './components/ReactFlow/ReactFlowEnv'
|
| 2 |
|
| 3 |
export default function App() {
|
| 4 |
return(
|
frontend/src/{Components β components}/Navagation/navbar.js
RENAMED
|
@@ -6,10 +6,11 @@ import { random_colour, random_emoji } from "../../helper/visual";
|
|
| 6 |
import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
|
| 7 |
|
| 8 |
export default class Navbar extends Component{
|
| 9 |
-
constructor(){
|
| 10 |
-
super()
|
| 11 |
this.fetch_classes()
|
| 12 |
this.temp_host = 0
|
|
|
|
| 13 |
this.state = {open : true,
|
| 14 |
menu : [],
|
| 15 |
colour : [],
|
|
@@ -19,11 +20,15 @@ export default class Navbar extends Component{
|
|
| 19 |
mode : false,
|
| 20 |
modal : false,
|
| 21 |
error : false
|
|
|
|
| 22 |
}
|
| 23 |
}
|
| 24 |
|
| 25 |
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
| 27 |
async fetch_classes(){
|
| 28 |
try {
|
| 29 |
setInterval( async () => {
|
|
@@ -47,35 +52,39 @@ export default class Navbar extends Component{
|
|
| 47 |
}
|
| 48 |
}
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
// emoji : this.state.emoji,
|
| 60 |
-
// error : true,
|
| 61 |
-
// modal : this.state.modal })
|
| 62 |
-
// return
|
| 63 |
-
// }
|
| 64 |
-
|
| 65 |
-
// if((this.state.text.includes("localhost") || this.state.text.includes("127.0.0.1"))
|
| 66 |
-
// && this.state.menu.some(e => e.host === this.state.text)){
|
| 67 |
-
// this.setState({open : this.state.open,
|
| 68 |
-
// menu : this.state.menu,
|
| 69 |
-
// text: this.state.text,
|
| 70 |
-
// name : this.state.name,
|
| 71 |
-
// colour : this.state.colour,
|
| 72 |
-
// emoji : this.state.emoji,
|
| 73 |
-
// error : true,
|
| 74 |
-
// modal : this.state.modal })
|
| 75 |
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
|
| 80 |
console.log(re)
|
| 81 |
fetch("http://localhost:2000/api/append/port", {method: 'POST', mode : 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify({file : "", kwargs : {}, name : this.state.name === "" ?`temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0 , host : this.state.text}) }).then(resp => {
|
|
@@ -88,16 +97,31 @@ export default class Navbar extends Component{
|
|
| 88 |
error : false,
|
| 89 |
modal : false })
|
| 90 |
|
| 91 |
-
}).catch(() => this.setState({open : this.state.open,
|
| 92 |
menu : this.state.menu,
|
| 93 |
-
text:
|
|
|
|
| 94 |
colour : this.state.colour,
|
| 95 |
emoji : this.state.emoji,
|
| 96 |
error : true,
|
| 97 |
modal : this.state.modal }))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
})
|
| 99 |
}
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
handelModal = (bool) => {
|
| 102 |
this.setState({open : this.state.open,
|
| 103 |
menu : this.state.menu,
|
|
@@ -109,25 +133,40 @@ export default class Navbar extends Component{
|
|
| 109 |
modal : bool})
|
| 110 |
}
|
| 111 |
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
onDragStart = (event, nodeType, item, index) => {
|
| 114 |
-
console.log(item)
|
| 115 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
| 116 |
-
event.dataTransfer.setData('application/host', item.host)
|
| 117 |
-
event.dataTransfer.setData('application/name', item.name)
|
| 118 |
event.dataTransfer.setData('application/colour', this.state.colour[index])
|
| 119 |
event.dataTransfer.setData('application/item', JSON.stringify(item))
|
| 120 |
-
|
| 121 |
event.dataTransfer.effectAllowed = 'move';
|
| 122 |
};
|
| 123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
onDragDrop = (e) => {
|
| 125 |
e.preventDefault();
|
| 126 |
var item = JSON.parse(e.dataTransfer.getData('application/item'));
|
| 127 |
fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
|
|
|
|
| 128 |
})
|
|
|
|
| 129 |
}
|
| 130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
hanelTabs = (e, d) => {
|
| 132 |
|
| 133 |
// if less then 0 we must remove colour's and emoji's
|
|
@@ -150,22 +189,39 @@ export default class Navbar extends Component{
|
|
| 150 |
c.push(random_colour());
|
| 151 |
j.push(random_emoji());
|
| 152 |
}
|
| 153 |
-
this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : this.state.colour
|
| 154 |
}
|
| 155 |
}
|
| 156 |
|
|
|
|
|
|
|
|
|
|
| 157 |
appendTabs = () => {
|
| 158 |
this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour] , emoji : [...this.state.emoji, random_emoji], error : this.state.error, modal : this.state.modal })
|
| 159 |
}
|
| 160 |
|
|
|
|
|
|
|
|
|
|
| 161 |
handelNavbar = () => {
|
| 162 |
this.setState({open : !this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
|
| 163 |
}
|
| 164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
updateText(e, type){
|
| 166 |
this.setState({open : this.state.open, menu : this.state.menu, text: type === "text" ? e.target.value : this.state.text, name: type === "name" ? e.target.value : this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
|
| 167 |
}
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
subComponents(item, index){
|
| 170 |
|
| 171 |
return(<>
|
|
@@ -213,7 +269,7 @@ export default class Navbar extends Component{
|
|
| 213 |
<span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
|
| 214 |
<BsSearch className="block float-left cursor-pointer mr-2"/>
|
| 215 |
</span>
|
| 216 |
-
<input className={`placeholder:italic placeholder:text-slate-400 block bg-transparent w-full border border-slate-300 border-dashed rounded-md py-2 pl-9 ${this.state.open ? "pr-3" : "hidden"} shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1
|
| 217 |
placeholder={`stream link...`}
|
| 218 |
type="text" name="search"
|
| 219 |
onChange={(e) => {
|
|
@@ -240,8 +296,22 @@ export default class Navbar extends Component{
|
|
| 240 |
|
| 241 |
{ this.state.error &&
|
| 242 |
<Message negative>
|
| 243 |
-
<Message.Header>π«
|
| 244 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
</Message>
|
| 246 |
}
|
| 247 |
|
|
|
|
| 6 |
import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
|
| 7 |
|
| 8 |
export default class Navbar extends Component{
|
| 9 |
+
constructor(props){
|
| 10 |
+
super(props)
|
| 11 |
this.fetch_classes()
|
| 12 |
this.temp_host = 0
|
| 13 |
+
this.deleteNode = props.onDelete
|
| 14 |
this.state = {open : true,
|
| 15 |
menu : [],
|
| 16 |
colour : [],
|
|
|
|
| 20 |
mode : false,
|
| 21 |
modal : false,
|
| 22 |
error : false
|
| 23 |
+
|
| 24 |
}
|
| 25 |
}
|
| 26 |
|
| 27 |
|
| 28 |
+
/**
|
| 29 |
+
* Asynchronously call the Flask api server every second to check if there exist a gradio application info
|
| 30 |
+
* @return null
|
| 31 |
+
*/
|
| 32 |
async fetch_classes(){
|
| 33 |
try {
|
| 34 |
setInterval( async () => {
|
|
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
+
/**
|
| 56 |
+
* Append new node from the user
|
| 57 |
+
*/
|
| 58 |
+
append_gradio = async () => {
|
| 59 |
+
const pattern = {
|
| 60 |
+
local : /^https?:\/\/(localhost)*(:[0-9]+)?(\/)?$/,
|
| 61 |
+
share : /^https?:\/\/*([0-9]{5})*(-gradio)*(.app)?(\/)?$/,
|
| 62 |
+
hugginFace : /^https?:\/\/*(hf.space)\/*(embed)\/*([a-zA-Z0-9+_-]+)\/*([a-zA-Z0-9+_-]+)\/*([+])?(\/)?$/
|
| 63 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
+
if (this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.host) }) !== -1 ||
|
| 66 |
+
this.state.text.includes(" ") ||
|
| 67 |
+
(!pattern.local.test(this.state.text) &&
|
| 68 |
+
!pattern.share.test(this.state.text) &&
|
| 69 |
+
!pattern.hugginFace.test(this.state.text))){
|
| 70 |
|
| 71 |
+
console.log(this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.host) }) !== -1)
|
| 72 |
+
console.log(this.state.text.includes(" ") )
|
| 73 |
+
console.log(this.state.text.includes("") )
|
| 74 |
+
console.log(!pattern.local.test(this.state.text) &&
|
| 75 |
+
!pattern.share.test(this.state.text) &&
|
| 76 |
+
!pattern.hugginFace.test(this.state.text))
|
| 77 |
+
this.setState({open : this.state.open,
|
| 78 |
+
menu : this.state.menu,
|
| 79 |
+
text: '',
|
| 80 |
+
name : '',
|
| 81 |
+
colour : this.state.colour,
|
| 82 |
+
emoji : this.state.emoji,
|
| 83 |
+
error : true,
|
| 84 |
+
modal : this.state.modal })
|
| 85 |
+
return
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
|
| 89 |
console.log(re)
|
| 90 |
fetch("http://localhost:2000/api/append/port", {method: 'POST', mode : 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify({file : "", kwargs : {}, name : this.state.name === "" ?`temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0 , host : this.state.text}) }).then(resp => {
|
|
|
|
| 97 |
error : false,
|
| 98 |
modal : false })
|
| 99 |
|
| 100 |
+
}).catch((err) => this.setState({open : this.state.open,
|
| 101 |
menu : this.state.menu,
|
| 102 |
+
text: '',
|
| 103 |
+
name : '',
|
| 104 |
colour : this.state.colour,
|
| 105 |
emoji : this.state.emoji,
|
| 106 |
error : true,
|
| 107 |
modal : this.state.modal }))
|
| 108 |
+
}).catch((err)=>{
|
| 109 |
+
console.log(err)
|
| 110 |
+
this.setState({open : this.state.open,
|
| 111 |
+
menu : this.state.menu,
|
| 112 |
+
text: '',
|
| 113 |
+
name : '',
|
| 114 |
+
colour : this.state.colour,
|
| 115 |
+
emoji : this.state.emoji,
|
| 116 |
+
error : true,
|
| 117 |
+
modal : this.state.modal })
|
| 118 |
})
|
| 119 |
}
|
| 120 |
|
| 121 |
+
/**
|
| 122 |
+
* error check the user input
|
| 123 |
+
* @param {*} bool boolean of the current state of the modal
|
| 124 |
+
*/
|
| 125 |
handelModal = (bool) => {
|
| 126 |
this.setState({open : this.state.open,
|
| 127 |
menu : this.state.menu,
|
|
|
|
| 133 |
modal : bool})
|
| 134 |
}
|
| 135 |
|
| 136 |
+
/**
|
| 137 |
+
* when dragged get all the information needed
|
| 138 |
+
* @param {*} event
|
| 139 |
+
* @param {*} nodeType string 'custom' node type
|
| 140 |
+
* @param {*} item object information returned from the api
|
| 141 |
+
* @param {*} index current index
|
| 142 |
+
*/
|
| 143 |
onDragStart = (event, nodeType, item, index) => {
|
|
|
|
| 144 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
|
|
|
|
|
|
| 145 |
event.dataTransfer.setData('application/colour', this.state.colour[index])
|
| 146 |
event.dataTransfer.setData('application/item', JSON.stringify(item))
|
|
|
|
| 147 |
event.dataTransfer.effectAllowed = 'move';
|
| 148 |
};
|
| 149 |
|
| 150 |
+
/**
|
| 151 |
+
* droped event that occurs when the user drops the Tab within the tash div.
|
| 152 |
+
* The function just deletes all nodes within React-Flow enviorment related,
|
| 153 |
+
* and remove it from the api.
|
| 154 |
+
* @param {*} e drop event
|
| 155 |
+
*/
|
| 156 |
onDragDrop = (e) => {
|
| 157 |
e.preventDefault();
|
| 158 |
var item = JSON.parse(e.dataTransfer.getData('application/item'));
|
| 159 |
fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
|
| 160 |
+
this.deleteNode(item.name)
|
| 161 |
})
|
| 162 |
+
|
| 163 |
}
|
| 164 |
|
| 165 |
+
/**
|
| 166 |
+
* update the tabs within the navbar
|
| 167 |
+
* @param {*} e current menu
|
| 168 |
+
* @param {*} d integer variable of the diffence between the current menu and new menu updated ment
|
| 169 |
+
*/
|
| 170 |
hanelTabs = (e, d) => {
|
| 171 |
|
| 172 |
// if less then 0 we must remove colour's and emoji's
|
|
|
|
| 189 |
c.push(random_colour());
|
| 190 |
j.push(random_emoji());
|
| 191 |
}
|
| 192 |
+
this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : [...this.state.colour, ...c], emoji : [...this.state.emoji, ...j], error : this.state.error, modal : this.state.modal })
|
| 193 |
}
|
| 194 |
}
|
| 195 |
|
| 196 |
+
/**
|
| 197 |
+
* Append a new colour, and emoji to the colour and emoji list with in the state of the component
|
| 198 |
+
*/
|
| 199 |
appendTabs = () => {
|
| 200 |
this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour] , emoji : [...this.state.emoji, random_emoji], error : this.state.error, modal : this.state.modal })
|
| 201 |
}
|
| 202 |
|
| 203 |
+
/**
|
| 204 |
+
* handel navagation open and close function
|
| 205 |
+
*/
|
| 206 |
handelNavbar = () => {
|
| 207 |
this.setState({open : !this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
|
| 208 |
}
|
| 209 |
|
| 210 |
+
/**
|
| 211 |
+
*
|
| 212 |
+
* @param {*} e : event type to get the target value of the current input
|
| 213 |
+
* @param {*} type : text | name string that set the changed value of the input to the current value
|
| 214 |
+
*/
|
| 215 |
updateText(e, type){
|
| 216 |
this.setState({open : this.state.open, menu : this.state.menu, text: type === "text" ? e.target.value : this.state.text, name: type === "name" ? e.target.value : this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
|
| 217 |
}
|
| 218 |
|
| 219 |
+
/**
|
| 220 |
+
*
|
| 221 |
+
* @param {*} item : object infomation from the flask api
|
| 222 |
+
* @param {*} index : current index with in the list
|
| 223 |
+
* @returns div component that contians infomation of gradio
|
| 224 |
+
*/
|
| 225 |
subComponents(item, index){
|
| 226 |
|
| 227 |
return(<>
|
|
|
|
| 269 |
<span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
|
| 270 |
<BsSearch className="block float-left cursor-pointer mr-2"/>
|
| 271 |
</span>
|
| 272 |
+
<input className={`placeholder:italic placeholder:text-slate-400 block bg-transparent w-full border border-slate-300 border-dashed rounded-md py-2 pl-9 ${this.state.open ? "pr-3" : "hidden"} shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm bg-transparent`}
|
| 273 |
placeholder={`stream link...`}
|
| 274 |
type="text" name="search"
|
| 275 |
onChange={(e) => {
|
|
|
|
| 296 |
|
| 297 |
{ this.state.error &&
|
| 298 |
<Message negative>
|
| 299 |
+
<Message.Header className=" text-lg text-center">π« Something went wrong...</Message.Header>
|
| 300 |
+
<br/>
|
| 301 |
+
<h1 className=" underline pb-3 font-bold text-lg">π€ Possible Things That could of happen <br/></h1>
|
| 302 |
+
<ul className="font-bold">
|
| 303 |
+
<li>- The input was empty</li>
|
| 304 |
+
<li>- The connection was forbidden</li>
|
| 305 |
+
<li>- The name was already taken</li>
|
| 306 |
+
<li>- The link you gave did not pass the regex</li>
|
| 307 |
+
<ul className="px-6">
|
| 308 |
+
<li>- http://localhost:xxxx</li>
|
| 309 |
+
<li>- http://xxxxx.gradio.app</li>
|
| 310 |
+
<li>- https://hf.space/embed/$user/$space_name/+</li>
|
| 311 |
+
</ul>
|
| 312 |
+
<li>- link already exist within the menu</li>
|
| 313 |
+
</ul>
|
| 314 |
+
|
| 315 |
</Message>
|
| 316 |
}
|
| 317 |
|
frontend/src/{Components β components}/Nodes/Custom.js
RENAMED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import React from "react"
|
| 2 |
import {TbResize} from 'react-icons/tb'
|
| 3 |
-
import {BiCube} from 'react-icons/bi'
|
| 4 |
import {BsTrash} from 'react-icons/bs'
|
| 5 |
import {CgLayoutGridSmall} from 'react-icons/cg'
|
| 6 |
import '../../css/counter.css'
|
|
@@ -14,19 +14,20 @@ export default class CustomNodeIframe extends React.Component {
|
|
| 14 |
reachable : this.isFetchable(data.host),
|
| 15 |
selected : true,
|
| 16 |
data : data,
|
| 17 |
-
width :
|
| 18 |
-
height :
|
| 19 |
-
size : false
|
|
|
|
| 20 |
}
|
| 21 |
|
| 22 |
}
|
| 23 |
|
| 24 |
handelSelected = () => {
|
| 25 |
-
this.setState({id : this.state.id, reachable : this.state.reachable, selected : !this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size})
|
| 26 |
}
|
| 27 |
|
| 28 |
handelSizeState = () => {
|
| 29 |
-
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : !this.state.size})
|
| 30 |
}
|
| 31 |
|
| 32 |
isFetchable = async (host) => {
|
|
@@ -45,14 +46,21 @@ export default class CustomNodeIframe extends React.Component {
|
|
| 45 |
this.state.data.delete(id)
|
| 46 |
}
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
handelOnChange(evt, type){
|
| 49 |
-
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : type === "width" ? parseInt(evt.target.value) : this.state.width, height : type === "height" ? parseInt(evt.target.value) : this.state.height, size : this.state.size})
|
| 50 |
type === "width" ? this.myRef.current.style.width = `${parseInt(evt.target.value)}px` : this.myRef.current.style.height = `${parseInt(evt.target.value)}px`
|
| 51 |
}
|
| 52 |
|
| 53 |
handelSize(evt, increment, change){
|
| 54 |
if (evt === "increment") {
|
| 55 |
-
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : change === "width" ? this.state.width + increment : this.state.width, height : change === "height" ? this.state.height + increment : this.state.height, size : this.state.size})
|
| 56 |
change === "width" ? this.myRef.current.style.width = `${this.state.width + increment}px` : this.myRef.current.style.height = `${this.state.height + increment}px`
|
| 57 |
}
|
| 58 |
|
|
@@ -77,15 +85,16 @@ export default class CustomNodeIframe extends React.Component {
|
|
| 77 |
return (<>
|
| 78 |
<>
|
| 79 |
<div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
|
| 80 |
-
<div title="Collaspse Node" className=" duration-300 cursor-pointer shadow-xl border-2
|
| 81 |
|
| 82 |
|
| 83 |
<div className={` flex ${this.state.selected ? '' : 'w-0 hidden'}`}>
|
| 84 |
<div title="Adjust Node Size" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Violet rounded-xl" onClick={this.handelSizeState}><TbResize className="h-full w-full text-white p-1"/></div>
|
| 85 |
<a href={this.state.data.host} target="_blank" rel="noopener noreferrer"><div title="Gradio Host Site" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Pink rounded-xl"><BiCube className="h-full w-full text-white p-1"/></div></a>
|
| 86 |
<div title="Delete Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Red rounded-xl" onClick={() => this.onNodeClick(this.state.id)}><BsTrash className="h-full w-full text-white p-1"/></div>
|
| 87 |
-
|
| 88 |
-
|
|
|
|
| 89 |
{this.Counter("width", this.state.width)}
|
| 90 |
{this.Counter("height", this.state.height)}
|
| 91 |
</div>}
|
|
@@ -97,11 +106,11 @@ export default class CustomNodeIframe extends React.Component {
|
|
| 97 |
<div className={`absolute h-full w-full ${this.state.data.colour} border-1shadow-2xl shadow-black rounded-xl -z-20`}></div>
|
| 98 |
<iframe
|
| 99 |
id="iframe"
|
|
|
|
| 100 |
src={this.state.data.host}
|
| 101 |
title={this.state.data.label}
|
| 102 |
frameBorder="0"
|
| 103 |
className=" -z-10 container h-full p-2 flex-grow space-iframe overflow-scroll "
|
| 104 |
-
allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking"
|
| 105 |
sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>
|
| 106 |
</div>
|
| 107 |
</>
|
|
|
|
| 1 |
import React from "react"
|
| 2 |
import {TbResize} from 'react-icons/tb'
|
| 3 |
+
import {BiCube, BiRefresh} from 'react-icons/bi'
|
| 4 |
import {BsTrash} from 'react-icons/bs'
|
| 5 |
import {CgLayoutGridSmall} from 'react-icons/cg'
|
| 6 |
import '../../css/counter.css'
|
|
|
|
| 14 |
reachable : this.isFetchable(data.host),
|
| 15 |
selected : true,
|
| 16 |
data : data,
|
| 17 |
+
width : 540,
|
| 18 |
+
height : 600,
|
| 19 |
+
size : false,
|
| 20 |
+
iframe : 0
|
| 21 |
}
|
| 22 |
|
| 23 |
}
|
| 24 |
|
| 25 |
handelSelected = () => {
|
| 26 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : !this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size, iframe : this.state.iframe})
|
| 27 |
}
|
| 28 |
|
| 29 |
handelSizeState = () => {
|
| 30 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : !this.state.size, iframe : this.state.iframe})
|
| 31 |
}
|
| 32 |
|
| 33 |
isFetchable = async (host) => {
|
|
|
|
| 46 |
this.state.data.delete(id)
|
| 47 |
}
|
| 48 |
|
| 49 |
+
onRefresh(){
|
| 50 |
+
if(!this.isFetchable) this.onNodeClick(this.state.id)
|
| 51 |
+
else{
|
| 52 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size, iframe : this.state.iframe + 1})
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
handelOnChange(evt, type){
|
| 57 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : type === "width" ? parseInt(evt.target.value) : this.state.width, height : type === "height" ? parseInt(evt.target.value) : this.state.height, size : this.state.size, iframe : this.state.iframe})
|
| 58 |
type === "width" ? this.myRef.current.style.width = `${parseInt(evt.target.value)}px` : this.myRef.current.style.height = `${parseInt(evt.target.value)}px`
|
| 59 |
}
|
| 60 |
|
| 61 |
handelSize(evt, increment, change){
|
| 62 |
if (evt === "increment") {
|
| 63 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : change === "width" ? this.state.width + increment : this.state.width, height : change === "height" ? this.state.height + increment : this.state.height, size : this.state.size, iframe : this.state.iframe})
|
| 64 |
change === "width" ? this.myRef.current.style.width = `${this.state.width + increment}px` : this.myRef.current.style.height = `${this.state.height + increment}px`
|
| 65 |
}
|
| 66 |
|
|
|
|
| 85 |
return (<>
|
| 86 |
<>
|
| 87 |
<div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
|
| 88 |
+
<div title="Collaspse Node" className=" duration-300 cursor-pointer shadow-xl border-2 border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Blue rounded-xl" onClick={this.handelSelected}><CgLayoutGridSmall className="h-full w-full text-white p-1"/></div>
|
| 89 |
|
| 90 |
|
| 91 |
<div className={` flex ${this.state.selected ? '' : 'w-0 hidden'}`}>
|
| 92 |
<div title="Adjust Node Size" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Violet rounded-xl" onClick={this.handelSizeState}><TbResize className="h-full w-full text-white p-1"/></div>
|
| 93 |
<a href={this.state.data.host} target="_blank" rel="noopener noreferrer"><div title="Gradio Host Site" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Pink rounded-xl"><BiCube className="h-full w-full text-white p-1"/></div></a>
|
| 94 |
<div title="Delete Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Red rounded-xl" onClick={() => this.onNodeClick(this.state.id)}><BsTrash className="h-full w-full text-white p-1"/></div>
|
| 95 |
+
<div title="Refresh Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Orange rounded-xl" onClick={() => this.onRefresh()}><BiRefresh className="h-full w-full text-white p-1"/></div>
|
| 96 |
+
|
| 97 |
+
{ this.state.size && <div className="duration-300 flex w-auto h-full mr-2 -mt-3 space-x-4">
|
| 98 |
{this.Counter("width", this.state.width)}
|
| 99 |
{this.Counter("height", this.state.height)}
|
| 100 |
</div>}
|
|
|
|
| 106 |
<div className={`absolute h-full w-full ${this.state.data.colour} border-1shadow-2xl shadow-black rounded-xl -z-20`}></div>
|
| 107 |
<iframe
|
| 108 |
id="iframe"
|
| 109 |
+
key={this.state.iframe}
|
| 110 |
src={this.state.data.host}
|
| 111 |
title={this.state.data.label}
|
| 112 |
frameBorder="0"
|
| 113 |
className=" -z-10 container h-full p-2 flex-grow space-iframe overflow-scroll "
|
|
|
|
| 114 |
sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>
|
| 115 |
</div>
|
| 116 |
</>
|
frontend/src/{Components β components}/ReactFlow/ReactFlowEnv.js
RENAMED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
import CustomNodeIframe from "../Nodes/Custom.js";
|
| 2 |
import '../../css/dist/output.css'
|
| 3 |
-
import '../../css/CustomNode.css'
|
| 4 |
import ReactFlow, { Background,
|
| 5 |
applyNodeChanges,
|
| 6 |
applyEdgeChanges,
|
|
@@ -16,14 +15,13 @@ const types = {
|
|
| 16 |
|
| 17 |
export default function ReactEnviorment() {
|
| 18 |
|
| 19 |
-
const [theme, setTheme] = useState(useThemeDetector
|
| 20 |
const [nodes, setNodes] = useState([]);
|
| 21 |
const [edges, setEdges] = useState([]);
|
| 22 |
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
| 23 |
const reactFlowWrapper = useRef(null);
|
| 24 |
|
| 25 |
|
| 26 |
-
|
| 27 |
const onNodesChange = useCallback(
|
| 28 |
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
| 29 |
[setNodes]
|
|
@@ -40,7 +38,7 @@ export default function ReactEnviorment() {
|
|
| 40 |
}, []);
|
| 41 |
|
| 42 |
const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
|
| 43 |
-
|
| 44 |
const onDrop = useCallback(
|
| 45 |
(event) => {
|
| 46 |
event.preventDefault();
|
|
@@ -74,7 +72,7 @@ export default function ReactEnviorment() {
|
|
| 74 |
<h1 className='text-4xl select-none' >{theme ? 'π' : 'βοΈ'}</h1>
|
| 75 |
</div>
|
| 76 |
<div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
|
| 77 |
-
<Navbar/>
|
| 78 |
<ReactFlowProvider>
|
| 79 |
<div className="h-screen w-screen" ref={reactFlowWrapper}>
|
| 80 |
<ReactFlow nodes={nodes} edges={edges} nodeTypes={types} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
|
|
|
|
| 1 |
import CustomNodeIframe from "../Nodes/Custom.js";
|
| 2 |
import '../../css/dist/output.css'
|
|
|
|
| 3 |
import ReactFlow, { Background,
|
| 4 |
applyNodeChanges,
|
| 5 |
applyEdgeChanges,
|
|
|
|
| 15 |
|
| 16 |
export default function ReactEnviorment() {
|
| 17 |
|
| 18 |
+
const [theme, setTheme] = useState(useThemeDetector)
|
| 19 |
const [nodes, setNodes] = useState([]);
|
| 20 |
const [edges, setEdges] = useState([]);
|
| 21 |
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
| 22 |
const reactFlowWrapper = useRef(null);
|
| 23 |
|
| 24 |
|
|
|
|
| 25 |
const onNodesChange = useCallback(
|
| 26 |
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
| 27 |
[setNodes]
|
|
|
|
| 38 |
}, []);
|
| 39 |
|
| 40 |
const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
|
| 41 |
+
const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
|
| 42 |
const onDrop = useCallback(
|
| 43 |
(event) => {
|
| 44 |
event.preventDefault();
|
|
|
|
| 72 |
<h1 className='text-4xl select-none' >{theme ? 'π' : 'βοΈ'}</h1>
|
| 73 |
</div>
|
| 74 |
<div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
|
| 75 |
+
<Navbar onDelete={deleteNodeContains}/>
|
| 76 |
<ReactFlowProvider>
|
| 77 |
<div className="h-screen w-screen" ref={reactFlowWrapper}>
|
| 78 |
<ReactFlow nodes={nodes} edges={edges} nodeTypes={types} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
|
frontend/src/css/CustomNode.css
DELETED
|
@@ -1,46 +0,0 @@
|
|
| 1 |
-
.hexagon {
|
| 2 |
-
position: relative;
|
| 3 |
-
width: 200px;
|
| 4 |
-
height: 115.47px;
|
| 5 |
-
background-color: #ffffff;
|
| 6 |
-
margin: 57.74px 0;
|
| 7 |
-
border-left: solid 3px #000000;
|
| 8 |
-
border-right: solid 3px #000000;
|
| 9 |
-
margin-left: auto;
|
| 10 |
-
margin-right: auto;
|
| 11 |
-
border-image-slice: 1;
|
| 12 |
-
border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
|
| 13 |
-
}
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
.hexagon:before,
|
| 17 |
-
.hexagon:after {
|
| 18 |
-
content: "";
|
| 19 |
-
position: absolute;
|
| 20 |
-
z-index: -1;
|
| 21 |
-
width: 141.42px;
|
| 22 |
-
height: 141.42px;
|
| 23 |
-
-webkit-transform: scaleY(0.5774) rotate(-30deg);
|
| 24 |
-
-ms-transform: scaleY(0.5774) rotate(-30deg);
|
| 25 |
-
transform: scaleY(0.5774) rotate(-45deg);
|
| 26 |
-
background-color: inherit;
|
| 27 |
-
left: 27.2893px;
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
.hexagon:before {
|
| 31 |
-
top: -70.7107px;
|
| 32 |
-
border-top: solid 4.8284px #000000;
|
| 33 |
-
border-right: solid 4.8284px #000000;
|
| 34 |
-
border-image-slice: 1;
|
| 35 |
-
border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
|
| 36 |
-
|
| 37 |
-
}
|
| 38 |
-
|
| 39 |
-
.hexagon:after {
|
| 40 |
-
bottom: -70.7107px;
|
| 41 |
-
border-bottom: solid 4.8284px #000000;
|
| 42 |
-
border-left: solid 4.8284px;
|
| 43 |
-
border-image-slice: 1;
|
| 44 |
-
border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
|
| 45 |
-
|
| 46 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/css/dist/output.css
CHANGED
|
@@ -744,22 +744,18 @@ video {
|
|
| 744 |
width: 0px;
|
| 745 |
}
|
| 746 |
|
| 747 |
-
.w
|
| 748 |
-
width:
|
| 749 |
-
}
|
| 750 |
-
|
| 751 |
-
.w-screen {
|
| 752 |
-
width: 100vw;
|
| 753 |
-
}
|
| 754 |
-
|
| 755 |
-
.w-\[560px\] {
|
| 756 |
-
width: 560px;
|
| 757 |
}
|
| 758 |
|
| 759 |
.w-\[540px\] {
|
| 760 |
width: 540px;
|
| 761 |
}
|
| 762 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 763 |
.flex-1 {
|
| 764 |
flex: 1 1 0%;
|
| 765 |
}
|
|
@@ -928,6 +924,11 @@ video {
|
|
| 928 |
background-color: rgb(255 96 93 / var(--tw-bg-opacity));
|
| 929 |
}
|
| 930 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 931 |
.bg-gradient-to-bl {
|
| 932 |
background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
|
| 933 |
}
|
|
@@ -992,6 +993,30 @@ video {
|
|
| 992 |
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 993 |
}
|
| 994 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 995 |
.via-purple-500 {
|
| 996 |
--tw-gradient-to: rgb(168 85 247 / 0);
|
| 997 |
--tw-gradient-stops: var(--tw-gradient-from), #a855f7, var(--tw-gradient-to);
|
|
@@ -1017,11 +1042,6 @@ video {
|
|
| 1017 |
--tw-gradient-stops: var(--tw-gradient-from), #F1A089, var(--tw-gradient-to);
|
| 1018 |
}
|
| 1019 |
|
| 1020 |
-
.via-Happy-Light-Magenta {
|
| 1021 |
-
--tw-gradient-to: rgb(207 123 198 / 0);
|
| 1022 |
-
--tw-gradient-stops: var(--tw-gradient-from), #CF7BC6, var(--tw-gradient-to);
|
| 1023 |
-
}
|
| 1024 |
-
|
| 1025 |
.via-Happy-Indego-Purple {
|
| 1026 |
--tw-gradient-to: rgb(148 98 233 / 0);
|
| 1027 |
--tw-gradient-stops: var(--tw-gradient-from), #9462E9, var(--tw-gradient-to);
|
|
@@ -1073,6 +1093,22 @@ video {
|
|
| 1073 |
--tw-gradient-to: #319B72;
|
| 1074 |
}
|
| 1075 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1076 |
.p-5 {
|
| 1077 |
padding: 1.25rem;
|
| 1078 |
}
|
|
@@ -1113,6 +1149,11 @@ video {
|
|
| 1113 |
padding-bottom: 0.5rem;
|
| 1114 |
}
|
| 1115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1116 |
.pt-8 {
|
| 1117 |
padding-top: 2rem;
|
| 1118 |
}
|
|
@@ -1141,6 +1182,10 @@ video {
|
|
| 1141 |
padding-top: 0.5rem;
|
| 1142 |
}
|
| 1143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1144 |
.text-left {
|
| 1145 |
text-align: left;
|
| 1146 |
}
|
|
@@ -1200,6 +1245,11 @@ video {
|
|
| 1200 |
color: rgb(0 0 0 / var(--tw-text-opacity));
|
| 1201 |
}
|
| 1202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1203 |
.shadow-lg {
|
| 1204 |
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
| 1205 |
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
@@ -1271,6 +1321,14 @@ video {
|
|
| 1271 |
color: rgb(148 163 184 / var(--tw-text-opacity));
|
| 1272 |
}
|
| 1273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1274 |
@-webkit-keyframes pulse {
|
| 1275 |
50% {
|
| 1276 |
opacity: .5;
|
|
|
|
| 744 |
width: 0px;
|
| 745 |
}
|
| 746 |
|
| 747 |
+
.w-auto {
|
| 748 |
+
width: auto;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 749 |
}
|
| 750 |
|
| 751 |
.w-\[540px\] {
|
| 752 |
width: 540px;
|
| 753 |
}
|
| 754 |
|
| 755 |
+
.w-screen {
|
| 756 |
+
width: 100vw;
|
| 757 |
+
}
|
| 758 |
+
|
| 759 |
.flex-1 {
|
| 760 |
flex: 1 1 0%;
|
| 761 |
}
|
|
|
|
| 924 |
background-color: rgb(255 96 93 / var(--tw-bg-opacity));
|
| 925 |
}
|
| 926 |
|
| 927 |
+
.bg-Warm-Orange {
|
| 928 |
+
--tw-bg-opacity: 1;
|
| 929 |
+
background-color: rgb(254 169 89 / var(--tw-bg-opacity));
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
.bg-gradient-to-bl {
|
| 933 |
background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
|
| 934 |
}
|
|
|
|
| 993 |
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 994 |
}
|
| 995 |
|
| 996 |
+
.from-Amethyst-Light {
|
| 997 |
+
--tw-gradient-from: #9D50BB;
|
| 998 |
+
--tw-gradient-to: rgb(157 80 187 / 0);
|
| 999 |
+
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 1000 |
+
}
|
| 1001 |
+
|
| 1002 |
+
.from-Peach-Red {
|
| 1003 |
+
--tw-gradient-from: #ED4264;
|
| 1004 |
+
--tw-gradient-to: rgb(237 66 100 / 0);
|
| 1005 |
+
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
.from-Deep-Space-Black {
|
| 1009 |
+
--tw-gradient-from: #000000;
|
| 1010 |
+
--tw-gradient-to: rgb(0 0 0 / 0);
|
| 1011 |
+
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 1012 |
+
}
|
| 1013 |
+
|
| 1014 |
+
.from-Sunshine-Red {
|
| 1015 |
+
--tw-gradient-from: #b92b27;
|
| 1016 |
+
--tw-gradient-to: rgb(185 43 39 / 0);
|
| 1017 |
+
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
| 1018 |
+
}
|
| 1019 |
+
|
| 1020 |
.via-purple-500 {
|
| 1021 |
--tw-gradient-to: rgb(168 85 247 / 0);
|
| 1022 |
--tw-gradient-stops: var(--tw-gradient-from), #a855f7, var(--tw-gradient-to);
|
|
|
|
| 1042 |
--tw-gradient-stops: var(--tw-gradient-from), #F1A089, var(--tw-gradient-to);
|
| 1043 |
}
|
| 1044 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1045 |
.via-Happy-Indego-Purple {
|
| 1046 |
--tw-gradient-to: rgb(148 98 233 / 0);
|
| 1047 |
--tw-gradient-stops: var(--tw-gradient-from), #9462E9, var(--tw-gradient-to);
|
|
|
|
| 1093 |
--tw-gradient-to: #319B72;
|
| 1094 |
}
|
| 1095 |
|
| 1096 |
+
.to-Amethyst-Dark {
|
| 1097 |
+
--tw-gradient-to: #6E48AA;
|
| 1098 |
+
}
|
| 1099 |
+
|
| 1100 |
+
.to-Peach-Yello {
|
| 1101 |
+
--tw-gradient-to: #FFEDBC;
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
.to-Deep-Space-Gray {
|
| 1105 |
+
--tw-gradient-to: #434343;
|
| 1106 |
+
}
|
| 1107 |
+
|
| 1108 |
+
.to-Sunshine-Blue {
|
| 1109 |
+
--tw-gradient-to: #1565C0;
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
.p-5 {
|
| 1113 |
padding: 1.25rem;
|
| 1114 |
}
|
|
|
|
| 1149 |
padding-bottom: 0.5rem;
|
| 1150 |
}
|
| 1151 |
|
| 1152 |
+
.px-6 {
|
| 1153 |
+
padding-left: 1.5rem;
|
| 1154 |
+
padding-right: 1.5rem;
|
| 1155 |
+
}
|
| 1156 |
+
|
| 1157 |
.pt-8 {
|
| 1158 |
padding-top: 2rem;
|
| 1159 |
}
|
|
|
|
| 1182 |
padding-top: 0.5rem;
|
| 1183 |
}
|
| 1184 |
|
| 1185 |
+
.pb-3 {
|
| 1186 |
+
padding-bottom: 0.75rem;
|
| 1187 |
+
}
|
| 1188 |
+
|
| 1189 |
.text-left {
|
| 1190 |
text-align: left;
|
| 1191 |
}
|
|
|
|
| 1245 |
color: rgb(0 0 0 / var(--tw-text-opacity));
|
| 1246 |
}
|
| 1247 |
|
| 1248 |
+
.underline {
|
| 1249 |
+
-webkit-text-decoration-line: underline;
|
| 1250 |
+
text-decoration-line: underline;
|
| 1251 |
+
}
|
| 1252 |
+
|
| 1253 |
.shadow-lg {
|
| 1254 |
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
| 1255 |
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
|
|
| 1321 |
color: rgb(148 163 184 / var(--tw-text-opacity));
|
| 1322 |
}
|
| 1323 |
|
| 1324 |
+
.placeholder\:text-transparent::-webkit-input-placeholder {
|
| 1325 |
+
color: transparent;
|
| 1326 |
+
}
|
| 1327 |
+
|
| 1328 |
+
.placeholder\:text-transparent::placeholder {
|
| 1329 |
+
color: transparent;
|
| 1330 |
+
}
|
| 1331 |
+
|
| 1332 |
@-webkit-keyframes pulse {
|
| 1333 |
50% {
|
| 1334 |
opacity: .5;
|
frontend/src/css/iframe.css
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
.Iframe_class{
|
| 2 |
-
position: absolute;
|
| 3 |
-
width: 100%!important;
|
| 4 |
-
height: 100%!important;
|
| 5 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/helper/visual.js
CHANGED
|
@@ -1,38 +1,41 @@
|
|
| 1 |
import '../css/dist/output.css'
|
| 2 |
-
const emote = ['πΊ',
|
| 3 |
|
| 4 |
-
const colour_map =
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
/**
|
| 19 |
-
*
|
| 20 |
-
*
|
| 21 |
-
"Warm-Violet" : "#8D379E",
|
| 22 |
-
"Warm-Pink" : "#F13484",
|
| 23 |
-
"Warm-Red" : "#FF605D",
|
| 24 |
-
"Warm-Orange" : "#FEA959",
|
| 25 |
-
"Warm-Yellow" : "#FEE27A",
|
| 26 |
*/
|
| 27 |
-
|
| 28 |
export const random_emoji = () =>{
|
| 29 |
return emote[Math.floor(Math.random() * emote.length)]
|
| 30 |
}
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
export const random_colour = () => {
|
| 33 |
-
return colour_map[Math.floor(Math.random() *
|
| 34 |
}
|
| 35 |
|
|
|
|
| 36 |
export const list_of_null = (idx) => {
|
| 37 |
var list = []
|
| 38 |
for(var i = 0; i < idx; i++ ) {
|
|
@@ -41,8 +44,11 @@ export const list_of_null = (idx) => {
|
|
| 41 |
return list
|
| 42 |
}
|
| 43 |
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
| 45 |
export const useThemeDetector = () => {
|
| 46 |
const getCurrentTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
|
| 47 |
-
return getCurrentTheme;
|
| 48 |
}
|
|
|
|
| 1 |
import '../css/dist/output.css'
|
| 2 |
+
const emote = ['πΊ','π','π','πΎ','π€','π₯','π§ ','πΏ','π¦Ύ','π¦','β¨','π‘','π΅','π¦','π','π','π₯','π','π','π§¬','π','π','π','π','π±','π']
|
| 3 |
|
| 4 |
+
const colour_map = [
|
| 5 |
+
'bg-gradient-to-bl from-Retro-light-blue to-Retro-light-pink',
|
| 6 |
+
'bg-gradient-to-bl from-Vapor-Violet to-Vapor-Orange',
|
| 7 |
+
'bg-gradient-to-bl from-Retro-purple to-Vapor-Pink',
|
| 8 |
+
'bg-gradient-to-bl from-Retro-purple to-Vapor-Blue',
|
| 9 |
+
'bg-gradient-to-bl from-Retro-light-pink to-Vapor-Blue',
|
| 10 |
+
'bg-gradient-to-bl from-indigo-500 via-purple-500 to-pink-500',
|
| 11 |
+
'bg-gradient-to-bl from-Vapor-Rose to-Vapor-Blue',
|
| 12 |
+
'bg-gradient-to-bl from-Warm-Blue via-Warm-Pink via-Warm-Red via-Warm-Orange to-Warm-Yellow',
|
| 13 |
+
'bg-gradient-to-bl from-Happy-Yellow via-Happy-Tangerine via-Happy-Indego-Purple via-Cool-Blue to-Happy-Sea-Blue',
|
| 14 |
+
'bg-gradient-to-bl from-Blue-Turquoise via-Blue-Midtone to-Blue-Royal',
|
| 15 |
+
'bg-gradient-to-bl from-Green-Black via-Green-Forest to-Green-Emerald',
|
| 16 |
+
'bg-gradient-to-bl from-Amethyst-Light to-Amethyst-Dark',
|
| 17 |
+
'bg-gradient-to-bl from-Peach-Red to-Peach-Yello',
|
| 18 |
+
'bg-gradient-to-bl from-Deep-Space-Black to-Deep-Space-Gray',
|
| 19 |
+
'bg-gradient-to-bl from-Sunshine-Red to-Sunshine-Blue'
|
| 20 |
+
]
|
| 21 |
|
| 22 |
/**
|
| 23 |
+
* Get a random emoji from emote array
|
| 24 |
+
* @returns random emoji from emote array
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
*/
|
|
|
|
| 26 |
export const random_emoji = () =>{
|
| 27 |
return emote[Math.floor(Math.random() * emote.length)]
|
| 28 |
}
|
| 29 |
|
| 30 |
+
/**
|
| 31 |
+
* Get a random color string from colour_map array
|
| 32 |
+
* @returns random color css string
|
| 33 |
+
*/
|
| 34 |
export const random_colour = () => {
|
| 35 |
+
return colour_map[Math.floor(Math.random() * colour_map.length)]
|
| 36 |
}
|
| 37 |
|
| 38 |
+
|
| 39 |
export const list_of_null = (idx) => {
|
| 40 |
var list = []
|
| 41 |
for(var i = 0; i < idx; i++ ) {
|
|
|
|
| 44 |
return list
|
| 45 |
}
|
| 46 |
|
| 47 |
+
/**
|
| 48 |
+
*
|
| 49 |
+
* @returns
|
| 50 |
+
*/
|
| 51 |
export const useThemeDetector = () => {
|
| 52 |
const getCurrentTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
|
| 53 |
+
return getCurrentTheme();
|
| 54 |
}
|
frontend/tailwind.config.js
CHANGED
|
@@ -7,6 +7,14 @@ module.exports = {
|
|
| 7 |
extend: {
|
| 8 |
|
| 9 |
colors : {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
"Retro-light-blue" : "#2de2e6",
|
| 11 |
"Retro-dark-blue" : "#035ee8",
|
| 12 |
"Retro-light-pink" : "#f6019d",
|
|
|
|
| 7 |
extend: {
|
| 8 |
|
| 9 |
colors : {
|
| 10 |
+
"Amethyst-Light" : "#9D50BB",
|
| 11 |
+
"Amethyst-Dark" : "#6E48AA",
|
| 12 |
+
"Peach-Red" : "#ED4264",
|
| 13 |
+
"Peach-Yello" : "#FFEDBC",
|
| 14 |
+
"Deep-Space-Black" : "#000000",
|
| 15 |
+
"Deep-Space-Gray" : "#434343",
|
| 16 |
+
"Sunshine-Red" : "#b92b27",
|
| 17 |
+
"Sunshine-Blue" : "#1565C0",
|
| 18 |
"Retro-light-blue" : "#2de2e6",
|
| 19 |
"Retro-dark-blue" : "#035ee8",
|
| 20 |
"Retro-light-pink" : "#f6019d",
|
images/application_dark.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
images/application_light.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|