vzcode 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +3 -0
- package/README.md +76 -7
- package/cli.js +67 -0
- package/index.html +13 -0
- package/package.json +31 -3
- package/prototype/shell.html +60 -0
- package/public/vite.svg +1 -0
- package/src/App.css +0 -0
- package/src/App.jsx +90 -0
- package/src/index.css +0 -0
- package/src/main.jsx +10 -0
- package/src/style.css +256 -0
- package/test/TestFile1.txt +0 -0
- package/test/TestFile2.txt +0 -0
- package/test/TestFile3.txt +0 -0
- package/test/index.html +9 -0
- package/test/index.js +1 -0
- package/vite.config.js +10 -0
package/.prettierignore
ADDED
package/README.md
CHANGED
|
@@ -1,16 +1,85 @@
|
|
|
1
1
|
# VZCode
|
|
2
|
+
|
|
2
3
|
Multiplayer code editor system
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
[Kanban](https://github.com/orgs/vizhub-core/projects/2/views/1)
|
|
6
|
+
|
|
7
|
+
## Project Description
|
|
8
|
+
|
|
9
|
+
- Open source code editor for JavaScript, HTML, CSS, and Markdown
|
|
10
|
+
- Support for real-time collaboration
|
|
11
|
+
- Invite collaborators over LAN or HTTP Tunneing
|
|
12
|
+
- Focus on instant feedback during development
|
|
13
|
+
- Core component of [VizHub](https://vizhub.com/) next generation editor
|
|
14
|
+
|
|
15
|
+
## Stack
|
|
16
|
+
|
|
17
|
+
- [NodeJS](https://nodejs.org/en/)
|
|
18
|
+
- [Express](https://expressjs.com/)
|
|
19
|
+
- [ShareDB](https://github.com/share/sharedb)
|
|
20
|
+
- [JSON1 Operational Transform](https://github.com/ottypes/json1)
|
|
21
|
+
- [CodeMirror 6](https://codemirror.net/)
|
|
22
|
+
- [React](https://reactjs.org/)
|
|
23
|
+
- [Vite](https://vitejs.dev/)
|
|
9
24
|
|
|
10
|
-
|
|
25
|
+
## Goals
|
|
26
|
+
|
|
27
|
+
- Create a usable alternative to VSCode + Live Share for use in front end development
|
|
28
|
+
- Enable developers to "enable" the VSCode editor on their projects via NPM
|
|
29
|
+
- Have the `npm run edit` command start a local server
|
|
30
|
+
- Develop a sidebar panel that lists files in the file system
|
|
31
|
+
- Develop a code editor panel using CodeMirror that lets users navigate between files
|
|
32
|
+
- Have the server auto-save files to disk when changes are made
|
|
33
|
+
- Synchronize code edits across multiple clients using Operational Transform (JSON1 and ShareDB)
|
|
34
|
+
- Ensure that the editor works well on top of the Vite dev server
|
|
35
|
+
- Dogfood the product to identify ways it can be improved
|
|
36
|
+
- Iterate based on feedback
|
|
37
|
+
- Share the project with the world
|
|
38
|
+
|
|
39
|
+
## Prior Work
|
|
40
|
+
|
|
41
|
+
This project is heavily based on prior work done in the [VizHub Project](https://github.com/vizhub-core/vizhub/). VizHub already has a code editor component that supports real-time collaboration. However, this was built using older versions of [CodeMirror](https://codemirror.net/5/) (version 5) and operational transform ([json0](https://github.com/ottypes/json0). Various prototypes were built as a proof-of-concept for building a similar editor using the latest CodeMirror (v6) and the latest operational transform library for ShareDB (json1).
|
|
42
|
+
|
|
43
|
+
There is a working demo at https://vizhub.community/ci/viz1 (try it in multiple tabs to see the real-time sync), whose source code lives at https://github.com/vizhub-core/vizhub/tree/main/vizhub-v3 . Also we'll draw from this standalone CodeMirror6 collaboration demo: https://github.com/vizhub-core/vizhub/tree/main/vizhub-v3/vizhub-codemirror. For this project we'll port components out of that demo so that the code editor is totally independent and isolated from anything specific to VizHub.
|
|
11
44
|
|
|
12
45
|

|
|
13
46
|
|
|
14
47
|
It will look something like this ☝️ once it's working. This VZCode project will draw inspiration (and possibly implementation) from the existing open source editor component of VizHub, and various prototypes that have been done with CodeMirror6.
|
|
15
48
|
|
|
16
|
-
|
|
49
|
+
## Milestones
|
|
50
|
+
|
|
51
|
+
See also [VZCode Kanban Board](https://github.com/orgs/vizhub-core/projects/2/views/1).
|
|
52
|
+
|
|
53
|
+
February 2023
|
|
54
|
+
|
|
55
|
+
- Get the first version working, including:
|
|
56
|
+
- ShareDB server
|
|
57
|
+
- Auto-save
|
|
58
|
+
- Edit the content of multiple files (no support for folders initially)
|
|
59
|
+
|
|
60
|
+
March 2023
|
|
61
|
+
|
|
62
|
+
- Make it usable, including:
|
|
63
|
+
- UX for adding new files, renaming files, deleting files
|
|
64
|
+
- Implement presence (the ability to see the cursors of others in real time)
|
|
65
|
+
- Test out how it works using tunneling services such as NGrok
|
|
66
|
+
|
|
67
|
+
April 2023
|
|
68
|
+
|
|
69
|
+
- Add support for nested directories, including:
|
|
70
|
+
- Develop a tree-based sidebar UI allowing directory navigation
|
|
71
|
+
- Dogfood the product and try to collaboratively develop something, maybe a data visualization
|
|
72
|
+
- Gather feedback from early users and iterate based on that
|
|
73
|
+
- Publish a YouTube video presentation of the work to date
|
|
74
|
+
|
|
75
|
+
## Team
|
|
76
|
+
|
|
77
|
+
- Curran Kelleher
|
|
78
|
+
- Students from [RPI RCOS](https://rcos.io/)
|
|
79
|
+
- Additional external collaborators, TBD
|
|
80
|
+
- Drop a line to Curran if interested in collaborating on this!
|
|
81
|
+
|
|
82
|
+
## Spaces
|
|
83
|
+
|
|
84
|
+
- https://github.com/vizhub-core/vzcode
|
|
85
|
+
- [Discord channel within RCOS](https://discord.com/channels/738593165438746634/1066068656045441044)
|
package/cli.js
CHANGED
|
@@ -1,2 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import ShareDB from 'sharedb';
|
|
5
|
+
import json1 from 'ot-json1';
|
|
6
|
+
import { WebSocketServer } from 'ws';
|
|
7
|
+
import WebSocketJSONStream from '@teamwork/websocket-json-stream';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
|
|
12
|
+
const fullPath = process.cwd();
|
|
13
|
+
|
|
14
|
+
// Isolate files, not directories.
|
|
15
|
+
// Inspired by https://stackoverflow.com/questions/41472161/fs-readdir-ignore-directories
|
|
16
|
+
const files = fs
|
|
17
|
+
.readdirSync(fullPath, { withFileTypes: true })
|
|
18
|
+
.filter((dirent) => dirent.isFile())
|
|
19
|
+
.map((dirent) => dirent.name);
|
|
20
|
+
|
|
21
|
+
const initialDocument = {};
|
|
22
|
+
console.log(files);
|
|
23
|
+
files.forEach((file) => {
|
|
24
|
+
const id = Math.floor(Math.random() * 10000000000);
|
|
25
|
+
initialDocument[id] = {
|
|
26
|
+
text: fs.readFileSync(file, 'utf-8'),
|
|
27
|
+
name: file,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(initialDocument);
|
|
32
|
+
|
|
2
33
|
console.log('Welcome to VZCode!');
|
|
34
|
+
|
|
35
|
+
ShareDB.types.register(json1.type);
|
|
36
|
+
|
|
37
|
+
const app = express();
|
|
38
|
+
const port = 3030;
|
|
39
|
+
|
|
40
|
+
const shareDBBackend = new ShareDB();
|
|
41
|
+
const shareDBConnection = shareDBBackend.connect();
|
|
42
|
+
const server = http.createServer(app);
|
|
43
|
+
const wss = new WebSocketServer({ server });
|
|
44
|
+
|
|
45
|
+
wss.on('connection', (ws) => {
|
|
46
|
+
shareDBBackend.listen(new WebSocketJSONStream(ws));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// app.get('/', (req, res) => {
|
|
50
|
+
// res.send('Hello World!');
|
|
51
|
+
// });
|
|
52
|
+
|
|
53
|
+
// Serve static files
|
|
54
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
55
|
+
const __dirname = path.dirname(__filename);
|
|
56
|
+
const dir = path.join(__dirname, '/dist');
|
|
57
|
+
|
|
58
|
+
app.use(express.static(dir));
|
|
59
|
+
|
|
60
|
+
// Create initial document
|
|
61
|
+
// TODO
|
|
62
|
+
// * figure out how to list files on disk with NodeJS
|
|
63
|
+
// * use that list to populate the files in our document.
|
|
64
|
+
const shareDBDoc = shareDBConnection.get('documents', '1');
|
|
65
|
+
shareDBDoc.create(initialDocument, json1.type.uri);
|
|
66
|
+
|
|
67
|
+
server.listen(port, () => {
|
|
68
|
+
console.log(`Editor is live at http://localhost:${port}`);
|
|
69
|
+
});
|
package/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite + React</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"bin": "cli.js",
|
|
7
|
-
"scripts": {
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "cd test; node ../cli.js",
|
|
10
|
+
"prettier": "prettier {*.*,**/*.*} --single-quote --write",
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"build": "vite build",
|
|
13
|
+
"preview": "vite preview",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
8
16
|
"repository": {
|
|
9
17
|
"type": "git",
|
|
10
18
|
"url": "git+https://github.com/vizhub-core/vzcode.git"
|
|
@@ -25,5 +33,25 @@
|
|
|
25
33
|
"bugs": {
|
|
26
34
|
"url": "https://github.com/vizhub-core/vzcode/issues"
|
|
27
35
|
},
|
|
28
|
-
"homepage": "https://github.com/vizhub-core/vzcode#readme"
|
|
36
|
+
"homepage": "https://github.com/vizhub-core/vzcode#readme",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
39
|
+
"express": "^4.18.2",
|
|
40
|
+
"ot-json1": "^1.0.2",
|
|
41
|
+
"react": "^18.2.0",
|
|
42
|
+
"react-dom": "^18.2.0",
|
|
43
|
+
"sharedb": "^3.2.1",
|
|
44
|
+
"sharedb-client-browser": "^2.2.49",
|
|
45
|
+
"ws": "^8.12.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@rollup/plugin-commonjs": "^24.0.1",
|
|
49
|
+
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
50
|
+
"@types/react": "^18.0.26",
|
|
51
|
+
"@types/react-dom": "^18.0.9",
|
|
52
|
+
"@vitejs/plugin-react": "^3.0.0",
|
|
53
|
+
"prettier": "^2.8.3",
|
|
54
|
+
"rollup-plugin-polyfill-node": "^0.12.0",
|
|
55
|
+
"vite": "^4.0.0"
|
|
56
|
+
}
|
|
29
57
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<!-- Inspired by: https://www.codinglabweb.com/2021/06/dropdown-sidebar-menu-html-css.html -->
|
|
3
|
+
<html lang="en" dir="ltr">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8">
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
<!-- Boxiocns CDN Link -->
|
|
9
|
+
<link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div class="tabList"></div>
|
|
15
|
+
<div class="bottomBar"></div>
|
|
16
|
+
<div class="sidebar show">
|
|
17
|
+
|
|
18
|
+
<ul class="nav-links">
|
|
19
|
+
<li>
|
|
20
|
+
<div class="iocn-link">
|
|
21
|
+
<a href="#">
|
|
22
|
+
<i class='bx bx-folder'></i>
|
|
23
|
+
<span class="link_name">Files</span>
|
|
24
|
+
</a>
|
|
25
|
+
<i class='bx bxs-chevron-down arrow'></i>
|
|
26
|
+
</div>
|
|
27
|
+
<ul class="sub-menu">
|
|
28
|
+
<li><a class="link_name" href="#">Files</a></li>
|
|
29
|
+
<li><a href="#">index.html</a></li>
|
|
30
|
+
<li><a href="#">style.css</a></li>
|
|
31
|
+
<li><a href="#">script.js</a></li>
|
|
32
|
+
</ul>
|
|
33
|
+
</li>
|
|
34
|
+
<li>
|
|
35
|
+
<div class="profile-details">
|
|
36
|
+
<a href="#">
|
|
37
|
+
<i class='bx bx-cog'></i>
|
|
38
|
+
<span class="link_name">Setting</span>
|
|
39
|
+
</a>
|
|
40
|
+
<ul class="sub-menu blank">
|
|
41
|
+
<li><a class="link_name" href="#">Setting</a></li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
</li>
|
|
45
|
+
</ul>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
</div>
|
|
49
|
+
<script>
|
|
50
|
+
let arrow = document.querySelectorAll(".arrow");
|
|
51
|
+
for (var i = 0; i < arrow.length; i++) {
|
|
52
|
+
arrow[i].addEventListener("click", (e) => {
|
|
53
|
+
let arrowParent = e.target.parentElement.parentElement;//selecting main parent of arrow
|
|
54
|
+
arrowParent.classList.toggle("showMenu");
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
</body>
|
|
59
|
+
|
|
60
|
+
</html>
|
package/public/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/src/App.css
ADDED
|
File without changes
|
package/src/App.jsx
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo } from "react";
|
|
2
|
+
import "./App.css";
|
|
3
|
+
import "./style.css";
|
|
4
|
+
import ShareDBClient from "sharedb-client-browser/sharedb-client-json1-browser.js";
|
|
5
|
+
|
|
6
|
+
const { Connection } = ShareDBClient;
|
|
7
|
+
const socket = new WebSocket("ws://" + window.location.host);
|
|
8
|
+
const connection = new Connection(socket);
|
|
9
|
+
|
|
10
|
+
function App() {
|
|
11
|
+
const [data, setData] = useState(null);
|
|
12
|
+
|
|
13
|
+
const [isFileMenuOpen, setIsFileMenuOpen] = useState(false);
|
|
14
|
+
const [activeFileId, setActiveFileId] = useState(null)
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const doc = connection.get("documents", "1");
|
|
18
|
+
|
|
19
|
+
doc.subscribe(() => {
|
|
20
|
+
setData(doc.data);
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
const activeFileText = (data && activeFileId) ? data[activeFileId].text : "";
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<div className="tabList"></div>
|
|
29
|
+
<div className="bottomBar"></div>
|
|
30
|
+
<div className="sidebar show">
|
|
31
|
+
<ul className="nav-links">
|
|
32
|
+
<li className={isFileMenuOpen ? "showMenu" : ""}>
|
|
33
|
+
<div className="icon-link">
|
|
34
|
+
<a href="#">
|
|
35
|
+
<i
|
|
36
|
+
id="folderIcon"
|
|
37
|
+
className={
|
|
38
|
+
isFileMenuOpen ? "bx bx-folder-open" : "bx bx-folder"
|
|
39
|
+
}
|
|
40
|
+
></i>
|
|
41
|
+
<span className="link_name">Files</span>
|
|
42
|
+
</a>
|
|
43
|
+
<i
|
|
44
|
+
className="bx bxs-chevron-down arrow"
|
|
45
|
+
onClick={() => {
|
|
46
|
+
setIsFileMenuOpen(!isFileMenuOpen);
|
|
47
|
+
}}
|
|
48
|
+
></i>
|
|
49
|
+
</div>
|
|
50
|
+
<ul className="sub-menu">
|
|
51
|
+
<li>
|
|
52
|
+
<a className="link_name" href="#">
|
|
53
|
+
Files
|
|
54
|
+
</a>
|
|
55
|
+
</li>
|
|
56
|
+
{data
|
|
57
|
+
? Object.keys(data).map((key) => (
|
|
58
|
+
<li onClick={() => {
|
|
59
|
+
setActiveFileId(key)
|
|
60
|
+
}
|
|
61
|
+
}>
|
|
62
|
+
<a>{data[key].name}</a>
|
|
63
|
+
</li>
|
|
64
|
+
))
|
|
65
|
+
: null}
|
|
66
|
+
</ul>
|
|
67
|
+
</li>
|
|
68
|
+
<li>
|
|
69
|
+
<div className="profile-details">
|
|
70
|
+
<a href="#">
|
|
71
|
+
<i className="bx bx-cog"></i>
|
|
72
|
+
<span className="link_name">Setting</span>
|
|
73
|
+
</a>
|
|
74
|
+
<ul className="sub-menu blank">
|
|
75
|
+
<li>
|
|
76
|
+
<a className="link_name" href="#">
|
|
77
|
+
Setting
|
|
78
|
+
</a>
|
|
79
|
+
</li>
|
|
80
|
+
</ul>
|
|
81
|
+
</div>
|
|
82
|
+
</li>
|
|
83
|
+
</ul>
|
|
84
|
+
</div >
|
|
85
|
+
<textarea className="TextEdit" name="editor" id="edit" value={activeFileId && activeFileText ? data[activeFileId].text : ""}></textarea>
|
|
86
|
+
</>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default App;
|
package/src/index.css
ADDED
|
File without changes
|
package/src/main.jsx
ADDED
package/src/style.css
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/* Inspired by: https://www.codinglabweb.com/2021/06/dropdown-sidebar-menu-html-css.html */
|
|
2
|
+
/* Google Fonts Import Link */
|
|
3
|
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
|
4
|
+
@import url('https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css');
|
|
5
|
+
|
|
6
|
+
* {
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
font-family: 'Poppins', sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
background: rgb(34, 34, 34);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.TextEdit {
|
|
18
|
+
position: fixed;
|
|
19
|
+
margin-top: 30px;
|
|
20
|
+
margin-left: 200px;
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 100%;
|
|
23
|
+
top: 30px;
|
|
24
|
+
bottom: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.tabList {
|
|
28
|
+
position: fixed;
|
|
29
|
+
top: 0;
|
|
30
|
+
left: 0;
|
|
31
|
+
height: 30px;
|
|
32
|
+
width: 100%;
|
|
33
|
+
background: rgb(25, 25, 25);
|
|
34
|
+
z-index: 100;
|
|
35
|
+
transition: all 0.5s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.bottomBar {
|
|
39
|
+
position: absolute;
|
|
40
|
+
bottom: 0;
|
|
41
|
+
left: 0;
|
|
42
|
+
height: 20px;
|
|
43
|
+
width: 100%;
|
|
44
|
+
background: rgb(45, 45, 45);
|
|
45
|
+
z-index: 100;
|
|
46
|
+
transition: all 0.5s ease;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sidebar {
|
|
50
|
+
position: fixed;
|
|
51
|
+
top: 0;
|
|
52
|
+
left: 0;
|
|
53
|
+
height: 100%;
|
|
54
|
+
width: 200px;
|
|
55
|
+
background: rgb(92, 92, 92);
|
|
56
|
+
z-index: 100;
|
|
57
|
+
transition: all 0.5s ease;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.sidebar.close {
|
|
61
|
+
width: 78px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sidebar .nav-links {
|
|
65
|
+
height: 100%;
|
|
66
|
+
padding: 0px 0 150px 0;
|
|
67
|
+
overflow: auto;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.sidebar.close .nav-links {
|
|
71
|
+
overflow: visible;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sidebar .nav-links::-webkit-scrollbar {
|
|
75
|
+
display: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.sidebar .nav-links li {
|
|
79
|
+
position: relative;
|
|
80
|
+
list-style: none;
|
|
81
|
+
transition: all 0.4s ease;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sidebar .nav-links li:hover {
|
|
85
|
+
background: rgb(92, 92, 92);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.sidebar .nav-links li .icon-link {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: space-between;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.sidebar.close .nav-links li .icon-link {
|
|
95
|
+
display: block;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sidebar .nav-links li i {
|
|
99
|
+
height: 50px;
|
|
100
|
+
min-width: 78px;
|
|
101
|
+
text-align: center;
|
|
102
|
+
line-height: 50px;
|
|
103
|
+
color: #fff;
|
|
104
|
+
font-size: 20px;
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
transition: all 0.3s ease;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.sidebar .nav-links li.showMenu i.arrow {
|
|
110
|
+
transform: rotate(-180deg);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sidebar.close .nav-links i.arrow {
|
|
114
|
+
display: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.sidebar .nav-links li a {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
text-decoration: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.sidebar .nav-links li a .link_name {
|
|
124
|
+
font-size: 18px;
|
|
125
|
+
font-weight: 400;
|
|
126
|
+
color: #fff;
|
|
127
|
+
transition: all 0.4s ease;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.sidebar.close .nav-links li a .link_name {
|
|
131
|
+
opacity: 0;
|
|
132
|
+
pointer-events: none;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sidebar .nav-links li .sub-menu {
|
|
136
|
+
padding: 6px 6px 14px 80px;
|
|
137
|
+
margin-top: -10px;
|
|
138
|
+
background: rgb(92, 92, 92);
|
|
139
|
+
display: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.sidebar .nav-links li.showMenu .sub-menu {
|
|
143
|
+
display: block;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.sidebar .nav-links li .sub-menu a {
|
|
147
|
+
color: #fff;
|
|
148
|
+
font-size: 15px;
|
|
149
|
+
padding: 5px 0;
|
|
150
|
+
white-space: nowrap;
|
|
151
|
+
opacity: 0.6;
|
|
152
|
+
transition: all 0.3s ease;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.sidebar .nav-links li .sub-menu a:hover {
|
|
156
|
+
opacity: 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.sidebar.close .nav-links li .sub-menu {
|
|
160
|
+
position: absolute;
|
|
161
|
+
left: 100%;
|
|
162
|
+
top: -10px;
|
|
163
|
+
margin-top: 0;
|
|
164
|
+
padding: 10px 20px;
|
|
165
|
+
border-radius: 0 6px 6px 0;
|
|
166
|
+
opacity: 0;
|
|
167
|
+
display: block;
|
|
168
|
+
pointer-events: none;
|
|
169
|
+
transition: 0s;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.sidebar.close .nav-links li:hover .sub-menu {
|
|
173
|
+
top: 0;
|
|
174
|
+
opacity: 1;
|
|
175
|
+
pointer-events: auto;
|
|
176
|
+
transition: all 0.4s ease;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.sidebar .nav-links li .sub-menu .link_name {
|
|
180
|
+
display: none;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.sidebar.close .nav-links li .sub-menu .link_name {
|
|
184
|
+
font-size: 18px;
|
|
185
|
+
opacity: 1;
|
|
186
|
+
display: block;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.sidebar .nav-links li .sub-menu.blank {
|
|
190
|
+
opacity: 1;
|
|
191
|
+
pointer-events: auto;
|
|
192
|
+
padding: 3px 20px 6px 16px;
|
|
193
|
+
opacity: 0;
|
|
194
|
+
pointer-events: none;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.sidebar .nav-links li:hover .sub-menu.blank {
|
|
198
|
+
top: 50%;
|
|
199
|
+
transform: translateY(-50%);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.sidebar .profile-details {
|
|
203
|
+
position: fixed;
|
|
204
|
+
bottom: 0;
|
|
205
|
+
width: 200px;
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: space-between;
|
|
209
|
+
background: rgb(92, 92, 92);
|
|
210
|
+
padding: 12px 0;
|
|
211
|
+
transition: all 0.5s ease;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.sidebar.close .profile-details {
|
|
215
|
+
background: none;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.sidebar.close .profile-details {
|
|
219
|
+
width: 78px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.sidebar .profile-details .profile-content {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.sidebar .profile-details img {
|
|
228
|
+
height: 52px;
|
|
229
|
+
width: 52px;
|
|
230
|
+
object-fit: cover;
|
|
231
|
+
border-radius: 16px;
|
|
232
|
+
margin: 0 14px 0 12px;
|
|
233
|
+
background: rgb(92, 92, 92);
|
|
234
|
+
transition: all 0.5s ease;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.sidebar.close .profile-details img {
|
|
238
|
+
padding: 10px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.sidebar .profile-details .profile_name,
|
|
242
|
+
.sidebar .profile-details .job {
|
|
243
|
+
color: #fff;
|
|
244
|
+
font-size: 18px;
|
|
245
|
+
font-weight: 500;
|
|
246
|
+
white-space: nowrap;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sidebar .profile-details .job {
|
|
250
|
+
font-size: 12px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.sidebar.close ~ .home-section {
|
|
254
|
+
left: 78px;
|
|
255
|
+
width: calc(100% - 78px);
|
|
256
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/index.html
ADDED
package/test/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
console.log('This is a test file to edit');
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import nodePolyfills from 'rollup-plugin-polyfill-node';
|
|
4
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
5
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
6
|
+
|
|
7
|
+
// https://vitejs.dev/config/
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [commonjs(), nodePolyfills(), nodeResolve(), react()],
|
|
10
|
+
});
|