diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1076a1f0f..102369529 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -182,8 +182,8 @@ jobs:
echo "${{ env.pythonLocation }}/bin" >> $GITHUB_PATH
- shell: bash
run: |
- # disable electron-builder signing
- #export CSC_IDENTITY_AUTO_DISCOVERY=false
+ # disable electron-builder signing and make dist
+ export CSC_IDENTITY_AUTO_DISCOVERY=false
make dist
env:
BUILD: osx
diff --git a/.gitignore b/.gitignore
index e60a6aa95..a1d4a5e9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,5 @@ locales/
/profile_stats.prof
/.vscode
__pycache__
+flaskserverport.json
+electron/yarn.lock
diff --git a/Makefile b/Makefile
index 64d6bed84..c4e214104 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,19 @@
+# used for distlocal
+OS=$(shell uname)
+
dist: version locales inx
+ python bin/generate-flaskserverport-file
bash bin/build-python
bash bin/build-electron
bash bin/build-distribution-archives
distclean:
- rm -rf build dist inx locales artifacts win mac *.spec *.tar.gz *.zip electron/node_modules electron/dist
+ rm -rf build dist inx locales artifacts win mac *.spec *.tar.gz *.zip electron/node_modules electron/dist electron/build/mac electron/build/mac-arm64 electron/build/win-ia32-unpacked electron/build/linux-unpacked electron/build/linux-arm64-unpacked electron/src/lib/flaskserverport.json
+
+distlocal:
+ @case ${OS} in "Darwin") export BUILD=osx ;; "Linux")export BUILD=linux ;; *) export BUILD=windows ;; esac; export VERSION=local-build; make distclean && make dist;
+manual:
+ make inx && cd electron && yarn install && cd ..
.PHONY: inx
inx: version locales
diff --git a/bin/build-distribution-archives b/bin/build-distribution-archives
index a79ad6416..b44cad463 100644
--- a/bin/build-distribution-archives
+++ b/bin/build-distribution-archives
@@ -1,4 +1,4 @@
-VERSION="$(echo ${GITHUB_REF} | sed -e 's|refs/heads/||' -e 's|refs/tags/||' -e 's|/|-|g')"
+VERSION="${VERSION:-$(echo ${GITHUB_REF} | sed -e 's|refs/heads/||' -e 's|refs/tags/||' -e 's|/|-|g')}"
OS="${BUILD:-$(uname)}"
ARCH="$(uname -m)"
mkdir artifacts
@@ -6,7 +6,7 @@ mkdir artifacts
if [ "$BUILD" = "osx" ]; then
cp -a icons locales print LICENSE VERSION images/examples palettes symbols fonts tiles dbus inx dist/inkstitch.app/Contents/Resources
# adding version to Info.plist
- sed -i '' 's/0.0.0/'${VERSION}'/' dist/inkstitch.app/Contents/Info.plist
+ plutil -replace CFBundleShortVersionString -string ${VERSION} dist/inkstitch.app/Contents/Info.plist
rm -rf dist/inkstitch/
# Install location for pkgbuild
PKG_INSTALL_PATH="/tmp/inkstitch/"
diff --git a/bin/build-electron b/bin/build-electron
index b0e935728..cdc98f9d3 100755
--- a/bin/build-electron
+++ b/bin/build-electron
@@ -2,15 +2,6 @@
set -e
set -x
-ARCH="$(uname -m)"
-# Check for cpu arch to build mac and linux electron arch
-if [[ "$ARCH" = "arm64" ]] || [[ "$ARCH" = "aarch64" ]]; then
- echo "Found ARM"
- sed -i'' -e 's/CPU_ARCH/'arm64'/' electron/package.json
-else
- echo "Found x64"
- sed -i'' -e 's/CPU_ARCH/'x64'/' electron/package.json
-fi
if [ "$BUILD" = "windows" ]; then
args="-w --ia32"
diff --git a/bin/build-python b/bin/build-python
index 92e1802ad..b8dd61ba9 100755
--- a/bin/build-python
+++ b/bin/build-python
@@ -2,26 +2,6 @@
set -e
info_year=$( date "+%Y" )
-site_packages="$(python -c "import os; print(os.path.dirname(os.__file__) + '/site-packages')")"
-arch=$(uname -m)
-if [ "$BUILD" = "linux" ]; then
- pyinstaller_args+="--add-binary /usr/lib/"$arch"-linux-gnu/gio/modules/libgiolibproxy.so:. "
- pyinstaller_args+="--add-binary /usr/lib/"$arch"-linux-gnu/libproxy.so.1:. "
- pyinstaller_args+="--add-binary /lib/"$arch"-linux-gnu/libnsl.so.1:. "
- pyinstaller_args+="--add-binary /usr/lib/"$arch"-linux-gnu/libxcb.so.1:. "
-fi
-
-# This one's tricky. ink/stitch doesn't actually _use_ gi.repository.Gtk,
-# but it does use GTK (through wxPython). pyinstaller has some special
-# logic to handle GTK apps that is engaged when you import
-# gi.repository.Gtk that pulls in things like themes, icons, etc. Without
-# that, the Params dialog is unthemed and barely usable. This hidden
-# import option is actually the only reason we had to install python-gi
-# above!
-pyinstaller_args+="--hidden-import gi.repository.Gtk "
-
-# mac and windows build seem to miss wx import
-pyinstaller_args+="--hidden-import wx "
# We need to use the precompiled bootloader linked with graphical Mac OS X
# libraries if we develop a GUI application for Mac:
@@ -29,9 +9,6 @@ if [ "$BUILD" = "osx" -o "$BUILD" = "windows" ]; then
pyinstaller_args+="--windowed "
fi
-# This lets pyinstaller see inkex.py, etc.
-pyinstaller_args+="-p inkscape/share/extensions "
-
# output useful debugging info that helps us trace library dependency issues
pyinstaller_args+="--log-level DEBUG "
@@ -67,7 +44,7 @@ if [ "$BUILD" = "windows" ]; then
pyinstaller_args+="--version-file installer_scripts/file_version_info.txt "
python -m PyInstaller $pyinstaller_args inkstitch.py
else
- LD_LIBRARY_PATH="${site_packages}/wx" python -m PyInstaller $pyinstaller_args --strip inkstitch.py;
+ python -m PyInstaller $pyinstaller_args --strip inkstitch.py;
fi
# pyinstaller put a whole mess of libraries under dist/inkstitch. We'd like
diff --git a/bin/build-windows-installer b/bin/build-windows-installer
old mode 100644
new mode 100755
index a2d421ce5..90f72d711
--- a/bin/build-windows-installer
+++ b/bin/build-windows-installer
@@ -1,5 +1,5 @@
#!/bin/bash
-VERSION="$(echo ${GITHUB_REF} | sed -e 's|refs/heads/||' -e 's|refs/tags/||' -e 's|/|-|g')"
+VERSION="${VERSION:-$(echo ${GITHUB_REF} | sed -e 's|refs/heads/||' -e 's|refs/tags/||' -e 's|/|-|g')}"
OS="${BUILD:-$(uname)}"
# Create windows installer
mkdir win
diff --git a/bin/generate-flaskserverport-file b/bin/generate-flaskserverport-file
new file mode 100755
index 000000000..d13239e9a
--- /dev/null
+++ b/bin/generate-flaskserverport-file
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+import os
+from json import dump
+from os.path import dirname
+
+path = os.path.join(dirname(dirname(__file__)), 'electron', 'src', 'lib', 'flaskserverport.json')
+
+data = {"_comment1" : "port should not be declared when commiting"}
+# write data to font.json into the same directory as the font file
+with open(path, 'w', encoding="utf8") as output:
+ dump(data, output, indent=4, ensure_ascii=False)
diff --git a/bin/notarize-app b/bin/notarize-app
deleted file mode 100644
index 4a2bbc418..000000000
--- a/bin/notarize-app
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh -u
-# source of this code: https://github.com/rednoah/notarize-app
-ASC_PROVIDER="$1"
-ASC_USERNAME="$2"
-ASC_PASSWORD="$3"
-
-BUNDLE_ID="$4"
-BUNDLE_PKG="$5"
-
-
-# create temporary files
-NOTARIZE_APP_LOG=$(mktemp -t notarize-app)
-NOTARIZE_INFO_LOG=$(mktemp -t notarize-info)
-
-# delete temporary files on exit
-function finish {
- rm "$NOTARIZE_APP_LOG" "$NOTARIZE_INFO_LOG"
-}
-trap finish EXIT
-
-
-# submit app for notarization
-if xcrun altool --notarize-app --primary-bundle-id "$BUNDLE_ID" --asc-provider "$ASC_PROVIDER" --username "$ASC_USERNAME" --password "$ASC_PASSWORD" -f "$BUNDLE_PKG" > "$NOTARIZE_APP_LOG" 2>&1; then
- cat "$NOTARIZE_APP_LOG"
- RequestUUID=$(awk -F ' = ' '/RequestUUID/ {print $2}' "$NOTARIZE_APP_LOG")
-
- # check status periodically
- while sleep 60 && date; do
- # check notarization status
- if xcrun altool --notarization-info "$RequestUUID" --asc-provider "$ASC_PROVIDER" --username "$ASC_USERNAME" --password "$ASC_PASSWORD" > "$NOTARIZE_INFO_LOG" 2>&1; then
- cat "$NOTARIZE_INFO_LOG"
-
- # once notarization is complete, run stapler and exit
- if ! grep -q "Status: in progress" "$NOTARIZE_INFO_LOG"; then
- xcrun stapler staple "$BUNDLE_PKG"
- exit $?
- fi
- else
- cat "$NOTARIZE_INFO_LOG" 1>&2
- exit 1
- fi
- done
-else
- cat "$NOTARIZE_APP_LOG" 1>&2
- exit 1
-fi
diff --git a/electron/.babelrc b/electron/.babelrc
deleted file mode 100644
index b10dbaf10..000000000
--- a/electron/.babelrc
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "comments": false,
- "env": {
- "main": {
- "presets": [
- ["env", {
- "targets": { "node": 7 }
- }],
- "stage-0"
- ]
- },
- "renderer": {
- "presets": [
- ["env", {
- "modules": false
- }],
- "stage-0"
- ]
- },
- "web": {
- "presets": [
- ["env", {
- "modules": false
- }],
- "stage-0"
- ]
- }
- },
- "plugins": ["transform-runtime"]
-}
diff --git a/electron/.browserslistrc b/electron/.browserslistrc
new file mode 100644
index 000000000..b62a035bf
--- /dev/null
+++ b/electron/.browserslistrc
@@ -0,0 +1,4 @@
+# https://github.com/browserslist/browserslist#queries
+> 1%
+last 2 versions
+not dead
diff --git a/electron/.compilerc b/electron/.compilerc
deleted file mode 100644
index 7bfc1b6c3..000000000
--- a/electron/.compilerc
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "env": {
- "development": {
- "application/javascript": {
- "presets": [
- [
- "env",
- {
- "targets": {
- "electron": "4.0"
- }
- }
- ],
- "react"
- ],
- "plugins": [
- "transform-async-to-generator"
- ],
- "sourceMaps": "inline"
- }
- },
- "production": {
- "application/javascript": {
- "presets": [
- [
- "env",
- {
- "targets": {
- "electron": "4.0"
- }
- }
- ],
- "react"
- ],
- "plugins": [
- "transform-async-to-generator"
- ],
- "sourceMaps": "none"
- }
- }
- }
-}
diff --git a/electron/.electron-vue/build.js b/electron/.electron-vue/build.js
deleted file mode 100644
index 2455fbcb2..000000000
--- a/electron/.electron-vue/build.js
+++ /dev/null
@@ -1,132 +0,0 @@
-'use strict'
-
-process.env.NODE_ENV = 'production'
-
-const { say } = require('cfonts')
-const chalk = require('chalk')
-const del = require('del')
-const { spawn } = require('child_process')
-const webpack = require('webpack')
-const Multispinner = require('multispinner')
-
-
-const mainConfig = require('./webpack.main.config')
-const rendererConfig = require('./webpack.renderer.config')
-const webConfig = require('./webpack.web.config')
-
-const doneLog = chalk.bgGreen.white(' DONE ') + ' '
-const errorLog = chalk.bgRed.white(' ERROR ') + ' '
-const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
-const isCI = process.env.CI || false
-
-if (process.env.BUILD_TARGET === 'clean') clean()
-else if (process.env.BUILD_TARGET === 'web') web()
-else build()
-
-function clean () {
- del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
- console.log(`\n${doneLog}\n`)
- process.exit()
-}
-
-function build () {
- greeting()
-
- del.sync(['dist/electron/*', '!.gitkeep'])
-
- const tasks = ['main', 'renderer']
- const m = new Multispinner(tasks, {
- preText: 'building',
- postText: 'process'
- })
-
- let results = ''
-
- m.on('success', () => {
- process.stdout.write('\x1B[2J\x1B[0f')
- console.log(`\n\n${results}`)
- console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
- process.exit()
- })
-
- pack(mainConfig).then(result => {
- results += result + '\n\n'
- m.success('main')
- }).catch(err => {
- m.error('main')
- console.log(`\n ${errorLog}failed to build main process`)
- console.error(`\n${err}\n`)
- process.exit(1)
- })
-
- pack(rendererConfig).then(result => {
- results += result + '\n\n'
- m.success('renderer')
- }).catch(err => {
- m.error('renderer')
- console.log(`\n ${errorLog}failed to build renderer process`)
- console.error(`\n${err}\n`)
- process.exit(1)
- })
-}
-
-function pack (config) {
- return new Promise((resolve, reject) => {
- config.mode = 'production'
- webpack(config, (err, stats) => {
- if (err) reject(err.stack || err)
- else if (stats.hasErrors()) {
- let err = ''
-
- stats.toString({
- chunks: false,
- colors: true
- })
- .split(/\r?\n/)
- .forEach(line => {
- err += ` ${line}\n`
- })
-
- reject(err)
- } else {
- resolve(stats.toString({
- chunks: false,
- colors: true
- }))
- }
- })
- })
-}
-
-function web () {
- del.sync(['dist/web/*', '!.gitkeep'])
- webConfig.mode = 'production'
- webpack(webConfig, (err, stats) => {
- if (err || stats.hasErrors()) console.log(err)
-
- console.log(stats.toString({
- chunks: false,
- colors: true
- }))
-
- process.exit()
- })
-}
-
-function greeting () {
- const cols = process.stdout.columns
- let text = ''
-
- if (cols > 85) text = 'lets-build'
- else if (cols > 60) text = 'lets-|build'
- else text = false
-
- if (text && !isCI) {
- say(text, {
- colors: ['yellow'],
- font: 'simple3d',
- space: false
- })
- } else console.log(chalk.yellow.bold('\n lets-build'))
- console.log()
-}
\ No newline at end of file
diff --git a/electron/.electron-vue/dev-client.js b/electron/.electron-vue/dev-client.js
deleted file mode 100644
index 2913ea4b0..000000000
--- a/electron/.electron-vue/dev-client.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
-
-hotClient.subscribe(event => {
- /**
- * Reload browser when HTMLWebpackPlugin emits a new index.html
- *
- * Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
- * https://github.com/SimulatedGREG/electron-vue/issues/437
- * https://github.com/jantimon/html-webpack-plugin/issues/680
- */
- // if (event.action === 'reload') {
- // window.location.reload()
- // }
-
- /**
- * Notify `mainWindow` when `main` process is compiling,
- * giving notice for an expected reload of the `electron` process
- */
- if (event.action === 'compiling') {
- document.body.innerHTML += `
-
-
-
- Compiling Main Process...
-
- `
- }
-})
diff --git a/electron/.electron-vue/dev-runner.js b/electron/.electron-vue/dev-runner.js
deleted file mode 100644
index 181df4111..000000000
--- a/electron/.electron-vue/dev-runner.js
+++ /dev/null
@@ -1,192 +0,0 @@
-'use strict'
-
-const chalk = require('chalk')
-const electron = require('electron')
-const path = require('path')
-const { say } = require('cfonts')
-const { spawn } = require('child_process')
-const webpack = require('webpack')
-const WebpackDevServer = require('webpack-dev-server')
-const webpackHotMiddleware = require('webpack-hot-middleware')
-
-const mainConfig = require('./webpack.main.config')
-const rendererConfig = require('./webpack.renderer.config')
-
-let electronProcess = null
-let manualRestart = false
-let hotMiddleware
-
-function logStats (proc, data) {
- let log = ''
-
- log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
- log += '\n\n'
-
- if (typeof data === 'object') {
- data.toString({
- colors: true,
- chunks: false
- }).split(/\r?\n/).forEach(line => {
- log += ' ' + line + '\n'
- })
- } else {
- log += ` ${data}\n`
- }
-
- log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
-
- console.log(log)
-}
-
-function startRenderer () {
- return new Promise((resolve, reject) => {
- rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
- rendererConfig.mode = 'development'
- const compiler = webpack(rendererConfig)
- hotMiddleware = webpackHotMiddleware(compiler, {
- log: false,
- heartbeat: 2500
- })
-
- compiler.hooks.compilation.tap('compilation', compilation => {
- compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
- hotMiddleware.publish({ action: 'reload' })
- cb()
- })
- })
-
- compiler.hooks.done.tap('done', stats => {
- logStats('Renderer', stats)
- })
-
- const server = new WebpackDevServer(
- compiler,
- {
- contentBase: path.join(__dirname, '../'),
- quiet: true,
- before (app, ctx) {
- app.use(hotMiddleware)
- ctx.middleware.waitUntilValid(() => {
- resolve()
- })
- }
- }
- )
-
- server.listen(9080)
- })
-}
-
-function startMain () {
- return new Promise((resolve, reject) => {
- mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
- mainConfig.mode = 'development'
- const compiler = webpack(mainConfig)
-
- compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
- logStats('Main', chalk.white.bold('compiling...'))
- hotMiddleware.publish({ action: 'compiling' })
- done()
- })
-
- compiler.watch({}, (err, stats) => {
- if (err) {
- console.log(err)
- return
- }
-
- logStats('Main', stats)
-
- if (electronProcess && electronProcess.kill) {
- manualRestart = true
- process.kill(electronProcess.pid)
- electronProcess = null
- startElectron()
-
- setTimeout(() => {
- manualRestart = false
- }, 5000)
- }
-
- resolve()
- })
- })
-}
-
-function startElectron () {
- process.argv.shift();
- process.argv.shift();
- var args = [
- '--inspect=5858',
- path.join(__dirname, '../dist/electron/main.js')
- ].concat(process.argv)
-
- // detect yarn or npm and process commandline args accordingly
- if (process.env.npm_execpath.endsWith('yarn.js')) {
- args = args.concat(process.argv.slice(3))
- } else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
- args = args.concat(process.argv.slice(2))
- }
-
- electronProcess = spawn(electron, args)
-
- electronProcess.stdout.on('data', data => {
- electronLog(data, 'blue')
- })
- electronProcess.stderr.on('data', data => {
- electronLog(data, 'red')
- })
-
- electronProcess.on('close', () => {
- if (!manualRestart) process.exit()
- })
-}
-
-function electronLog (data, color) {
- let log = ''
- data = data.toString().split(/\r?\n/)
- data.forEach(line => {
- log += ` ${line}\n`
- })
- if (/[0-9A-z]+/.test(log)) {
- console.log(
- chalk[color].bold('┏ Electron -------------------') +
- '\n\n' +
- log +
- chalk[color].bold('┗ ----------------------------') +
- '\n'
- )
- }
-}
-
-function greeting () {
- const cols = process.stdout.columns
- let text = ''
-
- if (cols > 104) text = 'electron-vue'
- else if (cols > 76) text = 'electron-|vue'
- else text = false
-
- if (text) {
- say(text, {
- colors: ['yellow'],
- font: 'simple3d',
- space: false
- })
- } else console.log(chalk.yellow.bold('\n electron-vue'))
- console.log(chalk.blue(' getting ready...') + '\n')
-}
-
-function init () {
- greeting()
-
- Promise.all([startRenderer(), startMain()])
- .then(() => {
- startElectron()
- })
- .catch(err => {
- console.error(err)
- })
-}
-
-init()
diff --git a/electron/.electron-vue/webpack.main.config.js b/electron/.electron-vue/webpack.main.config.js
deleted file mode 100644
index cfdbdf22c..000000000
--- a/electron/.electron-vue/webpack.main.config.js
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict'
-
-process.env.BABEL_ENV = 'main'
-
-const path = require('path')
-const { dependencies } = require('../package.json')
-const webpack = require('webpack')
-
-const BabiliWebpackPlugin = require('babili-webpack-plugin')
-
-let mainConfig = {
- entry: {
- main: path.join(__dirname, '../src/main/index.js')
- },
- externals: [
- ...Object.keys(dependencies || {})
- ],
- module: {
- rules: [
- {
- test: /\.js$/,
- use: 'babel-loader',
- exclude: /node_modules/
- },
- {
- test: /\.node$/,
- use: 'node-loader'
- }
- ]
- },
- node: {
- __dirname: process.env.NODE_ENV !== 'production',
- __filename: process.env.NODE_ENV !== 'production'
- },
- output: {
- filename: '[name].js',
- libraryTarget: 'commonjs2',
- path: path.join(__dirname, '../dist/electron')
- },
- plugins: [
- new webpack.NoEmitOnErrorsPlugin()
- ],
- resolve: {
- extensions: ['.js', '.json', '.node']
- },
- target: 'electron-main'
-}
-
-/**
- * Adjust mainConfig for development settings
- */
-if (process.env.NODE_ENV !== 'production') {
- mainConfig.plugins.push(
- new webpack.DefinePlugin({
- '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
- })
- )
-}
-
-/**
- * Adjust mainConfig for production settings
- */
-if (process.env.NODE_ENV === 'production') {
- mainConfig.plugins.push(
- new BabiliWebpackPlugin(),
- new webpack.DefinePlugin({
- 'process.env.NODE_ENV': '"production"'
- })
- )
-}
-
-module.exports = mainConfig
diff --git a/electron/.electron-vue/webpack.renderer.config.js b/electron/.electron-vue/webpack.renderer.config.js
deleted file mode 100644
index 8a848141a..000000000
--- a/electron/.electron-vue/webpack.renderer.config.js
+++ /dev/null
@@ -1,202 +0,0 @@
-'use strict'
-
-process.env.BABEL_ENV = 'renderer'
-
-const path = require('path')
-const { dependencies } = require('../package.json')
-const webpack = require('webpack')
-
-const BabiliWebpackPlugin = require('babili-webpack-plugin')
-const CopyWebpackPlugin = require('copy-webpack-plugin')
-const MiniCssExtractPlugin = require('mini-css-extract-plugin')
-const HtmlWebpackPlugin = require('html-webpack-plugin')
-const { VueLoaderPlugin } = require('vue-loader')
-
-/**
- * List of node_modules to include in webpack bundle
- *
- * Required for specific packages like Vue UI libraries
- * that provide pure *.vue files that need compiling
- * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
- */
-// 'vue-slider-component' needed here due to this issue:
-// https://github.com/SimulatedGREG/electron-vue/issues/725
-let whiteListedModules = ['vue', 'vue-slider-component', 'vuetify']
-
-let rendererConfig = {
- devtool: '#cheap-module-eval-source-map',
- entry: {
- renderer: path.join(__dirname, '../src/renderer/main.js')
- },
- externals: [
- ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
- ],
- module: {
- rules: [
- {
- test: /\.less$/,
- use: ['vue-style-loader', 'css-loader', 'less-loader']
- },
- {
- test: /\.css$/,
- use: ['vue-style-loader', 'css-loader']
- },
- {
- test: /\.html$/,
- use: 'vue-html-loader'
- },
- {
- test: /\.js$/,
- use: 'babel-loader',
- exclude: /node_modules/
- },
- {
- test: /\.node$/,
- use: 'node-loader'
- },
- {
- test: /\.vue$/,
- use: {
- loader: 'vue-loader',
- options: {
- extractCSS: process.env.NODE_ENV === 'production',
- loaders: {
- sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
- scss: 'vue-style-loader!css-loader!sass-loader',
- less: 'vue-style-loader!css-loader!less-loader'
- }
- }
- }
- },
- {
- test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
- use: {
- loader: 'url-loader',
- query: {
- limit: 10000,
- name: 'imgs/[name]--[folder].[ext]'
- }
- }
- },
- {
- test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
- loader: 'url-loader',
- options: {
- limit: 10000,
- name: 'media/[name]--[folder].[ext]'
- }
- },
- {
- test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
- use: {
- loader: 'url-loader',
- query: {
- limit: 10000,
- name: 'fonts/[name]--[folder].[ext]'
- }
- }
- },
- {
- test: /\.s(c|a)ss$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- {
- loader: 'sass-loader',
- // Requires sass-loader@^8.0.0
- options: {
- implementation: require('sass'),
- sassOptions: {
- indentedSyntax: true // optional
- },
- },
- },
- ],
- }
- ]
- },
- node: {
- __dirname: process.env.NODE_ENV !== 'production',
- __filename: process.env.NODE_ENV !== 'production'
- },
- plugins: [
- new VueLoaderPlugin(),
- new MiniCssExtractPlugin({filename: 'styles.css'}),
- new HtmlWebpackPlugin({
- filename: 'index.html',
- template: path.resolve(__dirname, '../src/index.ejs'),
- templateParameters(compilation, assets, options) {
- return {
- compilation: compilation,
- webpack: compilation.getStats().toJson(),
- webpackConfig: compilation.options,
- htmlWebpackPlugin: {
- files: assets,
- options: options
- },
- process
- }
- },
- minify: {
- collapseWhitespace: true,
- removeAttributeQuotes: true,
- removeComments: true
- },
- nodeModules: process.env.NODE_ENV !== 'production'
- ? path.resolve(__dirname, '../node_modules')
- : false
- }),
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ],
- output: {
- filename: '[name].js',
- libraryTarget: 'commonjs2',
- path: path.join(__dirname, '../dist/electron')
- },
- resolve: {
- alias: {
- '@': path.join(__dirname, '../src/renderer'),
- 'vue$': 'vue/dist/vue.esm.js'
- },
- extensions: ['.js', '.vue', '.json', '.css', '.node']
- },
- target: 'electron-renderer'
-}
-
-/**
- * Adjust rendererConfig for development settings
- */
-if (process.env.NODE_ENV !== 'production') {
- rendererConfig.plugins.push(
- new webpack.DefinePlugin({
- '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
- })
- )
-}
-
-/**
- * Adjust rendererConfig for production settings
- */
-if (process.env.NODE_ENV === 'production') {
- rendererConfig.devtool = ''
-
- rendererConfig.plugins.push(
- new BabiliWebpackPlugin(),
- new CopyWebpackPlugin([
- {
- from: path.join(__dirname, '../static'),
- to: path.join(__dirname, '../dist/electron/static'),
- ignore: ['.*']
- }
- ]),
- new webpack.DefinePlugin({
- 'process.env.NODE_ENV': '"production"'
- }),
- new webpack.LoaderOptionsPlugin({
- minimize: true
- })
- )
-}
-
-module.exports = rendererConfig
diff --git a/electron/.electron-vue/webpack.web.config.js b/electron/.electron-vue/webpack.web.config.js
deleted file mode 100644
index c19e42c5a..000000000
--- a/electron/.electron-vue/webpack.web.config.js
+++ /dev/null
@@ -1,161 +0,0 @@
-'use strict'
-
-process.env.BABEL_ENV = 'web'
-
-const path = require('path')
-const webpack = require('webpack')
-
-const BabiliWebpackPlugin = require('babili-webpack-plugin')
-const CopyWebpackPlugin = require('copy-webpack-plugin')
-const MiniCssExtractPlugin = require('mini-css-extract-plugin')
-const HtmlWebpackPlugin = require('html-webpack-plugin')
-const { VueLoaderPlugin } = require('vue-loader')
-
-let webConfig = {
- devtool: '#cheap-module-eval-source-map',
- entry: {
- web: path.join(__dirname, '../src/renderer/main.js')
- },
- module: {
- rules: [
- {
- test: /\.less$/,
- use: ['vue-style-loader', 'css-loader', 'less-loader']
- },
- {
- test: /\.css$/,
- use: ['vue-style-loader', 'css-loader']
- },
- {
- test: /\.html$/,
- use: 'vue-html-loader'
- },
- {
- test: /\.js$/,
- use: 'babel-loader',
- include: [ path.resolve(__dirname, '../src/renderer') ],
- exclude: /node_modules/
- },
- {
- test: /\.vue$/,
- use: {
- loader: 'vue-loader',
- options: {
- extractCSS: true,
- loaders: {
- sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
- scss: 'vue-style-loader!css-loader!sass-loader',
- less: 'vue-style-loader!css-loader!less-loader'
- }
- }
- }
- },
- {
- test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
- use: {
- loader: 'url-loader',
- query: {
- limit: 10000,
- name: 'imgs/[name].[ext]'
- }
- }
- },
- {
- test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
- use: {
- loader: 'url-loader',
- query: {
- limit: 10000,
- name: 'fonts/[name].[ext]'
- }
- }
- },
- {
- test: /\.s(c|a)ss$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- {
- loader: 'sass-loader',
- // Requires sass-loader@^8.0.0
- options: {
- implementation: require('sass'),
- sassOptions: {
- indentedSyntax: true // optional
- },
- },
- },
- ],
- },
- ]
- },
- plugins: [
- new VueLoaderPlugin(),
- new MiniCssExtractPlugin({filename: 'styles.css'}),
- new HtmlWebpackPlugin({
- filename: 'index.html',
- template: path.resolve(__dirname, '../src/index.ejs'),
- templateParameters(compilation, assets, options) {
- return {
- compilation: compilation,
- webpack: compilation.getStats().toJson(),
- webpackConfig: compilation.options,
- htmlWebpackPlugin: {
- files: assets,
- options: options
- },
- process
- }
- },
- minify: {
- collapseWhitespace: true,
- removeAttributeQuotes: true,
- removeComments: true
- },
- nodeModules: false
- }),
- new webpack.DefinePlugin({
- 'process.env.IS_WEB': 'true'
- }),
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ],
- output: {
- filename: '[name].js',
- path: path.join(__dirname, '../dist/web')
- },
- resolve: {
- alias: {
- '@': path.join(__dirname, '../src/renderer'),
- 'vue$': 'vue/dist/vue.esm.js'
- },
- extensions: ['.js', '.vue', '.json', '.css']
- },
- target: 'web'
-}
-
-/**
- * Adjust webConfig for production settings
- */
-if (process.env.NODE_ENV === 'production') {
- webConfig.devtool = ''
-
- webConfig.plugins.push(
- new BabiliWebpackPlugin(),
- new CopyWebpackPlugin([
- {
- from: path.join(__dirname, '../static'),
- to: path.join(__dirname, '../dist/web/static'),
- ignore: ['.*']
- }
- ]),
- new webpack.DefinePlugin({
- 'process.env.NODE_ENV': '"production"'
- }),
- new webpack.LoaderOptionsPlugin({
- minimize: true
- })
- )
-}
-
-module.exports = webConfig
diff --git a/electron/.eslintignore b/electron/.eslintignore
deleted file mode 100644
index e69de29bb..000000000
diff --git a/electron/.eslintrc b/electron/.eslintrc
deleted file mode 100644
index 64f12522e..000000000
--- a/electron/.eslintrc
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "extends": "eslint-config-airbnb",
- "rules": {
- "import/extensions": 0,
- "import/no-extraneous-dependencies": 0,
- "import/no-unresolved": [2, { "ignore": ["electron"] }],
- "linebreak-style": 0
- }
-}
diff --git a/electron/.eslintrc.js b/electron/.eslintrc.js
deleted file mode 100644
index 90cf05bbf..000000000
--- a/electron/.eslintrc.js
+++ /dev/null
@@ -1,26 +0,0 @@
-module.exports = {
- root: true,
- parser: 'babel-eslint',
- parserOptions: {
- sourceType: 'module'
- },
- env: {
- browser: true,
- node: true
- },
- extends: 'standard',
- globals: {
- __static: true
- },
- plugins: [
- 'html'
- ],
- 'rules': {
- // allow paren-less arrow functions
- 'arrow-parens': 0,
- // allow async-await
- 'generator-star-spacing': 0,
- // allow debugger during development
- 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
- }
-}
diff --git a/electron/.gitattributes b/electron/.gitattributes
new file mode 100644
index 000000000..6313b56c5
--- /dev/null
+++ b/electron/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/electron/babel.config.js b/electron/babel.config.js
new file mode 100644
index 000000000..ff2f95bea
--- /dev/null
+++ b/electron/babel.config.js
@@ -0,0 +1,16 @@
+module.exports = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ useBuiltIns: 'usage', // adds specific imports for polyfills when they are used in each file.
+ modules: false, // preserve ES modules.
+ corejs: { version: 3, proposals: true }, // enable polyfilling of every proposal supported by core-js.
+ },
+ ],
+ ],
+ plugins: [
+ '@babel/plugin-transform-runtime', // enables the re-use of Babel's injected helper code to save on codesize.
+ ],
+ exclude: [/core-js/],
+}
diff --git a/electron/package.json b/electron/package.json
index 7a0b318b9..dadf713d6 100644
--- a/electron/package.json
+++ b/electron/package.json
@@ -4,10 +4,12 @@
"version": "11.99.11",
"description": "Ink/Stitch GUI",
"main": "./dist/electron/main.js",
+ "private": true,
"scripts": {
- "pack": "electron-builder --dir",
- "dist": "node .electron-vue/build.js && electron-builder",
- "dev": "node --openssl-legacy-provider .electron-vue/dev-runner.js"
+ "dev": "node service/commands/dev.js",
+ "just-build": "node service/commands/build.js && node service/commands/build-main.js",
+ "dist": "yarn just-build && electron-builder",
+ "print": "yarn just-build && yarn dev"
},
"build": {
"productName": "inkstitch-gui",
@@ -22,10 +24,7 @@
"icon": "build/icons",
"target": [
{
- "target": "dir",
- "arch": [
- "CPU_ARCH"
- ]
+ "target": "dir"
}
]
},
@@ -37,10 +36,7 @@
"icon": "build/icons/mac/inkstitch.icns",
"target": [
{
- "target": "dir",
- "arch": [
- "CPU_ARCH"
- ]
+ "target": "dir"
}
],
"hardenedRuntime": true,
@@ -54,78 +50,70 @@
"author": "lex",
"license": "GPL-3.0-or-later",
"dependencies": {
- "@fortawesome/fontawesome-svg-core": "^1.2.22",
- "@fortawesome/free-solid-svg-icons": "^5.10.2",
- "@fortawesome/vue-fontawesome": "^0.1.6",
- "@mdi/font": "^5.5.55",
- "@svgdotjs/svg.filter.js": "^3.0.7",
- "@svgdotjs/svg.js": "^3.0.16",
- "@svgdotjs/svg.panzoom.js": "https://github.com/inkstitch/svg.panzoom.js",
- "axios": "^0.19.0",
- "electron-compile": "^6.4.4",
+ "@babel/plugin-transform-runtime": "^7.21.0",
+ "@babel/runtime": "^7.17.9",
+ "@fortawesome/fontawesome-svg-core": "^6.1.1",
+ "@fortawesome/free-solid-svg-icons": "^6.1.1",
+ "@fortawesome/vue-fontawesome": "^3.0.0-5",
+ "@svgdotjs/svg.filter.js": "^3.0.8",
+ "@svgdotjs/svg.js": "^3.1.2",
+ "@svgdotjs/svg.panzoom.js": "^2.1.2",
+ "axios": "^0.27.2",
+ "core-js": "^3.22.2",
"lodash.throttle": "^4.1.1",
- "mousetrap": "^1.6.3",
- "query-string": "^6.8.2",
- "svgpath": "^2.2.3",
- "tmp": "0.1.0",
- "vue": "^2.5.16",
- "vue-gettext": "^2.1.5",
- "vue-loading-overlay": "^3.2.0",
- "vue-router": "^3.0.1",
- "vue-slider-component": "^3.0.38",
- "vue2-transitions": "^0.3.0",
- "vuetify": "^2.3.9"
+ "node-polyfill-webpack-plugin": "^2.0.1",
+ "query-string": "^7.1.1",
+ "svgpath": "^2.5.0",
+ "vue": "^3.2.33",
+ "vue-loading-overlay": "^5.0",
+ "vue-mousetrap": "^1.0.5",
+ "vue-router": "4",
+ "vue-slider-component": "^4.1.0-beta.0",
+ "vue3-gettext": "^2.2.3",
+ "vue3-transitions": "^1.0.0",
+ "vuetify": "^3.1.7",
+ "webpack-plugin-vuetify": "^2.0.1"
},
"devDependencies": {
- "ajv": "^6.5.0",
- "babel-core": "^6.26.3",
- "babel-eslint": "^8.2.3",
- "babel-loader": "^7.1.4",
- "babel-plugin-transform-runtime": "^6.23.0",
- "babel-preset-env": "^1.7.0",
- "babel-preset-stage-0": "^6.24.1",
- "babel-register": "^6.26.0",
- "babili-webpack-plugin": "^0.1.2",
- "cfonts": "^2.1.2",
- "chalk": "^2.4.1",
- "copy-webpack-plugin": "^4.5.1",
- "cross-env": "^5.1.6",
- "css-loader": "^0.28.11",
+ "@babel/core": "^7.17.9",
+ "@babel/preset-env": "^7.16.11",
+ "@types/webpack-env": "^1.16.4",
+ "@vue/compiler-sfc": "^3.2.33",
+ "autoprefixer": "^10.4.5",
+ "babel-loader": "^8.2.5",
+ "case-sensitive-paths-webpack-plugin": "^2.4.0",
+ "chalk": "^4.1.2",
+ "copy-webpack-plugin": "^10.2.4",
+ "css-loader": "^6.7.1",
"deepmerge": "^4.2.2",
- "del": "^3.0.0",
- "devtron": "^1.4.0",
- "easygettext": "^2.7.0",
- "electron": "4.1.3",
+ "dotenv": "^16.0.0",
+ "dotenv-expand": "^8.0.3",
+ "electron": "14.2.9",
"electron-builder": "^23.0.3",
- "electron-debug": "^1.5.0",
- "electron-devtools-installer": "^2.2.4",
- "electron-prebuilt-compile": "4.0.0",
- "eslint": "^4.19.1",
- "eslint-config-standard": "^11.0.0",
- "eslint-friendly-formatter": "^4.0.1",
- "eslint-loader": "^2.0.0",
- "eslint-plugin-html": "^4.0.3",
- "eslint-plugin-import": "^2.12.0",
- "eslint-plugin-node": "^6.0.1",
- "eslint-plugin-promise": "^3.8.0",
- "eslint-plugin-standard": "^3.1.0",
- "file-loader": "^1.1.11",
- "html-webpack-plugin": "^3.2.0",
- "mini-css-extract-plugin": "0.4.0",
- "multispinner": "^0.2.1",
- "node-loader": "^0.6.0",
- "sass": "^1.26.10",
- "sass-loader": "^9.0.3",
- "style-loader": "^0.21.0",
- "url-loader": "^1.0.1",
- "vue-html-loader": "^1.2.4",
- "vue-loader": "^15.2.4",
- "vue-style-loader": "^4.1.0",
- "vue-template-compiler": "^2.5.16",
- "webpack": "^4.15.1",
- "webpack-cli": "^3.0.8",
- "webpack-dev-server": "^3.1.4",
- "webpack-hot-middleware": "^2.22.2",
- "webpack-merge": "^4.1.3"
+ "html-webpack-plugin": "^5.5.0",
+ "mini-css-extract-plugin": "^2.6.0",
+ "ora": "^5.4.1",
+ "postcss": "^8.4.12",
+ "postcss-html": "^1.4.1",
+ "postcss-loader": "^6.2.1",
+ "rimraf": "^3.0.2",
+ "sass": "~1.32",
+ "sass-loader": "^13.0.0",
+ "strip-ansi": "^6.0.0",
+ "style-loader": "^3.3.1",
+ "terser-webpack-plugin": "^5.3.1",
+ "thread-loader": "^3.0.4",
+ "ts-loader": "^9.2.8",
+ "typescript": "^4.6.3",
+ "url-loader": "^4.1.1",
+ "vue-loader": "^17.0.0",
+ "vue-style-loader": "^4.1.3",
+ "wait-on": "^6.0.1",
+ "webpack": "^5.72.0",
+ "webpack-dev-server": "^4.8.1",
+ "webpack-merge": "^5.8.0"
+ },
+ "engines": {
+ "node": ">=12.13.0"
}
}
diff --git a/electron/service/commands/build-main.js b/electron/service/commands/build-main.js
new file mode 100644
index 000000000..1b28ef91b
--- /dev/null
+++ b/electron/service/commands/build-main.js
@@ -0,0 +1,41 @@
+'use strict'
+
+const loadEnv = require('../utils/loadEnv')
+loadEnv()
+loadEnv('production')
+
+const rm = require('rimraf')
+const webpack = require('webpack')
+
+const { error, done } = require('../utils/logger')
+const { logWithSpinner, stopSpinner } = require('../utils/spinner')
+const paths = require('../utils/paths')
+// after renderer is built, main is next to build
+const webpackConfig = require('../config/main')
+const config = require('../project.config')
+
+logWithSpinner('Building for production...')
+// removed rm function to prevent the deletion of renderer
+webpack(webpackConfig, (err, stats) => {
+ stopSpinner(false)
+
+ if (err) throw err
+
+ process.stdout.write(
+ stats.toString({
+ colors: true,
+ modules: false,
+ children: false,
+ chunks: false,
+ chunkModules: false,
+ }) + '\n\n'
+ )
+
+ if (stats.hasErrors()) {
+ error('Build failed with errors.\n')
+ process.exit(1)
+ }
+
+ done('Build complete.\n')
+})
+
diff --git a/electron/service/commands/build.js b/electron/service/commands/build.js
new file mode 100644
index 000000000..097f70135
--- /dev/null
+++ b/electron/service/commands/build.js
@@ -0,0 +1,44 @@
+'use strict'
+
+const loadEnv = require('../utils/loadEnv')
+loadEnv()
+loadEnv('production')
+
+const rm = require('rimraf')
+const webpack = require('webpack')
+
+const { error, done } = require('../utils/logger')
+const { logWithSpinner, stopSpinner } = require('../utils/spinner')
+const paths = require('../utils/paths')
+// build renderer first
+const webpackConfig = require('../config/renderer')
+const config = require('../project.config')
+
+logWithSpinner('Building for production...')
+
+rm(paths.resolve(config.outputDir), (err) => {
+ if (err) throw err
+
+ webpack(webpackConfig, (err, stats) => {
+ stopSpinner(false)
+
+ if (err) throw err
+
+ process.stdout.write(
+ stats.toString({
+ colors: true,
+ modules: false,
+ children: false,
+ chunks: false,
+ chunkModules: false,
+ }) + '\n\n'
+ )
+
+ if (stats.hasErrors()) {
+ error('Build failed with errors.\n')
+ process.exit(1)
+ }
+
+ done('Build complete.\n')
+ })
+})
diff --git a/electron/service/commands/dev.js b/electron/service/commands/dev.js
new file mode 100644
index 000000000..bea420218
--- /dev/null
+++ b/electron/service/commands/dev.js
@@ -0,0 +1,102 @@
+'use strict'
+
+const loadEnv = require('../utils/loadEnv')
+loadEnv()
+loadEnv('development')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const WebpackDevServer = require('webpack-dev-server')
+const { info } = require('../utils/logger')
+const getLocalIP = require('../utils/getLocalIP')
+const devWebpackConfig = require('../config/dev')
+const devServerOptions = devWebpackConfig.devServer
+const { spawn } = require('node:child_process')
+const electron = require('electron')
+const path = require('path')
+const url = require('url')
+const fs = require('fs');
+
+let electronProcess = null
+let manualRestart = false
+// disable warnings in browser console
+process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'false'
+
+const protocol = devServerOptions.https ? 'https' : 'http'
+const host = devServerOptions.host || '0.0.0.0'
+const port = devServerOptions.port || 8080
+
+// older code that sets the url for the path I would assume
+var parseArg = process.argv[2] || ""
+var yarnArg = url.parse(parseArg)
+
+function resetPort() {
+ let resetData = { "_comment1": "port should not be declared when commiting" }
+ fs.writeFileSync(path.join(__dirname, "../../src/lib/flaskserverport.json"), JSON.stringify(resetData), 'utf8')
+ console.log("Resetting the flaskport")
+}
+
+function startElectron(webpackport) {
+var wbport = webpackport
+ // this sends url to proper position
+ process.argv.shift()
+ process.argv.shift()
+ // get URL from PrintPDF
+ // checks if url is http
+ if (yarnArg.protocol) {
+ var args = [
+ '--inspect=5858',
+ path.join(__dirname, '../../dist/electron/main.js')
+ ].concat(process.argv)
+ } else {
+ var args = [
+ '--inspect=5858',
+ `http://0.0.0.0:${wbport}/#${process.argv}`
+ ].concat(process.argv)
+ }
+ // detect yarn or npm and process commandline args accordingly
+ if (process.env.npm_execpath.endsWith('yarn.js')) {
+ args = args.concat(process.argv.slice(3))
+ } else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
+ args = args.concat(process.argv.slice(2))
+ }
+ electronProcess = spawn(electron, args)
+ electronProcess.on('close', () => {
+ if (!manualRestart) {
+ process.exit()
+ } else {
+ process.kill(electronProcess.pid)
+ }
+ resetPort()
+ })
+ electronProcess.on('exit', () => {
+ resetPort()
+ })
+}
+
+info('Starting development server...')
+const compiler = webpack(devWebpackConfig)
+const server = new WebpackDevServer(devServerOptions, compiler)
+
+compiler.hooks.done.tap('serve', (stats) => {
+ console.log()
+ console.log()
+ console.log(`App running at:`)
+ console.log(` - Local: ${chalk.cyan(`${protocol}://${host}:${port}`)}`)
+ console.log(` - Network: ${chalk.cyan(`${protocol}://${getLocalIP()}:${port}`)}`)
+ console.log()
+
+ // allows livereload for webpack devserver to work without multiple instances of electron
+ if (electronProcess) {
+ manualRestart = true
+ } else {
+ manualRestart = false
+ // starts nodejs electron commandline browser
+ startElectron(devServerOptions.port)
+ }
+})
+
+server.start(port, host, (err) => {
+ if (err) {
+ process.exit(0)
+ }
+})
diff --git a/electron/service/config/base.js b/electron/service/config/base.js
new file mode 100644
index 000000000..8743f3644
--- /dev/null
+++ b/electron/service/config/base.js
@@ -0,0 +1,126 @@
+'use strict'
+
+const { DefinePlugin, EnvironmentPlugin } = require('webpack')
+const { VueLoaderPlugin } = require('vue-loader')
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
+const HTMLPlugin = require('html-webpack-plugin')
+const { VuetifyPlugin } = require('webpack-plugin-vuetify')
+
+const resolveClientEnv = require('../utils/resolveClientEnv')
+const paths = require('../utils/paths')
+
+const config = require('../project.config')
+
+const isProd = process.env.NODE_ENV === 'production'
+
+module.exports = {
+ context: process.cwd(),
+
+ output: {
+ path: paths.resolve(config.outputDir),
+ publicPath: config.dev.publicPath,
+ filename: '[name].js',
+ },
+
+ resolve: {
+ alias: {
+ '@': paths.resolve('src'),
+ },
+ extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', 'html', 'ejs'],
+ },
+
+ plugins: [
+ new VueLoaderPlugin(),
+ new EnvironmentPlugin(['NODE_ENV']),
+ new CaseSensitivePathsPlugin(),
+ new HTMLPlugin({
+ template: paths.resolve('src/index.html'),
+ templateParameters: {
+ ...resolveClientEnv(
+ { publicPath: isProd ? config.build.publicPath : config.dev.publicPath },
+ false /* raw */
+ ),
+ },
+ }),
+ new VuetifyPlugin({ autoImport: true }),
+ new DefinePlugin({
+ // vue3 feature flags
+ __VUE_OPTIONS_API__: 'true',
+ __VUE_PROD_DEVTOOLS__: 'false',
+
+ ...resolveClientEnv({
+ publicPath: isProd ? config.build.publicPath : config.dev.publicPath,
+ }),
+ }),
+ ],
+
+ module: {
+ noParse: /^(vue|vue-router)$/,
+
+ rules: [
+ {
+ test: /\.vue$/,
+ loader: 'vue-loader',
+ },
+ // babel
+ {
+ test: /\.m?jsx?$/,
+ exclude: (file) => {
+ // always transpile js in vue files
+ if (/\.vue\.jsx?$/.test(file)) {
+ return false
+ }
+ // Don't transpile node_modules
+ return /node_modules/.test(file)
+ },
+ use: ['thread-loader', 'babel-loader'],
+ },
+
+ // ts
+ {
+ test: /\.tsx?$/,
+ use: [
+ 'thread-loader',
+ 'babel-loader',
+ {
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true,
+ appendTsSuffixTo: ['\\.vue$'],
+ happyPackMode: true,
+ },
+ },
+ ],
+ },
+
+ // images
+ {
+ test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
+ type: 'asset',
+ generator: { filename: 'img/[contenthash:8][ext][query]' },
+ },
+
+ // do not base64-inline SVGs.
+ // https://github.com/facebookincubator/create-react-app/pull/1180
+ {
+ test: /\.(svg)(\?.*)?$/,
+ type: 'asset/resource',
+ generator: { filename: 'img/[contenthash:8][ext][query]' },
+ },
+
+ // media
+ {
+ test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+ type: 'asset',
+ generator: { filename: 'media/[contenthash:8][ext][query]' },
+ },
+
+ // fonts
+ {
+ test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
+ type: 'asset',
+ generator: { filename: 'fonts/[contenthash:8][ext][query]' },
+ },
+ ],
+ },
+}
diff --git a/electron/service/config/css.js b/electron/service/config/css.js
new file mode 100644
index 000000000..3fb5893e6
--- /dev/null
+++ b/electron/service/config/css.js
@@ -0,0 +1,72 @@
+'use strict'
+
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+
+const isProd = process.env.NODE_ENV === 'production'
+
+const plugins = []
+if (isProd) {
+ const filename = 'css/[name].[contenthash:8].css'
+
+ plugins.push(
+ new MiniCssExtractPlugin({
+ filename,
+ chunkFilename: filename,
+ })
+ )
+}
+
+const genStyleRules = () => {
+ const cssLoader = {
+ loader: 'css-loader',
+ options: {
+ // how many loaders before css-loader should be applied to [@import]ed resources.
+ // stylePostLoader injected by vue-loader + postcss-loader
+ importLoaders: 1 + 1,
+ esModule: false, // css-loader using ES Modules as default in v4, but vue-style-loader support cjs only.
+ },
+ }
+ const postcssLoader = {
+ loader: 'postcss-loader',
+ options: {
+ postcssOptions: {
+ plugins: [require('autoprefixer')]
+ },
+ },
+ }
+ const extractPluginLoader = {
+ loader: MiniCssExtractPlugin.loader,
+ }
+ const vueStyleLoader = {
+ loader: 'vue-style-loader',
+ }
+
+ function createCSSRule(test, loader, loaderOptions) {
+ const loaders = [cssLoader, postcssLoader]
+
+ if (isProd) {
+ loaders.unshift(extractPluginLoader)
+ } else {
+ loaders.unshift(vueStyleLoader)
+ }
+
+ if (loader) {
+ loaders.push({ loader, options: loaderOptions })
+ }
+
+ return { test, use: loaders }
+ }
+
+ return [
+ createCSSRule(/\.css$/),
+ createCSSRule(/\.p(ost)?css$/),
+ createCSSRule(/\.scss$/, 'sass-loader')
+ ]
+}
+
+module.exports = {
+ plugins,
+ module: {
+ rules: genStyleRules(),
+ },
+}
diff --git a/electron/service/config/dev.js b/electron/service/config/dev.js
new file mode 100644
index 000000000..42a82b37b
--- /dev/null
+++ b/electron/service/config/dev.js
@@ -0,0 +1,43 @@
+'use strict'
+
+const { merge } = require('webpack-merge')
+
+const baseWebpackConfig = require('./base')
+const cssWebpackConfig = require('./css')
+const config = require('../project.config')
+const { ProvidePlugin, DefinePlugin } = require('webpack')
+
+
+module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
+ entry: {
+ main: './src/renderer/main.js'
+ },
+
+ mode: 'development',
+
+ devtool: 'eval-cheap-module-source-map',
+
+ devServer: {
+ watchFiles: ['src/**/*'],
+ historyApiFallback: {
+ rewrites: [{ from: /./, to: '/index.html' }],
+ },
+ devMiddleware: {
+ publicPath: config.dev.publicPath,
+ },
+ open: false,
+ host: '0.0.0.0',
+ port: 'auto',
+ liveReload: true,
+ },
+
+ infrastructureLogging: {
+ level: 'warn',
+ },
+
+ stats: {
+ assets: false,
+ modules: false,
+ errorDetails: false,
+ },
+})
diff --git a/electron/service/config/main.js b/electron/service/config/main.js
new file mode 100644
index 000000000..3083dea0c
--- /dev/null
+++ b/electron/service/config/main.js
@@ -0,0 +1,73 @@
+'use strict'
+
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
+const config = require('../project.config')
+
+const resolveClientEnv = require('../utils/resolveClientEnv')
+const paths = require('../utils/paths')
+const { merge } = require('webpack-merge')
+const TerserPlugin = require('terser-webpack-plugin')
+const cssWebpackConfig = require('./css')
+const terserOptions = require('./terserOptions')
+const isProd = process.env.NODE_ENV === 'production'
+
+module.exports = merge(cssWebpackConfig, {
+ context: process.cwd(),
+ mode: 'production',
+ entry: {
+ main: './src/main/index.js',
+ preload: './src/main/preload.js',
+ },
+
+ node: {
+ __dirname: false,
+ },
+
+ optimization: {
+ minimize: true,
+ minimizer: [new TerserPlugin(terserOptions())],
+ moduleIds: 'named',
+ },
+ target: ['electron-main'],
+
+ output: {
+ path: paths.resolve(config.outputDir),
+ publicPath: config.dev.publicPath,
+ filename: '[name].js',
+ },
+
+ resolve: {
+ alias: {
+ '@': paths.resolve('src'),
+ },
+ extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', 'html', 'ejs'],
+ },
+
+ plugins: [
+ new CaseSensitivePathsPlugin(),
+ ],
+
+ module: {
+ noParse: /^(vue|vue-router)$/,
+
+ rules: [
+ // ts
+ {
+ test: /\.tsx?$/,
+ use: [
+ 'thread-loader',
+ 'babel-loader',
+ {
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true,
+ appendTsSuffixTo: ['\\.vue$'],
+ happyPackMode: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+}
+)
\ No newline at end of file
diff --git a/electron/service/config/prod.js b/electron/service/config/prod.js
new file mode 100644
index 000000000..1d9e87262
--- /dev/null
+++ b/electron/service/config/prod.js
@@ -0,0 +1,41 @@
+'use strict'
+
+const { merge } = require('webpack-merge')
+const TerserPlugin = require('terser-webpack-plugin')
+
+const baseWebpackConfig = require('./base')
+const cssWebpackConfig = require('./css')
+const config = require('../project.config')
+const terserOptions = require('./terserOptions')
+
+module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
+ mode: 'production',
+
+ output: {
+ publicPath: config.build.publicPath,
+ },
+
+ optimization: {
+ minimize: true,
+ minimizer: [new TerserPlugin(terserOptions())],
+ moduleIds: 'deterministic',
+ moduleIds: 'named',
+ splitChunks: {
+ cacheGroups: {
+ defaultVendors: {
+ name: `chunk-vendors`,
+ test: /[\\/]node_modules[\\/]/,
+ priority: -10,
+ chunks: 'initial',
+ },
+ common: {
+ name: `chunk-common`,
+ minChunks: 2,
+ priority: -20,
+ chunks: 'initial',
+ reuseExistingChunk: true,
+ },
+ },
+ },
+ },
+})
diff --git a/electron/service/config/renderer.js b/electron/service/config/renderer.js
new file mode 100644
index 000000000..cf3fab01a
--- /dev/null
+++ b/electron/service/config/renderer.js
@@ -0,0 +1,45 @@
+'use strict'
+
+const { merge } = require('webpack-merge')
+const TerserPlugin = require('terser-webpack-plugin')
+
+const baseWebpackConfig = require('./base')
+const cssWebpackConfig = require('./css')
+const config = require('../project.config')
+const terserOptions = require('./terserOptions')
+
+module.exports = merge(baseWebpackConfig, cssWebpackConfig, {
+ mode: 'production',
+ entry: {
+ renderer: './src/renderer/main.js',
+ },
+
+ output: {
+ publicPath: config.build.publicPath,
+ },
+
+ optimization: {
+ minimize: true,
+ minimizer: [new TerserPlugin(terserOptions())],
+ moduleIds: 'deterministic',
+ moduleIds: 'named',
+ splitChunks: {
+ cacheGroups: {
+ defaultVendors: {
+ name: `chunk-vendors`,
+ test: /[\\/]node_modules[\\/]/,
+ priority: -10,
+ chunks: 'initial',
+ },
+ common: {
+ name: `chunk-common`,
+ minChunks: 2,
+ priority: -20,
+ chunks: 'initial',
+ reuseExistingChunk: true,
+ },
+ },
+ },
+ },
+ target: ['electron-renderer'],
+})
diff --git a/electron/service/config/terserOptions.js b/electron/service/config/terserOptions.js
new file mode 100644
index 000000000..134a32588
--- /dev/null
+++ b/electron/service/config/terserOptions.js
@@ -0,0 +1,42 @@
+'use strict'
+
+module.exports = (options) => ({
+ terserOptions: {
+ compress: {
+ // turn off flags with small gains to speed up minification
+ arrows: false,
+ collapse_vars: false, // 0.3kb
+ comparisons: false,
+ computed_props: false,
+ hoist_funs: false,
+ hoist_props: false,
+ hoist_vars: false,
+ inline: false,
+ loops: false,
+ negate_iife: false,
+ properties: false,
+ reduce_funcs: false,
+ reduce_vars: false,
+ switches: false,
+ toplevel: false,
+ typeofs: false,
+
+ // a few flags with noticable gains/speed ratio
+ // numbers based on out of the box vendor bundle
+ booleans: true, // 0.7kb
+ if_return: true, // 0.4kb
+ sequences: true, // 0.7kb
+ unused: true, // 2.3kb
+
+ // required features to drop conditional branches
+ conditionals: true,
+ dead_code: true,
+ evaluate: true,
+ },
+ mangle: {
+ safari10: true,
+ },
+ },
+ // parallel: options.parallel,
+ extractComments: false,
+})
diff --git a/electron/service/project.config.js b/electron/service/project.config.js
new file mode 100644
index 000000000..7e7df9c13
--- /dev/null
+++ b/electron/service/project.config.js
@@ -0,0 +1,16 @@
+'use strict'
+
+module.exports = {
+ // orginal was dist
+ outputDir: 'dist/electron',
+
+ dev: {
+ publicPath: '/',
+ port: 8080,
+ },
+
+ build: {
+ // orginal was /
+ publicPath: './',
+ },
+}
diff --git a/electron/service/utils/getLocalIP.js b/electron/service/utils/getLocalIP.js
new file mode 100644
index 000000000..14926ee20
--- /dev/null
+++ b/electron/service/utils/getLocalIP.js
@@ -0,0 +1,17 @@
+'use strict'
+
+const os = require('os')
+
+module.exports = function getLocalIP() {
+ const interfaces = os.networkInterfaces()
+
+ for (const devName in interfaces) {
+ const iface = interfaces[devName]
+ for (let i = 0; i < iface.length; i++) {
+ const alias = iface[i]
+ if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
+ return alias.address
+ }
+ }
+ }
+}
diff --git a/electron/service/utils/loadEnv.js b/electron/service/utils/loadEnv.js
new file mode 100644
index 000000000..3c054ff68
--- /dev/null
+++ b/electron/service/utils/loadEnv.js
@@ -0,0 +1,39 @@
+'use strict'
+
+const path = require('path')
+const dotenv = require('dotenv')
+const dotenvExpand = require('dotenv-expand')
+const { error } = require('./logger')
+
+module.exports = function loadEnv(mode) {
+ const basePath = path.resolve(process.cwd(), `.env${mode ? `.${mode}` : ``}`)
+ const localPath = `${basePath}.local`
+
+ const load = (envPath) => {
+ try {
+ const env = dotenv.config({ path: envPath, debug: process.env.DEBUG })
+ dotenvExpand.expand(env)
+ } catch (err) {
+ // only ignore error if file is not found
+ if (err.toString().indexOf('ENOENT') < 0) {
+ error(err)
+ }
+ }
+ }
+
+ load(localPath)
+ load(basePath)
+
+ // by default, NODE_ENV and BABEL_ENV are set to "development" unless mode
+ // is production or test. However the value in .env files will take higher
+ // priority.
+ if (mode) {
+ const defaultNodeEnv = mode === 'production' || mode === 'test' ? mode : 'development'
+ if (process.env.NODE_ENV == null) {
+ process.env.NODE_ENV = defaultNodeEnv
+ }
+ if (process.env.BABEL_ENV == null) {
+ process.env.BABEL_ENV = defaultNodeEnv
+ }
+ }
+}
diff --git a/electron/service/utils/logger.js b/electron/service/utils/logger.js
new file mode 100644
index 000000000..0d74c52c0
--- /dev/null
+++ b/electron/service/utils/logger.js
@@ -0,0 +1,72 @@
+'use strict'
+
+const chalk = require('chalk')
+const stripAnsi = require('strip-ansi')
+const readline = require('readline')
+const EventEmitter = require('events')
+
+exports.events = new EventEmitter()
+
+function _log(type, tag, message) {
+ if (process.env.VUE_CLI_API_MODE && message) {
+ exports.events.emit('log', {
+ message,
+ type,
+ tag,
+ })
+ }
+}
+
+const format = (label, msg) => {
+ return msg
+ .split('\n')
+ .map((line, i) => {
+ return i === 0 ? `${label} ${line}` : line.padStart(stripAnsi(label).length)
+ })
+ .join('\n')
+}
+
+const chalkTag = (msg) => chalk.bgBlackBright.white.dim(` ${msg} `)
+
+exports.log = (msg = '', tag = null) => {
+ tag ? console.log(format(chalkTag(tag), msg)) : console.log(msg)
+ _log('log', tag, msg)
+}
+
+exports.info = (msg, tag = null) => {
+ console.log(format(chalk.bgBlue.black(' INFO ') + (tag ? chalkTag(tag) : ''), msg))
+ _log('info', tag, msg)
+}
+
+exports.done = (msg, tag = null) => {
+ console.log(format(chalk.bgGreen.black(' DONE ') + (tag ? chalkTag(tag) : ''), msg))
+ _log('done', tag, msg)
+}
+
+exports.warn = (msg, tag = null) => {
+ console.warn(
+ format(chalk.bgYellow.black(' WARN ') + (tag ? chalkTag(tag) : ''), chalk.yellow(msg))
+ )
+ _log('warn', tag, msg)
+}
+
+exports.error = (msg, tag = null) => {
+ console.error(format(chalk.bgRed(' ERROR ') + (tag ? chalkTag(tag) : ''), chalk.red(msg)))
+ _log('error', tag, msg)
+ if (msg instanceof Error) {
+ console.error(msg.stack)
+ _log('error', tag, msg.stack)
+ }
+}
+
+exports.clearConsole = (title) => {
+ if (process.stdout.isTTY) {
+ const blank = '\n'.repeat(process.stdout.rows)
+ console.log(blank)
+ readline.cursorTo(process.stdout, 0, 0)
+ readline.clearScreenDown(process.stdout)
+ if (title) {
+ console.log(title)
+ }
+ }
+}
diff --git a/electron/service/utils/paths.js b/electron/service/utils/paths.js
new file mode 100644
index 000000000..a3e173c34
--- /dev/null
+++ b/electron/service/utils/paths.js
@@ -0,0 +1,6 @@
+'use strict'
+
+const path = require('path')
+
+// gen absolute path
+exports.resolve = (...args) => path.posix.join(process.cwd(), ...args)
diff --git a/electron/service/utils/resolveClientEnv.js b/electron/service/utils/resolveClientEnv.js
new file mode 100644
index 000000000..4a4505a65
--- /dev/null
+++ b/electron/service/utils/resolveClientEnv.js
@@ -0,0 +1,11 @@
+'use strict'
+const prefixRE = /^VUE_APP_/
+
+module.exports = function resolveClientEnv(options, raw) {
+ process.env.PUBLIC_PATH = options.publicPath
+
+ if (raw) {
+ return env
+ }
+
+}
\ No newline at end of file
diff --git a/electron/service/utils/spinner.js b/electron/service/utils/spinner.js
new file mode 100644
index 000000000..d643a9338
--- /dev/null
+++ b/electron/service/utils/spinner.js
@@ -0,0 +1,57 @@
+'use strict'
+
+const ora = require('ora')
+const chalk = require('chalk')
+
+const spinner = ora()
+let lastMsg = null
+let isPaused = false
+
+exports.logWithSpinner = (symbol, msg) => {
+ if (!msg) {
+ msg = symbol
+ symbol = chalk.green('✔')
+ }
+ if (lastMsg) {
+ spinner.stopAndPersist({
+ symbol: lastMsg.symbol,
+ text: lastMsg.text,
+ })
+ }
+ spinner.text = ' ' + msg
+ lastMsg = {
+ symbol: symbol + ' ',
+ text: msg,
+ }
+ spinner.start()
+}
+
+exports.stopSpinner = (persist) => {
+ if (lastMsg && persist !== false) {
+ spinner.stopAndPersist({
+ symbol: lastMsg.symbol,
+ text: lastMsg.text,
+ })
+ } else {
+ spinner.stop()
+ }
+ lastMsg = null
+}
+
+exports.pauseSpinner = () => {
+ if (spinner.isSpinning) {
+ spinner.stop()
+ isPaused = true
+ }
+}
+
+exports.resumeSpinner = () => {
+ if (isPaused) {
+ spinner.start()
+ isPaused = false
+ }
+}
+
+exports.failSpinner = (text) => {
+ spinner.fail(text)
+}
diff --git a/electron/src/index.ejs b/electron/src/index.ejs
deleted file mode 100644
index 381a86c7c..000000000
--- a/electron/src/index.ejs
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- inkstitch-gui
- <% if (htmlWebpackPlugin.options.nodeModules) { %>
-
-
- <% } %>
-
-
-
-
- <% if (!process.browser) { %>
-
- <% } %>
-
-
-
-
diff --git a/electron/src/index.html b/electron/src/index.html
new file mode 100644
index 000000000..1eb6fbabf
--- /dev/null
+++ b/electron/src/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/electron/src/lib/api.js b/electron/src/lib/api.js
index b6aa74e20..63818541d 100644
--- a/electron/src/lib/api.js
+++ b/electron/src/lib/api.js
@@ -6,11 +6,19 @@
*
*/
-const axios = require('axios')
-const queryString = require('query-string')
+import axios from 'axios';
+import flaskserverport from './flaskserverport.json'
-var port = queryString.parse(global.location.search).port
+if (flaskserverport.port === undefined) {
+ var theflaskport = window.inkstitchAPI.flaskport()
+ console.log("Installed mode")
+ console.log(theflaskport)
+} else {
+ var theflaskport = flaskserverport.port
+ console.log("Dev mode")
+ console.log(theflaskport)
+}
-module.exports = axios.create({
- baseURL: `http://127.0.0.1:${port}/`
+export const inkStitch = axios.create({
+ baseURL: `http://127.0.0.1:${theflaskport}`
})
diff --git a/electron/src/lib/i18n.js b/electron/src/lib/i18n.js
index de56fc8f7..2a7c4f665 100644
--- a/electron/src/lib/i18n.js
+++ b/electron/src/lib/i18n.js
@@ -6,22 +6,33 @@
*
*/
-module.exports.selectLanguage = function (translations) {
+export function selectLanguage(translations, flaskport) {
+ var port = flaskport
+ // get language from flask server, process in modern electron isn't exposed to renderer
+ const request = new XMLHttpRequest();
+ request.open('GET', `http://127.0.0.1:${port}/languages`, false)
+ request.send(null)
+ var process = undefined
+
+ if (request.status === 200) {
+ process = JSON.parse(request.responseText)
+ }
// get a list of available translations
var availableTranslations = ['en_US'];
- for(var k in translations) availableTranslations.push(k);
+ for (var k in translations) availableTranslations.push(k);
var lang = undefined;
// get system language / Inkscape language
['LANG', 'LC_MESSAGES', 'LC_ALL', 'LANGUAGE'].forEach(language => {
- if (process.env[language]) {
+ if (process[language]) {
// split encoding information, we don't need it
- var current_lang = process.env[language].split(".")[0];
+ var current_lang = process[language].split('.')[0];
+
if (current_lang.length == 2) {
// current language has only two letters (e.g. en),
// compare with available languages and if present, set to a long locale name (e.g. en_US)
- lang = availableTranslations.find(elem => elem.startsWith(current_lang));
+ lang = availableTranslations.find((elem) => elem.startsWith(current_lang));
} else {
lang = current_lang;
}
@@ -33,3 +44,4 @@ module.exports.selectLanguage = function (translations) {
}
return lang
}
+
diff --git a/electron/src/main/index.dev.js b/electron/src/main/index.dev.js
deleted file mode 100644
index 7fc8c159c..000000000
--- a/electron/src/main/index.dev.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Authors: see git history
- *
- * Copyright (c) 2010 Authors
- * Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
- *
- */
-
-/**
- * This file is used specifically and only for development. It installs
- * `electron-debug` & `vue-devtools`. There shouldn't be any need to
- * modify this file, but it can be used to extend your development
- * environment.
- */
-
-/* eslint-disable */
-
-// Install `electron-debug` with `devtron`
-require('electron-debug')({ showDevTools: true })
-
-// Install `vue-devtools`
-require('electron').app.on('ready', () => {
- let installExtension = require('electron-devtools-installer')
- installExtension.default(installExtension.VUEJS_DEVTOOLS)
- .then(() => {})
- .catch(err => {
- console.log('Unable to install `vue-devtools`: \n', err)
- })
-})
-
-// Require `main` process to boot app
-require('./index')
diff --git a/electron/src/main/index.js b/electron/src/main/index.js
index d6f259fe1..546580eaa 100644
--- a/electron/src/main/index.js
+++ b/electron/src/main/index.js
@@ -8,113 +8,104 @@
'use strict'
-import {app, BrowserWindow, ipcMain, dialog, shell} from 'electron'
-var fs = require('fs');
-var path = require('path');
-var tmp = require('tmp');
-
+const path = require('path')
+const fs = require('fs')
+const tmp = require('tmp')
const url = require('url')
+const { app, BrowserWindow, ipcMain, dialog, shell, Menu} = require('electron')
+// url for printPDF flask server which is used in development and production mode
-/**
- * Set `__static` path to static files in production
- * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
- */
-if (process.env.NODE_ENV === 'development') {
- // we were run as electron --inspect=5858 path/to/main.js
- // so get rid of the first two args
- console.log("args " + process.argv)
- process.argv.shift()
- process.argv.shift()
+var port = process.env.FLASKPORT
+const printPdfUrl = `http://127.0.0.1:${port}/`
+
+const isDev = process.env.BABEL_ENV === 'development'
+
+var target = null
+// Finds this url in the argv array and sets to target value
+if (process.argv.includes(printPdfUrl)) {
+ target = printPdfUrl
} else {
- global.__static = path.join(__dirname, '/static').replace(/\\/g, '\\\\')
+ target = process.argv[1] || "";
}
-
-let mainWindow
-
-var target = process.argv[1] || "";
var targetURL = url.parse(target)
-var winURL = null;
+var winURL = null
-// Print PDF will give us a full URL to a flask server, bypassing Vue entirely.
// Eventually this will be migrated to Vue.
if (targetURL.protocol) {
- winURL = target
+ winURL = target
} else {
- if (process.env.NODE_ENV === 'development') {
- winURL = `http://localhost:9080/?${targetURL.query || ""}#${targetURL.pathname || ""}`
- } else {
- winURL = `file://${__dirname}/index.html?${targetURL.query || ""}#${targetURL.pathname || ""}`;
- }
+ winURL = `file://${__dirname}/index.html?${targetURL.query || ""}#${targetURL.pathname || ""}`
}
function createWindow() {
- /**
- * Initial window options
- */
- mainWindow = new BrowserWindow({
- height: 563,
- useContentSize: true,
- width: 1000,
- webPreferences: {nodeIntegration: true}
- })
-
- mainWindow.loadURL(winURL)
- mainWindow.maximize()
-
- mainWindow.on('closed', () => {
- mainWindow = null
- })
+ const mainWindow = new BrowserWindow({
+ useContentSize: true,
+ webPreferences: {
+ preload: path.join(__dirname, 'preload.js'),
+ nodeIntegration: false,
+ contextIsolation: true,
+ },
+ })
+ if (isDev) {
+ // printPDF in development mode will have dev tools activated
+ // Vuejs parts of Ink/Stich will not and dev tools must be accessed though the menu of electron window
+ mainWindow.loadURL(winURL)
+ mainWindow.webContents.openDevTools()
+ } else {
+ mainWindow.loadURL(winURL)
+ }
+ // This will remove the menu from the release, in dev mode the menu is available.
+ if(process.platform === "darwin" && !isDev) {
+ Menu.setApplicationMenu(Menu.buildFromTemplate([]));
+ } if(process.platform === "win32" || process.platform === "linux" && !isDev) {
+ mainWindow.removeMenu();
+ }
+ mainWindow.maximize()
+ // save to PDF
+ ipcMain.on('save-pdf', (event, pageSize) => {
+ const webContents = event.sender
+ const win = BrowserWindow.fromWebContents(webContents)
+ const saveOpt = {
+ title: "Save PDF",
+ defaultPath: "Inkstitch.pdf",
+ bookmark: "true",
+ }
+ win.webContents.printToPDF({}).then(pageSize => {
+ dialog.showSaveDialog(saveOpt).then(filename => {
+ const { filePath } = filename;
+ fs.writeFileSync(filePath, pageSize, (error) => {
+ if (error) {
+ throw error
+ }
+ console.log(`Wrote PDF successfully to ${pdfPath}`)
+ })
+ }).catch(error => {
+ console.log(`Failed to write PDF to ${pdfPath}: `, error)
+ })
+ })
+ })
+ // openPDF
+ ipcMain.on('open-pdf', (event, pageSize) => {
+ const webContents = event.sender
+ const win = BrowserWindow.fromWebContents(webContents)
+ win.webContents.printToPDF({}).then(pageSize => {
+ tmp.file({keep: true, discardDescriptor: true}, function(err, path, fd, cleanupCallback) {
+ fs.writeFileSync(path, pageSize, 'utf-8');
+ shell.openPath(path);
+ })
+ })
+ })
}
-app.on('ready', createWindow)
+app.whenReady().then(() => {
+ createWindow()
+ app.on('activate', () => {
+ if(BrowserWindow.getAllWindows().length === 0) {
+ createWindow()
+ }
+ })
+})
app.on('window-all-closed', () => {
app.quit()
})
-
-app.on('activate', () => {
- if (mainWindow === null) {
- createWindow()
- }
-})
-
-ipcMain.on('save-pdf', function (event, pageSize) {
- mainWindow.webContents.printToPDF({"pageSize": pageSize}, function(error, data) {
- dialog.showSaveDialog(mainWindow, {"defaultPath": "inkstitch.pdf",
- "filters": [{ name: 'PDF', extensions: ['pdf'] }]
- }, function(filename, bookmark) {
- if (typeof filename !== 'undefined')
- fs.writeFileSync(filename, data, 'utf-8');
- })
- })
-})
-
-ipcMain.on('open-pdf', function (event, pageSize) {
- mainWindow.webContents.printToPDF({"pageSize": pageSize}, function(error, data) {
- tmp.file({keep: true, discardDescriptor: true}, function(err, path, fd, cleanupCallback) {
- fs.writeFileSync(path, data, 'utf-8');
- shell.openItem(path);
- })
- })
-})
-
-
-/**
- * Auto Updater
- *
- * Uncomment the following code below and install `electron-updater` to
- * support auto updating. Code Signing with a valid certificate is required.
- * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
- */
-
-/*
-import { autoUpdater } from 'electron-updater'
-
-autoUpdater.on('update-downloaded', () => {
- autoUpdater.quitAndInstall()
-})
-
-app.on('ready', () => {
- if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
-})
- */
diff --git a/electron/src/main/preload.js b/electron/src/main/preload.js
new file mode 100644
index 000000000..b7d1c02a9
--- /dev/null
+++ b/electron/src/main/preload.js
@@ -0,0 +1,7 @@
+const { contextBridge, ipcRenderer } = require ('electron')
+
+contextBridge.exposeInMainWorld('inkstitchAPI', {
+ savepdf: (pageSize) => { ipcRenderer.send('save-pdf', pageSize) },
+ openpdf: (pageSize) => { ipcRenderer.send('open-pdf', pageSize) },
+ flaskport: () => process.env.FLASKPORT,
+})
diff --git a/electron/src/renderer/App.vue b/electron/src/renderer/App.vue
index 2e5bbb9d3..b98b13999 100644
--- a/electron/src/renderer/App.vue
+++ b/electron/src/renderer/App.vue
@@ -9,20 +9,9 @@
-
-
-
-
-
-
-
diff --git a/electron/src/renderer/assets/js/simulator.js b/electron/src/renderer/assets/js/simulator.js
index 186e3e303..8a0423f36 100644
--- a/electron/src/renderer/assets/js/simulator.js
+++ b/electron/src/renderer/assets/js/simulator.js
@@ -5,19 +5,18 @@
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
+import { inkStitch } from '../../../lib/api.js'
-const inkStitch = require("../../../lib/api")
-const Mousetrap = require("mousetrap")
import { SVG } from '@svgdotjs/svg.js'
-require('@svgdotjs/svg.panzoom.js/src/svg.panzoom.js')
-require('@svgdotjs/svg.filter.js')
-const svgpath = require('svgpath')
+import '@svgdotjs/svg.panzoom.js'
+import '@svgdotjs/svg.filter.js'
+import svgpath from 'svgpath'
import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/vue-loading.css';
+import { reactive, toRefs } from 'vue'
import VueSlider from 'vue-slider-component'
-import 'vue-slider-component/theme/default.css'
-
-const throttle = require('lodash.throttle')
+import 'vue-slider-component/theme/antd.css'
+import throttle from 'lodash/throttle'
function SliderMark(command, icon) {
this.label = ""
@@ -31,6 +30,10 @@ export default {
Loading,
VueSlider
},
+ setup() {
+ const data = reactive({ value: 0 })
+ return toRefs(data)
+ },
data: function () {
return {
loading: false,
@@ -511,15 +514,23 @@ export default {
},
generatePage () {
this.$refs.simulator.style.backgroundColor = this.page_specs.deskcolor
+
let page = this.svg.rect(this.page_specs.width, this.page_specs.height)
.move(-this.stitchPlan.bounding_box[0],-this.stitchPlan.bounding_box[1])
.fill(this.page_specs.pagecolor)
- .stroke({width: 1, color: 'black'})
- .filterWith(add => {
- let blur = add.offset(2,2).in(add.$sourceAlpha).gaussianBlur(2)
- add.blend(add.$source, blur)
- })
+ .stroke({width: 0.1, color: this.page_specs.bordercolor})
.back()
+
+ if (this.page_specs.showpageshadow === "true") {
+ let shadow = this.svg.rect(this.page_specs.width, this.page_specs.height)
+ .move(-this.stitchPlan.bounding_box[0],-this.stitchPlan.bounding_box[1])
+ .fill(this.page_specs.bordercolor)
+ .filterWith(add => {
+ let blur = add.offset(.5,.5).in(add.$source).gaussianBlur(.5)
+ })
+ .back()
+ }
+
this.page_specs["bbox"] = page.bbox()
},
zoomDesign () {
@@ -606,29 +617,30 @@ export default {
this.generateColorSections()
this.generateScale()
this.generateCursor()
-
+ this.resizeCursor()
+
this.loading = false
// v-on:keydown doesn't seem to work, maybe an Electron issue?
- Mousetrap.bind("up", this.animationSpeedUp)
- Mousetrap.bind("down", this.animationSlowDown)
- Mousetrap.bind("left", this.animationReverse)
- Mousetrap.bind("right", this.animationForward)
- Mousetrap.bind("pagedown", this.animationPreviousCommand)
- Mousetrap.bind("pageup", this.animationNextCommand)
- Mousetrap.bind("space", this.toggleAnimation)
- Mousetrap.bind("+", this.animationForwardOneStitch)
- Mousetrap.bind("-", this.animationBackwardOneStitch)
- Mousetrap.bind("]", this.zoomDesign)
- Mousetrap.bind("[", this.zoomPage)
+ this.$mousetrap.bind("up", this.animationSpeedUp)
+ this.$mousetrap.bind("down", this.animationSlowDown)
+ this.$mousetrap.bind("left", this.animationReverse)
+ this.$mousetrap.bind("right", this.animationForward)
+ this.$mousetrap.bind("pagedown", this.animationPreviousCommand)
+ this.$mousetrap.bind("pageup", this.animationNextCommand)
+ this.$mousetrap.bind("space", this.toggleAnimation)
+ this.$mousetrap.bind("+", this.animationForwardOneStitch)
+ this.$mousetrap.bind("-", this.animationBackwardOneStitch)
+ this.$mousetrap.bind("]", this.zoomDesign)
+ this.$mousetrap.bind("[", this.zoomPage)
this.svg.on('zoom', this.resizeCursor)
- this.resizeCursor()
inkStitch.get('page_specs').then(response => {
this.page_specs = response.data
this.generatePage()
})
+
this.start()
})
}
diff --git a/electron/src/renderer/assets/style/simulator.css b/electron/src/renderer/assets/style/simulator.css
index 64047a7ef..e938cbe3a 100644
--- a/electron/src/renderer/assets/style/simulator.css
+++ b/electron/src/renderer/assets/style/simulator.css
@@ -5,11 +5,10 @@
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
*
*/
-
-* {
- box-sizing: border-box;
+ * {
+ padding: 1px;
+ margin: 1px;
}
-
.loading-icon {
text-align: center;
margin-bottom: 1rem;
@@ -32,7 +31,7 @@ button {
align-items: flex-start;
text-align: center;
cursor: default;
- background-color: buttonface;
+ background: linear-gradient(0deg, rgba(169,169,169,1) 0%, rgba(255,255,255,1) 68%, rgba(227,227,227,1) 100%);
box-sizing: border-box;
padding: 2px 6px 3px;
border-width: 2px;
@@ -183,7 +182,7 @@ button.pressed {
}
.vue-slider {
- height: 25px !important;
+ height: 10px !important;
margin-bottom: 14px;
}
@@ -203,7 +202,7 @@ button.pressed {
margin-right: 10px;
}
-.slider-container::v-deep .vue-slider-mark-step {
+.slider-container :deep(.vue-slider-mark-step) {
width: 2px;
height: 20px;
border-radius: 2px;
@@ -212,26 +211,26 @@ button.pressed {
box-shadow: inset 1px 0 1px #ffffffbd, inset -1px 0 1px black;
}
-.slider-container::v-deep .vue-slider-mark:first-child .vue-slider-mark-step,
-.slider-container::v-deep .vue-slider-mark:last-child .vue-slider-mark-step {
+.slider-container :deep(.vue-slider-mark:first-child .vue-slider-mark-step),
+.slider-container :deep(.vue-slider-mark:last-child .vue-slider-mark-step) {
display: block;
}
-.slider-container::v-deep .vue-slider-rail {
+.slider-container :deep(.vue-slider-rail) {
border: 1px solid #dedede;
}
-.slider-container::v-deep .vue-slider-process {
+.slider-container :deep(.vue-slider-process) {
border-radius: 0;
box-shadow: inset 0px 2px 2px #ffffff80, inset 0px -2px 2px #0000002e;
}
-.slider-container::v-deep .vue-slider-process:first-child {
+.slider-container :deep(.vue-slider-process:first-child) {
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
-.slider-container::v-deep .vue-slider-process:nth-last-child(3) {
+.slider-container :deep(.vue-slider-process:nth-last-child(3)) {
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
@@ -247,20 +246,20 @@ button.pressed {
}
.slider-label-trim {
- transform: scale(1, 0.75) translate(-50%, -9px);
+ transform: scale(1, 0.75) translate(-50%, -9px) !important;;
}
.slider-label-stop {
font-size: 1.2rem;
- transform: translate(-50%, 12px);
+ transform: translate(-50%, 12px) !important;;
}
.slider-label-jump {
- transform: translate(-50%, -50px);
+ transform: translate(-50%, -50px) !important;;
}
.slider-label-color-change {
- transform: translate(-50%, 10px);
+ transform: translate(-50%, 10px) !important;;
}
.current-stitch-input {
@@ -286,23 +285,23 @@ button.pressed {
/* we need ::v-deep here because the svg tag is added by svg.js and so Vue
can't add the data-v-* attribute
*/
-div.simulator::v-deep svg.simulation {
+div.simulator :deep(svg.simulation) {
flex-grow: 1;
flex-shrink: 1;
order: -2;
margin-bottom: -48px;
}
-div.simulator::v-deep svg.simulation-scale {
+div.simulator :deep(svg.simulation-scale) {
height: 50px;
order: -1;
margin-left: 5px;
}
-div.simulator::v-deep .simulation-scale-label {
+div.simulator :deep(.simulation-scale-label) {
font-size: 14px;
}
-div.simulator::v-deep .cursor {
+div.simulator :deep(.cursor) {
/* not sure what to add here to make it more visible */
}
diff --git a/electron/src/renderer/components/InstallPalettes.vue b/electron/src/renderer/components/InstallPalettes.vue
deleted file mode 100644
index 3608f858f..000000000
--- a/electron/src/renderer/components/InstallPalettes.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
- Install Palettes
-
-
-
- Ink/Stitch can install palettes for Inkscape matching the thread colors from popular machine embroidery thread manufacturers.
-
-
-
-
-
- If you are not sure which file path to choose, click on install directly. In most cases Ink/Stitch will guess the correct path.
-
-
-
-
- mdi-palette
- Install
-
-
- Cancel
-
-
-
-
-
-
- Installation Completed
-
-
-
-
- Inkscape palettes have been installed. Please restart Inkscape to load the new palettes.
-
-
-
-
- Done
-
-
-
-
-
-
- Installation Failed
-
-
-
- Inkscape add-on installation failed
-
-
- {{ error }}
-
-
-
- Try again
-
-
- Cancel
-
-
-
-
-
-
-
-
-
diff --git a/electron/src/renderer/components/NotFound.vue b/electron/src/renderer/components/NotFound.vue
new file mode 100644
index 000000000..4accf9019
--- /dev/null
+++ b/electron/src/renderer/components/NotFound.vue
@@ -0,0 +1,12 @@
+
+
+
+ Oops, it looks like the page you're looking for doesn't exist.
+
diff --git a/electron/src/renderer/components/Preferences.vue b/electron/src/renderer/components/Preferences.vue
index f68c942d2..101f1b8a8 100644
--- a/electron/src/renderer/components/Preferences.vue
+++ b/electron/src/renderer/components/Preferences.vue
@@ -1,13 +1,22 @@
+
+
-
+
-
+
Ink/Stitch Settings
-
+
This SVG
@@ -16,16 +25,16 @@
-
-
+
+
-
-
+
+
@@ -45,8 +54,8 @@
|
-
-
+
+
@@ -66,16 +75,16 @@
|
-
-
+
+
-
-
+
+
@@ -90,8 +99,8 @@
|
-
-
+
+
@@ -106,8 +115,8 @@
|
-
-
+
+
@@ -125,8 +134,8 @@
|
-
-
+
+
done
@@ -136,8 +145,7 @@