Spaces:
Configuration error
Configuration error
zack
commited on
Commit
·
3fde1d6
1
Parent(s):
651209c
✨ Enhance navbar responsiveness and UI/UX improvements
Browse files
frontend/src/components/Navagation/navbar.js
CHANGED
@@ -5,30 +5,31 @@ import { random_colour, random_emoji } from "../../helper/visual";
|
|
5 |
|
6 |
import "../../css/dist/output.css"
|
7 |
|
8 |
-
import {BsArrowLeftShort} from 'react-icons/bs';
|
9 |
-
import {ReactComponent as ReactLogo} from '../../images/logo.svg'
|
|
|
10 |
|
11 |
-
export default class Navbar extends Component{
|
12 |
-
constructor(props){
|
13 |
-
super(props)
|
14 |
this.temp_host = 0
|
15 |
this.deleteNode = props.onDelete
|
16 |
this.state = {
|
17 |
-
open
|
18 |
-
menu
|
19 |
-
colour
|
20 |
-
text
|
21 |
-
name
|
22 |
-
emoji
|
23 |
-
mode
|
24 |
-
modal
|
25 |
-
error
|
26 |
-
|
27 |
-
|
28 |
}
|
29 |
|
30 |
-
componentDidMount(){
|
31 |
-
this.fetch_classes()
|
32 |
|
33 |
}
|
34 |
|
@@ -38,17 +39,17 @@ export default class Navbar extends Component{
|
|
38 |
*/
|
39 |
fetch_classes = async () => {
|
40 |
try {
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
}catch(e){
|
52 |
console.log(e)
|
53 |
}
|
54 |
}
|
@@ -58,33 +59,34 @@ export default class Navbar extends Component{
|
|
58 |
*/
|
59 |
appendStreamNode = async (type) => {
|
60 |
const pattern = {
|
61 |
-
local
|
62 |
-
share
|
63 |
huggingFace: new RegExp('^https?://([a-zA-Z0-9-]+\\.hf\\.space)/?$'),
|
64 |
proxmoxVNC: new RegExp('^wss?://([a-zA-Z0-9-]+\\.yourdomain\\.com)/?$') // Regex pattern for Proxmox VNC URLs
|
65 |
-
}
|
66 |
|
67 |
if (this.state.name.length > 20 ||
|
68 |
-
this.state.text === ""||
|
69 |
-
this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.text) }) !== -1 ||
|
70 |
-
this.state.text.includes(" ") ||
|
71 |
(!pattern.local.test(this.state.text) &&
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
|
|
88 |
}
|
89 |
|
90 |
/**
|
@@ -96,11 +98,11 @@ export default class Navbar extends Component{
|
|
96 |
if (!proxmoxVncInfo) return null; // If no Proxmox VNC info, don't render anything
|
97 |
|
98 |
return (
|
99 |
-
<li onDragStart={(event) => this.onDragStart(event, 'proxmoxVNC', proxmoxVncInfo, -1)}
|
100 |
className="text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg p-5 px-2 mt-4 rounded-md hover:animate-pulse"
|
101 |
draggable>
|
102 |
<div className="absolute -mt-2 text-4xl opacity-60 z-10">{random_emoji()}</div>
|
103 |
-
<h4 className="max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20" style={{"textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)"}}>
|
104 |
Proxmox VNC
|
105 |
</h4>
|
106 |
</li>
|
@@ -112,8 +114,10 @@ export default class Navbar extends Component{
|
|
112 |
* @param {*} bool boolean of the current state of the modal
|
113 |
*/
|
114 |
handelModal = (bool) => {
|
115 |
-
this.setState({
|
116 |
-
|
|
|
|
|
117 |
}
|
118 |
|
119 |
/**
|
@@ -125,10 +129,10 @@ export default class Navbar extends Component{
|
|
125 |
*/
|
126 |
onDragStart = (event, nodeType, item, index) => {
|
127 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
128 |
-
event.dataTransfer.setData('application/style', JSON.stringify({colour
|
129 |
-
event.dataTransfer.setData('application/item',
|
130 |
event.dataTransfer.effectAllowed = 'move';
|
131 |
-
|
132 |
|
133 |
/**
|
134 |
* droped event that occurs when the user drops the Tab within the tash div.
|
@@ -138,11 +142,11 @@ export default class Navbar extends Component{
|
|
138 |
*/
|
139 |
onDragDrop = (e) => {
|
140 |
e.preventDefault();
|
141 |
-
var item
|
142 |
-
fetch("http://localhost:2000/api/remove/port", {method
|
143 |
this.deleteNode(item.name)
|
144 |
})
|
145 |
-
|
146 |
}
|
147 |
|
148 |
/**
|
@@ -157,37 +161,37 @@ export default class Navbar extends Component{
|
|
157 |
var c = []
|
158 |
var j = []
|
159 |
if (d.length - e.length === 0) return
|
160 |
-
else if(d.length - e.length < 0){
|
161 |
var a = this.state.menu.filter(item => e.includes(item)) // get the items not in menu anymore
|
162 |
c = this.state.colour
|
163 |
j = this.state.emoji
|
164 |
-
for(var k=0; k < d.length; k++){
|
165 |
c.splice(this.state.menu.indexOf(a[k]), 1)
|
166 |
j.splice(this.state.menu.indexOf(a[k]), 1)
|
167 |
}
|
168 |
-
this.setState({'colour'
|
169 |
-
}else{
|
170 |
//append new colours
|
171 |
-
for(var i =0; i < d.length; i++){
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
}
|
176 |
const colour = [...this.state.colour]
|
177 |
-
const emoji
|
178 |
-
this.setState({'colour'
|
179 |
}
|
180 |
}
|
181 |
|
182 |
handelError = (boolean) => {
|
183 |
-
this.setState({'error'
|
184 |
}
|
185 |
|
186 |
/**
|
187 |
* handel navagation open and close function
|
188 |
*/
|
189 |
handelNavbar = () => {
|
190 |
-
this.setState({'open'
|
191 |
}
|
192 |
|
193 |
/**
|
@@ -196,7 +200,7 @@ export default class Navbar extends Component{
|
|
196 |
* @param {*} type : text | name string that set the changed value of the input to the current value
|
197 |
*/
|
198 |
updateText = (e, type) => {
|
199 |
-
this.setState({[`${type}`]
|
200 |
}
|
201 |
|
202 |
/**
|
@@ -205,59 +209,62 @@ export default class Navbar extends Component{
|
|
205 |
* @param {*} index : current index with in the list
|
206 |
* @returns div component that contians infomation of gradio
|
207 |
*/
|
208 |
-
subComponents(item, index){
|
209 |
-
|
210 |
-
return(<>
|
211 |
-
|
212 |
-
|
213 |
-
p-5 px-2 mt-4 rounded-md ${
|
214 |
|
215 |
-
|
216 |
-
|
217 |
|
218 |
-
|
219 |
|
220 |
</>)
|
221 |
}
|
222 |
|
223 |
|
224 |
-
render(){
|
225 |
-
|
226 |
return (<div>
|
227 |
-
|
228 |
-
<div className={`z-10 flex-1 float-left bg-white dark:bg-stone-900 h-screen p-5 pt-8 ${this.state.open ? "lg:w-72 md:64 sm:w-60" : "w-10"} duration-300 absolute shadow-2xl border-black border-r-[1px] dark:border-white dark:text-white`} >
|
229 |
|
230 |
-
<
|
231 |
|
|
|
232 |
<div className="inline-flex w-full">
|
233 |
-
<
|
|
|
|
|
|
|
|
|
234 |
</div>
|
235 |
|
236 |
-
<div className={`rounded-md text-center ${this.state.open ? "" : "px-0"} py-3`} onClick={() => {this.handelModal(true)}}>
|
237 |
<div className={` text-center bg-transparent w-full h-10 border border-slate-300 hover:border-Retro-purple hover:animate-pulse border-dashed rounded-md py-2 pl-5 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
|
238 |
-
<Icon className=" block mr-auto ml-auto" name="plus"/>
|
239 |
</div>
|
240 |
</div>
|
241 |
-
<Import open={this.state.modal}
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
<div className=" relative z-10 h-auto overflow-auto pt-4">
|
249 |
<ul className="pt-2">
|
250 |
-
|
251 |
</ul>
|
252 |
</div>
|
253 |
|
254 |
-
<div className={`${this.state.open ? "" : "hidden"} absolute bottom-0 left-0 w-full text-center p-5`} onDragOver={(e)=> {e.preventDefault()}} onDrop={(e)=>{this.onDragDrop(e)}}>
|
255 |
<div className={` text-center bg-transparent w-full h-10 border border-red-600 border-dashed rounded-md py-2 pl-5 p-4 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
|
256 |
-
<Icon name='trash alternate' />
|
257 |
</div>
|
258 |
</div>
|
259 |
</div>
|
260 |
-
|
261 |
</div>)
|
262 |
}
|
263 |
}
|
|
|
5 |
|
6 |
import "../../css/dist/output.css"
|
7 |
|
8 |
+
import { BsArrowLeftShort } from 'react-icons/bs';
|
9 |
+
import { ReactComponent as ReactLogo } from '../../images/logo.svg'
|
10 |
+
import chattyImage from '../../images/chatty.png';
|
11 |
|
12 |
+
export default class Navbar extends Component {
|
13 |
+
constructor(props) {
|
14 |
+
super(props)
|
15 |
this.temp_host = 0
|
16 |
this.deleteNode = props.onDelete
|
17 |
this.state = {
|
18 |
+
open: true,
|
19 |
+
menu: [],
|
20 |
+
colour: props.colour || [],
|
21 |
+
text: "",
|
22 |
+
name: "",
|
23 |
+
emoji: props.emoji || [],
|
24 |
+
mode: false,
|
25 |
+
modal: false,
|
26 |
+
error: false
|
27 |
+
}
|
28 |
+
|
29 |
}
|
30 |
|
31 |
+
componentDidMount() {
|
32 |
+
this.fetch_classes()
|
33 |
|
34 |
}
|
35 |
|
|
|
39 |
*/
|
40 |
fetch_classes = async () => {
|
41 |
try {
|
42 |
+
setInterval(async () => {
|
43 |
+
await fetch("http://localhost:2000/api/open/ports", { method: 'GET', mode: 'cors', })
|
44 |
+
.then(response => response.json())
|
45 |
+
.then(data => {
|
46 |
+
this.handelTabs(this.state.menu, data, data)
|
47 |
+
this.setState({ menu: data })
|
48 |
+
})
|
49 |
+
.catch(error => { console.log(error) })
|
50 |
+
|
51 |
+
}, 1000);
|
52 |
+
} catch (e) {
|
53 |
console.log(e)
|
54 |
}
|
55 |
}
|
|
|
59 |
*/
|
60 |
appendStreamNode = async (type) => {
|
61 |
const pattern = {
|
62 |
+
local: new RegExp('^https?://(localhost)(:[0-9]+)?(/)?$'),
|
63 |
+
share: new RegExp('^https?://(?:[a-zA-Z0-9]+\\.gradio\\.live)/?$'),
|
64 |
huggingFace: new RegExp('^https?://([a-zA-Z0-9-]+\\.hf\\.space)/?$'),
|
65 |
proxmoxVNC: new RegExp('^wss?://([a-zA-Z0-9-]+\\.yourdomain\\.com)/?$') // Regex pattern for Proxmox VNC URLs
|
66 |
+
}
|
67 |
|
68 |
if (this.state.name.length > 20 ||
|
69 |
+
this.state.text === "" ||
|
70 |
+
this.state.menu.findIndex(element => { return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.text) }) !== -1 ||
|
71 |
+
this.state.text.includes(" ") ||
|
72 |
(!pattern.local.test(this.state.text) &&
|
73 |
+
!pattern.share.test(this.state.text) &&
|
74 |
+
!pattern.huggingFace.test(this.state.text) &&
|
75 |
+
!pattern.proxmoxVNC.test(this.state.text))) {
|
76 |
+
|
77 |
+
this.setState({
|
78 |
+
'text': '',
|
79 |
+
'name': '',
|
80 |
+
'error': true
|
81 |
+
})
|
82 |
+
return
|
83 |
+
}
|
84 |
+
fetch(this.state.text, { method: "GET", mode: 'no-cors' }).then((re) => {
|
85 |
+
fetch("http://localhost:2000/api/append/port", { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file: "", kwargs: { type: type }, name: this.state.name === "" ? `temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0, host: this.state.text }) }).then(resp => {
|
86 |
+
this.setState({ 'text': "", 'name': "", 'error': false, 'modal': false })
|
87 |
+
|
88 |
+
}).catch(() => this.setState({ 'text': '', 'name': '', 'error': true, }))
|
89 |
+
}).catch((err) => this.setState({ 'text': '', 'name': '', 'error': true, }))
|
90 |
}
|
91 |
|
92 |
/**
|
|
|
98 |
if (!proxmoxVncInfo) return null; // If no Proxmox VNC info, don't render anything
|
99 |
|
100 |
return (
|
101 |
+
<li onDragStart={(event) => this.onDragStart(event, 'proxmoxVNC', proxmoxVncInfo, -1)}
|
102 |
className="text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg p-5 px-2 mt-4 rounded-md hover:animate-pulse"
|
103 |
draggable>
|
104 |
<div className="absolute -mt-2 text-4xl opacity-60 z-10">{random_emoji()}</div>
|
105 |
+
<h4 className="max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20" style={{ "textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)" }}>
|
106 |
Proxmox VNC
|
107 |
</h4>
|
108 |
</li>
|
|
|
114 |
* @param {*} bool boolean of the current state of the modal
|
115 |
*/
|
116 |
handelModal = (bool) => {
|
117 |
+
this.setState({
|
118 |
+
'error': !bool ? false : this.state.error,
|
119 |
+
'modal': bool
|
120 |
+
})
|
121 |
}
|
122 |
|
123 |
/**
|
|
|
129 |
*/
|
130 |
onDragStart = (event, nodeType, item, index) => {
|
131 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
132 |
+
event.dataTransfer.setData('application/style', JSON.stringify({ colour: this.state.colour[index], emoji: this.state.emoji[index] }))
|
133 |
+
event.dataTransfer.setData('application/item', JSON.stringify(item))
|
134 |
event.dataTransfer.effectAllowed = 'move';
|
135 |
+
};
|
136 |
|
137 |
/**
|
138 |
* droped event that occurs when the user drops the Tab within the tash div.
|
|
|
142 |
*/
|
143 |
onDragDrop = (e) => {
|
144 |
e.preventDefault();
|
145 |
+
var item = JSON.parse(e.dataTransfer.getData('application/item'));
|
146 |
+
fetch("http://localhost:2000/api/remove/port", { method: "POST", mode: 'cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(item) }).then((re) => {
|
147 |
this.deleteNode(item.name)
|
148 |
})
|
149 |
+
|
150 |
}
|
151 |
|
152 |
/**
|
|
|
161 |
var c = []
|
162 |
var j = []
|
163 |
if (d.length - e.length === 0) return
|
164 |
+
else if (d.length - e.length < 0) {
|
165 |
var a = this.state.menu.filter(item => e.includes(item)) // get the items not in menu anymore
|
166 |
c = this.state.colour
|
167 |
j = this.state.emoji
|
168 |
+
for (var k = 0; k < d.length; k++) {
|
169 |
c.splice(this.state.menu.indexOf(a[k]), 1)
|
170 |
j.splice(this.state.menu.indexOf(a[k]), 1)
|
171 |
}
|
172 |
+
this.setState({ 'colour': c, 'emoji': j })
|
173 |
+
} else {
|
174 |
//append new colours
|
175 |
+
for (var i = 0; i < d.length; i++) {
|
176 |
+
c.push(random_colour(i === 0 ? null : c[i - 1]));
|
177 |
+
j.push(random_emoji(i === 0 ? null : c[i - 1]));
|
178 |
+
|
179 |
}
|
180 |
const colour = [...this.state.colour]
|
181 |
+
const emoji = [...this.state.emoji]
|
182 |
+
this.setState({ 'colour': [...colour, ...c], 'emoji': [...emoji, ...j], })
|
183 |
}
|
184 |
}
|
185 |
|
186 |
handelError = (boolean) => {
|
187 |
+
this.setState({ 'error': boolean })
|
188 |
}
|
189 |
|
190 |
/**
|
191 |
* handel navagation open and close function
|
192 |
*/
|
193 |
handelNavbar = () => {
|
194 |
+
this.setState({ 'open': !this.state.open })
|
195 |
}
|
196 |
|
197 |
/**
|
|
|
200 |
* @param {*} type : text | name string that set the changed value of the input to the current value
|
201 |
*/
|
202 |
updateText = (e, type) => {
|
203 |
+
this.setState({ [`${type}`]: e.target.value })
|
204 |
}
|
205 |
|
206 |
/**
|
|
|
209 |
* @param {*} index : current index with in the list
|
210 |
* @returns div component that contians infomation of gradio
|
211 |
*/
|
212 |
+
subComponents(item, index) {
|
213 |
+
|
214 |
+
return (<>
|
215 |
+
<li key={`${index}-li`} onDragStart={(event) => this.onDragStart(event, 'custom', item, index)}
|
216 |
+
className={` text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg
|
217 |
+
p-5 px-2 mt-4 rounded-md ${this.state.open ? `hover:animate-pulse ${this.state.colour[index] === null ? "" : this.state.colour[index]} ` : `hidden`} break-all -z-20`} draggable>
|
218 |
|
219 |
+
<div key={`${index}-div`} className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
|
220 |
+
<h4 key={`${index}-h4`} className={` max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20 ${this.state.open ? "" : "hidden"}`} style={{ "textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)" }} >{`${item.name}`} </h4>
|
221 |
|
222 |
+
</li >
|
223 |
|
224 |
</>)
|
225 |
}
|
226 |
|
227 |
|
228 |
+
render() {
|
229 |
+
|
230 |
return (<div>
|
|
|
|
|
231 |
|
232 |
+
<div className={`z-10 flex-1 float-left bg-white dark:bg-stone-900 h-screen p-5 pt-8 ${this.state.open ? "lg:w-72 md:64 sm:w-60" : "w-10"} duration-300 absolute shadow-2xl border-black border-r-[1px] dark:border-white dark:text-white`} >
|
233 |
|
234 |
+
<BsArrowLeftShort onClick={this.handelNavbar} className={` bg-white text-Retro-darl-blue text-3xl rounded-full absolute -right-3 top-9 border border-black cursor-pointer ${!this.state.open && 'rotate-180'} dark:border-white duration-300 dark:text-white dark:bg-stone-900 `} />
|
235 |
<div className="inline-flex w-full">
|
236 |
+
<img src={chattyImage} alt="Chat'nFace Logo" className={`h-12 w-auto ${this.state.open ? "visible" : "hidden"}`} /> {/* Display the image */}
|
237 |
+
<h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}>Chat-nFace</h1>
|
238 |
+
</div>
|
239 |
+
<div className="inline-flex w-full">
|
240 |
+
<h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}>Chat-nFace</h1>
|
241 |
</div>
|
242 |
|
243 |
+
<div className={`rounded-md text-center ${this.state.open ? "" : "px-0"} py-3`} onClick={() => { this.handelModal(true) }}>
|
244 |
<div className={` text-center bg-transparent w-full h-10 border border-slate-300 hover:border-Retro-purple hover:animate-pulse border-dashed rounded-md py-2 pl-5 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
|
245 |
+
<Icon className=" block mr-auto ml-auto" name="plus" />
|
246 |
</div>
|
247 |
</div>
|
248 |
+
<Import open={this.state.modal}
|
249 |
+
quitHandeler={this.handelModal}
|
250 |
+
textHandler={this.updateText}
|
251 |
+
appendHandler={this.appendStreamNode}
|
252 |
+
handelError={this.handelError}
|
253 |
+
catch={this.state.error} />
|
254 |
+
|
255 |
<div className=" relative z-10 h-auto overflow-auto pt-4">
|
256 |
<ul className="pt-2">
|
257 |
+
{this.state.menu.map((menu, index) => { return this.subComponents(menu, index) })}
|
258 |
</ul>
|
259 |
</div>
|
260 |
|
261 |
+
<div className={`${this.state.open ? "" : "hidden"} absolute bottom-0 left-0 w-full text-center p-5`} onDragOver={(e) => { e.preventDefault() }} onDrop={(e) => { this.onDragDrop(e) }}>
|
262 |
<div className={` text-center bg-transparent w-full h-10 border border-red-600 border-dashed rounded-md py-2 pl-5 p-4 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
|
263 |
+
<Icon name='trash alternate' />
|
264 |
</div>
|
265 |
</div>
|
266 |
</div>
|
267 |
+
|
268 |
</div>)
|
269 |
}
|
270 |
}
|