this.gui 1.0.17 → 1.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "this.gui",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "This Graphic User Interface.",
5
5
  "main": "dist/this-gui.umd.js",
6
6
  "module": "dist/this-gui.es.js",
@@ -25,6 +25,7 @@
25
25
  "classnames": "^2.5.1",
26
26
  "dotenv": "^16.4.5",
27
27
  "figlet": "^1.7.0",
28
+ "fs": "^0.0.1-security",
28
29
  "postcss": "^8.4.45",
29
30
  "react-icons": "^5.3.0",
30
31
  "react-router-dom": "^6.26.2"
package/src/App.jsx CHANGED
@@ -1,56 +1,32 @@
1
1
  import React from 'react';
2
- import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom';
2
+ import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
3
3
  import { ThemeProvider } from './themes/ThemeProvider';
4
- import MdxProvider from './MdxProvider'; // MDX Provider
5
- import SiteBuilder from './SiteBuilder'; // Import the site builder component
6
- import { SelectTheme } from './stories/Molecules/SelectTheme/SelectTheme'; // Import SelectTheme
7
- import { useTheme } from './themes/ThemeProvider'; // Import the hook
8
- import Page from './Page'; // Import the Page component
9
- import example from './example.json'; // Example JSON for Page component
4
+ import PageDashboard from './PageDashboard'; // Pages dashboard view
5
+ import CreatePage from './CreatePage'; // Create page view
6
+ import Page from './Page'; // Render dynamic pages
7
+ import SiteBuilder from './SiteBuilder'; // JSON Site builder
8
+ import MDXEditor from './MDXEditor'; // MDX Site builder
10
9
 
11
10
  const App = () => {
12
11
  return (
13
12
  <ThemeProvider>
14
- <MdxProvider>
15
- <Router>
16
- {/* Top navigation */}
17
- <nav>
18
- <Link to="/" style={{ marginRight: '20px' }}>Site Builder</Link>
19
- <Link to="/storybook" style={{ marginRight: '20px' }}>Storybook</Link>
20
- <Link to="/test-page" style={{ marginRight: '20px' }}>Test Page</Link> {/* New link */}
21
- </nav>
22
-
23
- {/* Render SelectTheme in the main app */}
24
- <ThemeSwitcher />
25
-
26
- {/* Route definitions */}
27
- <Routes>
28
- <Route path="/" element={<SiteBuilder />} /> {/* Site builder interface */}
29
- <Route path="/storybook" element={<Storybook />} /> {/* Documentation */}
30
- <Route path="/test-page" element={<Page config={example} />} /> {/* Test Page Route */}
31
- </Routes>
32
- </Router>
33
- </MdxProvider>
13
+ <Router>
14
+ <Routes>
15
+ {/* Main Dashboard */}
16
+ <Route path="/" element={<PageDashboard />} />
17
+ {/* Create new page */}
18
+ <Route path="/create-page" element={<CreatePage />} />
19
+ {/* Site builders for JSON and MDX */}
20
+ <Route path="/site-builder/json/:pageName" element={<SiteBuilder />} />
21
+ <Route path="/site-builder/mdx/:pageName" element={<MDXEditor />} />
22
+ {/* Storybook Route */}
23
+ <Route path="/storybook" element={<Storybook />} />
24
+ </Routes>
25
+ </Router>
34
26
  </ThemeProvider>
35
27
  );
36
28
  };
37
29
 
38
- // Component to handle theme switching using the context
39
- const ThemeSwitcher = () => {
40
- const { setTheme, setMode } = useTheme();
41
-
42
- return (
43
- <SelectTheme
44
- onThemeChange={(newTheme) => {
45
- setTheme(newTheme);
46
- }}
47
- onModeChange={(newMode) => {
48
- setMode(newMode);
49
- }}
50
- />
51
- );
52
- };
53
-
54
30
  // Storybook IFrame for browsing documentation
55
31
  const Storybook = () => (
56
32
  <iframe
@@ -0,0 +1,61 @@
1
+ import React, { useState } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+
4
+ const CreatePage = () => {
5
+ const navigate = useNavigate();
6
+ const [pageName, setPageName] = useState('');
7
+ const [pageType, setPageType] = useState('json'); // Default to JSON
8
+ const [errorMessage, setErrorMessage] = useState('');
9
+
10
+ const handleCreatePage = () => {
11
+ const newPage = {
12
+ pageName,
13
+ pageType,
14
+ content: '', // Optional: You can pass default content here if needed
15
+ };
16
+
17
+ // Call API to create the page on the backend
18
+ fetch('/api/create-page', {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ },
23
+ body: JSON.stringify(newPage),
24
+ })
25
+ .then((response) => response.json())
26
+ .then((data) => {
27
+ if (data.error) {
28
+ setErrorMessage(data.error);
29
+ } else {
30
+ // Navigate to the corresponding builder
31
+ if (pageType === 'json') {
32
+ navigate(`/site-builder/json/${pageName}`);
33
+ } else {
34
+ navigate(`/site-builder/mdx/${pageName}`);
35
+ }
36
+ }
37
+ })
38
+ .catch((error) => setErrorMessage(`Error: ${error.message}`));
39
+ };
40
+
41
+ return (
42
+ <div>
43
+ <h1>Create a New Page</h1>
44
+ <input
45
+ type="text"
46
+ placeholder="Enter page name"
47
+ value={pageName}
48
+ onChange={(e) => setPageName(e.target.value)}
49
+ />
50
+ <select value={pageType} onChange={(e) => setPageType(e.target.value)}>
51
+ <option value="json">JSON Format</option>
52
+ <option value="mdx">MDX Format</option>
53
+ </select>
54
+ <button onClick={handleCreatePage}>Create Page</button>
55
+
56
+ {errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
57
+ </div>
58
+ );
59
+ };
60
+
61
+ export default CreatePage;
@@ -0,0 +1,51 @@
1
+ //this.GUI/src/MDXEditor.jsx
2
+ import React, { useState } from 'react';
3
+ import { useNavigate, useParams } from 'react-router-dom';
4
+ import MdxProvider from './MdxProvider'; // Correct
5
+
6
+ const MDXEditor = () => {
7
+ const navigate = useNavigate();
8
+ const { pageName } = useParams();
9
+ const [mdxContent, setMdxContent] = useState(''); // Initial blank content
10
+
11
+ const handleInputChange = (e) => {
12
+ setMdxContent(e.target.value);
13
+ };
14
+
15
+ const handleSavePage = () => {
16
+ console.log('Saving MDX content:', mdxContent);
17
+ // Replace this with actual save functionality (e.g., send to a backend API)
18
+
19
+ // Optionally navigate back to the main dashboard or SiteBuilder
20
+ navigate(`/`);
21
+ };
22
+
23
+ return (
24
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
25
+ {/* MDX Editor */}
26
+ <textarea
27
+ value={mdxContent}
28
+ onChange={handleInputChange}
29
+ rows="15"
30
+ cols="80"
31
+ placeholder="Write your MDX content here..."
32
+ style={{ padding: '10px', fontSize: '16px' }}
33
+ />
34
+
35
+ {/* Live Preview */}
36
+ <div style={{ padding: '20px', border: '1px solid #ccc', marginTop: '20px' }}>
37
+ <h2>Live Preview</h2>
38
+ <MdxProvider>
39
+ <div>{mdxContent ? mdxContent : 'Your MDX preview will appear here.'}</div>
40
+ </MdxProvider>
41
+ </div>
42
+
43
+ {/* Save Button */}
44
+ <button onClick={handleSavePage} style={{ padding: '10px 20px', fontSize: '16px' }}>
45
+ Save MDX Page
46
+ </button>
47
+ </div>
48
+ );
49
+ };
50
+
51
+ export default MDXEditor;
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import Atoms from './stories/Atoms'; // Import the Atoms object
4
+ import Molecules from './stories/Molecules'; // Import the Atoms object
5
+ import siteConfig from '../GUI/config/siteConfig.json'; // Import the config
6
+
7
+ const PageDashboard = () => {
8
+ const navigate = useNavigate();
9
+
10
+ return (
11
+ <Atoms.Container
12
+ size='medium'>
13
+ <h1>Pages Dashboard</h1>
14
+
15
+ {/* Use this.GUI Button for "Add New Page" */}
16
+ <Atoms.Button
17
+ label="+ Add New Page"
18
+ variant="solid"
19
+ color="primary-color" // Correct color value
20
+ onClick={() => navigate('/create-page')}
21
+ style={{ marginBottom: '20px' }}
22
+ />
23
+
24
+ {siteConfig.pages.length === 0 ? (
25
+ <p>No pages created yet.</p>
26
+ ) : (
27
+ <div className="page-grid" style={{ display: 'flex', flexWrap: 'wrap', gap: '20px' }}>
28
+ {siteConfig.pages.map((page, index) => (
29
+ <Molecules.Card
30
+ key={index}
31
+ variant="outlined"
32
+ color="secondary"
33
+ style={{
34
+ width: '200px',
35
+ padding: '20px',
36
+ borderRadius: '8px',
37
+ boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
38
+ }}
39
+ >
40
+ <h3>{page.name}</h3>
41
+ <p>Type: {page.type}</p>
42
+ <Atoms.Button
43
+ label="Edit Page"
44
+ variant="outline"
45
+ color="secondary-color" // Correct the color value here
46
+ onClick={() => navigate(page.path)}
47
+ />
48
+ </Molecules.Card>
49
+ ))}
50
+ </div>
51
+ )}
52
+ </Atoms.Container>
53
+ );
54
+ };
55
+
56
+ export default PageDashboard;
@@ -1,39 +1,108 @@
1
+ //this.GUI/src/SiteBuilder.jsx
1
2
  import React, { useState } from 'react';
2
- import GUI from '../index';
3
+ import { renderComponent } from './scripts/renderComponents';
4
+ import ComponentRegistry from './scripts/ComponentRegistry'; // Import the component registry
3
5
 
4
6
  const SiteBuilder = () => {
5
- const [pageContent, setPageContent] = useState([]); // Store the page components
6
-
7
- // Example links for the sidebar
8
- const sidebarLinks = [
9
- { label: 'Dashboard', url: '/dashboard' },
10
- { label: 'Settings', url: '/settings' },
11
- { label: 'Profile', url: '/profile' },
12
- ];
13
-
14
- // Function to handle adding components
15
- const addComponent = (component) => {
16
- setPageContent([...pageContent, component]);
7
+ const [pageContent, setPageContent] = useState([]); // Stores the components added to the page
8
+ const [selectedComponent, setSelectedComponent] = useState(null); // Currently selected component for configuration
9
+
10
+ // Generate available components from the ComponentRegistry
11
+ const availableComponents = Object.keys(ComponentRegistry).map((key) => ({
12
+ type: key,
13
+ label: key,
14
+ }));
15
+
16
+ // Add a new component to the page
17
+ const addComponent = (componentType) => {
18
+ setPageContent([...pageContent, { type: componentType, props: {} }]);
19
+ };
20
+
21
+ // Update a component's properties
22
+ const updateComponentProps = (index, newProps) => {
23
+ const updatedPage = [...pageContent];
24
+ updatedPage[index].props = newProps;
25
+ setPageContent(updatedPage);
26
+ };
27
+
28
+ // Render components on the page
29
+ const renderPageContent = () => {
30
+ return pageContent.map((component, index) => {
31
+ const Component = renderComponent(component.type);
32
+ return (
33
+ <div
34
+ key={index}
35
+ onClick={() => setSelectedComponent(index)} // Select component for editing
36
+ style={{ border: selectedComponent === index ? '2px solid blue' : 'none' }}
37
+ >
38
+ {Component ? <Component {...component.props} /> : <p>Component not found</p>}
39
+ </div>
40
+ );
41
+ });
17
42
  };
18
43
 
19
44
  return (
20
- <div className="site-builder">
21
- {/* Fixed Navbar at the top */}
22
- <GUI.Molecules.Navbar links={sidebarLinks} /> {/* Using the same links for simplicity */}
23
-
24
- <div style={{ display: 'flex' }}>
25
- {/* Sidebar with components to drag and drop */}
26
- <GUI.Molecules.Sidebar links={sidebarLinks} addComponent={addComponent} />
27
-
28
- {/* Main content area where components are dropped */}
29
- <main className="builder-content" style={{ flex: 1, padding: '20px' }}>
30
- {pageContent.map((Component, idx) => (
31
- <div key={idx}>{Component}</div>
45
+ <div style={{ display: 'flex' }}>
46
+ {/* Sidebar with available components */}
47
+ <div style={{ width: '20%', padding: '10px', backgroundColor: '#f0f0f0' }}>
48
+ <h4>Available Components</h4>
49
+ <ul>
50
+ {availableComponents.map((comp, index) => (
51
+ <li key={index}>
52
+ <button onClick={() => addComponent(comp.type)}>{comp.label}</button>
53
+ </li>
32
54
  ))}
33
- </main>
55
+ </ul>
56
+ </div>
57
+
58
+ {/* Main canvas area for dragging and arranging components */}
59
+ <div style={{ width: '60%', padding: '10px' }}>
60
+ <h4>Canvas</h4>
61
+ {renderPageContent()}
62
+ </div>
63
+
64
+ {/* Configuration panel for the selected component */}
65
+ <div style={{ width: '20%', padding: '10px', backgroundColor: '#f9f9f9' }}>
66
+ <h4>Component Properties</h4>
67
+ {selectedComponent !== null && (
68
+ <ComponentConfigPanel
69
+ component={pageContent[selectedComponent]}
70
+ onUpdate={(newProps) => updateComponentProps(selectedComponent, newProps)}
71
+ />
72
+ )}
34
73
  </div>
35
74
  </div>
36
75
  );
37
76
  };
38
77
 
78
+ // A simple panel to edit component properties
79
+ const ComponentConfigPanel = ({ component, onUpdate }) => {
80
+ const [props, setProps] = useState(component.props);
81
+
82
+ const handleInputChange = (key, value) => {
83
+ setProps({ ...props, [key]: value });
84
+ };
85
+
86
+ const handleSave = () => {
87
+ onUpdate(props); // Send the updated props to the SiteBuilder
88
+ };
89
+
90
+ return (
91
+ <div>
92
+ <h5>Edit {component.type} Properties</h5>
93
+ {Object.keys(props).map((key) => (
94
+ <div key={key}>
95
+ <label>{key}</label>
96
+ <input
97
+ type="text"
98
+ value={props[key]}
99
+ onChange={(e) => handleInputChange(key, e.target.value)}
100
+ />
101
+ </div>
102
+ ))}
103
+ <button onClick={handleSave}>Save</button>
104
+ </div>
105
+ );
106
+ };
107
+
39
108
  export default SiteBuilder;
@@ -1,5 +1,5 @@
1
1
  // this.GUI/scripts/postinstall.js
2
- import { mkdir, writeFile, access } from 'fs/promises';
2
+ import { mkdir, writeFile, access, readFile } from 'fs/promises';
3
3
  import { join } from 'path';
4
4
 
5
5
  const appRootDir = process.env.INIT_CWD || process.cwd();
@@ -8,9 +8,8 @@ const appRootDir = process.env.INIT_CWD || process.cwd();
8
8
  const guiDir = join(appRootDir, 'GUI');
9
9
  const componentsDir = join(guiDir, 'components');
10
10
  const pagesDir = join(guiDir, 'pages'); // Pages directory for JSON layouts
11
- const builderDir = join(guiDir, 'builder'); // Builder directory for site builder UI
12
- const mdxDir = join(guiDir, 'mdx');
13
- const stylesDir = join(guiDir, 'styles');
11
+ const configDir = join(guiDir, 'config');
12
+ const configFile = join(configDir, 'siteConfig.json');
14
13
 
15
14
  // Helper function to create directories only if they don't already exist
16
15
  async function createDir(dirPath) {
@@ -34,23 +33,47 @@ async function createFile(filePath, content) {
34
33
  }
35
34
  }
36
35
 
36
+ // Helper function to update siteConfig.json
37
+ async function updateSiteConfig(newPages) {
38
+ try {
39
+ const configContent = await readFile(configFile, 'utf-8');
40
+ const config = JSON.parse(configContent);
41
+
42
+ // Add new pages if they don't already exist in the config
43
+ newPages.forEach((newPage) => {
44
+ const exists = config.pages.find((page) => page.name === newPage.name);
45
+ if (!exists) {
46
+ config.pages.push(newPage);
47
+ }
48
+ });
49
+
50
+ await writeFile(configFile, JSON.stringify(config, null, 2));
51
+ console.log(`Updated: ${configFile}`);
52
+ } catch (err) {
53
+ console.error(`Failed to update siteConfig: ${err}`);
54
+ }
55
+ }
56
+
37
57
  // Function to initialize the directory structure and files
38
58
  async function initializeFiles() {
39
- const mdxWelcomeFile = join(mdxDir, 'Welcome.mdx');
40
- const stylesFile = join(stylesDir, 'global.css');
59
+ const mdxWelcomeFile = join(pagesDir, 'Welcome.mdx');
41
60
  const samplePageFile = join(pagesDir, 'home.json'); // Sample JSON page
42
- const builderIndexFile = join(builderDir, 'index.html'); // Entry point for builder UI
43
61
 
62
+ // Create siteConfig.json
44
63
  await createFile(
45
- mdxWelcomeFile,
46
- `# Welcome to Your Custom GUI\n\nThis is your first MDX file. Edit it to start building your pages!`
64
+ configFile,
65
+ `{
66
+ "pages": []
67
+ }`
47
68
  );
48
69
 
70
+ // Create Welcome.mdx as a sample MDX file
49
71
  await createFile(
50
- stylesFile,
51
- `/* Add your custom styles here */\nbody { font-family: 'Roboto', sans-serif; }`
72
+ mdxWelcomeFile,
73
+ `# Welcome to Your Custom GUI\n\nThis is your first MDX file. Edit it to start building your pages!`
52
74
  );
53
75
 
76
+ // Create a sample JSON page layout
54
77
  await createFile(
55
78
  samplePageFile,
56
79
  `{
@@ -69,31 +92,19 @@ async function initializeFiles() {
69
92
  }`
70
93
  );
71
94
 
72
- await createFile(
73
- builderIndexFile,
74
- `<!DOCTYPE html>
75
- <html lang="en">
76
- <head>
77
- <meta charset="UTF-8">
78
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
79
- <title>GUI Builder</title>
80
- </head>
81
- <body>
82
- <div id="builder-root"></div>
83
- <script src="/path-to-your-builder-script.js"></script> <!-- Placeholder for the actual builder script -->
84
- </body>
85
- </html>`
86
- );
95
+ // Update siteConfig.json with the sample pages
96
+ await updateSiteConfig([
97
+ { name: 'Welcome', path: '/welcome', type: 'mdx', file: './pages/Welcome.mdx' },
98
+ { name: 'Home', path: '/home', type: 'json', file: './pages/home.json' },
99
+ ]);
87
100
  }
88
101
 
89
102
  // Create the directory structure and initialize files at the app level
90
103
  (async () => {
91
104
  await createDir(guiDir);
92
105
  await createDir(componentsDir);
93
- await createDir(mdxDir);
94
- await createDir(stylesDir);
95
- await createDir(pagesDir); // New directory for JSON-based pages
96
- await createDir(builderDir); // Directory for builder UI
106
+ await createDir(pagesDir); // New directory for JSON and MDX pages
107
+ await createDir(configDir); // Create config directory
97
108
  await initializeFiles();
98
109
 
99
110
  console.log('this.GUI setup complete at the app level!');