Last active
November 20, 2024 15:46
-
-
Save pankajbisht/51fe011f34ae7df61d2e10c11538c58c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import ReactQuill from 'react-quill'; | |
import 'react-quill/dist/quill.snow.css'; // Quill theme CSS | |
import mammoth from 'mammoth'; // Mammoth.js for DOCX to HTML conversion | |
import { Box, Container, Typography, Button, CircularProgress, Snackbar, IconButton, Stack } from '@mui/material'; | |
import { styled } from '@mui/system'; | |
import Brightness4Icon from '@mui/icons-material/Brightness4'; // Icon for Dark Mode | |
import Brightness7Icon from '@mui/icons-material/Brightness7'; // Icon for Light Mode | |
const DocDataMerging = () => { | |
const [editorContent, setEditorContent] = useState(''); // Right panel: Editable Quill content | |
const [previewContent, setPreviewContent] = useState(''); // Left panel: Preview Quill content | |
const [file, setFile] = useState(null); // File state | |
const [showHtml, setShowHtml] = useState(false); // Toggle to show HTML code | |
const [loading, setLoading] = useState(false); // File upload loading state | |
const [openSnackbar, setOpenSnackbar] = useState(false); // Snackbar state | |
const [darkMode, setDarkMode] = useState(false); // Dark mode state | |
// Example dynamic data to merge | |
const data = { | |
user: { | |
name: 'John Doe', | |
accountNumber: '1234567890', | |
address: { | |
city: 'New York', | |
street: '5th Avenue' | |
}, | |
registrationDate: '2024-05-22', | |
isActive: true, | |
balance: 1000 | |
}, | |
items: [ | |
{ name: 'Item 1', price: 100 }, | |
{ name: 'Item 2', price: 150 } | |
] | |
}; | |
const handleFileChange = (event) => { | |
const selectedFile = event.target.files[0]; | |
if (selectedFile) { | |
setLoading(true); | |
setFile(selectedFile); | |
processFile(selectedFile); | |
} | |
}; | |
const processFile = (file) => { | |
const reader = new FileReader(); | |
reader.onload = async () => { | |
const arrayBuffer = reader.result; | |
// Convert DOCX to HTML using Mammoth | |
try { | |
const result = await mammoth.convertToHtml({ arrayBuffer }); | |
const htmlContent = result.value; | |
// Set initial content for both preview and editor | |
setEditorContent(htmlContent); // Right panel: Initially set | |
setPreviewContent(htmlContent); // Left panel: Initially set | |
setLoading(false); // Stop loading | |
} catch (err) { | |
console.error('Error processing DOCX file:', err); | |
setLoading(false); // Stop loading | |
} | |
}; | |
reader.readAsArrayBuffer(file); // Read file as ArrayBuffer | |
}; | |
const handleMerge = () => { | |
const mergedPreviewContent = mergeData(editorContent, data); // Use the current editor content | |
setPreviewContent(mergedPreviewContent); | |
}; | |
const mergeData = (htmlContent, data) => { | |
let mergedContent = htmlContent; | |
mergedContent = mergedContent.replace(/{#items}[\s\S]*?{\/items}/g, (match) => { | |
return handleItems(data.items); | |
}); | |
mergedContent = mergedContent.replace(/{(.*?)}/g, (match, placeholder) => { | |
if (placeholder.startsWith('formatDate')) { | |
const dateFormat = placeholder.split(' ')[1].replace(/'/g, ''); | |
const date = new Date(data.user.registrationDate); | |
return formatDate(date, dateFormat); | |
} | |
if (placeholder.startsWith('currency')) { | |
return currency(data.user.balance); | |
} | |
if (placeholder.includes('?')) { | |
return evaluateCondition(placeholder, data); | |
} | |
return getValueFromData(placeholder, data) || match; | |
}); | |
return mergedContent; | |
}; | |
const handleItems = (items) => { | |
if (items.length === 0) return ''; | |
return items.map(item => `${item.name} - $${item.price}`).join(', '); | |
}; | |
const evaluateCondition = (condition, data) => { | |
try { | |
const replacedCondition = condition.replace(/{(.*?)}/g, (match, placeholder) => { | |
return getValueFromData(placeholder, data) || match; | |
}); | |
return eval(replacedCondition); | |
} catch (err) { | |
console.error('Error evaluating condition:', err); | |
return condition; | |
} | |
}; | |
const getValueFromData = (placeholder, data) => { | |
const parts = placeholder.split('.'); | |
let result = data; | |
for (let part of parts) { | |
result = result[part]; | |
if (result === undefined) return null; | |
} | |
return result; | |
}; | |
const formatDate = (date, format) => { | |
const options = { year: 'numeric', month: 'numeric', day: 'numeric' }; | |
return date.toLocaleDateString(undefined, options); | |
}; | |
const currency = (value) => { | |
return `$${value.toFixed(2)}`; | |
}; | |
const toggleDarkMode = () => { | |
setDarkMode(!darkMode); | |
}; | |
return ( | |
<Container maxWidth="lg" sx={{ padding: '20px', backgroundColor: darkMode ? '#333' : '#fff', color: darkMode ? '#fff' : '#000', minHeight: '100vh' }}> | |
{/* Header Section */} | |
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px', borderBottom: '2px solid #ccc', paddingBottom: '10px' }}> | |
<Typography variant="h4">Doc Data Merging</Typography> | |
<Stack direction="row" spacing={2} alignItems="center"> | |
{/* File Upload moved to Header */} | |
<input | |
type="file" | |
accept=".docx" | |
onChange={handleFileChange} | |
style={{ display: 'none' }} | |
id="upload-button" | |
/> | |
<label htmlFor="upload-button"> | |
<Button variant="contained" component="span"> | |
Upload DOCX | |
</Button> | |
</label> | |
<Button variant="contained" onClick={handleMerge} disabled={loading}> | |
Merge Data | |
</Button> | |
<Button variant="outlined" onClick={() => setShowHtml(!showHtml)}> | |
{showHtml ? 'Hide HTML' : 'Show HTML'} | |
</Button> | |
<IconButton onClick={toggleDarkMode}> | |
{darkMode ? ( | |
<Brightness7Icon sx={{ color: '#fff' }} /> | |
) : ( | |
<Brightness4Icon sx={{ color: '#000' }} /> | |
)} | |
</IconButton> | |
</Stack> | |
</Box> | |
<Box sx={{ display: 'flex', height: '85vh', boxShadow: 3, borderRadius: '8px', overflow: 'hidden', backgroundColor: darkMode ? '#444' : '#f5f5f5' }}> | |
{/* Left Panel: Read-only Quill Editor (Preview) */} | |
<Box sx={{ flex: 1, padding: '20px', borderRight: '2px solid #ccc' }}> | |
<Typography variant="h6" sx={{ mb: 2 }}>Preview</Typography> | |
{showHtml ? ( | |
<Box sx={{ whiteSpace: 'pre-wrap', wordWrap: 'break-word', backgroundColor: '#f4f4f4', padding: '10px', borderRadius: '4px' }}> | |
<Typography variant="body2" sx={{ fontFamily: 'monospace' }}> | |
{previewContent} | |
</Typography> | |
</Box> | |
) : ( | |
<ReactQuill | |
value={previewContent} | |
readOnly={true} | |
theme="snow" | |
style={{ height: '60vh' }} | |
/> | |
)} | |
</Box> | |
{/* Right Panel: Editable Quill Editor (Edit Mode) */} | |
<Box sx={{ flex: 1, padding: '20px' }}> | |
<Typography variant="h6" sx={{ mb: 2 }}>Edit Document</Typography> | |
{loading && <CircularProgress sx={{ display: 'block', margin: '20px auto' }} />} | |
<ReactQuill | |
value={editorContent} | |
onChange={setEditorContent} | |
theme="snow" | |
style={{ height: '60vh' }} | |
/> | |
</Box> | |
</Box> | |
<Snackbar | |
open={openSnackbar} | |
autoHideDuration={3000} | |
onClose={() => setOpenSnackbar(false)} | |
message="File uploaded successfully!" | |
/> | |
</Container> | |
); | |
}; | |
export default DocDataMerging; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// src/App.js | |
import React from 'react'; | |
import DocDataMerging from './DocDataMerging'; | |
import { ThemeProvider, createTheme } from '@mui/material/styles'; | |
import CssBaseline from '@mui/material/CssBaseline'; | |
const theme = createTheme({ | |
palette: { | |
primary: { | |
main: '#1976d2', | |
}, | |
secondary: { | |
main: '#dc004e', | |
}, | |
}, | |
}); | |
const App = () => { | |
return ( | |
<ThemeProvider theme={theme}> | |
<CssBaseline /> | |
<DocDataMerging /> | |
</ThemeProvider> | |
); | |
}; | |
export default App; | |
{ | |
"name": "blockly-hello-world", | |
"version": "0.1.0", | |
"private": true, | |
"dependencies": { | |
"@emotion/react": "^11.13.3", | |
"@emotion/styled": "^11.13.0", | |
"@mui/icons-material": "^6.1.7", | |
"@mui/material": "^6.1.7", | |
"@testing-library/jest-dom": "^5.17.0", | |
"@testing-library/react": "^13.4.0", | |
"@testing-library/user-event": "^13.5.0", | |
"dayjs": "^1.11.13", | |
"docxtemplater": "^3.53.0", | |
"html-docx-js": "^0.3.1", | |
"mammoth": "^1.8.0", | |
"pizzip": "^3.1.7", | |
"react": "^18.3.1", | |
"react-dom": "^18.3.1", | |
"react-quill": "^2.0.0", | |
"react-scripts": "5.0.1", | |
"web-vitals": "^2.1.4" | |
}, | |
"scripts": { | |
"start": "react-scripts start", | |
"build": "react-scripts build", | |
"test": "react-scripts test", | |
"eject": "react-scripts eject" | |
}, | |
"eslintConfig": { | |
"extends": [ | |
"react-app", | |
"react-app/jest" | |
] | |
}, | |
"browserslist": { | |
"production": [ | |
">0.2%", | |
"not dead", | |
"not op_mini all" | |
], | |
"development": [ | |
"last 1 chrome version", | |
"last 1 firefox version", | |
"last 1 safari version" | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "blockly-hello-world", | |
"version": "0.1.0", | |
"private": true, | |
"dependencies": { | |
"@emotion/react": "^11.13.3", | |
"@emotion/styled": "^11.13.0", | |
"@mui/icons-material": "^6.1.7", | |
"@mui/material": "^6.1.7", | |
"@testing-library/jest-dom": "^5.17.0", | |
"@testing-library/react": "^13.4.0", | |
"@testing-library/user-event": "^13.5.0", | |
"dayjs": "^1.11.13", | |
"docxtemplater": "^3.53.0", | |
"html-docx-js": "^0.3.1", | |
"mammoth": "^1.8.0", | |
"pizzip": "^3.1.7", | |
"react": "^18.3.1", | |
"react-dom": "^18.3.1", | |
"react-quill": "^2.0.0", | |
"react-scripts": "5.0.1", | |
"web-vitals": "^2.1.4" | |
}, | |
"scripts": { | |
"start": "react-scripts start", | |
"build": "react-scripts build", | |
"test": "react-scripts test", | |
"eject": "react-scripts eject" | |
}, | |
"eslintConfig": { | |
"extends": [ | |
"react-app", | |
"react-app/jest" | |
] | |
}, | |
"browserslist": { | |
"production": [ | |
">0.2%", | |
"not dead", | |
"not op_mini all" | |
], | |
"development": [ | |
"last 1 chrome version", | |
"last 1 firefox version", | |
"last 1 safari version" | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect, useRef, useState } from 'react'; | |
import * as Blockly from 'blockly/core'; | |
import 'blockly/blocks'; | |
import { javascriptGenerator } from 'blockly/javascript'; | |
const BlocklyWorkspace = () => { | |
const workspaceRef = useRef(null); | |
const [output, setOutput] = useState(''); // State to store the output | |
const [data, setData] = useState({ | |
user: { | |
name: 'John Doe', | |
accountNumber: '1234567890', | |
address: { | |
city: 'New York', | |
street: '5th Avenue' | |
}, | |
registrationDate: '2024-05-22', | |
isActive: true, | |
balance: 1000 | |
}, | |
items: [ | |
{ name: 'Item 1', price: 100 }, | |
{ name: 'Item 2', price: 150 } | |
] | |
}); | |
useEffect(() => { | |
const workspace = Blockly.inject(workspaceRef.current, { | |
toolbox: ` | |
<xml> | |
<category name="User"> | |
<block type="user_getname"></block> | |
<block type="user_getbalance"></block> | |
<block type="user_setbalance"> | |
<value name="BALANCE"> | |
<block type="math_number"> | |
<field name="NUM">1000</field> | |
</block> | |
</value> | |
</block> | |
</category> | |
<category name="Items"> | |
<block type="item_getname"> | |
<value name="ITEM_INDEX"> | |
<block type="math_number"> | |
<field name="NUM">0</field> | |
</block> | |
</value> | |
</block> | |
<block type="item_getprice"> | |
<value name="ITEM_INDEX"> | |
<block type="math_number"> | |
<field name="NUM">0</field> | |
</block> | |
</value> | |
</block> | |
</category> | |
</xml> | |
`, | |
grid: { | |
spacing: 20, | |
length: 3, | |
colour: '#ccc', | |
}, | |
}); | |
return () => workspace.dispose(); | |
}, []); | |
// Blockly block definitions with output | |
Blockly.Blocks['user_getname'] = { | |
init: function () { | |
this.appendDummyInput().appendField('Get user name'); | |
this.setOutput(true, 'String'); | |
this.setColour(230); | |
this.setTooltip('Returns the user\'s name'); | |
}, | |
}; | |
Blockly.Blocks['user_getbalance'] = { | |
init: function () { | |
this.appendDummyInput().appendField('Get user balance'); | |
this.setOutput(true, 'Number'); | |
this.setColour(230); | |
this.setTooltip('Returns the user\'s balance'); | |
}, | |
}; | |
Blockly.Blocks['user_setbalance'] = { | |
init: function () { | |
this.appendValueInput('BALANCE') | |
.setCheck('Number') | |
.appendField('Set user balance to'); | |
this.setPreviousStatement(true, null); | |
this.setNextStatement(true, null); | |
this.setColour(230); | |
this.setTooltip('Sets the user\'s balance'); | |
} | |
}; | |
Blockly.Blocks['item_getname'] = { | |
init: function () { | |
this.appendValueInput('ITEM_INDEX') | |
.setCheck('Number') | |
.appendField('Get item name at index'); | |
this.setOutput(true, 'String'); | |
this.setColour(230); | |
this.setTooltip('Returns the item name at the specified index'); | |
}, | |
}; | |
Blockly.Blocks['item_getprice'] = { | |
init: function () { | |
this.appendValueInput('ITEM_INDEX') | |
.setCheck('Number') | |
.appendField('Get item price at index'); | |
this.setOutput(true, 'Number'); | |
this.setColour(230); | |
this.setTooltip('Returns the item price at the specified index'); | |
}, | |
}; | |
// JavaScript code generation for each block | |
javascriptGenerator.forBlock['user_getname'] = function () { | |
return [`data.user.name`, javascriptGenerator.ORDER_ATOMIC]; | |
}; | |
javascriptGenerator.forBlock['user_getbalance'] = function () { | |
return [`data.user.balance`, javascriptGenerator.ORDER_ATOMIC]; | |
}; | |
javascriptGenerator.forBlock['user_setbalance'] = function (block) { | |
const value_balance = javascriptGenerator.valueToCode(block, 'BALANCE', javascriptGenerator.ORDER_ATOMIC); | |
// Directly update the state without returning any value | |
return `setData(prevData => ({ ...prevData, user: { ...prevData.user, balance: ${value_balance} } }));\n`; | |
}; | |
javascriptGenerator.forBlock['item_getname'] = function (block) { | |
const value_index = javascriptGenerator.valueToCode(block, 'ITEM_INDEX', javascriptGenerator.ORDER_ATOMIC); | |
return [`data.items[${value_index}].name`, javascriptGenerator.ORDER_ATOMIC]; | |
}; | |
javascriptGenerator.forBlock['item_getprice'] = function (block) { | |
const value_index = javascriptGenerator.valueToCode(block, 'ITEM_INDEX', javascriptGenerator.ORDER_ATOMIC); | |
return [`data.items[${value_index}].price`, javascriptGenerator.ORDER_ATOMIC]; | |
}; | |
// Run code and update output | |
const runCode = () => { | |
const code = javascriptGenerator.workspaceToCode(Blockly.getMainWorkspace()); | |
if (code) { | |
try { | |
// Execute the generated code and get the result | |
const result = eval(code); // Using eval to execute the generated code | |
if (result !== undefined) { | |
setOutput(result); // Update the output state with the result | |
} else { | |
setOutput("Action executed successfully, but no return value."); | |
} | |
} catch (error) { | |
setOutput(`Error: ${error.message}`); | |
} | |
} | |
}; | |
// Automatically run code periodically | |
useEffect(() => { | |
const intervalId = setInterval(() => { | |
// Generate code from Blockly workspace | |
const generatedCode = javascriptGenerator.workspaceToCode(Blockly.getMainWorkspace()); | |
//setCode(generatedCode); // Store the code in the state | |
// Execute the generated code | |
eval(generatedCode); // Execute the code (using eval for simplicity) | |
}, 2000); // Run every 2 seconds for demo | |
return () => clearInterval(intervalId); | |
}, []); | |
return ( | |
<div> | |
<div ref={workspaceRef} style={{ height: '400px', width: '100%' }}></div> | |
<button onClick={runCode}>Run Code</button> | |
<div> | |
<strong>Output:</strong> | |
<pre>{output !== undefined ? output : "No output"}</pre> {/* Display the output here */} | |
</div> | |
</div> | |
); | |
}; | |
export default BlocklyWorkspace; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// src/App.js | |
import React, { useState } from 'react'; | |
import BlocklyWorkspace from './BlocklyWorkspace'; | |
import { ThemeProvider, createTheme } from '@mui/material/styles'; | |
import CssBaseline from '@mui/material/CssBaseline'; | |
import { Characters } from './Characters'; | |
const theme = createTheme({ | |
palette: { | |
primary: { | |
main: '#1976d2', | |
}, | |
secondary: { | |
main: '#dc004e', | |
}, | |
}, | |
}); | |
const App = () => { | |
const [commands, setCommands] = useState([]); | |
const handleRunCode = (code) => { | |
const commandList = code.split("\n").filter((line) => line !== ""); | |
setCommands(commandList); | |
}; | |
return ( | |
<div> | |
<ThemeProvider theme={theme}> | |
<CssBaseline /> | |
<BlocklyWorkspace onRunCode={handleRunCode} /> | |
<Characters commands={commands} /> | |
</ThemeProvider> | |
</div> | |
); | |
}; | |
export default App; | |
import { useState } from "react"; | |
export const Characters = ({ commands }) => { | |
const [position, setPosition] = useState(0); | |
const [rotation, setRotation] = useState(0); | |
const executeCommands = () => { | |
commands.forEach((command) => { | |
if (command.startsWith('moveSteps')) { | |
const steps = parseInt(command.match(/\((.*)\)/)[1]); | |
moveSteps(steps); | |
} else if (command === 'moveLeft()' || command === 'moveLeft();') { | |
moveLeft(); | |
} else if (command === 'moveRight()' || command === 'moveRight();') { | |
moveRight(); | |
} else if (command === 'turnLeft()' || command === 'turnLeft();') { | |
turnLeft(); | |
} else if (command === 'turnRight()' || command === 'turnRight();') { | |
turnRight(); | |
} | |
}); | |
}; | |
const moveSteps = (steps) => { | |
setPosition((prev) => prev + steps); | |
}; | |
const moveLeft = () => { | |
setPosition((prev) => prev - 10); | |
}; | |
const moveRight = () => { | |
setPosition((prev) => prev + 10); | |
}; | |
const turnLeft = () => { | |
setRotation((prev) => prev - 45); | |
}; | |
const turnRight = () => { | |
setRotation((prev) => prev + 45); | |
}; | |
return ( | |
<div> | |
<div className="character-container"> | |
<img | |
src={'https://img.freepik.com/premium-vector/cute-unicon-monster-doodles_38841-90.jpg?w=360'} | |
alt="Character" | |
style={{ marginLeft: position, transform: `rotate(${rotation}deg)` }} | |
height={'100px'} | |
/> | |
</div> | |
<button onClick={executeCommands}>Execute Commands</button> | |
</div> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from "react"; | |
export const Characters = ({ commands }) => { | |
const [position, setPosition] = useState(0); | |
const [rotation, setRotation] = useState(0); | |
const executeCommands = () => { | |
commands.forEach((command) => { | |
if (command.startsWith('moveSteps')) { | |
const steps = parseInt(command.match(/\((.*)\)/)[1]); | |
moveSteps(steps); | |
} else if (command === 'moveLeft()' || command === 'moveLeft();') { | |
moveLeft(); | |
} else if (command === 'moveRight()' || command === 'moveRight();') { | |
moveRight(); | |
} else if (command === 'turnLeft()' || command === 'turnLeft();') { | |
turnLeft(); | |
} else if (command === 'turnRight()' || command === 'turnRight();') { | |
turnRight(); | |
} | |
}); | |
}; | |
const moveSteps = (steps) => { | |
setPosition((prev) => prev + steps); | |
}; | |
const moveLeft = () => { | |
setPosition((prev) => prev - 10); | |
}; | |
const moveRight = () => { | |
setPosition((prev) => prev + 10); | |
}; | |
const turnLeft = () => { | |
setRotation((prev) => prev - 45); | |
}; | |
const turnRight = () => { | |
setRotation((prev) => prev + 45); | |
}; | |
return ( | |
<div> | |
<div className="character-container"> | |
<img | |
src={'https://img.freepik.com/premium-vector/cute-unicon-monster-doodles_38841-90.jpg?w=360'} | |
alt="Character" | |
style={{ marginLeft: position, transform: `rotate(${rotation}deg)` }} | |
height={'100px'} | |
/> | |
</div> | |
<button onClick={executeCommands}>Execute Commands</button> | |
</div> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// src/App.js | |
import React, { useState } from 'react'; | |
import BlocklyWorkspace from './BlocklyWorkspace'; | |
import { ThemeProvider, createTheme } from '@mui/material/styles'; | |
import CssBaseline from '@mui/material/CssBaseline'; | |
import { Characters } from './Characters'; | |
const theme = createTheme({ | |
palette: { | |
primary: { | |
main: '#1976d2', | |
}, | |
secondary: { | |
main: '#dc004e', | |
}, | |
}, | |
}); | |
const App = () => { | |
const [commands, setCommands] = useState([]); | |
const handleRunCode = (code) => { | |
const commandList = code.split("\n").filter((line) => line !== ""); | |
setCommands(commandList); | |
}; | |
return ( | |
<div> | |
<ThemeProvider theme={theme}> | |
<CssBaseline /> | |
<BlocklyWorkspace onRunCode={handleRunCode} /> | |
<Characters commands={commands} /> | |
</ThemeProvider> | |
</div> | |
); | |
}; | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment