From 51e5319c907ad603dae325dbaef2986e6126adcc Mon Sep 17 00:00:00 2001 From: Jacek Pietal Date: Thu, 27 Jun 2019 22:34:14 +0200 Subject: [PATCH 01/59] version 0.2.0 Squashed commit of the following: commit 24789137ed2b664e77bd245ddb17a409cb2377b4 Author: Jacek Pietal Date: Wed Jun 26 23:32:54 2019 +0200 minor commit 6dd5f97947d2bcb08acf19bbbbca58c2425b2c6c Author: Jacek Pietal Date: Wed Jun 26 23:14:02 2019 +0200 minor commit b47c0522b25e60c7913c2f7f1eb49dfbaed10dc7 Author: Jacek Pietal Date: Wed Jun 26 23:06:28 2019 +0200 patch commit 239a5860fbe20283085df579a3e73f28b54634e0 Author: Jacek Pietal Date: Wed Jun 26 22:55:17 2019 +0200 features: code coloring and transpiled in popup commit 40e2dd0dfd3677d4524de1290612026ded97bee1 Author: Jacek Pietal Date: Wed Jun 26 20:35:53 2019 +0200 more css commit 7fb4e8ca406b40fa1df1d068152038f8e4e6b094 Author: Jacek Pietal Date: Wed Jun 26 09:22:31 2019 +0200 migrate all dependencies to latest -- temporarily broken pan resize commit 36a6de16cf300490561612f036d4c4ccc1d227d3 Author: Jacek Pietal Date: Tue Jun 25 23:23:16 2019 +0200 remove 1 dependency, fix build commit 785ca6f69dd5d7ec2514a79203c07c518d6f0960 Merge: de3af94 24621eb Author: Jacek Pietal Date: Tue Jun 25 23:16:43 2019 +0200 Merge branch 'master' into prozi commit de3af945cd565add75df03a49e81063806a11a19 Author: Jacek Pietal Date: Tue Jun 25 23:11:04 2019 +0200 minor commit 627777eb8c829f5b18a874b324ae8e50b8882b8c Author: Jacek Pietal Date: Tue Jun 25 23:09:16 2019 +0200 moar updatez commit d552af29be2eb84e9191aa2337b501647e093077 Author: Jacek Pietal Date: Tue Jun 25 22:50:29 2019 +0200 cleanup commit 9eb9214733f113f4fc8448fe4a7561a69f6a95c4 Author: Jacek Pietal Date: Tue Jun 25 22:46:43 2019 +0200 bump-fix commit 3a5ae9069528f2f8a7f02bda673836fd67d00776 Author: Jacek Pietal Date: Tue Jun 25 22:10:57 2019 +0200 fix pan resize commit bf6580a4d8737579371f971932bbfff1584ff229 Author: Jacek Pietal Date: Tue Jun 25 21:49:07 2019 +0200 minor commit c2e9e4e337990ad30a2a7e4b9481983bbb9f1c87 Author: Jacek Pietal Date: Tue Jun 25 21:41:51 2019 +0200 more updats to gfx / rwd commit ea84723ad6e31e6f64bc7a52297a7ed1b559ddf6 Author: Jacek Pietal Date: Mon Jun 24 23:45:15 2019 +0200 update push script commit 4bcb509ebac9ba05077f98c6ebebb4fe04be87c3 Author: Jacek Pietal Date: Mon Jun 24 20:11:12 2019 +0200 split header into vue components + immense update to gfx (cherry picked from commit dff3fe6bd2722b36bd23e29dcca21abb12a67aec) commit 088f4b7a53cc789c8d305b38d674edeb9606bc29 Author: Jacek Pietal Date: Mon Jun 24 09:38:14 2019 +0200 rwd (cherry picked from commit bd578f4c3c38a07d6c6068e7004f7529de7709e6) commit 77541e7c5881b5fc68b394832385b79ab4cae19b Author: Jacek Pietal Date: Mon Jun 24 09:37:03 2019 +0200 more-css (cherry picked from commit 1277b6dcd50dc9598b31c648c7ce56c3c307ca4e) commit fca2c76d0a5da948bca8b4a2e6b891c1f3a6dbc9 Author: Jacek Pietal Date: Mon Jun 24 09:26:27 2019 +0200 script commit c8000fa36525926894307057a616c7abb7ea2ae6 Author: Jacek Pietal Date: Mon Jun 24 09:21:35 2019 +0200 apply post review fixes (cherry picked from commit 0befd49f04fe020e6c816a8880d71e4e82ab302b) commit eeae7740a55806146eee6e3444cce871655ad494 Author: Jacek Pietal Date: Mon Jun 24 09:15:19 2019 +0200 correct-css commit e3b232f138d438924df0f0fe555b34f5b68d6901 Author: Jacek Pietal Date: Mon Jun 24 00:18:06 2019 +0200 poi start script commit b5bd1d6386c9ea0bcc0d83d0157ea748d1ea408f Author: Jacek Pietal Date: Mon Jun 24 00:09:51 2019 +0200 add dep commit 1505dfbcbb5d56b43da3900eea34195ea83ca02a Author: Jacek Pietal Date: Mon Jun 24 00:05:46 2019 +0200 for heroku, scripts commit d4ebb6bced77f5cc7b9c2b8f433b66851be013fa Author: Jacek Pietal Date: Sun Jun 23 23:10:15 2019 +0200 minor (cherry picked from commit ae5bd0627c4b44b1052a1df7a8f026795bddede4) commit b499cdcc3b07218ca18884c999edf15a19c89345 Author: Jacek Pietal Date: Sun Jun 23 22:49:27 2019 +0200 bag-of-css-changes commit 471f003a984fcfca6b5acbdfd0e872a74f1516d0 Author: Jacek Pietal Date: Sun Jun 23 21:37:22 2019 +0200 codepan-pixi-update commit bd3e5ace33bc0c448ee159539c99e16a0da3ac71 Author: Jacek Pietal Date: Sun Jun 23 20:32:30 2019 +0200 pixi-boilerplate-1.1.0 commit ed4c958d86e312768505905c8cf76b1be34317b6 Author: Jacek Pietal Date: Sun Jun 23 14:08:50 2019 +0200 moar updates commit b79ad90e2eba04cc3bcaa63ec91764244cd3363f Author: Jacek Pietal Date: Sun Jun 23 14:06:16 2019 +0200 make example work again lol commit d73808af26a104803fa762a2760c65bc5f483de2 Author: Jacek Pietal Date: Sun Jun 23 13:46:36 2019 +0200 adjust example to be more universal commit c34e6918cd621e993d91e499ea7642cf44b6c027 Author: Jacek Pietal Date: Sat Jun 22 19:40:32 2019 +0200 boilerplate: pixi (cherry picked from commit 1287e5b6bda424289ab09fc00b97b0006a5343b8) commit d9b307092a1cdf96644eebd87a72e001ad8e9d74 Author: Jacek Pietal Date: Sun Jun 23 11:46:53 2019 +0200 fix linting errors commit 6c47346fe38f8ba00453e1435c06512521e70fdb Author: Jacek Pietal Date: Sun Jun 23 11:40:11 2019 +0200 string-replace commit d8baa593d8a3539cf674027acebb79a83f55420f Author: Jacek Pietal Date: Fri Jun 21 19:21:56 2019 +0200 corner case with `%c` without further characters commit 6f67042b64686fe54372e22e707e5ac129eafbc3 Author: Jacek Pietal Date: Fri Jun 21 18:42:19 2019 +0200 add %c handling to console, add color support for proxy console --- .eslintignore | 2 + .eslintrc.js | 18 + index.ejs | 2 + package.json | 133 +- poi.config.js | 86 +- src/boilerplates/pixi/codepan.js | 23 +- src/boilerplates/pixi/index.js | 2 +- src/boilerplates/rxjs/codepan.js | 4 +- src/components/App.vue | 387 +- src/components/CSSPan.vue | 3 +- src/components/CompiledCodeDialog.vue | 59 +- src/components/ConsolePan.vue | 119 +- src/components/HTMLPan.vue | 19 +- src/components/Highlight.js | 11 - src/components/HomeHeader.vue | 445 +- src/components/JSPan.vue | 21 +- src/components/OutputPan.vue | 92 +- src/components/PanResizer.vue | 173 +- src/components/header/AddBoilerplate.vue | 41 + src/components/header/AddLibrary.vue | 50 + src/components/header/AutorunButton.vue | 27 + src/components/header/PanToggles.vue | 62 + src/components/header/RunButton.vue | 48 + src/components/header/SaveGist.vue | 102 + src/components/header/UploadOptions.vue | 204 + src/index.js | 7 +- src/polyfill.js | 1 + src/router/index.js | 2 +- src/store/index.js | 17 +- src/utils/create-editor.js | 31 +- src/utils/create-pan.js | 25 +- src/utils/get-scripts.js | 1 + src/utils/github-api.js | 10 +- src/utils/highlight.js | 2 + src/utils/iframe.js | 1 + src/utils/pan-position.js | 23 +- src/utils/proxy-console.js | 45 +- src/utils/transform.js | 97 +- src/views/EditorPage.vue | 177 +- src/views/GitHubSuccess.vue | 1 - yarn.lock | 10172 +++++++++++++-------- 41 files changed, 7853 insertions(+), 4892 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.js delete mode 100644 src/components/Highlight.js create mode 100644 src/components/header/AddBoilerplate.vue create mode 100644 src/components/header/AddLibrary.vue create mode 100644 src/components/header/AutorunButton.vue create mode 100644 src/components/header/PanToggles.vue create mode 100644 src/components/header/RunButton.vue create mode 100644 src/components/header/SaveGist.vue create mode 100644 src/components/header/UploadOptions.vue diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0b74c70 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +src/boilerplates/** + diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4d7fb8f --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { + node: true + }, + extends: ["plugin:vue/essential", "eslint:recommended"], + rules: { + "no-console": process.env.NODE_ENV === "production" ? "error" : "off", + "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", + indent: ["error", 2], + "object-curly-spacing": ["error", "always"], + semi: ["error", "never"], + quotes: ["error", "single", { allowTemplateLiterals: true }] + }, + parserOptions: { + parser: "babel-eslint" + } +}; diff --git a/index.ejs b/index.ejs index df82a39..50e6b91 100644 --- a/index.ejs +++ b/index.ejs @@ -69,6 +69,8 @@ headwayScript.src = 'https://cdn.headwayapp.co/widget.js' headwayScript.async = true document.body.appendChild(headwayScript) + var element = document.querySelector(HW_config.selector) + element && (element.style.display = 'inline-block') } diff --git a/package.json b/package.json index 9fba9e7..32f4626 100644 --- a/package.json +++ b/package.json @@ -6,101 +6,74 @@ "details": "CodePan is where people prototype front-end apps, you are free to use it offline anytime anywhere.", "main": "src/index.js", "homepage": "https://codepan.net/", - "version": "0.1.0", + "version": "0.2.0", "repository": {}, "scripts": { "test": "npm run lint", - "lint": "xo", - "dev": "poi", - "build": "poi build", + "lint": "eslint --ext=.vue,.js -c .eslintrc.js src ./*.js", + "dev": "poi --serve", "deploy": "surge -p dist -d codepan.net", - "predeploy": "npm run build && cp dist/index.html dist/200.html", - "report": "poi build --bundle-report" - }, - "xo": { - "parser": "babel-eslint", - "extends": [ - "rem" - ], - "envs": [ - "browser" - ], - "extensions": [ - "vue" - ], - "plugins": [ - "html" - ], - "rules": { - "no-new": 0, - "import/no-unresolved": 0, - "import/no-extraneous-dependencies": 0, - "import/no-unassigned-import": 0, - "no-warning-comments": 0, - "import/prefer-default-export": 0, - "no-multi-assign": 0, - "complexity": 0, - "guard-for-in": 0, - "unicorn/filename-case": 0, - "import/no-webpack-loader-syntax": 0, - "unicorn/no-abusive-eslint-disable": 0, - "no-case-declarations": 0 - }, - "ignores": [ - "src/boilerplates/**", - "src/utils/vue-jsx-merge-props.js", - "static/**" - ] + "build": "NODE_ENV=production poi --prod && cp dist/index.html dist/200.html", + "start": "http-server dist -p$PORT" }, "devDependencies": { - "babel-eslint": "^7.2.3", - "babel-plugin-component": "^0.10.0", + "@babel/core": "^7.4.5", + "@babel/polyfill": "^7.4.4", + "@poi/plugin-vue-static": "^12.0.7", + "axios": "^0.19.0", + "babel-eslint": "^10.0.2", + "babel-plugin-component": "^1.1.1", "babel-preset-babili": "^0.1.4", - "buble-loader": "^0.4.1", - "eslint-config-rem": "^3.2.0", - "eslint-plugin-html": "^3.2.0", - "gh-pages": "^1.0.0", - "less": "^2.7.3", - "offline-plugin": "^4.8.3", - "poi": "^9.6.7", - "poi-preset-babel-minify": "^1.0.3", - "poi-preset-bundle-report": "^2.0.1", - "poi-preset-offline": "^9.0.3", - "raw-loader": "^0.5.1", - "repo-latest-commit": "^1.0.0", - "stylus": "^0.54.5", - "stylus-loader": "^3.0.1", - "surge": "^0.19.0", - "webpack-node-modules": "^0.1.1", - "xo": "^0.18.2" - }, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.0.0-beta.32", - "axios": "^0.16.2", - "babel-preset-vue": "^2.0.0", + "babel-preset-poi": "^10.0.2", + "babel-preset-vue": "^2.0.2", + "buble": "^0.19.7", + "buble-loader": "^0.5.1", "cm-highlight": "^0.1.1", - "codemirror": "^5.28.0", + "codemirror": "^5.48.0", "codemirror-emmet": "^1.0.0", - "debounce": "^1.0.2", - "element-ui": "^2.0.11", - "is-electron": "^2.1.0", - "loadjs": "^3.5.1", - "marked3": "^0.5.1", + "debounce": "^1.2.0", + "element-ui": "^2.10.0", + "eslint-config-rem": "^4.0.0", + "eslint-config-vue-preset": "^0.1.0", + "eslint-config-xo-vue": "^1.1.0", + "eslint-plugin-html": "^5.0.5", + "eslint-plugin-vue": "^5.2.3", + "gh-pages": "^2.0.1", + "is-electron": "^2.2.0", + "less": "^3.9.0", + "loadjs": "^3.6.1", + "marked3": "^0.5.2", "notie": "^4.3.1", "nprogress": "^0.2.0", "object-assign": "^4.1.1", + "offline-plugin": "^5.0.7", "parse-package-name": "^0.1.0", - "pify": "^3.0.0", - "promise-polyfill": "^6.0.2", + "pify": "^4.0.1", + "poi": "^12.6.10", + "poi-preset-babel-minify": "^1.0.3", + "poi-preset-bundle-report": "^2.0.2", + "poi-preset-offline": "^9.0.3", + "promise-polyfill": "^8.1.3", + "raw-loader": "^3.0.0", + "react": "^16.8.6", "reqjs": "^1.0.3", - "svelte": "^1.30.0", - "v-tippy": "^1.0.0", - "vue-feather-icons": "^4.5.0", - "vue-ga": "^1.0.0", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.2", + "surge": "^0.21.3", + "svelte": "^3.6.1", + "v-tippy": "^2.0.0", + "vue": "^2.6.10", + "vue-feather-icons": "^4.22.0", + "vue-ga": "^1.1.0", "vue-inline": "^1.0.1", - "vue-router": "^2.7.0", + "vue-router": "^3.0.6", "vue-slim-modal": "^1.0.4", - "vuex": "^2.3.1" + "vue-template-compiler": "^2.6.10", + "vuex": "^3.1.1", + "webpack-node-modules": "^0.1.1" + }, + "license": "MIT", + "dependencies": { + "http-server": "^0.11.1" } } diff --git a/poi.config.js b/poi.config.js index ac9bc7e..ef2e913 100644 --- a/poi.config.js +++ b/poi.config.js @@ -1,43 +1,46 @@ +const { execSync } = require('child_process') const nodeModules = require('webpack-node-modules') -const repoLatestCommit = require('repo-latest-commit') const pkg = require('./package') +const LATEST_COMMIT = execSync( + 'if [ -d ".git" ]; then git rev-parse HEAD; else echo unknown; fi', + { + encoding: 'utf8' + } +).slice(0, 7) + const cdns = { - BABEL_CDN: 'https://cdn.jsdelivr.net/npm/@babel/standalone@7.0.0-beta.32/babel.min.js', + BABEL_CDN: + 'https://cdn.jsdelivr.net/npm/@babel/standalone@7.0.0-beta.32/babel.min.js', PUG_CDN: 'https://cdn.jsdelivr.net/npm/browserified-pug@0.3.0/index.js', - CSSNEXT_CDN: 'https://cdn.jsdelivr.net/npm/browserified-postcss-cssnext@0.3.0/index.js', - POSTCSS_CDN: 'https://cdn.jsdelivr.net/npm/browserified-postcss@0.3.0/index.js', - TYPESCRIPT_CDN: 'https://cdn.jsdelivr.net/npm/browserified-typescript@0.3.0/index.js' + CSSNEXT_CDN: + 'https://cdn.jsdelivr.net/npm/browserified-postcss-cssnext@0.3.0/index.js', + POSTCSS_CDN: + 'https://cdn.jsdelivr.net/npm/browserified-postcss@0.3.0/index.js', + TYPESCRIPT_CDN: + 'https://cdn.jsdelivr.net/npm/browserified-typescript@0.3.0/index.js' } module.exports = { - extendWebpack(config) { - config.module.set('noParse', /babel-preset-vue/) - - config.module.rule('js') - .include - .add(nodeModules()) - + entry: './src/index.js', + output: { + sourceMap: false, + publicUrl: '/' + }, + chainWebpack(config) { + config.module.set('noParse', /babel-preset-poi/) + config.module.rule('js').include.add(nodeModules()) config.node.set('fs', 'empty') - config.externals({ electron: 'commonjs electron' }) }, - production: { - sourceMap: false - }, - hash: false, - homepage: '/', - env: Object.assign({ - VERSION: `v${pkg.version}-${repoLatestCommit().commit.slice(0, 7)}`, - LATEST_COMMIT: repoLatestCommit().commit.slice(0, 7) - }, cdns), - presets: [ - require('poi-preset-bundle-report')(), - require('poi-preset-babel-minify')(), - require('poi-preset-offline')({ - pluginOptions: { + plugins: [ + { resolve: 'poi-preset-bundle-report' }, + { resolve: 'poi-preset-babel-minify', options: { removeUndefined: false } }, + { + resolve: 'poi-preset-offline', + options: { version: '[hash]', autoUpdate: true, safeToUseOptionalCaches: true, @@ -54,22 +57,19 @@ module.exports = { events: true, FALLBACK: { '/': '/' } }, - externals: [].concat(Object.keys(cdns).reduce((res, name) => { - return res.concat(cdns[name]) - }, [])) + externals: [].concat( + Object.keys(cdns).reduce((res, name) => { + return res.concat(cdns[name]) + }, []) + ) } - }) + } ], - babel: { - babelrc: false, - presets: [ - require.resolve('babel-preset-poi') - ], - plugins: [[require.resolve('babel-plugin-component'), [ - { - libraryName: 'element-ui', - styleLibraryName: 'theme-chalk' - } - ]]] - } + envs: Object.assign( + { + VERSION: `v${pkg.version}-${LATEST_COMMIT}`, + LATEST_COMMIT + }, + cdns + ) } diff --git a/src/boilerplates/pixi/codepan.js b/src/boilerplates/pixi/codepan.js index a887371..352b601 100644 --- a/src/boilerplates/pixi/codepan.js +++ b/src/boilerplates/pixi/codepan.js @@ -1,22 +1,21 @@ -const sprite = createSprite() -const app = createApp() +const sprite = createSprite(); +const app = createApp(); function createSprite() { - const sprite = PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png') - sprite.anchor.set(0.5) - sprite.scale.set(3) - return sprite + const bunny = 'https://pixijs.io/examples/examples/assets/bunny.png' + const sprite = PIXI.Sprite.from(bunny); + sprite.anchor.set(0.5); + sprite.scale.set(3); + return sprite; } function createApp() { - return new PIXI.Tiled.FullscreenApplication(tick, { - backgroundColor: 0xffffff - }) + return new PIXI.Tiled.FullscreenApplication(tick, { transparent: true }); } function tick(time) { - sprite.position.set(innerWidth / 2, innerHeight / 2) - sprite.rotation = time / 100 + sprite.position.set(innerWidth / 2, innerHeight / 2); + sprite.rotation = time / 100; } -app.stage.addChild(sprite) +app.stage.addChild(sprite); diff --git a/src/boilerplates/pixi/index.js b/src/boilerplates/pixi/index.js index ef42068..f050231 100644 --- a/src/boilerplates/pixi/index.js +++ b/src/boilerplates/pixi/index.js @@ -7,7 +7,7 @@ export default async () => { return { js: { code: jsCode, - transformer: 'js' + transformer: 'jsx' }, html: { code: htmlCode, diff --git a/src/boilerplates/rxjs/codepan.js b/src/boilerplates/rxjs/codepan.js index 0fb36ce..9a2f5d1 100644 --- a/src/boilerplates/rxjs/codepan.js +++ b/src/boilerplates/rxjs/codepan.js @@ -3,6 +3,6 @@ in this case we will emit first value after 1 second and subsequent values every 2 seconds after */ -const source = Rx.Observable.timer(1000, 2000); +const source = Rx.Observable.timer(1000, 2000) //output: 0,1,2,3,4,5...... -const subscribe = source.subscribe(val => console.log(val)); +const subscribe = source.subscribe(val => console.log(val)) diff --git a/src/components/App.vue b/src/components/App.vue index 8c6d523..17fe404 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -1,13 +1,13 @@ @@ -15,71 +15,318 @@ - diff --git a/src/components/CSSPan.vue b/src/components/CSSPan.vue index e051aa2..2114984 100644 --- a/src/components/CSSPan.vue +++ b/src/components/CSSPan.vue @@ -22,8 +22,7 @@ - - + diff --git a/src/components/CompiledCodeDialog.vue b/src/components/CompiledCodeDialog.vue index d760a15..0a43907 100644 --- a/src/components/CompiledCodeDialog.vue +++ b/src/components/CompiledCodeDialog.vue @@ -2,11 +2,13 @@ + :click-outside="() => $emit('update:show', false)" + > - {{ transforming ? 'Compiling..' : transformedCode }} + Compiled with {{ transformerName }} + +
   
 
 
@@ -16,7 +18,7 @@ import { mapActions, mapState } from 'vuex'
 import { RepeatIcon } from 'vue-feather-icons'
 import { getHumanlizedTransformerName } from '@/utils'
 import * as transform from '@/utils/transform'
-import Highlight from './Highlight'
+import CodeMirror from '@/utils/highlight'
 
 export default {
   name: 'compiled-code-dialog',
@@ -31,7 +33,8 @@ export default {
       if (!show) return
       await this.transform(true)
       try {
-        this.transformedCode = await transform[this.type](this.code)
+        const code = await transform[this.type](this.code)
+        this.transformedCode = CodeMirror.highlight(code, { mode: this.highlight, theme: 'default' })
       } catch (err) {
         const message = `compiler error: ${err.message}`
         this.addLog({ type: 'error', message })
@@ -55,32 +58,38 @@ export default {
   },
   components: {
     Modal,
-    Highlight,
     RepeatIcon
   }
 }
 
 
 
diff --git a/src/components/ConsolePan.vue b/src/components/ConsolePan.vue
index d9df33b..f6a721b 100644
--- a/src/components/ConsolePan.vue
+++ b/src/components/ConsolePan.vue
@@ -1,22 +1,8 @@
 
 
 
 
 
diff --git a/src/components/HTMLPan.vue b/src/components/HTMLPan.vue
index 626d4f5..a2e5a3e 100644
--- a/src/components/HTMLPan.vue
+++ b/src/components/HTMLPan.vue
@@ -18,19 +18,18 @@
 
       
     
-    
-    
+    
   
 
 
 
diff --git a/src/components/Highlight.js b/src/components/Highlight.js
deleted file mode 100644
index 68a3993..0000000
--- a/src/components/Highlight.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import highlight from 'cm-highlight'
-
-export default {
-  name: 'highlight',
-  functional: true,
-  render(h, ctx) {
-    const { theme = 'default', mode = 'javascript' } = ctx.props
-    const code = highlight(ctx.props.code || ctx.children[0].text, { mode })
-    return 
- } -} diff --git a/src/components/HomeHeader.vue b/src/components/HomeHeader.vue index 05246ef..68ec66c 100644 --- a/src/components/HomeHeader.vue +++ b/src/components/HomeHeader.vue @@ -1,407 +1,60 @@ diff --git a/src/components/JSPan.vue b/src/components/JSPan.vue index aab1989..9114c72 100644 --- a/src/components/JSPan.vue +++ b/src/components/JSPan.vue @@ -24,20 +24,19 @@ - - + diff --git a/src/components/OutputPan.vue b/src/components/OutputPan.vue index 1b6cf75..42017db 100644 --- a/src/components/OutputPan.vue +++ b/src/components/OutputPan.vue @@ -1,13 +1,6 @@ diff --git a/src/components/header/AddBoilerplate.vue b/src/components/header/AddBoilerplate.vue new file mode 100644 index 0000000..ea4f720 --- /dev/null +++ b/src/components/header/AddBoilerplate.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/header/AddLibrary.vue b/src/components/header/AddLibrary.vue new file mode 100644 index 0000000..68a6f93 --- /dev/null +++ b/src/components/header/AddLibrary.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/components/header/AutorunButton.vue b/src/components/header/AutorunButton.vue new file mode 100644 index 0000000..23cb599 --- /dev/null +++ b/src/components/header/AutorunButton.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/header/PanToggles.vue b/src/components/header/PanToggles.vue new file mode 100644 index 0000000..6d4d3a7 --- /dev/null +++ b/src/components/header/PanToggles.vue @@ -0,0 +1,62 @@ + + + + + \ No newline at end of file diff --git a/src/components/header/RunButton.vue b/src/components/header/RunButton.vue new file mode 100644 index 0000000..ca2dc6e --- /dev/null +++ b/src/components/header/RunButton.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/components/header/SaveGist.vue b/src/components/header/SaveGist.vue new file mode 100644 index 0000000..da77594 --- /dev/null +++ b/src/components/header/SaveGist.vue @@ -0,0 +1,102 @@ + + + diff --git a/src/components/header/UploadOptions.vue b/src/components/header/UploadOptions.vue new file mode 100644 index 0000000..f1041e9 --- /dev/null +++ b/src/components/header/UploadOptions.vue @@ -0,0 +1,204 @@ + + + + + + diff --git a/src/index.js b/src/index.js index 1b72674..1fac290 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,16 @@ import './polyfill' import Vue from 'vue' import Tippy from 'v-tippy' -// @ is the path to `./src` folder -import App from '@/components/App' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-chalk/index.css' + +import App from '@/components/App.vue' import router from '@/router' import store from '@/store' Vue.config.productionTip = false +Vue.use(ElementUI) Vue.use(Tippy, { position: 'bottom' }) diff --git a/src/polyfill.js b/src/polyfill.js index 817286a..eb7b56e 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -1,3 +1,4 @@ +import '@babel/polyfill' import Promise from 'promise-polyfill' if (!window.Promise) { diff --git a/src/router/index.js b/src/router/index.js index 0cd8e02..2c35d8b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -10,7 +10,7 @@ const NotFound = () => import(/* webpackChunkName: "not-found-page" */ '@/views/ const GitHubSuccess = () => import(/* webpackChunkName: "ghlogin-result" */ '@/views/GitHubSuccess.vue') const router = new Router({ - mode: 'history', + mode: 'hash', routes: [ { name: 'home', diff --git a/src/store/index.js b/src/store/index.js index 07c7241..9de4e75 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,5 +1,7 @@ import Vue from 'vue' import Vuex from 'vuex' +import progress from 'nprogress' +import req from 'reqjs' import { loadBabel, loadPug, @@ -14,9 +16,7 @@ import { loadTypescript, loadStylus } from '@/utils/transformer' -import progress from 'nprogress' import api from '@/utils/github-api' -import req from 'reqjs' import Event from '@/utils/event' Vue.use(Vuex) @@ -53,7 +53,7 @@ const getFileNameByLang = { const boilerplates = { empty: async () => ({ ...emptyPans(), - showPans: ['html', 'js', 'output'] + showPans: ['js', 'output'] }) } function importAll(r) { @@ -62,13 +62,14 @@ function importAll(r) { boilerplates[name] = r(key).default }) } + importAll(require.context('@/boilerplates', true, /index.js$/)) const store = new Vuex.Store({ state: { ...emptyPans(), logs: [], - visiblePans: ['html', 'js', 'output'], + visiblePans: ['js', 'output'], activePan: 'js', autoRun: false, githubToken: localStorage.getItem('codepan:gh-token') || '', @@ -99,6 +100,7 @@ const store = new Vuex.Store({ } else { pans.splice(idx, 1) } + state.visiblePans = sortPans(pans) }, SHOW_PANS(state, pans) { @@ -181,6 +183,7 @@ const store = new Vuex.Store({ } else if (transformer === 'stylus') { await loadStylus() } + commit('UPDATE_TRANSFORMER', { type, transformer }) }, transform({ commit }, status) { @@ -232,7 +235,7 @@ const store = new Vuex.Store({ }, async setGist({ commit, dispatch, state }, id) { const data = await api(`gists/${id}`, state.githubToken, progress.done) - const files = data.files + const { files } = data if (!files) return @@ -252,12 +255,13 @@ const store = new Vuex.Store({ } } } + await dispatch('setBoilerplate', main) delete data.files commit('SET_GIST_META', data) }, - async setGitHubToken({ commit, dispatch }, token) { + async setGitHubToken({ commit }, token) { commit('SET_GITHUB_TOKEN', token) let userMeta = {} if (token) { @@ -266,6 +270,7 @@ const store = new Vuex.Store({ } else { localStorage.removeItem('codepan:gh-token') } + commit('SET_USER_META', userMeta) if (Object.keys(userMeta).length > 0) { localStorage.setItem('codepan:user-meta', JSON.stringify(userMeta)) diff --git a/src/utils/create-editor.js b/src/utils/create-editor.js index 4fb347d..a9108bc 100644 --- a/src/utils/create-editor.js +++ b/src/utils/create-editor.js @@ -1,5 +1,6 @@ /* eslint-disable import/no-unassigned-import */ import CodeMirror from 'codemirror' +import emmet from 'codemirror-emmet' import 'codemirror/mode/htmlmixed/htmlmixed' import 'codemirror/mode/jsx/jsx' import 'codemirror/mode/css/css' @@ -40,11 +41,11 @@ export default function (el, opts = {}) { } else if (cm.getOption('mode').indexOf('html') > -1) { try { cm.execCommand('emmetExpandAbbreviation') - } catch (err) { - console.error(err) + } catch (error) { + console.error(error) } } else { - const spaces = Array(cm.getOption('indentUnit') + 1).join(' ') + const spaces = new Array(cm.getOption('indentUnit') + 1).join(' ') cm.replaceSelection(spaces, 'end', '+input') } }, @@ -60,18 +61,18 @@ export default function (el, opts = {}) { } }) - import(/* webpackChunkName: "codemirror-emmet" */ 'codemirror-emmet').then(emmet => { - emmet(CodeMirror) - editor.setOption('extraKeys', { - ...editor.getOption('extraKeys'), - Enter: 'emmetInsertLineBreak' - }) - editor.setOption('emmet', { - markupSnippets: { - 'script:unpkg': 'script[src="https://unpkg.com/"]', - 'script:jsd': 'script[src="https://cdn.jsdelivr.net/npm/"]' - } - }) + emmet(CodeMirror) + + editor.setOption('extraKeys', { + ...editor.getOption('extraKeys'), + Enter: 'emmetInsertLineBreak' + }) + + editor.setOption('emmet', { + markupSnippets: { + 'script:unpkg': 'script[src="https://unpkg.com/"]', + 'script:jsd': 'script[src="https://cdn.jsdelivr.net/npm/"]' + } }) return editor diff --git a/src/utils/create-pan.js b/src/utils/create-pan.js index fc74fda..d12007d 100644 --- a/src/utils/create-pan.js +++ b/src/utils/create-pan.js @@ -5,8 +5,11 @@ import PanResizer from '@/components/PanResizer.vue' import CompiledCodeSwitcher from '@/components/CompiledCodeSwitcher.vue' import createEditor from '@/utils/create-editor' import Event from '@/utils/event' -import panPosition from '@/utils/pan-position' -import { hasNextPan, getHumanlizedTransformerName, getEditorModeByTransfomer } from '@/utils' +import { + hasNextPan, + getHumanlizedTransformerName, + getEditorModeByTransfomer +} from '@/utils' export default ({ name, editor, components } = {}) => { return { @@ -37,8 +40,8 @@ export default ({ name, editor, components } = {}) => { }, visiblePans: { immediate: true, - handler(val) { - this.style = panPosition(val, name) + handler() { + this.style.height = `${100 / this.visiblePans.length}%` } }, [`${name}.transformer`](val) { @@ -51,8 +54,8 @@ export default ({ name, editor, components } = {}) => { } } }, - mounted() { - this.editor = createEditor(this.$refs.editor, { + async mounted() { + this.editor = await createEditor(this.$refs.editor, { ...editor, readOnly: 'readonly' in this.$route.query }) @@ -66,7 +69,8 @@ export default ({ name, editor, components } = {}) => { } }) Event.$on('refresh-editor', () => { - this.editor.setValue(this[name].code) + if (!this[name].code) return + this.editor.setValue(this[name].code.default || this[name].code) this.editor.refresh() }) // Focus the editor @@ -84,7 +88,12 @@ export default ({ name, editor, components } = {}) => { }) }, methods: { - ...mapActions(['updateCode', 'updateTransformer', 'setActivePan', 'editorChanged']), + ...mapActions([ + 'updateCode', + 'updateTransformer', + 'setActivePan', + 'editorChanged' + ]), async setTransformer(transformer) { await this.updateTransformer({ type: name, transformer }) }, diff --git a/src/utils/get-scripts.js b/src/utils/get-scripts.js index 64f70d2..1ba376a 100644 --- a/src/utils/get-scripts.js +++ b/src/utils/get-scripts.js @@ -29,6 +29,7 @@ export default async (code, scripts) => { replacement += `var ${variable.local} = ${moduleName}.${variable.imported};\n` } } + if (replacement) { replacements.push(replacement) } diff --git a/src/utils/github-api.js b/src/utils/github-api.js index 26d8ef3..d823d0e 100644 --- a/src/utils/github-api.js +++ b/src/utils/github-api.js @@ -13,10 +13,10 @@ export default async function (endpoint, token, errCb = () => {}) { }).then(res => res.data) return data - } catch (err) { + } catch (error) { errCb() - if (err.response) { - const { headers, status } = err.response + if (error.response) { + const { headers, status } = error.response if (!token && status === 403 && headers['x-ratelimit-remaining'] === '0') { notie.confirm({ text: 'API rate limit exceeded, do you want to login?', @@ -27,14 +27,14 @@ export default async function (endpoint, token, errCb = () => {}) { } else { notie.alert({ type: 'error', - text: err.response.data.message, + text: error.response.data.message, time: 5 }) } } else { notie.alert({ type: 'error', - text: err.message || 'GitHub API Error' + text: error.message || 'GitHub API Error' }) } } diff --git a/src/utils/highlight.js b/src/utils/highlight.js index 72e0f51..05618f7 100644 --- a/src/utils/highlight.js +++ b/src/utils/highlight.js @@ -41,3 +41,5 @@ CodeMirror.highlight = function (string, options = {}) { return html } + +export default CodeMirror diff --git a/src/utils/iframe.js b/src/utils/iframe.js index df43e89..621db32 100644 --- a/src/utils/iframe.js +++ b/src/utils/iframe.js @@ -3,6 +3,7 @@ class Iframe { if (!el) { throw new Error('Expect "el" to mount iframe to!') } + this.$el = el this.sandboxAttributes = sandboxAttributes } diff --git a/src/utils/pan-position.js b/src/utils/pan-position.js index 50ab425..81ab675 100644 --- a/src/utils/pan-position.js +++ b/src/utils/pan-position.js @@ -1,49 +1,50 @@ -export default (pans, pan) => { +export default (pans = [], pan) => { const panWidth = 100 / pans.length const pansCount = matchedPans => { return pans.filter(p => { return matchedPans.indexOf(p) !== -1 }).length } + const rightOffset = leftCount => pans.length - 1 - leftCount const suffix = count => `${count * panWidth}%` if (pan === 'html') { return { - left: 0, - right: suffix(rightOffset(0)) + top: 0, + bottom: suffix(rightOffset(0)) } } if (pan === 'css') { const leftCount = pansCount(['html']) return { - left: suffix(leftCount), - right: suffix(rightOffset(leftCount)) + top: suffix(leftCount), + bottom: suffix(rightOffset(leftCount)) } } if (pan === 'js') { const leftCount = pansCount(['html', 'css']) return { - left: suffix(leftCount), - right: suffix(rightOffset(leftCount)) + top: suffix(leftCount), + bottom: suffix(rightOffset(leftCount)) } } if (pan === 'console') { const leftCount = pansCount(['html', 'css', 'js']) return { - left: suffix(leftCount), - right: suffix(rightOffset(leftCount)) + top: suffix(leftCount), + bottom: suffix(rightOffset(leftCount)) } } if (pan === 'output') { const leftCount = pansCount(['html', 'css', 'js', 'console']) return { - left: suffix(leftCount), - right: 0 + top: suffix(leftCount), + bottom: 0 } } } diff --git a/src/utils/proxy-console.js b/src/utils/proxy-console.js index 822096d..3180a35 100644 --- a/src/utils/proxy-console.js +++ b/src/utils/proxy-console.js @@ -1,7 +1,8 @@ (function () { - window.onerror = function (message) { + /*eslint-disable no-empty*/ + window.addEventListener('error', message => { window.parent.postMessage({ type: 'iframe-error', message }, '*') - } + }) window.addEventListener('unhandledrejection', err => { window.parent.postMessage( { type: 'iframe-error', message: err.reason.stack }, @@ -23,10 +24,10 @@ const htmlEntities = function (str) { return String(str) - // .replace(/&/g, '&') - // .replace(//g, '>') - // .replace(/"/g, '"') + // .replace(/&/g, '&') + // .replace(//g, '>') + // .replace(/"/g, '"') } /** @@ -35,7 +36,6 @@ * Goes 2 levels deep. */ return function stringify(o, visited, buffer) { - // eslint-disable-line complexity let i let vi let type = '' @@ -48,6 +48,7 @@ if (o === null) { return 'null' } + if (typeof o === 'undefined') { return 'undefined' } @@ -55,7 +56,7 @@ // Determine the type try { type = {}.toString.call(o) - } catch (err) { + } catch (error) { // only happens when typeof is protected (...randomly) type = '[object Object]' } @@ -64,12 +65,15 @@ if (type === '[object Number]') { return String(o) } + if (type === '[object Boolean]') { return o ? 'true' : 'false' } + if (type === '[object Function]') { return o.toString().split('\n ').join('\n' + buffer) } + if (type === '[object String]') { return '"' + htmlEntities(o.replace(/"/g, '\\"')) + '"' } @@ -98,6 +102,7 @@ for (i = 0; i < o.length; i++) { parts.push(stringify(o[i], visited)) } + return '[' + parts.join(', ') + ']' } @@ -115,10 +120,9 @@ // Some objects don't like 'in', so just skip them try { for (i in o) { - // eslint-disable-line guard-for-in names.push(i) } - } catch (err) {} + } catch (error) {} names.sort(sortci) for (i = 0; i < names.length; i++) { @@ -129,7 +133,7 @@ ': ' + stringify(o[names[i]], visited, newBuffer) ) - } catch (err) {} + } catch (error) {} } } @@ -156,7 +160,7 @@ // TODO this was forEach but when the array is [undefined] it wouldn't // iterate over them let i = 0 - const length = args.length + const { length } = args let arg for (; i < length; i++) { arg = args[i] @@ -166,6 +170,7 @@ newArgs.push(stringify(arg)) } } + return newArgs } @@ -186,6 +191,7 @@ while (output.indexOf('%s') !== -1) { output = output.replace('%s', texts.shift()) } + return output } @@ -204,11 +210,11 @@ const styles = [] for (let i = 1; i < args.length; i++) { switch (replacements.shift().substr(0, 2)) { - case '%s': texts.push(args[i]) - break - case '%c': styles.push(args[i]) - break - default: + case '%s': texts.push(args[i]) + break + case '%c': styles.push(args[i]) + break + default: } } @@ -248,9 +254,8 @@ // Create console method const originalMethod = console[method] const originalClear = console.clear - ProxyConsole.prototype[method] = function () { + ProxyConsole.prototype[method] = function (...originalArgs) { // Replace args that can't be sent through postMessage - const originalArgs = [].slice.call(arguments) const args = handleArgs(originalArgs) // Post up with method and the arguments @@ -284,4 +289,4 @@ })() window.console = proxyConsole -})() // eslint-disable-line semi +})() diff --git a/src/utils/transform.js b/src/utils/transform.js index 29f4c04..4c74105 100644 --- a/src/utils/transform.js +++ b/src/utils/transform.js @@ -16,14 +16,18 @@ const defaultPresets = [ export async function js({ code, transformer }) { if (transformer === 'js') { return code - } else if ( + } + + if ( transformer === 'babel' || transformer === 'jsx' /* @deprecated, use "babel" */ ) { return window.Babel.transform(code, { presets: [...defaultPresets, 'flow', 'react'] }).code - } else if (transformer === 'typescript') { + } + + if (transformer === 'typescript') { const res = window.typescript.transpileModule(code, { fileName: '/foo.ts', reportDiagnostics: true, @@ -33,14 +37,18 @@ export async function js({ code, transformer }) { }) console.log(res) return res.outputText - } else if (transformer === 'vue-jsx') { + } + + if (transformer === 'vue-jsx') { return window.Babel.transform(code, { presets: [...defaultPresets, 'flow', transformers.get('VuePreset')] }).code.replace( /import [^\s]+ from ['"]babel-helper-vue-jsx-merge-props['"];?/, transformers.get('VueJSXMergeProps') ) - } else if (transformer === 'svelte') { + } + + if (transformer === 'svelte') { return ( transformers.get('svelte').compile(code, { format: 'es' @@ -49,7 +57,9 @@ export async function js({ code, transformer }) { 'new SvelteComponent({target: document.body})' ) ) - } else if (transformer === 'reason') { + } + + if (transformer === 'reason') { const wrapInExports = code => `;(function(exports) {\n${code}\n})(window.exports = {})` @@ -58,10 +68,10 @@ export async function js({ code, transformer }) { const res = JSON.parse(window.ocaml.compile(ocamlCode)) if (res.js_error_msg) return res.js_error_msg return wrapInExports(res.js_code) - } catch (err) { - console.log(err) - return `${err.message}${ - err.location ? `\n${JSON.stringify(err.location, null, 2)}` : '' + } catch (error) { + console.log(error) + return `${error.message}${ + error.location ? `\n${JSON.stringify(error.location, null, 2)}` : '' }` } } else if (transformer === 'coffeescript-2') { @@ -78,54 +88,61 @@ export async function js({ code, transformer }) { if (data.error) { return data.error.trim() } + return `console.log(${JSON.stringify(data.result.trim())})` } + throw new Error(`Unknow transformer: ${transformer}`) } export async function html({ code, transformer }) { if (transformer === 'html') { return code - } else if (transformer === 'pug') { + } + + if (transformer === 'pug') { return window.pug.render(code) - } else if (transformer === 'markdown') { + } + + if (transformer === 'markdown') { return transformers.get('markdown')(code) } + throw new Error(`Unknow transformer: ${transformer}`) } export async function css({ code, transformer }) { switch (transformer) { - case 'css': - return code - case 'cssnext': - return window - .postcss([window.cssnext]) - .process(code) - .then(res => res.css) - case 'less': - return transformers - .get('less') - .render(code) - .then(res => res.css) - case 'scss': - case 'sass': - return new Promise((resolve, reject) => { - transformers.get('sass').compile(code, { - indentedSyntax: transformer === 'sass' - }, result => { - if (result.status === 0) return resolve(result.text) - reject(new Error(result.formatted)) - }) + case 'css': + return code + case 'cssnext': + return window + .postcss([window.cssnext]) + .process(code) + .then(res => res.css) + case 'less': + return transformers + .get('less') + .render(code) + .then(res => res.css) + case 'scss': + case 'sass': + return new Promise((resolve, reject) => { + transformers.get('sass').compile(code, { + indentedSyntax: transformer === 'sass' + }, result => { + if (result.status === 0) return resolve(result.text) + reject(new Error(result.formatted)) }) - case 'stylus': - return new Promise((resolve, reject) => { - window.stylus.render(code, { filename: 'codepan.styl' }, (err, css) => { - if (err) return reject(err) - resolve(css) - }) + }) + case 'stylus': + return new Promise((resolve, reject) => { + window.stylus.render(code, { filename: 'codepan.styl' }, (err, css) => { + if (err) return reject(err) + resolve(css) }) - default: - throw new Error(`Unknow transformer: ${transformer}`) + }) + default: + throw new Error(`Unknow transformer: ${transformer}`) } } diff --git a/src/views/EditorPage.vue b/src/views/EditorPage.vue index d65102a..d985cd7 100644 --- a/src/views/EditorPage.vue +++ b/src/views/EditorPage.vue @@ -1,42 +1,46 @@ @@ -98,16 +102,13 @@ export default { isReadOnly: 'readonly' in this.$route.query } }, - computed: { - ...mapState(['visiblePans', 'editorStatus', 'js', 'css', 'html']) - }, + computed: mapState(['visiblePans', 'editorStatus', 'js', 'css', 'html']), beforeRouteEnter(to, from, next) { next(async vm => { await handleRouteChange(to, vm) }) }, async beforeRouteUpdate(to, from, next) { - console.log('route updated to', to) await handleRouteChange(to, this) next() }, @@ -115,7 +116,7 @@ export default { '$route.query.show': { handler(next, prev) { if (!next && prev) { - this.showPans(['js', 'html', 'output']) + this.showPans(['js', 'output']) } else if (next !== prev) { this.showPans(next.split(',')) } @@ -140,14 +141,16 @@ export default { // Since in prevous versions we didn't fetch userMeta after login // We need to force user to re-login in order to get that data - if (this.$store.state.githubToken && Object.keys(this.$store.state.userMeta).length === 0) { - this.$store.dispatch('setGitHubToken', null) - .then(() => { - notie.alert({ - type: 'warning', - text: `You need to login again to use the new version!` - }) + if ( + this.$store.state.githubToken && + Object.keys(this.$store.state.userMeta).length === 0 + ) { + this.$store.dispatch('setGitHubToken', null).then(() => { + notie.alert({ + type: 'warning', + text: `You need to login again to use the new version!` }) + }) } Event.$on('show-compiled-code', type => { @@ -180,7 +183,10 @@ export default { } }, async getCodeFund() { - const res = await axios.get('https://codefund.io/properties/241/funder.html') + if (!this.$refs.codefund) return + const res = await axios.get( + 'https://codefund.io/properties/241/funder.html' + ) this.$refs.codefund.innerHTML = res.data } }, @@ -200,73 +206,36 @@ export default { - - diff --git a/src/views/GitHubSuccess.vue b/src/views/GitHubSuccess.vue index b332252..bbcff20 100644 --- a/src/views/GitHubSuccess.vue +++ b/src/views/GitHubSuccess.vue @@ -2,7 +2,6 @@
success!
- diff --git a/src/store/index.js b/src/store/index.js index 903ef78..df32088 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -108,13 +108,7 @@ const store = new Vuex.Store({ } state.visiblePans = sortPans(pans) - history.pushState( - null, - document.title, - `?pans=${state.visiblePans.join(',')}${ - urlParams.menu === 'false' ? '&menu=false' : '' - }${urlParams.layout ? 'layout=' + urlParams.layout : ''}` - ) + history.pushState(null, document.title, createUrl(state)) }, SHOW_PANS(state, pans) { state.visiblePans = sortPans(pans) @@ -327,4 +321,20 @@ const store = new Vuex.Store({ } }) +function createUrl(state) { + const elements = { + pans: state.visiblePans.join(','), + menu: urlParams.menu === 'false' ? '&menu=false' : '', + layout: urlParams.layout || 'column' + } + return ( + location.href.substr(0, location.href.indexOf('?')) + + '?' + + Object.entries(elements).reduce((carry, [key, value]) => { + value && carry.push(`${key}=${value}`) + return carry + }, []) + ) +} + export default store diff --git a/src/utils/index.js b/src/utils/index.js index ff5f7ef..df917ec 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -54,10 +54,13 @@ export const getEditorModeByTransfomer = transformer => { export const inIframe = window.self !== window.top export function getUrlParams() { - return location.href.split(/[?&]/).slice(1).reduce((carry, pair) => { - const parts = pair.split('=') - if (parts[0] || parts[1]) - Object.assign(carry, { [parts[0]] : parts[1] }) - return carry - }, {}) + return location.href + .split(/[?&]/) + .slice(1) + .reduce((carry, pair) => { + const parts = pair.split('=') + if (parts[0] || parts[1]) + Object.assign(carry, { [parts[0]]: parts[1].split('#')[0] }) + return carry + }, {}) } diff --git a/src/views/EditorPage.vue b/src/views/EditorPage.vue index b67e8bc..9e17eca 100644 --- a/src/views/EditorPage.vue +++ b/src/views/EditorPage.vue @@ -29,11 +29,7 @@
- - - - - +
@@ -86,6 +96,7 @@ export default { name: 'editor-page', data() { return { + codefundVisible: true, showCompiledCode: { js: false, css: false, @@ -157,11 +168,12 @@ export default { }) } + this.codefundVisible && this.getCodeFund() + }, + created() { Event.$on('show-compiled-code', type => { this.showCompiledCode[type] = true }) - - this.getCodeFund() }, methods: { ...mapActions(['setBoilerplate', 'setGist', 'showPans', 'setAutoRun']), @@ -216,20 +228,4 @@ export default { flex-direction: column; position: relative; } - -.pan { - flex: 1; - position: static; - resize: vertical; - background-color: #f9f9f9; - overflow: auto; - - &:last-child { - flex-grow: 1; - } - - &.active-pan { - background-color: white; - } -} From 37e496c06a8bb6b66312e36f754d494ef7acf325 Mon Sep 17 00:00:00 2001 From: Jacek Pietal Date: Tue, 2 Jul 2019 23:12:19 +0200 Subject: [PATCH 12/59] add local storage "boilerplate" --- src/boilerplates/local-storage/codepan.html | 0 src/boilerplates/local-storage/codepan.js | 0 src/boilerplates/local-storage/index.js | 17 +++++++++++++++++ src/components/App.vue | 2 +- src/components/OutputPan.vue | 8 ++++++-- src/components/header/AddBoilerplate.vue | 1 + 6 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/boilerplates/local-storage/codepan.html create mode 100644 src/boilerplates/local-storage/codepan.js create mode 100644 src/boilerplates/local-storage/index.js diff --git a/src/boilerplates/local-storage/codepan.html b/src/boilerplates/local-storage/codepan.html new file mode 100644 index 0000000..e69de29 diff --git a/src/boilerplates/local-storage/codepan.js b/src/boilerplates/local-storage/codepan.js new file mode 100644 index 0000000..e69de29 diff --git a/src/boilerplates/local-storage/index.js b/src/boilerplates/local-storage/index.js new file mode 100644 index 0000000..112204d --- /dev/null +++ b/src/boilerplates/local-storage/index.js @@ -0,0 +1,17 @@ +export default () => { + return { + js: { + code: localStorage.getItem('codepan.js') || '', + transformer: 'jsx' + }, + html: { + code: localStorage.getItem('codepan.html') || '', + transformer: 'html' + }, + css: { + code: localStorage.getItem('codepan.css') || '', + transformer: 'css' + }, + showPans: ['js', 'output'] + } +} diff --git a/src/components/App.vue b/src/components/App.vue index 6734d3b..ee78a19 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -136,7 +136,7 @@ pre { } .pans[class*=row] { - #cf { + #cf, .codefund-container { display: none !important; } } diff --git a/src/components/OutputPan.vue b/src/components/OutputPan.vue index f08f3e7..84a5d8a 100644 --- a/src/components/OutputPan.vue +++ b/src/components/OutputPan.vue @@ -51,7 +51,7 @@ const makeGist = (data, { showPans, activePan }) => { } files['codepan.json'] = { - content: JSON.stringify(manifest) + content: JSON.stringify(manifest, null, 2) } return files @@ -158,6 +158,10 @@ export default { throw err }) + localStorage.setItem('codepan.css', transformed.css) + localStorage.setItem('codepan.html', transformed.html) + localStorage.setItem('codepan.js', transformed.js) + transformed.js = ` try { if (window.Vue) { @@ -186,7 +190,6 @@ export default { const headStyle = createElement('style')(transformed.css) const codePanRuntime = [ - createElement('script')('console.clear();'), createElement('script')(`window.process = window.process || { env: { NODE_ENV: 'development' } }`), createElement('script')(proxyConsole), ...scripts.map(script => @@ -198,6 +201,7 @@ export default { const body = [ transformed.html, + createElement('script')('console.clear();'), createElement('script')(transformed.js) ].join('\n') diff --git a/src/components/header/AddBoilerplate.vue b/src/components/header/AddBoilerplate.vue index ea4f720..ace7495 100644 --- a/src/components/header/AddBoilerplate.vue +++ b/src/components/header/AddBoilerplate.vue @@ -13,6 +13,7 @@ ES import Rust Pixi + Local Storage From e2e226a13b2f0378dedeb59d2a76d18474cb628b Mon Sep 17 00:00:00 2001 From: Jacek Pietal Date: Tue, 2 Jul 2019 23:22:16 +0200 Subject: [PATCH 13/59] local storage --- src/components/App.vue | 8 ++++++++ src/components/OutputPan.vue | 6 +++--- src/store/index.js | 1 + src/views/EditorPage.vue | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/App.vue b/src/components/App.vue index ee78a19..c56a5c8 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -292,6 +292,10 @@ span:empty { position: relative; } +.pans.headless .pan-head { + display: none; +} + .pans[class*=column] { .pan { width: 100% !important; @@ -359,6 +363,10 @@ span:empty { max-height: 100%; } + .el-dropdown-menu.el-popper { + overflow-y: auto; + } + .page { flex-direction: row; } diff --git a/src/components/OutputPan.vue b/src/components/OutputPan.vue index 84a5d8a..62530bf 100644 --- a/src/components/OutputPan.vue +++ b/src/components/OutputPan.vue @@ -158,9 +158,9 @@ export default { throw err }) - localStorage.setItem('codepan.css', transformed.css) - localStorage.setItem('codepan.html', transformed.html) - localStorage.setItem('codepan.js', transformed.js) + localStorage.setItem('codepan.css', this.css.code) + localStorage.setItem('codepan.html', this.html.code) + localStorage.setItem('codepan.js', this.js.code) transformed.js = ` try { diff --git a/src/store/index.js b/src/store/index.js index e7dff53..b92ae72 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -331,6 +331,7 @@ function createUrlParams(state) { return Object.entries({ pans: state.visiblePans.join(','), menu: urlParams.menu || 'true', + title: urlParams.title || 'true', layout: urlParams.layout || 'column' }) .reduce((carry, [key, value]) => { diff --git a/src/views/EditorPage.vue b/src/views/EditorPage.vue index fd96c91..49c0bdb 100644 --- a/src/views/EditorPage.vue +++ b/src/views/EditorPage.vue @@ -28,7 +28,7 @@ > -
+
Date: Wed, 3 Jul 2019 23:18:49 +0200 Subject: [PATCH 14/59] code cleanup a bit --- README.md | 12 +++++------- package.json | 2 +- src/components/ConsolePan.vue | 1 - src/components/OutputPan.vue | 2 +- src/store/index.js | 37 ++++++++++++----------------------- src/utils/index.js | 15 ++++++++++++++ src/utils/proxy-console.js | 18 +++-------------- src/views/EditorPage.vue | 16 +++++---------- 8 files changed, 43 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 8170f1d..3f002c7 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,15 @@ You can use url GET param: - `pans=html,css,js,console,output` -First specified pan will open, -their order is determined by specified, -you can also open multiple instances of same tab (idk why you would) +Sets types of visible open pans, any number is ok -- `menu=false` +- `layout=column|row` -Any other value or not specifying it will show the menu header/side bar +Sets the desired layout of open pans -- `layout=row|column` +- `headless=false|true` -Defaults to column layout +Doesnt show ads, menu or pan header titles ## License diff --git a/package.json b/package.json index d369c61..3df7153 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "details": "CodePan is where people prototype front-end apps, you are free to use it offline anytime anywhere.", "main": "src/index.js", "homepage": "https://codepan.net/", - "version": "0.2.0", + "version": "0.2.1", "repository": {}, "scripts": { "test": "npm run lint", diff --git a/src/components/ConsolePan.vue b/src/components/ConsolePan.vue index a174b21..20a123f 100644 --- a/src/components/ConsolePan.vue +++ b/src/components/ConsolePan.vue @@ -49,7 +49,6 @@ export default { .console-log { white-space: pre-wrap; padding: 10px; - border-bottom: 1px solid #efefef; } .console-log-error { diff --git a/src/components/OutputPan.vue b/src/components/OutputPan.vue index 62530bf..65ab52f 100644 --- a/src/components/OutputPan.vue +++ b/src/components/OutputPan.vue @@ -200,8 +200,8 @@ export default { const head = `${headStyle}\n${codePanRuntime}` const body = [ - transformed.html, createElement('script')('console.clear();'), + transformed.html, createElement('script')(transformed.js) ].join('\n') diff --git a/src/store/index.js b/src/store/index.js index b92ae72..0a18d48 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -18,7 +18,7 @@ import { } from '@/utils/transformer' import api from '@/utils/github-api' import Event from '@/utils/event' -import { getUrlParams } from '../utils' +import { getUrlParams, createUrlBase, createUrlParams } from '../utils' Vue.use(Vuex) @@ -66,9 +66,16 @@ function importAll(r) { importAll(require.context('@/boilerplates', true, /index.js$/)) -const urlParams = getUrlParams() -const visiblePans = (urlParams.pans || 'js,output').split(',') -const activePan = urlParams.active || visiblePans[0] +const urlParams = Object.assign( + { + pans: 'js,output', + layout: 'column', + headless: 'false' + }, + getUrlParams() +) +const visiblePans = urlParams.pans.split(',') +const activePan = visiblePans[0] const store = new Vuex.Store({ state: { @@ -109,7 +116,8 @@ const store = new Vuex.Store({ state.visiblePans = sortPans(pans) - const location = createUrlBase() + '?' + createUrlParams(state) + const location = + createUrlBase() + '?' + createUrlParams(urlParams, state) history.replaceState(null, document.title, location) }, SHOW_PANS(state, pans) { @@ -322,23 +330,4 @@ const store = new Vuex.Store({ } }) -function createUrlBase() { - const index = location.href.indexOf('?') - return index === -1 ? location.href : location.href.substr(0, index) -} - -function createUrlParams(state) { - return Object.entries({ - pans: state.visiblePans.join(','), - menu: urlParams.menu || 'true', - title: urlParams.title || 'true', - layout: urlParams.layout || 'column' - }) - .reduce((carry, [key, value]) => { - value && carry.push(`${key}=${value}`) - return carry - }, []) - .join('&') -} - export default store diff --git a/src/utils/index.js b/src/utils/index.js index df917ec..c1ab109 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -64,3 +64,18 @@ export function getUrlParams() { return carry }, {}) } + +export function createUrlBase() { + const index = location.href.indexOf('?') + return index === -1 ? location.href : location.href.substr(0, index) +} + +export function createUrlParams(urlParams, state) { + return Object.entries( + Object.assign({}, urlParams, { pans: state.visiblePans.join(',') }) + ) + .reduce((carry, [key, value]) => { + value && carry.push(`${key}=${value}`) + return carry + }, []).join('&') +} diff --git a/src/utils/proxy-console.js b/src/utils/proxy-console.js index 8319013..d533966 100644 --- a/src/utils/proxy-console.js +++ b/src/utils/proxy-console.js @@ -267,8 +267,7 @@ methods.forEach(method => { // Create console method - const originalMethod = console[method] - const originalClear = console.clear + const originalMethod = console[method] || console.log ProxyConsole.prototype[method] = function(...originalArgs) { // Replace args that can't be sent through postMessage const args = handleArgs(originalArgs) @@ -283,19 +282,8 @@ '*' ) - // If the browner supports it, use the browser console but ignore _raw, - // as _raw should only go to the proxy console. - // Ignore clear if it doesn't exist as it's beahviour is different than - // log and we let it fallback to jsconsole for the panel and to nothing - // for the browser console - if (!originalMethod) { - method = 'log' - } - - if (method !== '_raw') { - if (method !== 'clear' || (method === 'clear' && originalClear)) { - originalMethod.apply(ProxyConsole, originalArgs) - } + if (method !== '_raw' && method !== 'clear') { + originalMethod.apply(ProxyConsole, originalArgs) } } }) diff --git a/src/views/EditorPage.vue b/src/views/EditorPage.vue index 49c0bdb..c6b2a19 100644 --- a/src/views/EditorPage.vue +++ b/src/views/EditorPage.vue @@ -1,6 +1,6 @@ @@ -58,6 +51,7 @@ import isElectron from 'is-electron' import axios from 'axios' import { inIframe } from '@/utils' import Event from '@/utils/event' +import Codefund from '@/components/Codefund.vue' import HomeHeader from '@/components/HomeHeader.vue' import DynamicPan from '@/components/DynamicPan.vue' import CompiledCodeDialog from '@/components/CompiledCodeDialog.vue' @@ -96,7 +90,6 @@ export default { name: 'editor-page', data() { return { - codefundVisible: true, showCompiledCode: { js: false, css: false, @@ -137,11 +130,6 @@ export default { } }, mounted() { - // Tell the parent window we're ready! - if (inIframe) { - window.parent.postMessage({ type: 'codepan-ready' }, '*') - } - window.addEventListener('storage', this.handleStorageChanged) window.addEventListener('beforeunload', e => { @@ -164,8 +152,6 @@ export default { }) }) } - - this.codefundVisible && this.getCodeFund() }, created() { Event.$on('show-compiled-code', type => { @@ -195,13 +181,6 @@ export default { } } }, - async getCodeFund() { - if (!this.$refs.codefund) return - const res = await axios.get( - 'https://codefund.io/properties/241/funder.html' - ) - this.$refs.codefund.innerHTML = res.data - } }, beforeDestroy() { window.removeEventListener('storage', this.handleStorageChanged) @@ -209,6 +188,7 @@ export default { components: { HomeHeader, DynamicPan, + Codefund, CompiledCodeDialog } } From 3672aeeae41ca204f28da8f5b9ce23b789ab061e Mon Sep 17 00:00:00 2001 From: Jacek Pietal Date: Sun, 4 Aug 2019 20:03:46 +0200 Subject: [PATCH 19/59] fix console and iframe --- package.json | 20 +- poi.config.js | 3 +- src/components/CompiledCodeDialog.vue | 5 +- src/components/OutputPan.vue | 114 ++- src/store/index.js | 20 +- src/utils/index.js | 12 + src/utils/proxy-console.js | 31 +- src/views/EditorPage.vue | 47 +- yarn.lock | 1102 ++++++++++++++----------- 9 files changed, 745 insertions(+), 609 deletions(-) diff --git a/package.json b/package.json index 3df7153..12a75da 100644 --- a/package.json +++ b/package.json @@ -17,17 +17,17 @@ "start": "http-server dist -p$PORT" }, "devDependencies": { - "@babel/core": "^7.4.5", + "@babel/core": "^7.5.5", "axios": "^0.19.0", "babel-preset-poi": "^10.0.2", "babel-preset-vue": "^2.0.2", - "buble": "^0.19.7", + "buble": "^0.19.8", "buble-loader": "^0.5.1", - "codemirror": "^5.48.0", + "codemirror": "^5.48.2", "codemirror-emmet": "^1.0.0", "core-js": "^3.1.4", "debounce": "^1.2.0", - "element-ui": "^2.10.0", + "element-ui": "^2.11.1", "is-electron": "^2.2.0", "less": "^3.9.0", "loadjs": "^3.6.1", @@ -38,21 +38,21 @@ "offline-plugin": "^5.0.7", "parse-package-name": "^0.1.0", "pify": "^4.0.1", - "poi": "^12.6.10", + "poi": "^12.7.1", "poi-preset-babel-minify": "^1.0.3", "poi-preset-bundle-report": "^2.0.2", "poi-preset-offline": "^9.0.3", "promise-polyfill": "^8.1.3", - "raw-loader": "^3.0.0", + "raw-loader": "^3.1.0", "reqjs": "^1.0.3", "stylus": "^0.54.5", "stylus-loader": "^3.0.2", - "svelte": "^3.6.1", + "svelte": "^3.6.11", "v-tippy": "^2.0.0", "vue": "^2.6.10", - "vue-feather-icons": "^4.22.0", + "vue-feather-icons": "^5.0.0", "vue-ga": "^1.1.0", - "vue-router": "^3.0.6", + "vue-router": "^3.0.7", "vue-slim-modal": "^1.0.4", "vue-template-compiler": "^2.6.10", "vuex": "^3.1.1", @@ -64,7 +64,7 @@ }, "optionalDependencies": { "babel-eslint": "^10.0.2", - "eslint": "^6.0.1", + "eslint": "^6.1.0", "eslint-plugin-vue": "^5.2.3" } } diff --git a/poi.config.js b/poi.config.js index ef2e913..3d70abc 100644 --- a/poi.config.js +++ b/poi.config.js @@ -12,7 +12,8 @@ const LATEST_COMMIT = execSync( const cdns = { BABEL_CDN: 'https://cdn.jsdelivr.net/npm/@babel/standalone@7.0.0-beta.32/babel.min.js', - PUG_CDN: 'https://cdn.jsdelivr.net/npm/browserified-pug@0.3.0/index.js', + PUG_CDN: + 'https://cdn.jsdelivr.net/npm/browserified-pug@0.3.0/index.js', CSSNEXT_CDN: 'https://cdn.jsdelivr.net/npm/browserified-postcss-cssnext@0.3.0/index.js', POSTCSS_CDN: diff --git a/src/components/CompiledCodeDialog.vue b/src/components/CompiledCodeDialog.vue index 0a43907..b7431fa 100644 --- a/src/components/CompiledCodeDialog.vue +++ b/src/components/CompiledCodeDialog.vue @@ -35,9 +35,8 @@ export default { try { const code = await transform[this.type](this.code) this.transformedCode = CodeMirror.highlight(code, { mode: this.highlight, theme: 'default' }) - } catch (err) { - const message = `compiler error: ${err.message}` - this.addLog({ type: 'error', message }) + } catch ({ message, stack }) { + this.addLog({ type: 'error', message: stack || message }) this.transformedCode = message } await this.$nextTick() diff --git a/src/components/OutputPan.vue b/src/components/OutputPan.vue index eac96f5..ac76d0b 100644 --- a/src/components/OutputPan.vue +++ b/src/components/OutputPan.vue @@ -1,17 +1,13 @@