Skip to content

Commit 387f044

Browse files
author
Julia Bakerink
committed
Added dropdowns to the nav bar buttons but functionality needs to be added. importComponentMixin has been started but not yet complete
1 parent 7ea737e commit 387f044

File tree

7 files changed

+289
-26
lines changed

7 files changed

+289
-26
lines changed

src/components/ExportComponentMixin.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export default {
167167
// concat all code within script tags
168168
// if exportAsTypescript is on, out should be <script lang="ts">
169169
let output;
170-
if (this.exportAsTypescript === 'on') {
170+
if (this.exportAsTypescript === "on") {
171171
output = "\n\n<script lang='ts'>\n";
172172
output += imports + "\nexport default defineComponent ({\n name: '" + componentName + "'";
173173
} else {
@@ -180,7 +180,7 @@ export default {
180180
output += computed;
181181
output += methods;
182182
// eslint-disable-next-line no-useless-escape
183-
if (this.exportAsTypescript === 'on') {
183+
if (this.exportAsTypescript === "on") {
184184
output += "});\n<\/script>";
185185
186186
} else {
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<script>
2+
3+
export default {
4+
5+
methods: {
6+
//emitter to send the importedObj to CreateComponent when fully parsed.
7+
createImport(importObj){
8+
this.$emit('imported', importObj)
9+
},
10+
11+
//renders the open file
12+
importComponent() {
13+
ipcRenderer
14+
.invoke("openProject", {
15+
properties: ["openProject"],
16+
filters: [
17+
{
18+
name: "Vue Files",
19+
extensions: ["vue"],
20+
},
21+
],
22+
})
23+
.then((res) => this.openVueFile(res.filePaths))
24+
.catch((err) => console.log(err));
25+
},
26+
27+
//parses script tag string for props
28+
parsingStringToProps (str){
29+
let props = [];
30+
let split = str.split(' ');
31+
for(let i = 0; i < split.length; i++){
32+
if(split[i].includes(':') && split[i] !== 'computed:' && split[i] !== 'methods:' && split[i] !== 'name:' && split[i] !=='components:'){
33+
let cleanStr = split[i].slice(0,split[i].indexOf(':'))
34+
props.push(cleanStr)
35+
}
36+
}
37+
return props
38+
},
39+
40+
//parses script tag string for actions
41+
parsingStringToAction (str){
42+
let action = [];
43+
if (str.indexOf('...mapActions') === -1){return action};
44+
let trashedSlice = str.slice(str.lastIndexOf('...mapActions')+15);
45+
let slice = trashedSlice.slice(0, trashedSlice.indexOf('])'));
46+
let split = slice.split(' ')
47+
for(let i = 0; i < split.length; i++){
48+
if (split[i].includes(',')){
49+
let cleanStr = split[i].slice(split[i].indexOf('"')+1,split[i].lastIndexOf('"'))
50+
action.push(cleanStr)
51+
}
52+
}
53+
return action;
54+
},
55+
56+
//parses script tag string for state
57+
parsingStringToState (str){
58+
let state = [];
59+
if (str.indexOf('...mapState') === -1){return state};
60+
let trashedSlice = str.slice(str.lastIndexOf('...mapState')+15);
61+
let slice = trashedSlice.slice(0, trashedSlice.indexOf('])'));
62+
let split = slice.split(' ')
63+
for (let i = 0; i < split.length; i++){
64+
if (split[i].includes(',')){
65+
let cleanStr = split[i].slice(split[i].indexOf('"')+1,split[i].lastIndexOf('"'))
66+
state.push(cleanStr)
67+
}
68+
}
69+
return state
70+
},
71+
72+
//the bulk of the work for this component
73+
openVueFile(data) {
74+
if (data === undefined) return;
75+
76+
const importObj = {}; //final output
77+
const htmlList = []; //array populated with substrings '<div>' '</div>' '<p>' etc.
78+
let compName = data[0].slice(data[0].lastIndexOf('/')+1).replace(/[^a-z0-9-_.]/gi, '').replace(/.vue/, '');
79+
const vueFile = fs.readFileSync(data[0], "utf8");
80+
81+
for (const key in this.$store.state.componentMap){
82+
if (this.$store.state.componentMap[key].componentName === compName){
83+
compName += 'duplicate'; //appends duplicate if the componentName already exists in state.
84+
}
85+
}
86+
importObj.componentName = compName;
87+
88+
const htmlElementMap = { //OverVue state management only handles these HTML tags.
89+
div: ["<div>", "</div>"],
90+
button: ["<button>", "</button>"],
91+
form: ["<form>", "</form>"],
92+
img: ["<img>", ""],
93+
link: ['<a href="#"/>', ""],
94+
list: ["<li>", "</li>"],
95+
paragraph: ["<p>", "</p>"],
96+
"list-ol": ["<ol>", "</ol>"],
97+
"list-ul": ["<ul>", "</ul>"],
98+
input: ["<input />", ""],
99+
navbar: ["<nav>", "</nav>"],
100+
};
101+
102+
103+
let htmlString = vueFile.substring(vueFile.indexOf('<template >')+10, vueFile.indexOf('</template>'));
104+
let scriptString = vueFile.substring(vueFile.indexOf(`<script>`)+8, vueFile.indexOf(`/script>`)-1)
105+
106+
htmlParser(htmlString);
107+
importObj.props = this.parsingStringToProps(scriptString);
108+
importObj.actions = this.parsingStringToAction(scriptString);
109+
importObj.state = this.parsingStringToState(scriptString);
110+
111+
htmlList.pop(); htmlList.shift(); //OverVue adds a <div></div> wrapper to all components. remove this before importing.
112+
113+
let groupings = findGroupings(htmlList);
114+
let groupingObj = objectGenerator(groupings);
115+
let groupingArray = [];
116+
for (const key in groupingObj){
117+
groupingArray.push(groupingObj[key])
118+
}
119+
importObj.htmlList = groupingArray;
120+
this.createImport(importObj) //send the importObj to CreateComponent.
121+
122+
/**
123+
* @name: htmlParser
124+
* @desc: parses imported .vue file for html elements and state, props and actions
125+
* @param: a string generated by reading a .vue file from the filesystem
126+
* @return: nothing: passes the substrings into buildList to generate an array of elements
127+
*/
128+
129+
function htmlParser(htmlString){
130+
if (!htmlString){return}
131+
//remove new lines and tabs from HTML
132+
htmlString = htmlString.replaceAll('\n', '').replaceAll('\t', '');
133+
//find index for the first < and > in the string
134+
let openTag = htmlString.indexOf('<');
135+
let closeTag = htmlString.indexOf('>');
136+
137+
//push the substring wrapped by < and > into the helper func
138+
buildList(htmlString.substring(openTag+1, closeTag))
139+
140+
//recursively call htmlParser on the remainder of the string
141+
return htmlParser(htmlString.substring(closeTag+1))
142+
}
143+
144+
145+
/**
146+
* @name: buildList
147+
* @desc: takes incoming substrings and pushes the appropriate
148+
* elements fromt he htmlElementMap defined by Overvue
149+
*
150+
* @param: substrings from htmlParser function
151+
* @return: nothing -- pushes into htmlList array which is defined outside scope of buildList
152+
*/
153+
154+
function buildList(substring){
155+
for (const elem in htmlElementMap){
156+
for (let i = 0; i < htmlElementMap[elem].length; i++){
157+
//if the htmlElementMap[elem][index] matches the substring, push it into the output array
158+
if (substring === 'p'){
159+
htmlList.push(htmlElementMap.paragraph[0])
160+
return;
161+
} else if (substring === '/p') {
162+
htmlList.push(htmlElementMap.paragraph[1])
163+
return;
164+
}
165+
if (htmlElementMap[elem][i].indexOf(substring) !== -1){
166+
htmlList.push(htmlElementMap[elem][i])
167+
return;
168+
}
169+
}
170+
}
171+
}
172+
173+
/**
174+
* @name: findGroupings
175+
* @desc: creates groupings of parent/child elements
176+
* @param: array generated by buildList of html elements from imported Vue file
177+
* @return: returns an array of arrays (grouped by parent/child)
178+
*/
179+
180+
function findGroupings(array){
181+
let count = 0; //tracks where the parent ends
182+
let stopIndexes = []; //an array that will be used to slice out the parent/child relationships
183+
for (let i = 0; i < array.length; i++){
184+
if (array[i][1] !== '/'){
185+
if (array[i] === '<img>' || array[i] === '<a href="#"/>' || array[i] === '<input />'){
186+
if (count === 0){
187+
stopIndexes.push(i);
188+
continue;
189+
}
190+
} else {
191+
count++;
192+
}
193+
} else {
194+
count--;
195+
}
196+
if (count === 0){
197+
stopIndexes.push(i)
198+
}
199+
}
200+
let groupings = [];
201+
let startIndex = 0;
202+
for (let i = 0; i < stopIndexes.length; i++){
203+
groupings.push(array.slice(startIndex, stopIndexes[i]+1));
204+
startIndex = stopIndexes[i]+1;
205+
}
206+
return groupings;
207+
}
208+
209+
210+
/**
211+
* @name: objectGenerator
212+
* @desc: generates a nested object from the result of findGroupings nesting children within parents
213+
* @param: array generated by findGroupings
214+
* @return: returns an object containing parent/children html elements nested.
215+
*/
216+
217+
function objectGenerator(array){
218+
let groupingObj = {};
219+
for (let i = 0; i < array.length; i++){
220+
for (const key in htmlElementMap){
221+
if (array[i][0] === htmlElementMap[key][0]){
222+
let idGen = Date.now()-Math.floor(Math.random()*1000000);
223+
groupingObj[i] = {text: key, id: idGen}
224+
}
225+
}
226+
array[i].pop();
227+
array[i].shift();
228+
if (array[i].length > 0){
229+
const childGroupings = findGroupings(array[i]);
230+
const childrenObj = objectGenerator(childGroupings);
231+
const childrenArray = [];
232+
for (const key in childrenObj){
233+
childrenArray.push(childrenObj[key])
234+
}
235+
groupingObj[i].children = childrenArray;
236+
} else {
237+
groupingObj[i].children = [];
238+
}
239+
}
240+
return groupingObj;
241+
}
242+
}
243+
}
244+
}
245+
246+
</script>
247+
248+
249+
250+
251+
252+

src/components/dashboard_items/CodeSnippet.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export default {
176176
}
177177
178178
// if Typescript toggle is on, import defineComponent
179-
if (this.exportAsTypescript === 'on') {
179+
if (this.exportAsTypescript === "on") {
180180
imports += 'import { defineComponent } from "vue";\n';
181181
}
182182
@@ -230,7 +230,7 @@ export default {
230230
// concat all code within script tags
231231
// if exportAsTypescript is on, out should be <script lang="ts">
232232
let output;
233-
if (this.exportAsTypescript === 'on') {
233+
if (this.exportAsTypescript === "on") {
234234
output = "\n\n<script lang='ts'>\n";
235235
output += imports + "\nexport default defineComponent ({\n name: '" + componentName + "';";
236236
} else {
@@ -243,7 +243,7 @@ export default {
243243
output += computed;
244244
output += methods;
245245
246-
if (this.exportAsTypescript === 'on') {
246+
if (this.exportAsTypescript === "on") {
247247
output += "});\n<\/script>\n\n<style scoped>\n</style>"
248248
249249
} else {

src/components/file_system_interface/ExportProject.vue

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,26 @@ Description:
1010
-->
1111

1212
<template>
13-
<q-btn
14-
class="export-btn"
15-
color="secondary"
16-
label="Export"
17-
@click="exportProject"
18-
/>
13+
<q-btn class="export-btn" color="secondary" label="Export">
14+
<q-menu>
15+
<div class="settings-dropdown column items-center">
16+
<q-btn class="menu-btn" no-caps color="secondary" label="Export Project" @click="exportProject"/>
17+
<!-- Export active component is incorrectly exporting the entire project. Need to also disable this button when no active component is selected
18+
-->
19+
<q-btn class="menu-btn" no-caps color="secondary" label="Export Active Component" @click="handleExportComponent"/>
20+
</div>
21+
</q-menu>
22+
23+
</q-btn>
1924
</template>
2025
<script>
2126
import { mapState } from "vuex";
27+
import handleExportComponentMixin from "../ExportComponentMixin.vue";
2228
const { fs, ipcRenderer } = window;
2329
2430
export default {
2531
name: "ExportProjectComponent",
32+
mixins: [handleExportComponentMixin],
2633
methods: {
2734
showExportDialog() {
2835
ipcRenderer
@@ -74,7 +81,7 @@ export default {
7481
*/
7582
createExport(appChildren) {
7683
let str;
77-
if (this.exportAsTypescript === 'on') {
84+
if (this.exportAsTypescript === "on") {
7885
str = "export default createRouter({\n\thistory: createWebHistory(process.env.BASE_URL),\n\troutes: [\n";
7986
} else {
8087
str = "export default createRouter({\n\thistory: createWebHistory(),\n\tbase: process.env.BASE_URL,\n\troutes: [\n";
@@ -275,7 +282,7 @@ export default {
275282
}
276283
// concat all code within script tags
277284
let output;
278-
if (this.exportAsTypescript === 'on') {
285+
if (this.exportAsTypescript === "on") {
279286
output = "\n\n<script lang='ts'>\n";
280287
output += imports + "\nexport default defineComponent ({\n name: '" + componentName + "'";
281288
} else {
@@ -288,7 +295,7 @@ export default {
288295
output += computed;
289296
output += methods;
290297
// eslint-disable-next-line no-useless-escape
291-
if (this.exportAsTypescript === 'on') {
298+
if (this.exportAsTypescript === "on") {
292299
output += "});\n<\/script>";
293300
} else {
294301
output += "};\n<\/script>";
@@ -509,4 +516,6 @@ export default {
509516
text-transform: capitalize;
510517
padding: 3px 8px;
511518
}
519+
520+
512521
</style>

src/components/file_system_interface/OpenProjectComponent.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ Description:
55
-->
66

77
<template>
8-
<q-btn
9-
class="export-btn"
10-
color="secondary"
11-
label="Import"
12-
@click="openProjectJSON"
13-
/>
8+
<q-btn class="export-btn" color="secondary" label="Import">
9+
<q-menu>
10+
<div class="settings-dropdown column items-center">
11+
<q-btn class="menu-btn" no-caps color="secondary" label="Import Project" @click="openProjectJSON"/>
12+
<q-btn class="menu-btn" no-caps color="secondary" label="Import Component" @click="exportProject"/>
13+
</div>
14+
</q-menu>
15+
16+
</q-btn>
1417
</template>
1518

1619
<script>

0 commit comments

Comments
 (0)