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.
@@ -0,0 +1,3 @@
1
+ .gitignore
2
+ .prettierignore
3
+ *.swp
package/README.md CHANGED
@@ -1,16 +1,85 @@
1
1
  # VZCode
2
+
2
3
  Multiplayer code editor system
3
4
 
4
- * Open source code editor for JavaScript
5
- * Support for real-time collaboration
6
- * Focus on instant feedback during development
7
- * Built on open source: CodeMirror, NodeJS, ShareDB
8
- * Core component of [VizHub](https://vizhub.com/) next generation editor
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
- Just getting started here! Nothing in this repo yet... but 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.
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
  ![image](https://user-images.githubusercontent.com/68416/213894278-51c7c9a9-dc11-42bc-ba10-c23109c473cd.png)
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
- Collaborators welcome! I'm holding a meeting on Monday January 23 at 2pm Eastern (Video call link: https://meet.google.com/ajx-nmpx-ygt), feel free to drop in if you have any interest in collaborating on this project or providing input!
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.2",
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>
@@ -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
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ import * as ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+ import './index.css';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
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
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width" />
6
+ <title>Test Page</title>
7
+ </head>
8
+ <body></body>
9
+ </html>
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
+ });