Skip to content

Commit 56586c1

Browse files
Julia BakerinkJulia Bakerink
authored andcommitted
Added functionality to export single component Coauthored: Megan Nadkarni, Julia Bakerink
1 parent 52d8d36 commit 56586c1

File tree

5 files changed

+253
-5
lines changed

5 files changed

+253
-5
lines changed

TestAgain/Test.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<div>
3+
<div></div>
4+
</div>
5+
</template>
6+
7+
<script>
8+
9+
export default {
10+
name: 'Test',
11+
components: {
12+
},
13+
};
14+
</script>
15+
16+
<style scoped>
17+
</style>

TestTwoComponents/Test.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<div>
3+
<div></div>
4+
</div>
5+
</template>
6+
7+
<script>
8+
import TestChild from '@/components/TestChild.vue';
9+
10+
export default {
11+
name: 'Test',
12+
components: {
13+
TestChild,
14+
},
15+
};
16+
</script>
17+
18+
<style scoped>
19+
</style>

src-electron/electron-main.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ ipcMain.handle("clearImage", async (event, arg) => {
6969
return result;
7070
})
7171

72+
// Handle dialogs for exporting a component
73+
ipcMain.handle("exportComponent", async (event, arg) => {
74+
const result = await dialog.showSaveDialog(arg);
75+
return result;
76+
});
77+
7278

7379
// ************** Slack OAuth functions **********************
7480
// Sends request to Slack for User's information,

src/components/ComponentDisplay.vue

Lines changed: 210 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Description:
3939
<q-menu context-menu>
4040
<q-list color="black" class="menu">
4141
<q-item clickable v-ripple v-close-popup @click="handleExportComponent">
42-
<q-item-section class="layer" style="color: white"
42+
<q-item-section style="color: white"
4343
>Export Component</q-item-section
4444
>
4545
<q-item-section avatar>
@@ -100,6 +100,7 @@ Description:
100100
import { mapState, mapActions } from "vuex";
101101
import VueDraggableResizable from "vue-draggable-resizable/src/components/vue-draggable-resizable.vue";
102102
import "vue-draggable-resizable/src/components/vue-draggable-resizable.css";
103+
const { fs, ipcRenderer } = window;
103104
104105
const cloneDeep = require("lodash.clonedeep");
105106
@@ -366,10 +367,215 @@ export default {
366367
if (!(this.activeComponent === "")) this.setActiveComponent("");
367368
}
368369
},
369-
// OVERVUE 6.0: if user right clicks on component, ability to export specific component
370-
handleExportComponent() {
371-
370+
showExportDialog() {
371+
ipcRenderer
372+
.invoke("exportComponent", {
373+
title: "Choose location to save folder in",
374+
message: "Choose location to save folder in",
375+
nameFieldLabel: "Component Name",
376+
})
377+
.then((result) => this.exportFile(result.filePath))
378+
.catch((err) => console.log(err));
379+
},
380+
/**
381+
* @description: creates component code <template>, <script>, <style>
382+
* invokes writeTemplate, writeScript, writeStyle
383+
*/
384+
createComponentCode(componentLocation, componentName, children) {
385+
console.log("createComponentCode", componentLocation, componentName, children);
386+
fs.writeFileSync(
387+
componentLocation + ".vue",
388+
this.writeTemplate(componentName, children) +
389+
this.writeScript(componentName, children) +
390+
this.writeStyle(componentName)
391+
);
392+
},
393+
writeTemplateTag(componentName) {
394+
console.log("writeTemplateTag", componentName);
395+
// create reference object
396+
const htmlElementMap = {
397+
div: ["<div>", "</div>"],
398+
button: ["<button>", "</button>"],
399+
form: ["<form>", "</form>"],
400+
img: ["<img>", ""],
401+
link: ['<a href="#"/>', ""],
402+
list: ["<li>", "</li>"],
403+
paragraph: ["<p>", "</p>"],
404+
"list-ol": ["<ol>", "</ol>"],
405+
"list-ul": ["<ul>", "</ul>"],
406+
input: ["<input />", ""],
407+
navbar: ["<nav>", "</nav>"],
408+
};
409+
// function to loop through nested elements
410+
function writeNested(childrenArray, indent) {
411+
console.log("writeNested", childrenArray, indent);
412+
if (!childrenArray.length) {
413+
return "";
414+
}
415+
let indented = indent + " ";
416+
let nestedString = "";
417+
childrenArray.forEach((child) => {
418+
nestedString += indented;
419+
if (!child.text) {
420+
nestedString += `<${child}/>\n`;
421+
} else {
422+
if (child.children.length) {
423+
nestedString += htmlElementMap[child.text][0];
424+
nestedString += "\n";
425+
nestedString += writeNested(child.children, indented);
426+
nestedString += indented + htmlElementMap[child.text][1];
427+
nestedString += "\n";
428+
} else {
429+
nestedString +=
430+
htmlElementMap[child.text][0] +
431+
htmlElementMap[child.text][1] +
432+
"\n";
433+
}
434+
}
435+
});
436+
return nestedString;
437+
}
438+
// iterate through component's htmllist
439+
let htmlArr = this.componentMap[componentName].htmlList;
440+
let outputStr = ``;
441+
// eslint-disable-next-line no-unused-vars
442+
for (let el of htmlArr) {
443+
if (!el.text) {
444+
outputStr += ` <${el}/>\n`;
445+
} else {
446+
outputStr += ` `;
447+
if (el.children.length) {
448+
outputStr += htmlElementMap[el.text][0];
449+
outputStr += "\n";
450+
outputStr += writeNested(el.children, ` `);
451+
outputStr += ` `;
452+
outputStr += htmlElementMap[el.text][1];
453+
outputStr += ` \n`;
454+
} else {
455+
outputStr +=
456+
htmlElementMap[el.text][0] + htmlElementMap[el.text][1] + "\n";
457+
}
458+
}
459+
}
460+
return outputStr;
461+
},
462+
/**
463+
* @description creates the <router-link> boilerplate for /views/components
464+
* also creates the <template></template> tag for each component
465+
*/
466+
writeTemplate(componentName, children) {
467+
console.log("writeTemplate", componentName, children);
468+
let str = "";
469+
str += `<div>\n`;
470+
// writes the HTML tag boilerplate
471+
let templateTagStr = this.writeTemplateTag(componentName);
472+
return `<template>\n\t${str}${templateTagStr}\t</div>\n</template>`;
473+
},
474+
/**
475+
* @description imports child components into <script>
476+
*/
477+
writeScript(componentName, children) {
478+
console.log("writeScript", componentName, children)
479+
// add import mapstate and mapactions if they exist
480+
const currentComponent = this.componentMap[componentName];
481+
let imports = "";
482+
if (currentComponent.actions.length || currentComponent.state.length) {
483+
imports += "import { ";
484+
if (
485+
currentComponent.actions.length &&
486+
currentComponent.state.length
487+
) {
488+
imports += "mapState, mapActions";
489+
} else if (currentComponent.state.length) imports += "mapState";
490+
else imports += "mapActions";
491+
imports += ' } from "vuex"\n';
492+
}
493+
// add imports for children
494+
children.forEach((name) => {
495+
imports += `import ${name} from '@/components/${name}.vue';\n`;
496+
});
497+
// add components section
372498
499+
// if true add data section and populate with props
500+
let childrenComponentNames = "";
501+
children.forEach((name) => {
502+
childrenComponentNames += ` ${name},\n`;
503+
});
504+
// if true add data section and populate with props
505+
let data = "";
506+
if (currentComponent.props.length) {
507+
data += " data () {\n return {";
508+
currentComponent.props.forEach((prop) => {
509+
data += `\n ${prop}: "PLACEHOLDER FOR VALUE",`;
510+
});
511+
data += "\n";
512+
data += " }\n";
513+
data += " },\n";
514+
}
515+
// if true add computed section and populate with state
516+
let computed = "";
517+
if (currentComponent.state.length) {
518+
computed += " computed: {";
519+
computed += "\n ...mapState([";
520+
currentComponent.state.forEach((state) => {
521+
computed += `\n "${state}",`;
522+
});
523+
computed += "\n ]),\n";
524+
computed += " },\n";
525+
}
526+
// if true add methods section and populate with actions
527+
let methods = "";
528+
if (currentComponent.actions.length) {
529+
methods += " methods: {";
530+
methods += "\n ...mapActions([";
531+
currentComponent.actions.forEach((action) => {
532+
methods += `\n "${action}",`;
533+
});
534+
methods += "\n ]),\n";
535+
methods += " },\n";
536+
}
537+
// concat all code within script tags
538+
let output = "\n\n<script>\n";
539+
output +=
540+
imports + "\nexport default {\n name: '" + componentName + "'";
541+
output += ",\n components: {\n";
542+
output += childrenComponentNames + " },\n";
543+
output += data;
544+
output += computed;
545+
output += methods;
546+
// eslint-disable-next-line no-useless-escape
547+
output += "};\n<\/script>";
548+
return output;
549+
},
550+
/**
551+
* @description writes the <style> in vue component
552+
* if component is 'App', writes css, else returns <style scoped>
553+
*/
554+
writeStyle(componentName) {
555+
console.log("writeStyle", componentName);
556+
return `\n\n<style scoped>\n</style>`;
557+
},
558+
559+
exportFile(data) {
560+
console.log("exportFile", data);
561+
if (data === undefined) return;
562+
if (!fs.existsSync(data)) {
563+
fs.mkdirSync(data);
564+
// console.log(`data: ${data}`); // displays the directory path
565+
}
566+
// main logic below for creating components
567+
// eslint-disable-next-line no-unused-vars
568+
// TO DO: need to update logic to only look at the component being exported and its children
569+
this.createComponentCode(
570+
path.join(data, this.activeComponent),
571+
this.activeComponent,
572+
this.componentMap[this.activeComponent].children
573+
);
574+
},
575+
// OVERVUE 6.0: if user right clicks on component, ability to export specific component
576+
handleExportComponent(event) {
577+
console.log("Export button clicked");
578+
this.showExportDialog();
373579
},
374580
375581
// event handler for copying (ctrl+C)

src/components/file_system_interface/CopyExportProject.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { mapState } from "vuex";
2222
const { fs, ipcRenderer } = window;
2323
2424
export default {
25-
name: "ExportProjectComponent",
25+
name: "ExportComponent",
2626
methods: {
2727
showExportDialog() {
2828
ipcRenderer

0 commit comments

Comments
 (0)