17 | ) => (
18 | component: React.ComponentType>
19 | ) => any = ws as any
20 |
--------------------------------------------------------------------------------
/electron-shell/README.md:
--------------------------------------------------------------------------------
1 | # About
2 |
3 | This is the very early version of fluid-outliner electron app.
4 |
5 | Currently, the electron app does not provide any advantages over using the PWA, but in future it is expected to have better native integration and synchronization capabilities.
6 |
7 | ## Running the app
8 |
9 | ```
10 | cd fluid-outliner
11 | yarn
12 | cd electron-shell
13 | yarn
14 | cd app
15 | yarn
16 | cd ..
17 | yarn run build
18 |
19 | # In separate terminals:
20 | yarn run renderer-dev-server -- --port 9666
21 | yarn run start
22 | ```
23 |
24 | The DX is expected to improve when the electron shell matures.
25 |
26 | ## Guidelines
27 |
28 | - As a general policy it is expected that if something can be handled at the PWA layer, it goes there.
29 | - For performance, or better native integration experience, it may be desirable to provide alternative implementation of a few features in electron-shell.
30 | - Electron specific feaures are to be added only as a last resort, when handling them at the PWA layer proves too restrictive or cumbersome even with latest HTML5/ES-next APIs.
31 |
32 | ## FAQs
33 |
34 | ### Why are there so many package.json files
35 |
36 | Primarily to prevent contributors contributing to PWA (which constitutes the bulk of this application) from having to download electron and related dependencies.
37 |
38 | `app/node_modules` is actually bundled with the application, so any native dependencies or dependencies which can't be webpacked belong in `app/package.json`.
39 |
--------------------------------------------------------------------------------
/electron-shell/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fluid-notion/fluid-outliner-electron-shell",
3 | "productName": "fluid-notion",
4 | "version": "0.0.1",
5 | "description": "Open source web based outliner",
6 | "main": "./dist/main.js",
7 | "author": "Lorefnon ",
8 | "license": "GPL-3.0",
9 | "scripts": {
10 | "postinstall": "npm rebuild --runtime=electron --target=1.6.6 --disturl=https://atom.io/download/atom-shell --build-from-source"
11 | },
12 | "dependencies": {}
13 | }
14 |
--------------------------------------------------------------------------------
/electron-shell/app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Fluid Outliner
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/electron-shell/app/src/renderer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render } from "react-dom"
3 | import { AppContainer } from "react-hot-loader"
4 | import { App } from "../../../core/components/App"
5 |
6 | const renderApp = () => {
7 | render(
8 |
9 |
10 | ,
11 | document.getElementById("root")
12 | )
13 | }
14 |
15 | renderApp()
16 |
17 | if ((module as any).hot) {
18 | ;(module as any).hot.accept("../../../core/components/App", () => {
19 | renderApp();
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/electron-shell/app/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 |
--------------------------------------------------------------------------------
/electron-shell/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fluid-notion/fluid-outliner-electron-shell",
3 | "version": "0.0.1",
4 | "description": "Fluid Outliner Electron Shell",
5 | "author": "Lorefnon ",
6 | "license": "GPL-3.0",
7 | "private": true,
8 | "devDependencies": {
9 | "@types/electron": "^1.6.10",
10 | "@types/electron-builder": "^2.8.0",
11 | "asar": "^0.14.3",
12 | "devtron": "^1.4.0",
13 | "electron": "^2.0.5",
14 | "electron-builder": "^20.24.4",
15 | "electron-builder-http": "^19.27.5",
16 | "electron-devtools-installer": "^2.2.4",
17 | "spectron": "^3.8.0"
18 | },
19 | "scripts": {
20 | "renderer-dev-server": "../node_modules/.bin/webpack-dev-server --hot --config webpack.config.renderer.ts --progress --profile --colors",
21 | "build-main": "../node_modules/.bin/webpack --config webpack.config.main.ts --progress --profile --colors",
22 | "build-renderer": "../node_modules/.bin/webpack --config webpack.config.renderer.ts --progress --profile --colors",
23 | "build": "yarn run build-main && yarn run build-renderer",
24 | "start": "electron ./app",
25 | "postinstall": "yarn run build",
26 | "dev": "yarn run hot-server -- --start-hot",
27 | "package": "yarn run build && build --publish never",
28 | "package-win": "yarn run build && build --win --x64",
29 | "package-linux": "yarn run build && build --linux",
30 | "package-all": "yarn run build && build -mwl",
31 | "clean": "rm -rf app/dist"
32 | },
33 | "build": {
34 | "productName": "FluidOutliner",
35 | "appId": "in.fluidnotion.fluidoutliner",
36 | "dmg": {
37 | "contents": [
38 | {
39 | "x": 410,
40 | "y": 150,
41 | "type": "link",
42 | "path": "/Applications"
43 | },
44 | {
45 | "x": 130,
46 | "y": 150,
47 | "type": "file"
48 | }
49 | ]
50 | },
51 | "files": [
52 | "dist/",
53 | "node_modules/",
54 | "app.html",
55 | "main.js",
56 | "main.js.map",
57 | "package.json"
58 | ],
59 | "directories": {
60 | "buildResources": "resources",
61 | "output": "release"
62 | },
63 | "win": {
64 | "target": "nsis"
65 | },
66 | "linux": {
67 | "target": [
68 | "deb",
69 | "AppImage"
70 | ]
71 | }
72 | },
73 | "bin": {
74 | "electron": "./node_modules/.bin/electron"
75 | },
76 | "dependencies": {
77 | "electron-debug": "^2.0.0"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/electron-shell/webpack.config.base.ts:
--------------------------------------------------------------------------------
1 | import path from "path"
2 | import merge from "webpack-merge"
3 |
4 | import commonConfig from "../webpack.config.common"
5 |
6 | export default merge(commonConfig, {
7 | output: {
8 | path: path.join(__dirname, "app/dist"),
9 | filename: "bundle.js",
10 | // https://github.com/webpack/webpack/issues/1114
11 | libraryTarget: "commonjs2",
12 | },
13 | resolve: {
14 | modules: [path.join(__dirname, "app"), "node_modules"],
15 | },
16 | })
17 |
--------------------------------------------------------------------------------
/electron-shell/webpack.config.main.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Build config for electron 'Main Process' file
3 | */
4 |
5 | import merge from "webpack-merge"
6 | import baseConfig from "./webpack.config.base"
7 |
8 | export default merge(baseConfig, {
9 | entry: ["./app/src/main.ts"],
10 |
11 | // 'main.js' in root
12 | output: {
13 | filename: "main.js",
14 | },
15 |
16 | /**
17 | * Set target to Electron specific node.js env.
18 | * https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
19 | */
20 | target: "electron-main",
21 |
22 | /**
23 | * Disables webpack processing of __dirname and __filename.
24 | * If you run the bundle in node.js it falls back to these values of node.js.
25 | * https://github.com/webpack/webpack/issues/2010
26 | */
27 | node: {
28 | __dirname: false,
29 | __filename: false,
30 | },
31 |
32 | externals: {
33 | "electron-devtools-installer": "electron-devtools-installer",
34 | "electron-debug": "electron-debug"
35 | }
36 | })
37 |
--------------------------------------------------------------------------------
/electron-shell/webpack.config.renderer.ts:
--------------------------------------------------------------------------------
1 | import merge from "webpack-merge"
2 | // tslint:disable-next-line:
3 | import HtmlWebpackPlugin from "html-webpack-plugin"
4 | import baseConfig from "./webpack.config.base"
5 |
6 | let entry
7 | let output
8 |
9 | const port = process.env.PORT || 9666
10 |
11 | if (baseConfig.mode === "production") {
12 | entry = "./app/src/renderer.tsx"
13 | output = {
14 | publicPath: "./dist-webpack/",
15 | }
16 | } else {
17 | entry = [
18 | "react-hot-loader/patch",
19 | `webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr&reload=true`,
20 | "./app/src/renderer.tsx",
21 | ]
22 | output = {
23 | publicPath: `http://localhost:${port}/dist-webpack/`,
24 | }
25 | }
26 |
27 | export default merge(baseConfig, {
28 | devtool: "source-map",
29 | entry,
30 | output,
31 | plugins: [
32 | new HtmlWebpackPlugin({
33 | filename: "index.html",
34 | template: "app/src/index.html",
35 | }),
36 | ],
37 | // https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
38 | target: "electron-renderer",
39 | })
40 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | trailingComma: "es5",
3 | printWidth: 80,
4 | tabWidth: 4,
5 | semi: false,
6 | }
--------------------------------------------------------------------------------
/pwa-shell/deploy/deploy.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const ghpages = require('gh-pages');
3 |
4 | if (process.env.NODE_ENV !== "production") {
5 | throw new Error("Attempted to deploy without setting production environment");
6 | }
7 |
8 | ghpages.publish(path.join(__dirname, '../dist'), function(err) {
9 | if (err) {
10 | console.error(err);
11 | console.error('Failed to deploy');
12 | } else {
13 | console.log('Success !');
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/pwa-shell/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fluid-notion/fluid-outliner-pwa-shell",
3 | "version": "0.0.1",
4 | "description": "Open source web based outliner",
5 | "author": "Lorefnon ",
6 | "license": "GPL-3.0",
7 | "private": false,
8 | "publishConfig": {
9 | "access": "public"
10 | },
11 | "scripts": {
12 | "build": "../node_modules/.bin/webpack --config webpack.config.ts",
13 | "webpack-dev-server": "../node_modules/.bin/webpack-dev-server --hot --progress --profile --colors",
14 | "clean": "../node_modules/.bin/rimraf ./dist",
15 | "deploy": "yarn run clean && yarn run build && node ./scripts/deploy"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/pwa-shell/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Fluid Outliner
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/pwa-shell/src/index.tsx:
--------------------------------------------------------------------------------
1 | import _debug from "debug"
2 |
3 | import React from "react"
4 | import { render } from "react-dom"
5 | import { App } from "../../core/components/App"
6 | import { installOfflinePlugin } from "../../core/utils/offline-plugin-runtime"
7 |
8 | const debug = _debug("fluid-outliner:index")
9 |
10 | // @ts-ignore
11 | import "typeface-roboto"
12 |
13 | debug("Installing Service Workers")
14 | installOfflinePlugin()
15 |
16 | debug("Bootstrapping React root")
17 |
18 | document.addEventListener("DOMContentLoaded", () => {
19 | render(, document.getElementById("root"))
20 | })
21 |
--------------------------------------------------------------------------------
/pwa-shell/src/outdated-browser-check.js:
--------------------------------------------------------------------------------
1 | import checkOutdated from "outdated-browser-rework";
2 | import "outdated-browser-rework/dist/style.css";
3 |
4 | checkOutdated();
--------------------------------------------------------------------------------
/pwa-shell/webpack.config.ts:
--------------------------------------------------------------------------------
1 | import path from "path"
2 | import merge from "webpack-merge"
3 |
4 | // @ts-ignore
5 | import WebpackPwaManifest from "webpack-pwa-manifest"
6 | import HtmlWebpackPlugin from "html-webpack-plugin" // tslint:disable-line
7 | // @ts-ignore
8 | import OfflinePlugin from "offline-plugin"
9 | // @ts-ignore
10 | import FaviconsWebpackPlugin from "favicons-webpack-plugin"
11 |
12 | import commonConfig from "../webpack.config.common"
13 |
14 | export default merge(commonConfig, {
15 | entry: {
16 | main: "./src/index.tsx",
17 | "outdated-browser-check": "./src/outdated-browser-check.js",
18 | },
19 | output: {
20 | path: path.join(__dirname, "dist"),
21 | filename: "[name].[hash].js",
22 | publicPath:
23 | commonConfig.mode === "production" ? "/fluid-outliner" : "/",
24 | },
25 | plugins: [
26 | new HtmlWebpackPlugin({
27 | title: "Fluid Outliner",
28 | template: "src/index.html",
29 | }),
30 | new OfflinePlugin({
31 | responseStrategy: "network-first",
32 | appShell: "/",
33 | }),
34 | new FaviconsWebpackPlugin({
35 | logo: path.join(__dirname, "../assets/logo-text.png"),
36 | }),
37 | new WebpackPwaManifest({
38 | name: "Fluid Outliner",
39 | short_name: "Outliner",
40 | display: "standalone",
41 | theme_color: "#673ab7",
42 | background_color: "#673ab7",
43 | orientation: "portrait",
44 | inject: true,
45 | fingerprints: true,
46 | icons: [
47 | {
48 | src: path.join(__dirname, "../assets/colored-logo.png"),
49 | sizes: [96, 128, 192, 256, 384, 512],
50 | },
51 | ],
52 | }),
53 | ],
54 | watchOptions: {
55 | ignored: /node_modules/,
56 | },
57 | devServer: {
58 | contentBase: path.join(__dirname, "dist"),
59 | },
60 | })
61 |
--------------------------------------------------------------------------------
/pwa-shell/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 |
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const cp = require("child_process");
4 | const path = require("path");
5 | const log = require("fancy-log");
6 |
7 | console.log("You probably don't want to build all sub-projects including the mobile and electron apps. Refer project README")
8 |
9 | const buildIn = (target, subDir, proceedAfterFailure = true) => {
10 | log("Building:", target)
11 | try {
12 | cp.spawnSync("yarn", ["run", "build"], {
13 | stdio: "inherit",
14 | cwd: path.join(__dirname, "..", subDir),
15 | shell: true
16 | });
17 | } catch (e) {
18 | log.error(e)
19 | log.error("Failed to build: ", target)
20 | if (!proceedAfterFailure) {
21 | log.error("Terminating build")
22 | process.exit(1)
23 | }
24 | }
25 | }
26 |
27 | buildIn("PWA", "pwa-shell", false)
28 | buildIn("Node Server", "server")
29 | buildIn("Desktop App", "electron-shell")
30 | buildIn("Mobile App", "cordova-shell")
31 |
--------------------------------------------------------------------------------
/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const cp = require("child_process");
4 | const path = require("path")
5 |
6 | const deployIn = (subDir) =>
7 | cp.spawnSync("yarn", ["run", "deploy"], {
8 | stdio: "inherit",
9 | cwd: path.join(__dirname, "..", subDir),
10 | shell: true
11 | });
12 |
13 | buildIn("pwa-shell")
14 |
--------------------------------------------------------------------------------
/scripts/install.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const cp = require("child_process");
4 | const path = require("path");
5 |
6 | [
7 | ".",
8 | "pwa-shell",
9 | "electron-shell",
10 | "electron-shell/app",
11 | "cordova-shell"
12 | ].forEach((dir) => {
13 | console.log(`Installing dependencies in ${dir}`);
14 | cp.spawnSync("yarn", ["install"], {
15 | stdio: "inherit",
16 | shell: true,
17 | cwd: path.join(__dirname, '..', dir)
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/scripts/pre-publish.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const cp = require('child_process');
4 | const {inPublish} = require('in-publish');
5 | const log = require('fancy-log');
6 |
7 | if (inPublish()) {
8 | log('Linting the project');
9 | cp.spawnSync("yarn", ["run", "tslint"], {
10 | shell: true,
11 | stdio: "inherit"
12 | });
13 | log('Building project');
14 | cp.spawnSync("yarn", ["run", "build"], {
15 | shell: true,
16 | stdio: "inherit"
17 | });
18 | } else {
19 | log('Not really publishing. Pre-publish hook will be skipped.');
20 | }
21 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fluid-notion/fluid-outliner-server",
3 | "version": "0.0.1",
4 | "description": "Open source web based outliner",
5 | "author": "Lorefnon ",
6 | "license": "GPL-3.0",
7 | "private": true,
8 | "scripts": {
9 | "start": "node dist/index.js",
10 | "build": "tsc"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/server/src/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import express from "express"
4 | import path from "path"
5 |
6 | const app = express()
7 | app.use(express.static(path.join(__dirname, "../../pwa-shell/dist")))
8 | app.listen(process.env.FLUID_OUTLINER_HTTP_SERVER_PORT || 9000)
9 |
--------------------------------------------------------------------------------
/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/tsconfig.client.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "target": "ES6",
5 | "module": "esNext"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES5",
4 | "module": "commonjs",
5 | "moduleResolution": "Node",
6 | "sourceMap": true,
7 | "strict": true,
8 | "noUnusedLocals": true,
9 | "noUnusedParameters": true,
10 | "noImplicitReturns": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "jsx": "react",
13 | "project": ".",
14 | "outDir": "dist-tsc",
15 | "experimentalDecorators": true,
16 | "esModuleInterop": true,
17 | "emitDecoratorMetadata": true,
18 | "allowSyntheticDefaultImports": true,
19 | "lib": [
20 | "dom",
21 | "es2015",
22 | "es2016",
23 | "es2017",
24 | "dom.iterable"
25 | ]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "tslint:latest",
4 | "tslint-config-prettier"
5 | ],
6 | "rules": {
7 | "object-literal-sort-keys": false,
8 | "no-submodule-imports": false,
9 | "no-implicit-dependencies": false,
10 | "curly": [true, "ignore-same-line"],
11 | "ordered-imports": false,
12 | "variable-name": [false],
13 | "prefer-conditional-expression": false
14 | }
15 | }
--------------------------------------------------------------------------------