Spaces:
Configuration error
Configuration error
LucaVivona
commited on
Commit
β’
c2ebfb9
1
Parent(s):
16543f4
Save Board πΎ
Browse files
frontend/src/components/Navagation/navbar.js
CHANGED
@@ -8,19 +8,19 @@ import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
|
|
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 :
|
17 |
text : "",
|
18 |
name : "",
|
19 |
-
emoji :
|
20 |
mode : false,
|
21 |
modal : false,
|
22 |
error : false
|
23 |
}
|
|
|
24 |
}
|
25 |
|
26 |
|
@@ -79,7 +79,7 @@ export default class Navbar extends Component{
|
|
79 |
}
|
80 |
|
81 |
fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
|
82 |
-
console.log(re)
|
83 |
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 => {
|
84 |
this.setState({open : this.state.open,
|
85 |
menu : this.state.menu,
|
@@ -99,7 +99,7 @@ export default class Navbar extends Component{
|
|
99 |
error : true,
|
100 |
modal : this.state.modal }))
|
101 |
}).catch((err)=>{
|
102 |
-
console.log(err)
|
103 |
this.setState({open : this.state.open,
|
104 |
menu : this.state.menu,
|
105 |
text: '',
|
@@ -135,7 +135,7 @@ export default class Navbar extends Component{
|
|
135 |
*/
|
136 |
onDragStart = (event, nodeType, item, index) => {
|
137 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
138 |
-
event.dataTransfer.setData('application/
|
139 |
event.dataTransfer.setData('application/item', JSON.stringify(item))
|
140 |
event.dataTransfer.effectAllowed = 'move';
|
141 |
};
|
@@ -161,7 +161,10 @@ export default class Navbar extends Component{
|
|
161 |
* @param {*} d integer variable of the diffence between the current menu and new menu updated ment
|
162 |
*/
|
163 |
hanelTabs = (e, d) => {
|
164 |
-
|
|
|
|
|
|
|
165 |
// if less then 0 we must remove colour's and emoji's
|
166 |
// get index of the object
|
167 |
// remove
|
@@ -178,6 +181,7 @@ export default class Navbar extends Component{
|
|
178 |
this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : c, emoji : j, error : this.state.error, modal : this.state.modal })
|
179 |
}else{
|
180 |
//append new colours
|
|
|
181 |
for(var i =0; i < d; i++){
|
182 |
c.push(random_colour(i === 0 ? null : c[i-1]));
|
183 |
j.push(random_emoji(i === 0 ? null : c[i-1]));
|
@@ -187,13 +191,6 @@ export default class Navbar extends Component{
|
|
187 |
}
|
188 |
}
|
189 |
|
190 |
-
/**
|
191 |
-
* Append a new colour, and emoji to the colour and emoji list with in the state of the component
|
192 |
-
*/
|
193 |
-
appendTabs = () => {
|
194 |
-
this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour(this.state.colour[this.state.colour.length - 1] )] , emoji : [...this.state.emoji, random_emoji(this.state.emoji[this.state.emoji.length - 1] )], error : this.state.error, modal : this.state.modal })
|
195 |
-
}
|
196 |
-
|
197 |
/**
|
198 |
* handel navagation open and close function
|
199 |
*/
|
@@ -224,7 +221,7 @@ export default class Navbar extends Component{
|
|
224 |
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>
|
225 |
|
226 |
<div className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
|
227 |
-
<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={{"
|
228 |
|
229 |
</li >
|
230 |
|
@@ -260,7 +257,7 @@ export default class Navbar extends Component{
|
|
260 |
Append Shared Gradio Hosts
|
261 |
</Header>
|
262 |
<Modal.Content>
|
263 |
-
<div className=" text-center select-none">Host other HugginFace Models or Gradio application via shared
|
264 |
<div className={`flex items-center rounded-md bg-light-white mt-6 border-dashed`}>
|
265 |
<label className="relative block w-full">
|
266 |
<span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
|
|
|
8 |
export default class Navbar extends Component{
|
9 |
constructor(props){
|
10 |
super(props)
|
|
|
11 |
this.temp_host = 0
|
12 |
this.deleteNode = props.onDelete
|
13 |
this.state = {open : true,
|
14 |
menu : [],
|
15 |
+
colour : props.colour,
|
16 |
text : "",
|
17 |
name : "",
|
18 |
+
emoji : props.emoji,
|
19 |
mode : false,
|
20 |
modal : false,
|
21 |
error : false
|
22 |
}
|
23 |
+
this.fetch_classes()
|
24 |
}
|
25 |
|
26 |
|
|
|
79 |
}
|
80 |
|
81 |
fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
|
82 |
+
//console.log(re)
|
83 |
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 => {
|
84 |
this.setState({open : this.state.open,
|
85 |
menu : this.state.menu,
|
|
|
99 |
error : true,
|
100 |
modal : this.state.modal }))
|
101 |
}).catch((err)=>{
|
102 |
+
//console.log(err)
|
103 |
this.setState({open : this.state.open,
|
104 |
menu : this.state.menu,
|
105 |
text: '',
|
|
|
135 |
*/
|
136 |
onDragStart = (event, nodeType, item, index) => {
|
137 |
event.dataTransfer.setData('application/reactflow', nodeType);
|
138 |
+
event.dataTransfer.setData('application/style', JSON.stringify({colour : this.state.colour[index], emoji : this.state.emoji[index] }))
|
139 |
event.dataTransfer.setData('application/item', JSON.stringify(item))
|
140 |
event.dataTransfer.effectAllowed = 'move';
|
141 |
};
|
|
|
161 |
* @param {*} d integer variable of the diffence between the current menu and new menu updated ment
|
162 |
*/
|
163 |
hanelTabs = (e, d) => {
|
164 |
+
if (e.length === this.state.colour.length){
|
165 |
+
this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
|
166 |
+
return
|
167 |
+
}
|
168 |
// if less then 0 we must remove colour's and emoji's
|
169 |
// get index of the object
|
170 |
// remove
|
|
|
181 |
this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : c, emoji : j, error : this.state.error, modal : this.state.modal })
|
182 |
}else{
|
183 |
//append new colours
|
184 |
+
|
185 |
for(var i =0; i < d; i++){
|
186 |
c.push(random_colour(i === 0 ? null : c[i-1]));
|
187 |
j.push(random_emoji(i === 0 ? null : c[i-1]));
|
|
|
191 |
}
|
192 |
}
|
193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
/**
|
195 |
* handel navagation open and close function
|
196 |
*/
|
|
|
221 |
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>
|
222 |
|
223 |
<div className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
|
224 |
+
<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>
|
225 |
|
226 |
</li >
|
227 |
|
|
|
257 |
Append Shared Gradio Hosts
|
258 |
</Header>
|
259 |
<Modal.Content>
|
260 |
+
<div className=" text-center select-none">Host other HugginFace Models or Gradio application via shared link</div>
|
261 |
<div className={`flex items-center rounded-md bg-light-white mt-6 border-dashed`}>
|
262 |
<label className="relative block w-full">
|
263 |
<span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
|
frontend/src/components/Nodes/Custom.js
CHANGED
@@ -37,7 +37,6 @@ export default class CustomNodeIframe extends React.Component {
|
|
37 |
fetch(host, {mode: 'no-cors'}).then((re) => {
|
38 |
return true
|
39 |
}).catch((err)=>{
|
40 |
-
alert(`π€ͺ Something went wrong the url that that was put in is not reachable...\n\n${err}`)
|
41 |
return false
|
42 |
})
|
43 |
return false
|
@@ -49,8 +48,9 @@ export default class CustomNodeIframe extends React.Component {
|
|
49 |
}
|
50 |
|
51 |
onRefresh(){
|
52 |
-
if(!this.isFetchable
|
53 |
-
|
|
|
54 |
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, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
|
55 |
}
|
56 |
}
|
@@ -74,8 +74,9 @@ export default class CustomNodeIframe extends React.Component {
|
|
74 |
}
|
75 |
|
76 |
resize = (e) => {
|
77 |
-
|
78 |
-
this.
|
|
|
79 |
}
|
80 |
|
81 |
Counter(focus, size){
|
@@ -93,7 +94,7 @@ export default class CustomNodeIframe extends React.Component {
|
|
93 |
}
|
94 |
|
95 |
render(){
|
96 |
-
if (!this.state.reachable) this.onNodeClick(this.state.id)
|
97 |
return (<>
|
98 |
<>
|
99 |
<div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
|
@@ -128,8 +129,8 @@ export default class CustomNodeIframe extends React.Component {
|
|
128 |
{/* (Experimental) Do not uncomment */}
|
129 |
<div className={`absolute bottom-0 w-full h-10 bg-transparent border-1 shadow-2xl rounded-xl z-10 cursor-ns-resize`}
|
130 |
draggable
|
131 |
-
onDragStart={(e) => { this.initial(e)}}
|
132 |
-
onDrag={(e) => { this.resize(e)}}
|
133 |
></div>
|
134 |
</>
|
135 |
</>)
|
|
|
37 |
fetch(host, {mode: 'no-cors'}).then((re) => {
|
38 |
return true
|
39 |
}).catch((err)=>{
|
|
|
40 |
return false
|
41 |
})
|
42 |
return false
|
|
|
48 |
}
|
49 |
|
50 |
onRefresh(){
|
51 |
+
if(!this.isFetchable(this.state.data.host)){
|
52 |
+
this.onNodeClick(this.state.id)
|
53 |
+
} else{
|
54 |
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, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
|
55 |
}
|
56 |
}
|
|
|
74 |
}
|
75 |
|
76 |
resize = (e) => {
|
77 |
+
var new_height = parseInt(this.state.initial_size) + parseInt(e.clientY - this.state.initial_pos)
|
78 |
+
this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : new_height, size : this.state.size, iframe : this.state.iframe, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
|
79 |
+
this.myRef.current.style.height = `${new_height}px`
|
80 |
}
|
81 |
|
82 |
Counter(focus, size){
|
|
|
94 |
}
|
95 |
|
96 |
render(){
|
97 |
+
if (!this.state.reachable) {this.onNodeClick(this.state.id) }
|
98 |
return (<>
|
99 |
<>
|
100 |
<div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
|
|
|
129 |
{/* (Experimental) Do not uncomment */}
|
130 |
<div className={`absolute bottom-0 w-full h-10 bg-transparent border-1 shadow-2xl rounded-xl z-10 cursor-ns-resize`}
|
131 |
draggable
|
132 |
+
onDragStart={(e) => { this.initial(e) }}
|
133 |
+
onDrag={(e) => { this.resize(e) }}
|
134 |
></div>
|
135 |
</>
|
136 |
</>)
|
frontend/src/components/ReactFlow/ReactFlowEnv.js
CHANGED
@@ -2,10 +2,9 @@ import CustomNodeIframe from "../Nodes/Custom.js";
|
|
2 |
import '../../css/dist/output.css'
|
3 |
import ReactFlow, { Background,
|
4 |
applyNodeChanges,
|
5 |
-
applyEdgeChanges,
|
6 |
ReactFlowProvider,
|
7 |
} from 'react-flow-renderer';
|
8 |
-
import React ,{ useState, useCallback, useRef } from 'react';
|
9 |
import Navbar from '../Navagation/navbar';
|
10 |
import { useThemeDetector } from '../../helper/visual'
|
11 |
|
@@ -17,20 +16,31 @@ 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]
|
28 |
);
|
29 |
|
30 |
-
const onEdgesChange = useCallback(
|
31 |
-
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
32 |
-
[setEdges]
|
33 |
-
);
|
34 |
|
35 |
const onDragOver = useCallback((event) => {
|
36 |
event.preventDefault();
|
@@ -40,6 +50,25 @@ export default function ReactEnviorment() {
|
|
40 |
const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
|
41 |
const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
const onDrop = useCallback(
|
45 |
(event) => {
|
@@ -49,7 +78,7 @@ export default function ReactEnviorment() {
|
|
49 |
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
50 |
const type = event.dataTransfer.getData('application/reactflow');
|
51 |
const item = JSON.parse(event.dataTransfer.getData('application/item'));
|
52 |
-
const
|
53 |
// check if the dropped element is valid
|
54 |
if (typeof type === 'undefined' || !type) {
|
55 |
return;
|
@@ -59,13 +88,15 @@ export default function ReactEnviorment() {
|
|
59 |
x: event.clientX - reactFlowBounds.left,
|
60 |
y: event.clientY - reactFlowBounds.top,
|
61 |
});
|
|
|
62 |
const newNode = {
|
63 |
-
id: `${item.name}-${nodes.length}`,
|
64 |
type,
|
65 |
position,
|
66 |
dragHandle : `#draggable`,
|
67 |
-
data: { label: `${item.name}`, host : `${item.host}`, colour : `${colour}`, delete : deleteNode },
|
68 |
};
|
|
|
69 |
setNodes((nds) => nds.concat(newNode));
|
70 |
}
|
71 |
},
|
@@ -73,14 +104,15 @@ export default function ReactEnviorment() {
|
|
73 |
|
74 |
return (
|
75 |
<>
|
76 |
-
<div className=' absolute top-4 right-5 z-50'
|
77 |
-
<h1
|
|
|
78 |
</div>
|
79 |
<div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
|
80 |
-
<Navbar onDelete={deleteNodeContains}/>
|
81 |
<ReactFlowProvider>
|
82 |
<div className="h-screen w-screen" ref={reactFlowWrapper}>
|
83 |
-
<ReactFlow nodes={nodes}
|
84 |
<Background variant='dots' size={1} className=" bg-white dark:bg-neutral-800"/>
|
85 |
</ReactFlow>
|
86 |
</div>
|
|
|
2 |
import '../../css/dist/output.css'
|
3 |
import ReactFlow, { Background,
|
4 |
applyNodeChanges,
|
|
|
5 |
ReactFlowProvider,
|
6 |
} from 'react-flow-renderer';
|
7 |
+
import React ,{ useState, useCallback, useRef, useEffect } from 'react';
|
8 |
import Navbar from '../Navagation/navbar';
|
9 |
import { useThemeDetector } from '../../helper/visual'
|
10 |
|
|
|
16 |
|
17 |
const [theme, setTheme] = useState(useThemeDetector)
|
18 |
const [nodes, setNodes] = useState([]);
|
|
|
19 |
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
20 |
const reactFlowWrapper = useRef(null);
|
21 |
|
22 |
|
23 |
+
useEffect(() => {
|
24 |
+
const restore = () => {
|
25 |
+
const flow = JSON.parse(localStorage.getItem('flowkey'));
|
26 |
+
|
27 |
+
if(flow){
|
28 |
+
flow.nodes.map((nds) => {
|
29 |
+
nds.data.delete = deleteNode
|
30 |
+
})
|
31 |
+
setNodes(flow.nodes || [])
|
32 |
+
|
33 |
+
}
|
34 |
+
}
|
35 |
+
restore()
|
36 |
+
},[])
|
37 |
+
|
38 |
+
|
39 |
const onNodesChange = useCallback(
|
40 |
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
41 |
[setNodes]
|
42 |
);
|
43 |
|
|
|
|
|
|
|
|
|
44 |
|
45 |
const onDragOver = useCallback((event) => {
|
46 |
event.preventDefault();
|
|
|
50 |
const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
|
51 |
const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
|
52 |
|
53 |
+
const onSave = useCallback(() => {
|
54 |
+
if (reactFlowInstance) {
|
55 |
+
alert("Saved")
|
56 |
+
const flow = reactFlowInstance.toObject();
|
57 |
+
localStorage.setItem('flowkey', JSON.stringify(flow));
|
58 |
+
var labels = [];
|
59 |
+
var colour = [];
|
60 |
+
var emoji = [];
|
61 |
+
for(let i = 0; i < flow.nodes.length; i++){
|
62 |
+
if (!labels.includes(flow.nodes[i].data.label))
|
63 |
+
colour.push(flow.nodes[i].data.colour)
|
64 |
+
emoji.push(flow.nodes[i].data.emoji)
|
65 |
+
labels.push(flow.nodes[i].data.label)
|
66 |
+
}
|
67 |
+
localStorage.setItem('colour',JSON.stringify(colour))
|
68 |
+
localStorage.setItem('emoji', JSON.stringify(emoji))
|
69 |
+
}
|
70 |
+
}, [reactFlowInstance]);
|
71 |
+
|
72 |
|
73 |
const onDrop = useCallback(
|
74 |
(event) => {
|
|
|
78 |
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
79 |
const type = event.dataTransfer.getData('application/reactflow');
|
80 |
const item = JSON.parse(event.dataTransfer.getData('application/item'));
|
81 |
+
const style = JSON.parse(event.dataTransfer.getData('application/style'));
|
82 |
// check if the dropped element is valid
|
83 |
if (typeof type === 'undefined' || !type) {
|
84 |
return;
|
|
|
88 |
x: event.clientX - reactFlowBounds.left,
|
89 |
y: event.clientY - reactFlowBounds.top,
|
90 |
});
|
91 |
+
|
92 |
const newNode = {
|
93 |
+
id: `${item.name}-${nodes.length+1}`,
|
94 |
type,
|
95 |
position,
|
96 |
dragHandle : `#draggable`,
|
97 |
+
data: { label: `${item.name}`, host : `${item.host}`, colour : `${style.colour}`, emoji : `${style.emoji}`, delete : deleteNode },
|
98 |
};
|
99 |
+
|
100 |
setNodes((nds) => nds.concat(newNode));
|
101 |
}
|
102 |
},
|
|
|
104 |
|
105 |
return (
|
106 |
<>
|
107 |
+
<div className=' absolute top-4 right-5 z-50 cursor-default select-none text-4xl ' >
|
108 |
+
<h1 title={theme ? 'Dark Mode' : 'Light Mode'} onClick={() => setTheme(!theme)} >{theme ? 'π' : 'βοΈ'}</h1>
|
109 |
+
<h1 title="Save" className=" pt-5" onClick={() => onSave()}>πΎ</h1>
|
110 |
</div>
|
111 |
<div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
|
112 |
+
<Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))}/>
|
113 |
<ReactFlowProvider>
|
114 |
<div className="h-screen w-screen" ref={reactFlowWrapper}>
|
115 |
+
<ReactFlow nodes={nodes} nodeTypes={types} onNodesChange={onNodesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
|
116 |
<Background variant='dots' size={1} className=" bg-white dark:bg-neutral-800"/>
|
117 |
</ReactFlow>
|
118 |
</div>
|
frontend/src/css/dist/output.css
CHANGED
@@ -790,6 +790,10 @@ video {
|
|
790 |
cursor: ns-resize;
|
791 |
}
|
792 |
|
|
|
|
|
|
|
|
|
793 |
.select-none {
|
794 |
-webkit-user-select: none;
|
795 |
user-select: none;
|
@@ -1210,6 +1214,10 @@ video {
|
|
1210 |
padding-top: 0.5rem;
|
1211 |
}
|
1212 |
|
|
|
|
|
|
|
|
|
1213 |
.text-center {
|
1214 |
text-align: center;
|
1215 |
}
|
|
|
790 |
cursor: ns-resize;
|
791 |
}
|
792 |
|
793 |
+
.cursor-default {
|
794 |
+
cursor: default;
|
795 |
+
}
|
796 |
+
|
797 |
.select-none {
|
798 |
-webkit-user-select: none;
|
799 |
user-select: none;
|
|
|
1214 |
padding-top: 0.5rem;
|
1215 |
}
|
1216 |
|
1217 |
+
.pt-5 {
|
1218 |
+
padding-top: 1.25rem;
|
1219 |
+
}
|
1220 |
+
|
1221 |
.text-center {
|
1222 |
text-align: center;
|
1223 |
}
|