├── .gitignore
├── LICENSE
├── README.md
├── _data
└── demo.csv
├── babel.config.js
├── build
├── README_BUILD.md
├── icon.png
└── icon_src
│ ├── cat.png
│ └── icon.xcf
├── changelog.md
├── demo.gif
├── notes.md
├── package-lock.json
├── package.json
├── public
└── index.html
├── screenshot.png
├── src
├── main
│ ├── background.js
│ └── menus
│ │ ├── _darwin.js
│ │ ├── _file.js
│ │ ├── _info.js
│ │ ├── _view.js
│ │ └── menu.js
├── renderer
│ ├── App.vue
│ ├── assets
│ │ ├── angle-right.svg
│ │ ├── cat.jpg
│ │ ├── cat.png
│ │ ├── file-download.svg
│ │ ├── file-import-light.svg
│ │ ├── file-import.svg
│ │ ├── file-plus.svg
│ │ ├── info-circle.svg
│ │ ├── logo.png
│ │ ├── long-arrow-right.svg
│ │ ├── plus-circle.svg
│ │ ├── plus-square.svg
│ │ ├── plus.svg
│ │ ├── redo-alt.svg
│ │ ├── redo.svg
│ │ └── tasks.svg
│ ├── components
│ │ ├── Form
│ │ │ ├── TheFileSelector.vue
│ │ │ ├── TheFileSelectorModal.vue
│ │ │ ├── TheForm.vue
│ │ │ ├── TheHeadersSelector.vue
│ │ │ ├── TheOutput.vue
│ │ │ └── TheResetBtn.vue
│ │ ├── TheFooter.vue
│ │ ├── TheHeader.vue
│ │ └── TheProgressBar.vue
│ └── main.js
└── shared
│ └── fileHelper.js
└── vue.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | *.env
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw*
23 |
24 | #Electron-builder output
25 | /dist_electron
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Brian Zelip
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # concats
2 |
3 | Cross platform desktop app for outputting a single-column csv file of rows of concatenated fields from an input delimiter-separated values file.
4 |
5 | Accepts .csv, .tsv, and extension-less files (_data.csv_, _data.tsv_, _data_) as input.
6 |
7 | 
8 |
9 | ## Download
10 |
11 | v1.13.3
12 |
13 | - [macOS](https://github.com/brianzelip/concats/releases/download/v1.13.13/concats-1.13.13.dmg) (46.9 MB)
14 | - [Windows](https://github.com/brianzelip/concats/releases/download/v1.13.13/concats.Setup.1.13.13.exe) (34.8 MB)
15 |
16 | ## Made with
17 |
18 | - [electron](https://github.com/electron/electron)
19 | - [vue](https://github.com/vuejs/vue)
20 | - [vue-cli-plugin-electron-builder](https://github.com/nklayman/vue-cli-plugin-electron-builder)
21 |
22 | ## Development
23 |
24 | To run concats locally (_requires [Node.js](https://nodejs.org) v8.9 or above_):
25 |
26 | ```bash
27 |
28 | git clone git@github.com/brianzelip/concats.git
29 |
30 | cd concats
31 |
32 | npm install
33 |
34 | npm run electron:serve
35 |
36 | ```
37 |
38 | ## Build binaries
39 |
40 | To build the executable binary for `$PLATFORM`, you must have [Node.js](https://nodejs.org) v8.9 or above on `$PLATFORM`, and run:
41 |
42 | ```bash
43 | git clone git@github.com/brianzelip/concats.git
44 |
45 | cd concats
46 |
47 | npm install
48 |
49 | npm run electron:build
50 | ```
51 |
--------------------------------------------------------------------------------
/_data/demo.csv:
--------------------------------------------------------------------------------
1 | "Date","Meeting ID","Group Name","Meeting Rep Name","Meeting Rep Phone"
2 | "1/6/2019","102","BBB","Rob","5559387654"
3 | "1/13/2019","102","CYE","Tara","9876554321"
4 | "1/20/2019","102","UYT","Glen","3437654652"
5 | "1/27/2019","102","OEK","Jeff","4542445652"
6 | "1/6/2019","103","WWB","Paul","3159396652"
7 | "1/13/2019","103","KNR","Lottie","6925914652"
8 | "1/20/2019","103","PLL","Patti","3987074652"
9 | "1/27/2019","103","MWW","Dominic","4317981652"
10 | "1/13/2019","104","QPD","Sonya","7158055652"
11 | "1/13/2019","101","IOA","Hara","7158055652"
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/build/README_BUILD.md:
--------------------------------------------------------------------------------
1 | # README for build/
2 |
3 | This directory exists solely for generating an app icon (under _most_ scenarios), as suggested via the [electron-builder docs](https://www.electron.build/icons#macos).
4 |
5 | See ./icon_src/ for the native GIMP logo file.
6 |
--------------------------------------------------------------------------------
/build/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/build/icon.png
--------------------------------------------------------------------------------
/build/icon_src/cat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/build/icon_src/cat.png
--------------------------------------------------------------------------------
/build/icon_src/icon.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/build/icon_src/icon.xcf
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # changelog
2 |
3 | _started as of v1.4.0, on the concats feature branch_
4 |
5 | ## `components` branch, starting at v1.4.0
6 |
7 | Breaking up into components means whittling away at `TheInput.vue`.
8 |
9 | This branch impacted the development experience, not the app user experience.
10 |
11 | Basically, this feature branch work turned this directory structure:
12 |
13 | ```
14 | src/components
15 | ├── global
16 | │ └── TheHeader.vue
17 | ├── Input
18 | │ └── TheInput.vue
19 | └── Output
20 | └── TheOutput.vue
21 | ```
22 |
23 | into this:
24 |
25 | ```
26 | src/components
27 | ├── Form
28 | │ ├── TheControls.vue
29 | │ ├── TheFileSelector.vue
30 | │ ├── TheForm.vue
31 | │ ├── TheHeadersSelection.vue
32 | │ ├── TheHeadersSelector.vue
33 | │ └── TheOutput.vue
34 | ├── TheFooter.vue
35 | └── TheHeader.vue
36 | ```
37 |
38 | This feature branch created the minor bump to v1.5.0.
39 |
40 | ## `app-steps-transitions` branch, starting at v1.5.0
41 |
42 | Design the app's user steps so that, instead of scrolling down the page as steps are completed, each completed step transitions away to make room for the next step. So in this scenario, there is no scrolling beyond the size of the app window.
43 |
44 | ## `redesign` branch, starting at v1.6.2
45 |
46 | - replace header with thin icon progress bar showing the app workflow steps in total and which step the user is currently on
47 | - add reset button to this progress bar area
48 | - reconsider metadata from header and footer, make it all available via OS native menus, NOT via app UI
49 | - expand the drop zone, and the click area for user to select input file
50 | - make app ui more minimal centered around app workflow
51 |
52 | ## `app-metdata` feature branch, starting at v1.7.0
53 |
54 | - removes footer
55 | - adds completed metadata fields in package.json
56 |
57 | ## `menus` feature branch, starting at v1.7.4
58 |
59 | - implements native OS menu system, including:
60 | - darwin menu if on darwin build
61 | - file
62 | - view
63 | - info - including an external link to app source repo and About concats pop up dialog on windows builds
64 | - new app icon
65 | - I read through the source code for Hyper by Zeit, and used their module approach to the menu organization
66 |
67 | ## `progress-bar-ui` feature branch, starting at v1.8.4
68 |
69 | - adds step number underneath each step icon in progress bar via ::after psuedo element, opacity, and props on div wrapper around each svg
70 |
71 | ## `input-file-type` feature branch, starting at v1.9.1
72 |
73 | - shows temporary modal when invalid file types are dropped onto TheFileSelector dropzone
74 | - adds helpful text about valid file types to TheFileSelector
75 | - here's [the !SO answer](https://stackoverflow.com/a/48481398/2145103) that helped me achieve the temporary modal solution by using the mounted() hook in the modal component to implement the `setTimeout()`
76 |
77 | ## `progress-svg-opacity` feature branch, starting at v1.10.0
78 |
79 | - change the opacity transition of the angle arrows in the progress bar to point the user to the next step
80 | - gets rid of all `.iscomplete` classes in favor of `.iscurrent`
81 |
82 | ## `maintenance` feature branch, starting at v1.11.0
83 |
84 | - refactor src/\* into main/ and renderer/
85 | - add README to build/
86 |
87 | ## `allow-plain-text` feature branch, starting at v1.12.0
88 |
89 | - allow user to input an extension-less file or a csv/tsv file
90 | - introduces a directory of shared modules between `src/main/` and `src/renderer/`
91 |
92 | ## `progress-bar-update` feature branch, starting at v1.13.1
93 |
94 | - shows progress bar step numbers by default, and only the current step in bold
95 | - makes LICENSE current
96 | - cleans up readme
97 |
98 | ## `demo` feature branch, starting at v1.13.5
99 |
100 | - create animated gif from screenshot video of using concats
101 | - updates README with demo
102 | - cleans up README to close some issues
103 |
104 | ## [1.13.11] - 2019-05-30
105 |
106 | - starting point: v1.13.10
107 | - ending point: v1.13.11
108 | - branch name: security
109 |
110 | - steps:
111 | - run `npm audit fix`
112 | - install 1/2 peer dependencies (see 26ec9498d4 commit message)
113 |
114 | ## [1.13.12] - 2019-07-27
115 |
116 | - starting point: v1.13.11
117 | - ending point: v1.13.12
118 | - branch name: sec2019-07-27
119 |
120 | - steps:
121 | - run `npm audit fix`
122 | - install earlier version of ajv module as peer dependency via npm warning
123 |
124 | ## [1.13.13] - 2019-08-16
125 |
126 | ### Meta
127 |
128 | - branch: gh-release
129 | - description: I want to make use of GitHub's "release" feature to include of build binary files for mac and windows concats apps. See https://help.github.com/en/articles/creating-releases
130 |
131 | ### Updated
132 |
133 | - public/index.html: Remove favicon.ico import
134 |
135 | ### Deleted
136 |
137 | - public/favicon.ico
138 |
139 | ## [1.13.14] - 2020-01-25
140 |
141 | - branch: vuln-patch
142 | - description: Run `npm audit fix` to fix vulnerabilities
143 |
144 | ### Updated
145 |
146 | - package-lock.json
147 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/demo.gif
--------------------------------------------------------------------------------
/notes.md:
--------------------------------------------------------------------------------
1 | ## User workflow:
2 |
3 | 1. Select file
4 | 2. Select headers
5 | 3. Output
6 | 4. Reset
7 |
8 | ## Components
9 |
10 | - Input
11 | - FileSelector
12 | - HeadersSelector
13 | - Submit
14 | - Reset
15 | - Output
16 | - Output
17 |
18 | ## Menu
19 |
20 | what fundamental app behaviors should be available in the menus?
21 |
22 | - load file
23 | - reset app
24 | - view dev tools
25 | - get info about the app
26 |
27 | The following are behavior of secondary importance:
28 |
29 | - view full screen
30 | - maximize
31 | - minimize
32 | - close
33 | - all the apple-specific stuff like, hide, hide others, etc.
34 | -
35 |
36 | There could be:
37 |
38 | - preferences, whereby the user sets default input and output directories
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "concats",
3 | "description": "Output a single-column csv file containing rows of concatenated fields from an input delimiter-separated values file. Desktop app built using Electron.js and Vue.js.",
4 | "version": "1.13.14",
5 | "private": false,
6 | "author": {
7 | "name": "Brian Zelip"
8 | },
9 | "license": "MIT",
10 | "homepage": "https://github.com/brianzelip/concats",
11 | "repository": "https://github.com/brianzelip/concats",
12 | "scripts": {
13 | "serve": "vue-cli-service serve",
14 | "build": "vue-cli-service build",
15 | "lint": "vue-cli-service lint",
16 | "electron:build": "vue-cli-service electron:build",
17 | "electron:serve": "vue-cli-service electron:serve",
18 | "postinstall": "electron-builder install-app-deps"
19 | },
20 | "dependencies": {
21 | "ajv": "^5.5.2",
22 | "csvtojson": "^2.0.8",
23 | "vue": "^2.5.21"
24 | },
25 | "devDependencies": {
26 | "@vue/cli-plugin-babel": "^3.2.0",
27 | "@vue/cli-plugin-eslint": "^3.2.0",
28 | "@vue/cli-service": "^3.8.0",
29 | "babel-eslint": "^10.0.1",
30 | "electron": "^2.0.0",
31 | "eslint": "^5.8.0",
32 | "eslint-plugin-vue": "^5.0.0-0",
33 | "vue-cli-plugin-electron-builder": "^1.3.4",
34 | "vue-svg-loader": "^0.11.0",
35 | "vue-template-compiler": "^2.5.21"
36 | },
37 | "eslintConfig": {
38 | "root": true,
39 | "env": {
40 | "node": true
41 | },
42 | "extends": [
43 | "plugin:vue/essential",
44 | "eslint:recommended"
45 | ],
46 | "rules": {},
47 | "parserOptions": {
48 | "parser": "babel-eslint"
49 | }
50 | },
51 | "postcss": {
52 | "plugins": {
53 | "autoprefixer": {}
54 | }
55 | },
56 | "browserslist": [
57 | "> 1%",
58 | "last 2 versions",
59 | "not ie <= 8"
60 | ],
61 | "main": "background.js"
62 | }
63 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | concats
8 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/screenshot.png
--------------------------------------------------------------------------------
/src/main/background.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { app, protocol, BrowserWindow, Menu } from 'electron';
4 | import {
5 | createProtocol,
6 | installVueDevtools
7 | } from 'vue-cli-plugin-electron-builder/lib';
8 |
9 | import appMenu from './menus/menu.js';
10 |
11 | const isDevelopment = process.env.NODE_ENV !== 'production';
12 |
13 | // Keep a global reference of the window object, if you don't, the window will
14 | // be closed automatically when the JavaScript object is garbage collected.
15 | let win;
16 |
17 | // Standard scheme must be registered before the app is ready
18 | protocol.registerStandardSchemes(['app'], { secure: true });
19 | function createWindow() {
20 | // Create the browser window.
21 | win = new BrowserWindow({
22 | width: 1000,
23 | height: 800,
24 | show: false
25 | });
26 |
27 | // show window gracefully
28 | // via https://electronjs.org/docs/api/browser-window#showing-window-gracefully
29 | win.once('ready-to-show', () => {
30 | win.show();
31 | });
32 |
33 | if (isDevelopment || process.env.IS_TEST) {
34 | // Load the url of the dev server if in development mode
35 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
36 | if (!process.env.IS_TEST) win.webContents.openDevTools();
37 | } else {
38 | createProtocol('app');
39 | // Load the index.html when not in development
40 | win.loadURL('app://./index.html');
41 | }
42 |
43 | win.on('closed', () => {
44 | win = null;
45 | });
46 | }
47 |
48 | // Quit when all windows are closed.
49 | app.on('window-all-closed', () => {
50 | // On macOS it is common for applications and their menu bar
51 | // to stay active until the user quits explicitly with Cmd + Q
52 | if (process.platform !== 'darwin') {
53 | app.quit();
54 | }
55 | });
56 |
57 | app.on('activate', () => {
58 | // On macOS it's common to re-create a window in the app when the
59 | // dock icon is clicked and there are no other windows open.
60 | if (win === null) {
61 | createWindow();
62 | }
63 | });
64 |
65 | // This method will be called when Electron has finished
66 | // initialization and is ready to create browser windows.
67 | // Some APIs can only be used after this event occurs.
68 | app.on('ready', async () => {
69 | if (isDevelopment && !process.env.IS_TEST) {
70 | // Install Vue Devtools
71 | await installVueDevtools();
72 | }
73 | createWindow();
74 | Menu.setApplicationMenu(appMenu(win));
75 | });
76 |
77 | // Exit cleanly on request from parent process in development mode.
78 | if (isDevelopment) {
79 | if (process.platform === 'win32') {
80 | process.on('message', data => {
81 | if (data === 'graceful-exit') {
82 | app.quit();
83 | }
84 | });
85 | } else {
86 | process.on('SIGTERM', () => {
87 | app.quit();
88 | });
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/menus/_darwin.js:
--------------------------------------------------------------------------------
1 | import { app } from 'electron';
2 |
3 | export default showAbout => {
4 | return {
5 | label: app.getName(),
6 | submenu: [
7 | {
8 | label: 'About concats',
9 | click() {
10 | showAbout();
11 | }
12 | },
13 | { type: 'separator' },
14 | { role: 'services' },
15 | { type: 'separator' },
16 | { role: 'hide' },
17 | { role: 'hideothers' },
18 | { role: 'unhide' },
19 | { type: 'separator' },
20 | { role: 'quit' }
21 | ]
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/src/main/menus/_file.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 |
3 | import { dialog } from 'electron';
4 |
5 | import { fCheck, openDialogOptions } from '../../shared/fileHelper.js';
6 |
7 | export default function(BrowserWindow) {
8 | const fileMenu = {
9 | label: 'File',
10 | submenu: [
11 | {
12 | label: 'Open',
13 | accelerator: 'CmdOrCtrl+O',
14 | click() {
15 | dialog.showOpenDialog(openDialogOptions, filePaths => {
16 | if (filePaths != undefined) {
17 | fCheck.fileIsValid(filePaths[0])
18 | ? fs.readFile(filePaths[0], 'utf-8', function(
19 | err,
20 | fileAsString
21 | ) {
22 | if (err) {
23 | throw err;
24 | }
25 | BrowserWindow.webContents.send('file-input', fileAsString);
26 | })
27 | : console.log(fCheck.errorMsg(filePaths[0]));
28 | }
29 | });
30 | }
31 | },
32 | {
33 | label: 'Reset',
34 | click() {
35 | BrowserWindow.webContents.send('reset-app');
36 | },
37 | accelerator: 'CmdOrCtrl+R'
38 | }
39 | ]
40 | };
41 |
42 | if (process.platform !== 'darwin') {
43 | fileMenu.submenu.push(
44 | { type: 'separator' },
45 | { role: 'quit', accelerator: 'Ctrl+Q' }
46 | );
47 | }
48 |
49 | return fileMenu;
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/menus/_info.js:
--------------------------------------------------------------------------------
1 | import { app, shell } from 'electron';
2 |
3 | import { homepage } from '../../../package.json';
4 |
5 | export default showAbout => {
6 | const submenu = [
7 | {
8 | label: 'Go to concats homepage →',
9 | click() {
10 | shell.openExternal(homepage);
11 | }
12 | }
13 | ];
14 |
15 | if (process.platform !== 'darwin') {
16 | submenu.unshift({
17 | label: `About ${app.getName()}`,
18 | click() {
19 | showAbout();
20 | }
21 | });
22 | }
23 |
24 | return {
25 | label: 'Info',
26 | submenu
27 | };
28 | };
29 |
--------------------------------------------------------------------------------
/src/main/menus/_view.js:
--------------------------------------------------------------------------------
1 | export default () => {
2 | return {
3 | label: 'View',
4 | submenu: [{ role: 'toggledevtools' }, { role: 'togglefullscreen' }]
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/src/main/menus/menu.js:
--------------------------------------------------------------------------------
1 | import { app, Menu, dialog } from 'electron';
2 |
3 | import fileMenu from './_file';
4 | import viewMenu from './_view';
5 | import infoMenu from './_info';
6 | import darwinMenu from './_darwin';
7 |
8 | export default BrowserWindow => {
9 | const currentYear = new Date().getFullYear();
10 |
11 | const showAbout = () => {
12 | dialog.showMessageBox({
13 | type: 'info',
14 | title: `About ${app.getName()}`,
15 | message: `${app.getName()} v${app.getVersion()}`,
16 | detail: `Made with Electron.js and Vue.js.\nSee the Info menu for a link to the source code.\n\nCopyright © 2018-${currentYear} Brian Zelip`,
17 | buttons: []
18 | });
19 | };
20 |
21 | const template = [
22 | ...(process.platform === 'darwin' ? [darwinMenu(showAbout)] : []),
23 | fileMenu(BrowserWindow),
24 | viewMenu(),
25 | infoMenu(showAbout)
26 | ];
27 |
28 | return Menu.buildFromTemplate(template);
29 | };
30 |
--------------------------------------------------------------------------------
/src/renderer/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
17 |
18 |
51 |
52 |
70 |
--------------------------------------------------------------------------------
/src/renderer/assets/angle-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/src/renderer/assets/cat.jpg
--------------------------------------------------------------------------------
/src/renderer/assets/cat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/src/renderer/assets/cat.png
--------------------------------------------------------------------------------
/src/renderer/assets/file-download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/file-import-light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/file-import.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/file-plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/info-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brianzelip/concats/d762a4694274048f3c7dd9ad162018521f02c58e/src/renderer/assets/logo.png
--------------------------------------------------------------------------------
/src/renderer/assets/long-arrow-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/plus-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/plus-square.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/redo-alt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/redo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/assets/tasks.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheFileSelector.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
click to select a data file
15 |
19 |
or drag and drop a file
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
72 |
73 |
120 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheFileSelectorModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
27 |
28 |
58 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
160 |
161 |
180 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheHeadersSelector.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
35 |
36 |
63 |
64 |
144 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheOutput.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Preview of output:
4 | {{ csvOutput }}
5 |
6 |
7 |
8 |
13 |
14 |
23 |
24 |
--------------------------------------------------------------------------------
/src/renderer/components/Form/TheResetBtn.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
69 |
70 |
--------------------------------------------------------------------------------
/src/renderer/components/TheFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
35 |
36 |
45 |
--------------------------------------------------------------------------------
/src/renderer/components/TheHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/src/renderer/components/TheProgressBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
16 |
20 |
24 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
41 |
68 |
69 |
124 |
--------------------------------------------------------------------------------
/src/renderer/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 |
4 | Vue.config.productionTip = false;
5 |
6 | new Vue({
7 | render: h => h(App)
8 | }).$mount('#app');
9 |
--------------------------------------------------------------------------------
/src/shared/fileHelper.js:
--------------------------------------------------------------------------------
1 | const fCheck = {
2 | fileIsValid(file) {
3 | // analyze file extension approach via https://stackoverflow.com/a/22864057/2145103
4 | function hasExtension(file) {
5 | return (
6 | file
7 | .split('/')
8 | .pop()
9 | .split('.').length > 1
10 | );
11 | }
12 | function getExtension(file) {
13 | return file
14 | .split('/')
15 | .pop()
16 | .split('.')
17 | .pop();
18 | }
19 | function isExtensionWeLike(ext) {
20 | return ext === 'csv' || ext === 'tsv';
21 | }
22 | return (hasExtension(file) && isExtensionWeLike(getExtension(file))) ||
23 | !hasExtension(file)
24 | ? true
25 | : false;
26 | },
27 | errorMsg(fileName) {
28 | return `File selected had wrong extension (${fileName}); please select a csv/tsv file or a data file with no extension.`;
29 | }
30 | };
31 |
32 | const openDialogOptions = {
33 | title: 'Select a data file',
34 | properties: ['openFile']
35 | };
36 |
37 | export { fCheck, openDialogOptions };
38 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | chainWebpack: config => {
3 | // svgRule code via
4 | // https://cli.vuejs.org/guide/webpack.html#replacing-loaders-of-a-rule
5 | const svgRule = config.module.rule('svg');
6 |
7 | // clear all existing loaders.
8 | // if you don't do this, the loader below will be appended to
9 | // existing loaders of the rule.
10 | svgRule.uses.clear();
11 |
12 | // add replacement loader(s)
13 | svgRule.use('vue-svg-loader').loader('vue-svg-loader');
14 |
15 | // change webpack entry point from src/main.js
16 | // code via https://stackoverflow.com/a/52773981/2145103
17 | // ...figured it out after a bit of trials and trib,
18 | // ...plus `vue inspect` on the cli
19 |
20 | // clear the existing entry point
21 | config.entry('app').clear();
22 | // add your custom entry point
23 | config.entry('app').add('./src/renderer/main.js');
24 | },
25 | pluginOptions: {
26 | electronBuilder: {
27 | mainProcessFile: './src/main/background.js'
28 | }
29 | }
30 | };
31 |
--------------------------------------------------------------------------------