├── .github
└── preview.png
├── .gitignore
├── README.md
├── assets
├── icon.icns
├── icon.ico
├── icon.png
└── icon.svg
├── package.json
├── src
├── main
│ ├── app.js
│ └── utils
│ │ ├── assets-path.js
│ │ └── check-url.js
└── renderer
│ ├── modules
│ └── zen-mode
│ │ ├── index.js
│ │ └── style.css
│ ├── preload.js
│ ├── styles
│ └── style.css
│ └── utils
│ └── inject-css.js
├── webpack
├── main.webpack.js
├── renderer.webpack.js
└── rules.webpack.js
└── yarn.lock
/.github/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maykbrito/electron-codepen-omni/9ee105230fe3e7187c0ab795da60053c8a62ba9c/.github/preview.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | packages/
2 | out/
3 | node_modules/
4 | .DS_Store
5 | .webpack
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Codepen.io Omni
2 |
3 | With ElectronJS, let's inject some CSS to customize Codepen ;)
4 |
5 |
6 | How to build
7 | Contact
8 |
9 |
10 |
11 | 
12 |
13 | The preview above are in `zen mode` (only works with JS tab + console).
14 |
15 | To toggle it, just press: `Alt+Shift+control+r`
16 |
17 | ---
18 |
19 | ## How to build
20 |
21 | 1. Install
22 |
23 | ```sh
24 | yarn
25 | ```
26 |
27 | 2. Build
28 |
29 | ```sh
30 | yarn package
31 | ```
32 |
33 | 3. Run your new app.
34 | _It will be at dir ./out_
35 |
36 | # Contact
37 |
38 | Mayk Brito
39 |
40 | - [maykbrito.dev](https://maykbrito.dev)
41 |
42 | ---
43 |
44 | If this project helps you, please leave your star 🌟 Thank you 💛
45 |
--------------------------------------------------------------------------------
/assets/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maykbrito/electron-codepen-omni/9ee105230fe3e7187c0ab795da60053c8a62ba9c/assets/icon.icns
--------------------------------------------------------------------------------
/assets/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maykbrito/electron-codepen-omni/9ee105230fe3e7187c0ab795da60053c8a62ba9c/assets/icon.ico
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maykbrito/electron-codepen-omni/9ee105230fe3e7187c0ab795da60053c8a62ba9c/assets/icon.png
--------------------------------------------------------------------------------
/assets/icon.svg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maykbrito/electron-codepen-omni/9ee105230fe3e7187c0ab795da60053c8a62ba9c/assets/icon.svg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codepen-omni",
3 | "version": "1.0.0",
4 | "description": "Run codepen.io custom theme with this App",
5 | "main": "./.webpack/main/index.js",
6 | "scripts": {
7 | "start": "electron-forge start",
8 | "package": "electron-forge package",
9 | "make": "electron-forge make"
10 | },
11 | "devDependencies": {
12 | "@electron-forge/cli": "^6.0.0-beta.61",
13 | "@electron-forge/maker-deb": "^6.0.0-beta.61",
14 | "@electron-forge/maker-rpm": "^6.0.0-beta.61",
15 | "@electron-forge/maker-squirrel": "^6.0.0-beta.61",
16 | "@electron-forge/maker-zip": "^6.0.0-beta.61",
17 | "@electron-forge/plugin-webpack": "^6.0.0-beta.61",
18 | "@marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
19 | "electron": "^15.3.0",
20 | "node-loader": "^2.0.0",
21 | "webpack": "^5.61.0",
22 | "webpack-cli": "^4.9.1"
23 | },
24 | "keywords": [
25 | "Editor",
26 | "Front-end",
27 | "HTML",
28 | "CSS",
29 | "JavaScript"
30 | ],
31 | "author": "Mayk Brito ",
32 | "license": "MIT",
33 | "dependencies": {
34 | "electron-squirrel-startup": "^1.0.0"
35 | },
36 | "config": {
37 | "forge": {
38 | "packagerConfig": {
39 | "name": "codepen-omni",
40 | "executableName": "codepen-omni",
41 | "icon": "assets/icon",
42 | "extraResource": [
43 | "assets",
44 | "src"
45 | ]
46 | },
47 | "plugins": [
48 | [
49 | "@electron-forge/plugin-webpack",
50 | {
51 | "mainConfig": "./webpack/main.webpack.js",
52 | "renderer": {
53 | "config": "./webpack/renderer.webpack.js",
54 | "entryPoints": [
55 | {
56 | "js": "./src/renderer/preload.js",
57 | "name": "main_window",
58 | "preload": {
59 | "js": "./src/renderer/preload.js"
60 | }
61 | }
62 | ]
63 | }
64 | }
65 | ]
66 | ],
67 | "makers": [
68 | {
69 | "name": "@electron-forge/maker-squirrel",
70 | "config": {
71 | "name": "codepen-omni",
72 | "setupExe": "${name}-${version}-setup.exe",
73 | "setupIcon": "./assets/icon.ico",
74 | "iconUrl": "https://raw.githubusercontent.com/maykbrito/codepen-omni/assets/icon.ico"
75 | }
76 | },
77 | {
78 | "name": "@electron-forge/maker-zip",
79 | "platforms": [
80 | "darwin"
81 | ]
82 | },
83 | {
84 | "name": "@electron-forge/maker-deb",
85 | "config": {}
86 | },
87 | {
88 | "name": "@electron-forge/maker-rpm",
89 | "config": {}
90 | }
91 | ],
92 | "publishers": [
93 | {
94 | "name": "@electron-forge/publisher-github",
95 | "config": {
96 | "repository": {
97 | "owner": "maykbrito",
98 | "name": "codepen-omni"
99 | },
100 | "draft": true
101 | }
102 | }
103 | ]
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/app.js:
--------------------------------------------------------------------------------
1 | import {
2 | app,
3 | BrowserWindow,
4 | screen,
5 | nativeImage,
6 | globalShortcut
7 | } from 'electron'
8 | import path from 'path'
9 |
10 | import { assetsPath } from './utils/assets-path'
11 | import { checkerURL } from './utils/check-url'
12 |
13 | let win = null
14 | app.allowRendererProcessReuse = true
15 |
16 | async function createWindow() {
17 | win = new BrowserWindow({
18 | icon: nativeImage.createFromPath(
19 | path.join(assetsPath, 'assets', 'icon.png')
20 | ),
21 | frame: false,
22 | // titleBarStyle: 'customButtonsOnHover',
23 | webPreferences: {
24 | nodeIntegration: true,
25 | contextIsolation: true,
26 | preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
27 | }
28 | })
29 |
30 | adjustWindow(win)
31 |
32 | win.loadURL('https://codepen.io/pen/?editors=0012')
33 |
34 | win.webContents.on('new-window', checkerURL) // add event listener for URL check
35 | }
36 |
37 | function adjustWindow(win) {
38 | const { size } = screen.getPrimaryDisplay()
39 | const { width, height } = size
40 |
41 | win.setPosition(0, 0)
42 | win.setSize(width, height)
43 | }
44 |
45 | function createShortcuts() {
46 | const toggleHide = 'Alt+Shift+control+r'
47 | globalShortcut.register(toggleHide, () => {
48 | win.webContents.send('toggleHide')
49 | })
50 | }
51 |
52 | //Verifica se o app já foi iniciado
53 | const isUnicInstance = app.requestSingleInstanceLock()
54 |
55 | if (!isUnicInstance) {
56 | app.quit()
57 | } else {
58 | // This method will be called when Electron has finished
59 | // initialization and is ready to create browser windows.
60 | // Some APIs can only be used after this event occurs.
61 | app
62 | .whenReady()
63 | .then(createWindow)
64 | .then(() => createShortcuts())
65 | .catch(e => console.error(e))
66 | }
67 |
68 | // Faz com que o programa não inicie várias vezes durante a instalação no windows
69 | if (require('electron-squirrel-startup')) {
70 | app.quit()
71 | }
72 |
73 | app.on('second-instance', () => {
74 | const win = BrowserWindow.getAllWindows()[0]
75 | if (win.isMinimized()) {
76 | win.restore()
77 | }
78 | win.focus()
79 | })
80 |
81 | // Quit when all windows are closed.
82 | app.on('window-all-closed', () => {
83 | // On macOS it is common for applications and their menu bar
84 | // to stay active until the user quits explicitly with Cmd + Q
85 | if (process.platform !== 'darwin') {
86 | app.quit()
87 | }
88 | })
89 |
90 | app.on('activate', recreateWindow)
91 |
92 | function recreateWindow() {
93 | // On macOS it's common to re-create a window in the app when the
94 | // dock icon is clicked and there are no other windows open.
95 | if (BrowserWindow.getAllWindows().length === 0) {
96 | setTimeout(createWindow, 200)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/utils/assets-path.js:
--------------------------------------------------------------------------------
1 | import { app, ipcMain } from 'electron'
2 |
3 | const assetsPath =
4 | process.env.NODE_ENV === 'production'
5 | ? process.resourcesPath
6 | : app.getAppPath()
7 |
8 | ipcMain.on('request-app-path', (event, arg) => {
9 | event.returnValue = assetsPath
10 | })
11 |
12 | export { assetsPath }
13 |
--------------------------------------------------------------------------------
/src/main/utils/check-url.js:
--------------------------------------------------------------------------------
1 | import { shell } from 'electron'
2 | /**
3 | * This function is used electron's new-window event
4 | * It allows non-electron links to be opened with the computer's default browser
5 | * Keep opening pop-ups for google login for example
6 | * @param {NewWindowEvent} e
7 | * @param {String} url
8 | */
9 | function checkerURL(e, url) {
10 | const isNotUrlOfTheNotion = !url.match('/ecstatic-shaw-7ceb62.netlify.app/')
11 |
12 | if (isNotUrlOfTheNotion) {
13 | e.preventDefault()
14 | shell.openExternal(url)
15 | }
16 | }
17 |
18 | export { checkerURL }
19 |
--------------------------------------------------------------------------------
/src/renderer/modules/zen-mode/index.js:
--------------------------------------------------------------------------------
1 | const { ipcRenderer } = require('electron')
2 |
3 | console.log('zen-mode Loaded')
4 |
5 | const injectCSS = require('../../utils/inject-css')
6 |
7 | /* Hide Elements */
8 | ipcRenderer.on('toggleHide', () => toggleHideElements())
9 |
10 | let hide = false
11 | function toggleHideElements() {
12 | hide
13 | ? document.body.classList.add('zen')
14 | : document.body.classList.remove('zen')
15 |
16 | hide = !hide
17 | }
18 |
19 | toggleHideElements()
20 |
21 | module.exports = () => {
22 | injectCSS('src', 'renderer', 'modules', 'zen-mode', 'style.css')
23 | }
24 |
--------------------------------------------------------------------------------
/src/renderer/modules/zen-mode/style.css:
--------------------------------------------------------------------------------
1 | /* zen mode ONLY ALLOW JS */
2 | body.zen {
3 | padding: 0 !important;
4 | }
5 |
6 | body.zen .unsaved-editor-message,
7 | body.zen #main-header,
8 | body.zen #box-css,
9 | body.zen #box-html,
10 | body.zen #react-pen-footer {
11 | display: none !important;
12 | }
13 |
14 | body.zen #box-js {
15 | height: 100% !important;
16 | }
17 |
--------------------------------------------------------------------------------
/src/renderer/preload.js:
--------------------------------------------------------------------------------
1 | const injectCSS = require('./utils/inject-css')
2 |
3 | window.addEventListener('DOMContentLoaded', () => {
4 | injectCSS('src', 'renderer', 'styles', 'style.css')
5 |
6 | /** zen mode */
7 | require('./modules/zen-mode/index')()
8 | })
9 |
--------------------------------------------------------------------------------
/src/renderer/styles/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | /* Dark */
3 | --dark-hue: 253;
4 | --dark: hsl(var(--dark-hue), 24%, 10%);
5 | --dark-1: hsl(var(--dark-hue), 24%, 14%);
6 | --dark-2: hsl(var(--dark-hue), 24%, 18%);
7 | --dark-3: hsl(var(--dark-hue), 24%, 22%);
8 | --dark-4: hsl(var(--dark-hue), 24%, 26%);
9 | --dark-5: hsl(var(--dark-hue), 24%, 30%);
10 | /* Primary */
11 | --primary-hue: 132;
12 | --primary: hsl(var(--primary-hue), 70%, 65%);
13 | --primary-1: hsl(var(--primary-hue), 70%, 55%);
14 | --primary-2: hsl(var(--primary-hue), 70%, 45%);
15 | --primary-3: hsl(var(--primary-hue), 70%, 35%);
16 | --primary-4: hsl(var(--primary-hue), 70%, 25%);
17 | --primary-5: hsl(var(--primary-hue), 70%, 15%);
18 |
19 | /* colors */
20 | --pink: hsl(326, 100%, 74%);
21 | --green: hsl(132, 70%, 65%);
22 | --purple: hsl(253, 35%, 66%);
23 | --purple-dark: hsl(257, 26%, 40%);
24 | --yellow: hsl(55, 70%, 69%);
25 | --blue: hsl(189, 64%, 68%);
26 | --white: hsl(240, 9%, 89%);
27 | --orange: hsl(26, 74%, 65%);
28 |
29 | /* codepen */
30 | --tab-bg: var(--dark);
31 | --tab-border-color: var(--dark);
32 | --editor-top-bar-background: var(--dark);
33 | --resizer-border: var(--dark-3);
34 |
35 | --cp-color-12: var(--dark-1);
36 | --cp-color-13: var(--dark-2);
37 | --cp-color-14: var(--dark-3);
38 | --cp-color-15: var(--dark-4);
39 | }
40 |
41 | /* */
42 | .box.box.box,
43 | .editor .top-boxes,
44 | .CodeMirror-gutter-wrapper,
45 | body.project .editor-pane,
46 | body.project .editor {
47 | background: var(--dark);
48 | }
49 |
50 | .CodeMirror-simplescroll-horizontal div,
51 | .CodeMirror-simplescroll-vertical div {
52 | background: var(--green);
53 | }
54 |
55 | .CodeMirror,
56 | .cm-s-default .CodeMirror-gutters {
57 | background-color: var(--dark) !important;
58 | color: #f8f8f2 !important;
59 | border: none;
60 | }
61 |
62 | .console-wrap {
63 | background-color: var(--dark) !important;
64 | }
65 |
66 | .console-command-line {
67 | background: var(--dark-1);
68 | }
69 |
70 | .CodeMirror-gutters {
71 | color: var(--dark) !important;
72 | }
73 | .CodeMirror-cursor {
74 | border-left: solid thin #f8f8f0;
75 | }
76 | .CodeMirror-linenumber {
77 | color: var(--purple-dark);
78 | }
79 | .CodeMirror-selected {
80 | background: rgba(255, 255, 255, 0.1);
81 | }
82 | .CodeMirror-line::selection,
83 | .CodeMirror-line > span::selection,
84 | .CodeMirror-line > span > span::selection {
85 | background: rgba(255, 255, 255, 0.1);
86 | }
87 | .CodeMirror-line::-moz-selection,
88 | .CodeMirror-line > span::-moz-selection,
89 | .CodeMirror-line > span > span::-moz-selection {
90 | background: rgba(255, 255, 255, 0.1);
91 | }
92 |
93 | span.cm-comment {
94 | color: var(--purple-dark);
95 | }
96 | span.cm-string,
97 | span.cm-string-2 {
98 | color: var(--yellow);
99 | }
100 | span.cm-number {
101 | color: var(--blue);
102 | }
103 | span.cm-variable {
104 | color: var(--white);
105 | }
106 | span.cm-variable-2 {
107 | color: var(--white);
108 | }
109 | span.cm-def {
110 | color: var(--white);
111 | }
112 | span.cm-operator {
113 | color: var(--pink);
114 | }
115 | span.cm-keyword {
116 | color: var(--pink);
117 | }
118 | span.cm-atom {
119 | color: #bd93f9;
120 | }
121 | span.cm-meta {
122 | color: #f8f8f2;
123 | }
124 | span.cm-tag {
125 | color: var(--pink);
126 | }
127 | span.cm-attribute {
128 | color: var(--green);
129 | }
130 | span.cm-qualifier {
131 | color: var(--green);
132 | }
133 | span.cm-property {
134 | color: var(--green);
135 | }
136 | span.cm-builtin {
137 | color: var(--green);
138 | }
139 | span.cm-variable-3,
140 | span.cm-type {
141 | color: var(--orange);
142 | }
143 |
144 | .CodeMirror-activeline-background {
145 | background: rgba(255, 255, 255, 0.1);
146 | }
147 | .CodeMirror-matchingbracket {
148 | text-decoration: underline;
149 | color: white !important;
150 | }
151 |
--------------------------------------------------------------------------------
/src/renderer/utils/inject-css.js:
--------------------------------------------------------------------------------
1 | const { ipcRenderer } = require('electron')
2 | const path = require('path')
3 | const appPath = ipcRenderer.sendSync('request-app-path')
4 | const fs = require('fs')
5 |
6 | function injectCSS(...cssPathSegments) {
7 | const cssPath = path.resolve(appPath, ...cssPathSegments)
8 |
9 | console.log(cssPath)
10 | const cssContent = fs.readFileSync(cssPath)
11 | const styleEl = document.createElement('style')
12 | styleEl.innerHTML = cssContent
13 | document.head.append(styleEl)
14 | }
15 |
16 | module.exports = injectCSS
17 |
--------------------------------------------------------------------------------
/webpack/main.webpack.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | resolve: {
3 | extensions: ['.js']
4 | },
5 | entry: './src/main/app.js',
6 | module: {
7 | rules: require('./rules.webpack')
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/webpack/renderer.webpack.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | resolve: {
3 | extensions: ['.js', '.css'],
4 | fallback: {
5 | path: false,
6 | fs: false,
7 | util: false,
8 | assert: false,
9 | stream: false,
10 | constants: false
11 | }
12 | },
13 | target: 'electron-renderer',
14 | module: {
15 | rules: require('./rules.webpack')
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/webpack/rules.webpack.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | test: /\.node$/,
4 | use: 'node-loader'
5 | },
6 | {
7 | test: /\.(m?js|node)$/,
8 | parser: { amd: false },
9 | use: {
10 | loader: '@marshallofsound/webpack-asset-relocator-loader',
11 | options: {
12 | outputAssetBase: 'native_modules'
13 | }
14 | }
15 | }
16 | ]
17 |
--------------------------------------------------------------------------------