kopia lustrzana https://github.com/inkstitch/inkstitch
Update electron version to v14.2.9 (#2214)
Authored-by: rejbasket Co-authored-by: Kaalleen Co-authored-by: Lex Nevapull/2316/head
rodzic
da54f104e6
commit
ef6f6580df
|
@ -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
|
||||
|
|
|
@ -24,3 +24,5 @@ locales/
|
|||
/profile_stats.prof
|
||||
/.vscode
|
||||
__pycache__
|
||||
flaskserverport.json
|
||||
electron/yarn.lock
|
||||
|
|
11
Makefile
11
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
|
||||
|
|
|
@ -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/"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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"]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# https://github.com/browserslist/browserslist#queries
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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 += `
|
||||
<style>
|
||||
#dev-client {
|
||||
background: #4fc08d;
|
||||
border-radius: 4px;
|
||||
bottom: 20px;
|
||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
color: #fff;
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
left: 20px;
|
||||
padding: 8px 12px;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="dev-client">
|
||||
Compiling Main Process...
|
||||
</div>
|
||||
`
|
||||
}
|
||||
})
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
* text=auto eol=lf
|
|
@ -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/],
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
})
|
||||
|
|
@ -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')
|
||||
})
|
||||
})
|
|
@ -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)
|
||||
}
|
||||
})
|
|
@ -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 <http://link.vuejs.org/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]' },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
|
@ -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(),
|
||||
},
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
})
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
)
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
|
@ -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'],
|
||||
})
|
|
@ -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,
|
||||
})
|
|
@ -0,0 +1,16 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
// orginal was dist
|
||||
outputDir: 'dist/electron',
|
||||
|
||||
dev: {
|
||||
publicPath: '/',
|
||||
port: 8080,
|
||||
},
|
||||
|
||||
build: {
|
||||
// orginal was /
|
||||
publicPath: './',
|
||||
},
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
// gen absolute path
|
||||
exports.resolve = (...args) => path.posix.join(process.cwd(), ...args)
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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.
|
||||
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>inkstitch-gui</title>
|
||||
<% if (htmlWebpackPlugin.options.nodeModules) { %>
|
||||
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
|
||||
<script>
|
||||
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>')
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- Set `__static` path to static files in production -->
|
||||
<% if (!process.browser) { %>
|
||||
<script>
|
||||
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
|
||||
</script>
|
||||
<% } %>
|
||||
|
||||
<!-- webpack builds are automatically injected -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
<!--
|
||||
|
||||
Authors: see git history
|
||||
|
||||
Copyright (c) 2010 Authors
|
||||
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
global = globalThis
|
||||
</script>
|
|
@ -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}`
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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')
|
|
@ -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 <args>
|
||||
// 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
|
||||
} 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,
|
||||
const mainWindow = new BrowserWindow({
|
||||
useContentSize: true,
|
||||
width: 1000,
|
||||
webPreferences: {nodeIntegration: 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()
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
// 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()
|
||||
})
|
||||
*/
|
||||
|
|
|
@ -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,
|
||||
})
|
|
@ -9,20 +9,9 @@
|
|||
|
||||
<template>
|
||||
<div id="app">
|
||||
<v-app>
|
||||
<v-main>
|
||||
<router-view></router-view>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'my-project'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons');
|
||||
</style>
|
||||
|
|
|
@ -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'})
|
||||
.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(2,2).in(add.$sourceAlpha).gaussianBlur(2)
|
||||
add.blend(add.$source, blur)
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -1,123 +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.
|
||||
|
||||
-->
|
||||
|
||||
<template>
|
||||
<v-dialog max-width="500px" value="true">
|
||||
<v-card v-if="step == 'pick'" key="pick" rounded="lg" :loading="installing" :disabled="installing">
|
||||
<v-card-title>
|
||||
<translate>
|
||||
Install Palettes
|
||||
</translate>
|
||||
</v-card-title>
|
||||
<v-card-text class="text--primary">
|
||||
<translate>Ink/Stitch can install palettes for Inkscape matching the thread colors from popular machine embroidery thread manufacturers.
|
||||
</translate>
|
||||
</v-card-text>
|
||||
<v-file-input class="mb-3 mx-3" webkitdirectory hide-details v-model="path" truncate-length="45"
|
||||
:label="$gettext('Choose Inkscape directory')">
|
||||
</v-file-input>
|
||||
<v-card-text>
|
||||
<translate>If you are not sure which file path to choose, click on install directly. In most cases Ink/Stitch will guess the correct path.
|
||||
</translate>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn text color="primary" v-on:click="install">
|
||||
<v-icon>mdi-palette</v-icon>
|
||||
<translate>Install</translate>
|
||||
</v-btn>
|
||||
<v-btn text color="primary" v-on:click="close">
|
||||
<translate>Cancel</translate>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<v-card v-if="step == 'done'" key="done">
|
||||
<v-card-title>
|
||||
<translate>
|
||||
Installation Completed
|
||||
</translate>
|
||||
</v-card-title>
|
||||
<v-card-text class="text--primary">
|
||||
<translate>
|
||||
Inkscape palettes have been installed. Please restart Inkscape to load the new palettes.
|
||||
</translate>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn text color="primary" v-on:click="close">
|
||||
Done
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<v-card v-if="step == 'error'" key="error">
|
||||
<v-card-title>
|
||||
<translate>
|
||||
Installation Failed
|
||||
</translate>
|
||||
</v-card-title>
|
||||
<v-card-text class="text--primary">
|
||||
<translate>Inkscape add-on installation failed</translate>
|
||||
</v-card-text>
|
||||
<v-card-text class="text--secondary">
|
||||
{{ error }}
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn text color="primary" v-on:click="retry">
|
||||
<translate>Try again</translate>
|
||||
</v-btn>
|
||||
<v-btn text color="primary" v-on:click="close">
|
||||
<translate>Cancel</translate>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const inkStitch = require("../../lib/api")
|
||||
|
||||
export default {
|
||||
name: "InstallPalettes",
|
||||
data: function () {
|
||||
return {
|
||||
path: null,
|
||||
installing: false,
|
||||
step: "pick",
|
||||
error: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
install() {
|
||||
this.installing = true
|
||||
inkStitch.post('install/palettes', {path: this.path.path || this.path.name}).then(response => {
|
||||
this.step = "done"
|
||||
}).catch(error => {
|
||||
this.step = "error"
|
||||
this.error = error.response.data.error
|
||||
}).then(() => {
|
||||
this.installing = false
|
||||
})
|
||||
},
|
||||
close() {
|
||||
window.close()
|
||||
},
|
||||
retry() {
|
||||
this.installing = false
|
||||
this.step = "pick"
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
inkStitch.get("install/default-path").then(response => {
|
||||
this.path = new File([""], response.data, {})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
<!--
|
||||
|
||||
Authors: see git history
|
||||
|
||||
Copyright (c) 2010 Authors
|
||||
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
-->
|
||||
|
||||
<template>
|
||||
<h1>Oops, it looks like the page you're looking for doesn't exist.</h1>
|
||||
</template>
|
|
@ -1,13 +1,22 @@
|
|||
<!--
|
||||
|
||||
Authors: see git history
|
||||
|
||||
Copyright (c) 2010 Authors
|
||||
Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
-->
|
||||
|
||||
<template>
|
||||
<v-card raised rounded="lg" class="preferences-card">
|
||||
<v-card elevation="8" rounded="lg" class="preferences-card">
|
||||
<v-card-title class="text-center justify-center py-6">
|
||||
<h1 class="font-weight-bold text-h2 basil--text">
|
||||
<h1 class="font-weight-bold text-h2 text-basil">
|
||||
Ink/Stitch Settings
|
||||
</h1>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-tabs v-model="tab" background-color="transparent" grow>
|
||||
<v-tabs v-model="tab" bg-color="transparent" class="text-primary" grow>
|
||||
<v-tab key="this_svg_settings">
|
||||
This SVG
|
||||
</v-tab>
|
||||
|
@ -16,16 +25,16 @@
|
|||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<v-tabs-items v-model="tab">
|
||||
<v-tab-item key="this_svg_settings">
|
||||
<v-window v-model="tab">
|
||||
<v-window-item key="this_svg_settings">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<label for="collapse_len_mm" v-on="on" v-bind="attrs"><translate>Minimum jump stitch length</translate></label>
|
||||
<template v-slot:activator="{ props }">
|
||||
<label for="collapse_len_mm" v-bind="props"><translate>Minimum jump stitch length</translate></label>
|
||||
</template>
|
||||
<label for="collapse_len_mm"><translate>Jump stitches smaller than this will be treated as normal stitches.</translate></label>
|
||||
</v-tooltip>
|
||||
|
@ -45,8 +54,8 @@
|
|||
<tr>
|
||||
<td class="label">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<label for="min_stitch_len_mm" v-on="on" v-bind="attrs"><translate>Minimum stitch length</translate></label>
|
||||
<template v-slot:activator="{ props }">
|
||||
<label for="min_stitch_len_mm" v-bind="props"><translate>Minimum stitch length</translate></label>
|
||||
</template>
|
||||
<label for="min_stitch_len_mm"><translate>Drop stitches smaller than this value.</translate></label>
|
||||
</v-tooltip>
|
||||
|
@ -66,16 +75,16 @@
|
|||
</table>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
<v-tab-item key="global_settings">
|
||||
</v-window-item>
|
||||
<v-window-item key="global_settings">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<label for="default_collapse_len_mm" v-on="on" v-bind="attrs"><translate>Default minimum jump stitch length</translate></label>
|
||||
<template v-slot:activator="{ props }">
|
||||
<label for="default_collapse_len_mm" v-bind="props"><translate>Default minimum jump stitch length</translate></label>
|
||||
</template>
|
||||
<label for="default_collapse_len_mm"><translate>Used for new SVGs.</translate></label>
|
||||
</v-tooltip>
|
||||
|
@ -90,8 +99,8 @@
|
|||
<tr>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<label for="default_min_stitch_len_mm" v-on="on" v-bind="attrs"><translate>Default minimum stitch length</translate></label>
|
||||
<template v-slot:activator="{ props }">
|
||||
<label for="default_min_stitch_len_mm" v-bind="props"><translate>Default minimum stitch length</translate></label>
|
||||
</template>
|
||||
<label for="default_min_stitch_len_mm"><translate>Used for new SVGs.</translate></label>
|
||||
</v-tooltip>
|
||||
|
@ -106,8 +115,8 @@
|
|||
<tr>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{on, attrs}">
|
||||
<label for="cache_size" v-on="on" v-bind="attrs"><translate>Stitch plan cache size</translate></label>
|
||||
<template v-slot:activator="{ props }">
|
||||
<label for="cache_size" v-bind="props"><translate>Stitch plan cache size</translate></label>
|
||||
</template>
|
||||
<label for="default_min_stitch_len_mm"><translate>The greater the number, the more stitch plans can be cached, speeding up stitch plan calculation. Default: 100</translate></label>
|
||||
</v-tooltip>
|
||||
|
@ -125,8 +134,8 @@
|
|||
</table>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn text color="primary" @click="close"><translate>done</translate></v-btn>
|
||||
|
@ -136,8 +145,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const inkStitch = require("../../lib/api")
|
||||
|
||||
import { inkStitch } from '../../lib/api.js'
|
||||
export default {
|
||||
name: "Preferences",
|
||||
data: function () {
|
||||
|
@ -202,10 +210,11 @@ td.label {
|
|||
td.preference {
|
||||
padding-right: 4px;
|
||||
padding-left: 16px;
|
||||
max-width: 100px;
|
||||
max-width: 15em;
|
||||
min-width: 8em;
|
||||
}
|
||||
|
||||
td.preference::v-deep input {
|
||||
td.preference :deep(input) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<div class="window-controls">
|
||||
<div ref="controlInfoButton" class="control-info-button" v-on:click="toggleInfo">
|
||||
<font-awesome-icon icon="info"/>
|
||||
<collapse-transition>
|
||||
<Transition name="collapse">
|
||||
<div class="control-info" v-show="infoExpanded" v-bind:style="{'max-height': infoMaxHeight + 'px'}">
|
||||
<h1>
|
||||
<font-awesome-icon icon="info" class="info-icon"/>
|
||||
|
@ -163,14 +163,14 @@
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</collapse-transition>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="toggle-controls" v-on:click="toggleControls">
|
||||
<font-awesome-icon v-if="controlsExpanded" icon="minus"/>
|
||||
<font-awesome-icon v-else icon="plus"/>
|
||||
</div>
|
||||
</div>
|
||||
<collapse-transition>
|
||||
<Transition name="collapse">
|
||||
<div class="panel" v-show="controlsExpanded">
|
||||
<fieldset class="controls">
|
||||
<legend>
|
||||
|
@ -203,7 +203,7 @@
|
|||
</fieldset>
|
||||
<fieldset class="speed">
|
||||
<legend>
|
||||
<translate :translate-n="speed" translate-plural="Speed: %{speed} stitches/sec">Speed: %{speed} stitch/sec</translate>
|
||||
<translate :translate-params="{ speed: speed }" :translate-n="speed" translate-plural="Speed: %{speed} stitches/sec">Speed: %{speed} stitch/sec</translate>
|
||||
</legend>
|
||||
<button v-on:click="animationSlowDown" :title="$gettext('Slow down (arrow down)')">
|
||||
<font-awesome-icon icon="hippo" size="2x" class="fa-button"/>
|
||||
|
@ -248,7 +248,7 @@
|
|||
<input id="stop-checkbox" type="checkbox" v-model="showStops"/>
|
||||
<label for="stop-checkbox"><font-awesome-icon icon="pause"/> <translate>stops</translate></label>
|
||||
</span>
|
||||
<span>
|
||||
<span class="npp">
|
||||
<input id="npp-checkbox" type="checkbox" v-model="showNeedlePenetrationPoints"/>
|
||||
<label for="npp-checkbox">
|
||||
<font-awesome-layers>
|
||||
|
@ -270,12 +270,11 @@
|
|||
</span>
|
||||
</fieldset>
|
||||
</div>
|
||||
</collapse-transition>
|
||||
</Transition>
|
||||
<div class="slider-container">
|
||||
<span>1</span>
|
||||
<span class="slider-box">
|
||||
<vue-slider
|
||||
:value="currentStitchDisplay"
|
||||
<vue-slider v-model="currentStitchDisplay"
|
||||
@change="setCurrentStitch"
|
||||
:min="0"
|
||||
:max="numStitches"
|
||||
|
@ -297,7 +296,7 @@
|
|||
@focus="stop"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<loading :active.sync="loading" :is-full-page="false">
|
||||
<loading :active="loading" :is-full-page="false">
|
||||
<div class="loading">
|
||||
<div class="loading-icon">
|
||||
<font-awesome-icon icon="spinner" size="4x" pulse/>
|
||||
|
|
|
@ -7,111 +7,68 @@
|
|||
*/
|
||||
|
||||
// ES6
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
import App from './App'
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
import {library} from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faAlignRight,
|
||||
faAngleDoubleLeft,
|
||||
faAngleDoubleRight,
|
||||
faAngleRight,
|
||||
faCircle,
|
||||
faCut,
|
||||
faExchangeAlt,
|
||||
faEye,
|
||||
faFrog,
|
||||
faLink,
|
||||
faHippo,
|
||||
faHorse,
|
||||
faInfo,
|
||||
faMinus,
|
||||
faPalette,
|
||||
faPause,
|
||||
faPlay,
|
||||
faPlus,
|
||||
faShoePrints,
|
||||
faSpinner,
|
||||
faStepBackward,
|
||||
faStepForward,
|
||||
faStop,
|
||||
faSearchPlus,
|
||||
faSearchMinus
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import {FontAwesomeIcon, FontAwesomeLayers} from '@fortawesome/vue-fontawesome'
|
||||
import Transitions from 'vue2-transitions'
|
||||
import GetTextPlugin from 'vue-gettext'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { fas } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
|
||||
import { createGettext } from 'vue3-gettext'
|
||||
import translations from './assets/translations.json'
|
||||
import {selectLanguage} from '../lib/i18n'
|
||||
import Vuetify from 'vuetify'
|
||||
import 'vuetify/dist/vuetify.min.css'
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import { selectLanguage } from '../lib/i18n.js'
|
||||
|
||||
// We have to add to the library every icon we use anywhere in the UI.
|
||||
// This avoids the need to bundle the entire font-awesome icon set with
|
||||
// Ink/Stitch.
|
||||
library.add(
|
||||
faAlignRight,
|
||||
faAngleDoubleLeft,
|
||||
faAngleDoubleRight,
|
||||
faAngleRight,
|
||||
faCircle,
|
||||
faCut,
|
||||
faExchangeAlt,
|
||||
faEye,
|
||||
faFrog,
|
||||
faLink,
|
||||
faHippo,
|
||||
faHorse,
|
||||
faInfo,
|
||||
faMinus,
|
||||
faPalette,
|
||||
faPause,
|
||||
faPlay,
|
||||
faPlus,
|
||||
faShoePrints,
|
||||
faSpinner,
|
||||
faStepBackward,
|
||||
faStepForward,
|
||||
faStop,
|
||||
faSearchPlus,
|
||||
faSearchMinus
|
||||
)
|
||||
import flaskserverport from '../lib/flaskserverport.json'
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
Vue.component('font-awesome-layers', FontAwesomeLayers)
|
||||
import { createVuetify, ThemeDefinition } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
import 'vuetify/styles'
|
||||
|
||||
Vue.use(Transitions)
|
||||
Vue.use(GetTextPlugin, {
|
||||
translations: translations,
|
||||
defaultLanguage: selectLanguage(translations),
|
||||
silent: true
|
||||
})
|
||||
import VueMousetrapPlugin from 'vue-mousetrap'
|
||||
|
||||
Vue.http = Vue.prototype.$http = axios
|
||||
Vue.config.productionTip = false
|
||||
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)
|
||||
}
|
||||
|
||||
Vue.use(Vuetify)
|
||||
const vuetify = new Vuetify({
|
||||
theme: {
|
||||
themes: {
|
||||
light: {
|
||||
const inkStitchTheme = {
|
||||
dark: false,
|
||||
colors: {
|
||||
primary: '#003399',
|
||||
secondary: '#000000',
|
||||
accent: '#8c9eff',
|
||||
error: '#b71c1c',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
const vuetify = new createVuetify({
|
||||
components,
|
||||
directives,
|
||||
ssr: true,
|
||||
theme: {
|
||||
defaultTheme: 'inkStitchTheme',
|
||||
themes: {
|
||||
inkStitchTheme,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
vuetify,
|
||||
components: {App},
|
||||
router,
|
||||
template: '<App/>'
|
||||
}).$mount('#app')
|
||||
library.add(fas)
|
||||
const app = createApp(App)
|
||||
app.component('font-awesome-icon', FontAwesomeIcon)
|
||||
app.component('font-awesome-layers', FontAwesomeLayers)
|
||||
|
||||
app.use(createGettext({
|
||||
defaultLanguage: selectLanguage(translations, theflaskport),
|
||||
translations: translations,
|
||||
silent: true,
|
||||
setGlobalProperties: true,
|
||||
}))
|
||||
app.use(VueMousetrapPlugin)
|
||||
app.use(vuetify)
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
|
|
|
@ -5,32 +5,32 @@
|
|||
* Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
routes: [
|
||||
import { createWebHashHistory, createRouter } from 'vue-router'
|
||||
const routes = [
|
||||
{
|
||||
path: '/simulator',
|
||||
name: 'simulator',
|
||||
component: require('@/components/Simulator').default
|
||||
},
|
||||
{
|
||||
path: '/install',
|
||||
name: 'install',
|
||||
component: require('@/components/InstallPalettes').default
|
||||
component: () => import('../components/Simulator.vue')
|
||||
},
|
||||
{
|
||||
path: '/preferences',
|
||||
name: 'preferences',
|
||||
component: require('@/components/Preferences').default
|
||||
component: () => import('../components/Preferences.vue')
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
redirect: '/'
|
||||
}
|
||||
]
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import('../components/NotFound.vue')
|
||||
},
|
||||
]
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
})
|
||||
// Sets title for each routes
|
||||
const DEFAULT_TITLE = 'Ink/Stitch';
|
||||
|
||||
router.beforeEach((to) => {
|
||||
document.title = to.meta.title || DEFAULT_TITLE
|
||||
})
|
||||
export default router
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": ["webpack-env"],
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable", "ScriptHost"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
11337
electron/yarn.lock
11337
electron/yarn.lock
Plik diff jest za duży
Load Diff
|
@ -22,7 +22,7 @@ AppUpdatesURL={#URL}
|
|||
DefaultDirName={userappdata}\inkscape\extensions\
|
||||
DefaultGroupName={#PROGRAMNAME}
|
||||
; Remove the following line to run in administrative install mode (install for all users.)
|
||||
ArchitecturesAllowed=x64 x86
|
||||
ArchitecturesAllowed=x64 x86 arm64
|
||||
PrivilegesRequired=lowest
|
||||
OutputBaseFilename=inkstitch
|
||||
OutputDir=.
|
||||
|
|
|
@ -1,55 +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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from glob import glob
|
||||
|
||||
from flask import Blueprint, jsonify, request
|
||||
|
||||
from ..utils import get_bundled_dir, guess_inkscape_config_path
|
||||
|
||||
install = Blueprint('install', __name__)
|
||||
|
||||
|
||||
@install.route('/palettes', methods=["POST"])
|
||||
def palettes():
|
||||
try:
|
||||
base_path = request.json.get('path') or guess_inkscape_config_path()
|
||||
path = os.path.join(base_path, 'palettes')
|
||||
src_dir = get_bundled_dir('palettes')
|
||||
copy_files(glob(os.path.join(src_dir, "*")), path)
|
||||
except Exception as exc:
|
||||
return jsonify({"error": str(exc)}), 500
|
||||
|
||||
return jsonify({"status": "success"})
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
# If we try to just use shutil.copy it says the operation requires elevation.
|
||||
def copy_files(files, dest):
|
||||
import pythoncom
|
||||
import winutils
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
|
||||
if not os.path.exists(dest):
|
||||
os.makedirs(dest)
|
||||
|
||||
winutils.copy(files, dest)
|
||||
else:
|
||||
def copy_files(files, dest):
|
||||
import shutil
|
||||
|
||||
if not os.path.exists(dest):
|
||||
os.makedirs(dest)
|
||||
|
||||
for palette_file in files:
|
||||
shutil.copy(palette_file, dest)
|
||||
|
||||
|
||||
@install.route('/default-path')
|
||||
def default_path():
|
||||
return guess_inkscape_config_path()
|
|
@ -0,0 +1,11 @@
|
|||
import os
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
|
||||
languages = Blueprint('languages', __name__)
|
||||
|
||||
|
||||
@languages.route('')
|
||||
def get_lang():
|
||||
languages = dict(os.environ)
|
||||
return jsonify(languages)
|
|
@ -15,16 +15,22 @@ def get_page_specs():
|
|||
height = svg.get('height', 0)
|
||||
pagecolor = "white"
|
||||
deskcolor = "white"
|
||||
bordercolor = "black"
|
||||
showpageshadow = True
|
||||
|
||||
namedview = svg.namedview
|
||||
if namedview is not None:
|
||||
pagecolor = namedview.get('pagecolor', pagecolor)
|
||||
deskcolor = namedview.get('inkscape:deskcolor', deskcolor)
|
||||
bordercolor = namedview.get('bordercolor', bordercolor)
|
||||
showpageshadow = namedview.get('inkscape:showpageshadow', showpageshadow)
|
||||
|
||||
page_specs = {
|
||||
"width": width,
|
||||
"height": height,
|
||||
"pagecolor": pagecolor,
|
||||
"deskcolor": deskcolor
|
||||
"deskcolor": deskcolor,
|
||||
"bordercolor": bordercolor,
|
||||
"showpageshadow": showpageshadow
|
||||
}
|
||||
return jsonify(page_specs)
|
||||
|
|
|
@ -9,17 +9,20 @@ import socket
|
|||
import sys
|
||||
import time
|
||||
from threading import Thread
|
||||
from contextlib import closing
|
||||
|
||||
import requests
|
||||
from flask import Flask, g
|
||||
from werkzeug.serving import make_server
|
||||
|
||||
from ..utils.json import InkStitchJSONProvider
|
||||
from .install import install
|
||||
from .simulator import simulator
|
||||
from .stitch_plan import stitch_plan
|
||||
from .preferences import preferences
|
||||
from .page_specs import page_specs
|
||||
from .lang import languages
|
||||
# this for electron axios
|
||||
from flask_cors import CORS
|
||||
|
||||
|
||||
class APIServer(Thread):
|
||||
|
@ -42,13 +45,14 @@ class APIServer(Thread):
|
|||
cli.show_server_banner = lambda *x: None
|
||||
|
||||
self.app = Flask(__name__)
|
||||
CORS(self.app)
|
||||
self.app.json = InkStitchJSONProvider(self.app)
|
||||
|
||||
self.app.register_blueprint(simulator, url_prefix="/simulator")
|
||||
self.app.register_blueprint(stitch_plan, url_prefix="/stitch_plan")
|
||||
self.app.register_blueprint(install, url_prefix="/install")
|
||||
self.app.register_blueprint(preferences, url_prefix="/preferences")
|
||||
self.app.register_blueprint(page_specs, url_prefix="/page_specs")
|
||||
self.app.register_blueprint(languages, url_prefix="/languages")
|
||||
|
||||
@self.app.before_request
|
||||
def store_extension():
|
||||
|
@ -67,25 +71,21 @@ class APIServer(Thread):
|
|||
def disable_logging(self):
|
||||
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
||||
|
||||
# https://github.com/aluo-x/Learning_Neural_Acoustic_Fields/blob/master/train.py
|
||||
# https://github.com/pytorch/pytorch/issues/71029
|
||||
def find_free_port(self):
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||
s.bind(('localhost', 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
def run(self):
|
||||
self.disable_logging()
|
||||
|
||||
self.host = "127.0.0.1"
|
||||
self.port = 5000
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.port = self.find_free_port()
|
||||
self.flask_server = make_server(self.host, self.port, self.app)
|
||||
self.server_thread = Thread(target=self.flask_server.serve_forever)
|
||||
self.server_thread.start()
|
||||
except socket.error as e:
|
||||
if e.errno == errno.EADDRINUSE:
|
||||
self.port += 1
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
break
|
||||
|
||||
def ready_checker(self):
|
||||
"""Wait until the server is started.
|
||||
|
|
|
@ -4,18 +4,48 @@
|
|||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from .base import InkstitchExtension
|
||||
from ..api import APIServer
|
||||
from ..gui import open_url
|
||||
import os
|
||||
import sys
|
||||
from glob import glob
|
||||
from ..utils import get_bundled_dir, guess_inkscape_config_path
|
||||
from inkex import errormsg
|
||||
from ..i18n import _
|
||||
|
||||
|
||||
class Install(InkstitchExtension):
|
||||
def __init__(self):
|
||||
InkstitchExtension.__init__(self)
|
||||
def __init__(self, *args, **kwargs):
|
||||
InkstitchExtension.__init__(self, *args, **kwargs)
|
||||
|
||||
def effect(self):
|
||||
api_server = APIServer(self)
|
||||
port = api_server.start_server()
|
||||
electron = open_url("/install?port=%d" % port)
|
||||
electron.wait()
|
||||
api_server.stop()
|
||||
api_server.join()
|
||||
path = os.path.join(guess_inkscape_config_path(), 'palettes')
|
||||
src_dir = get_bundled_dir('palettes')
|
||||
try:
|
||||
copy_files(glob(os.path.join(src_dir, "*")), path)
|
||||
errormsg(_("Successfully installed color palettes for Inkscape.\n\n"
|
||||
"Please restart Inkscape."))
|
||||
except IOError:
|
||||
errormsg(_("Could not install color palettes. Please file an issue on "
|
||||
"https://github.com/inkstitch/inkstitch/issues"))
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
# If we try to just use shutil.copy it says the operation requires elevation.
|
||||
def copy_files(files, dest):
|
||||
import pythoncom
|
||||
import winutils
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
|
||||
if not os.path.exists(dest):
|
||||
os.makedirs(dest)
|
||||
|
||||
winutils.copy(files, dest)
|
||||
else:
|
||||
def copy_files(files, dest):
|
||||
import shutil
|
||||
|
||||
if not os.path.exists(dest):
|
||||
os.makedirs(dest)
|
||||
|
||||
for palette_file in files:
|
||||
shutil.copy(palette_file, dest)
|
||||
|
|
|
@ -27,7 +27,7 @@ class Preferences(InkstitchExtension):
|
|||
def effect(self):
|
||||
api_server = APIServer(self)
|
||||
port = api_server.start_server()
|
||||
electron = open_url("/preferences?port=%d" % port)
|
||||
electron = open_url("/preferences", port)
|
||||
electron.wait()
|
||||
api_server.stop()
|
||||
api_server.join()
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
@ -13,6 +12,7 @@ import time
|
|||
from copy import deepcopy
|
||||
from datetime import date
|
||||
from threading import Thread
|
||||
from contextlib import closing
|
||||
|
||||
import appdirs
|
||||
from flask import Flask, Response, jsonify, request, send_from_directory
|
||||
|
@ -162,25 +162,24 @@ class PrintPreviewServer(Thread):
|
|||
def disable_logging(self):
|
||||
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
||||
|
||||
# https://github.com/aluo-x/Learning_Neural_Acoustic_Fields/blob/master/train.py
|
||||
# https://github.com/pytorch/pytorch/issues/71029
|
||||
def find_free_port(self):
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||
s.bind(('localhost', 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
def run(self):
|
||||
self.disable_logging()
|
||||
|
||||
self.host = "127.0.0.1"
|
||||
self.port = 5000
|
||||
self.port = self.find_free_port()
|
||||
# exporting the port number for languages to work in electron vuejs part of inkstitch
|
||||
os.environ['FLASKPORT'] = str(self.port)
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.flask_server = make_server(self.host, self.port, self.app)
|
||||
self.server_thread = Thread(target=self.flask_server.serve_forever)
|
||||
self.server_thread.start()
|
||||
except socket.error as e:
|
||||
if e.errno == errno.EADDRINUSE:
|
||||
self.port += 1
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
class Print(InkstitchExtension):
|
||||
|
@ -331,13 +330,12 @@ class Print(InkstitchExtension):
|
|||
realistic_color_block_svgs=realistic_color_block_svgs
|
||||
)
|
||||
print_server.start()
|
||||
|
||||
# Wait for print_server.host and print_server.port to be populated.
|
||||
# Hacky, but Flask doesn't have an option for a callback to be run
|
||||
# after startup.
|
||||
time.sleep(0.5)
|
||||
|
||||
browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port))
|
||||
browser_window = open_url(print_server.host, print_server.port, True)
|
||||
browser_window.wait()
|
||||
print_server.stop()
|
||||
print_server.join()
|
||||
|
|
|
@ -18,7 +18,7 @@ class Simulator(InkstitchExtension):
|
|||
return
|
||||
api_server = APIServer(self)
|
||||
port = api_server.start_server()
|
||||
electron = open_url("/simulator?port=%d" % port)
|
||||
electron = open_url("/simulator", port)
|
||||
electron.wait()
|
||||
api_server.stop()
|
||||
api_server.join()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -12,11 +13,27 @@ from ..utils import get_bundled_dir
|
|||
app_process = None
|
||||
|
||||
|
||||
def open_url(url):
|
||||
def open_url(url, port, pdf=False): # noqa: C901
|
||||
global app
|
||||
|
||||
command = []
|
||||
if not pdf:
|
||||
url = f'{url}?port={port}'
|
||||
os.environ['FLASKPORT'] = str(port)
|
||||
|
||||
# this creates the .json for dev mode to get translations
|
||||
if getattr(sys, 'frozen', None) is None:
|
||||
dynamic_port = {
|
||||
"_comment1": "port should not be declared when commiting",
|
||||
"port": port,
|
||||
}
|
||||
port_object = json.dumps(dynamic_port, indent=1)
|
||||
with open(os.path.join("electron/src/lib/flaskserverport.json"), "w") as outfile:
|
||||
outfile.write(port_object)
|
||||
else:
|
||||
url = f'http://{url}:{port}/'
|
||||
|
||||
cwd = None
|
||||
searchstring = "http"
|
||||
|
||||
if getattr(sys, 'frozen', None) is not None:
|
||||
electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui")
|
||||
|
@ -42,8 +59,33 @@ def open_url(url):
|
|||
pass
|
||||
else:
|
||||
mac_dev_env["PATH"] = yarn_path + mac_dev_env["PATH"]
|
||||
# checking URL for flask server address for printToPDF
|
||||
if searchstring in url:
|
||||
with open(os.devnull, 'w') as null:
|
||||
subprocess.Popen(["yarn", "just-build"], cwd=cwd, stdout=null, env=mac_dev_env).wait()
|
||||
else:
|
||||
pass
|
||||
|
||||
with open(os.devnull, 'w') as null:
|
||||
return subprocess.Popen(command, cwd=cwd, stdout=null, env=mac_dev_env)
|
||||
else:
|
||||
if searchstring in url and getattr(sys, 'frozen', None) is None:
|
||||
with open(os.devnull, 'w') as null:
|
||||
subprocess.Popen(["yarn", "just-build"], cwd=cwd, stdout=null).wait()
|
||||
else:
|
||||
pass
|
||||
if sys.platform == "linux":
|
||||
# Pyinstaller fix for gnome document view not opening.
|
||||
lenv = dict(os.environ)
|
||||
lp_key = 'LD_LIBRARY_PATH'
|
||||
lp_orig = lenv.get(lp_key + '_ORIG')
|
||||
if lp_orig is not None:
|
||||
lenv[lp_key] = lp_orig # restore the original, unmodified value
|
||||
else:
|
||||
lenv.pop(lp_key, None)
|
||||
|
||||
with open(os.devnull, 'w') as null:
|
||||
return subprocess.Popen(command, cwd=cwd, stdout=null, env=lenv)
|
||||
else:
|
||||
with open(os.devnull, 'w') as null:
|
||||
return subprocess.Popen(command, cwd=cwd, stdout=null)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
var electron = require('electron');
|
||||
|
||||
$.postJSON = function(url, data, success=null) {
|
||||
return $.ajax(url, {
|
||||
type: 'POST',
|
||||
|
@ -379,12 +377,12 @@ $(function() {
|
|||
|
||||
$('button.print').click(function() {
|
||||
var pageSize = $('select#printing-size').find(':selected').text();
|
||||
electron.ipcRenderer.send('open-pdf', pageSize)
|
||||
window.inkstitchAPI.openpdf(pageSize)
|
||||
});
|
||||
|
||||
$('button.save-pdf').click(function() {
|
||||
var pageSize = $('select#printing-size').find(':selected').text();
|
||||
electron.ipcRenderer.send('save-pdf', pageSize)
|
||||
window.inkstitchAPI.savepdf(pageSize)
|
||||
});
|
||||
|
||||
$('button.settings').click(function(){
|
||||
|
|
|
@ -27,6 +27,6 @@ fonttools
|
|||
trimesh>=3.15.2
|
||||
scipy
|
||||
diskcache
|
||||
|
||||
flask-cors
|
||||
pywinutils ; sys_platform == 'win32'
|
||||
pywin32 ; sys_platform == 'win32'
|
||||
|
|
Ładowanie…
Reference in New Issue