├── .gitignore
├── README.md
├── config
├── env.js
├── jest
│ ├── CSSStub.js
│ └── FileStub.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── demo.gif
├── package.json
├── public
├── bg.png
├── index.html
├── playfair
│ ├── playfairdisplay-bold-webfont.woff
│ ├── playfairdisplay-bold-webfont.woff2
│ ├── playfairdisplay-bolditalic-webfont.woff
│ ├── playfairdisplay-bolditalic-webfont.woff2
│ ├── playfairdisplay-italic-webfont.woff
│ ├── playfairdisplay-italic-webfont.woff2
│ ├── playfairdisplay-regular-webfont.woff
│ ├── playfairdisplay-regular-webfont.woff2
│ └── stylesheet.css
├── search-alpha.png
└── search.png
├── sample-savefile.json
├── scripts
├── build.js
├── start.js
└── test.js
└── src
├── About.js
├── Article.js
├── Editor.js
├── Menu.js
├── Saved.js
├── configure-localStore.js
├── index.css
├── index.js
├── localStore.js
└── localStore.test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Write
2 |
3 | A web-based writing app based on [Flowstate](http://hailoverman.com/flowstate). Built using React.
4 |
5 | The premise is simple. You set a duration during which you write; within that duration, if you stop typing for more than 5 seconds, all your progress is lost.
6 |
7 | The typical use case of Flowstate is to avoid writer's block and get something down in writing. Personally, I've been using it for journalling; it's been a good exercise getting all of my thoughts, latent or prominent, down in writing. The duration has also helped me keep a consistent routine; if I know it's only going to be fifteen minutes every session, it's easier to sit down and get through it.
8 |
9 | ## Setup Instructions
10 |
11 | This app was scaffolded using [create-react-app](https://github.com/facebookincubator/create-react-app) and then ejected.
12 |
13 | In order to run it locally, clone this repository, run `npm install`, and then either:
14 |
15 | - run `node scripts/start.js` to start a local server
16 | - run `node scripts/build.js` to create a production-optimized build
17 |
18 | ## Roadmap
19 |
20 | Have suggestions/ideas for improvement? Feel free to submit them in the form of an issue (pull requests also welcome).
21 |
22 | - [x] Setting up DNS for write.itskrish.co (formerly accessible at [write.surge.sh](http://write.surge.sh))
23 | - [x] Refactoring storage from localStorage to a backwards-compatible ORM-esque system.
24 | - [x] Refactoring timekeeping with system time instead of setTimeout.
25 | - [ ] Setting up benchmarking + optimizing for speed.
26 | - [ ] Packaging as an Electron (Desktop) app.
27 |
--------------------------------------------------------------------------------
/config/env.js:
--------------------------------------------------------------------------------
1 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
2 | // injected into the application via DefinePlugin in Webpack configuration.
3 |
4 | var REACT_APP = /^REACT_APP_/i;
5 |
6 | function getClientEnvironment(publicUrl) {
7 | var processEnv = Object
8 | .keys(process.env)
9 | .filter(key => REACT_APP.test(key))
10 | .reduce((env, key) => {
11 | env[key] = JSON.stringify(process.env[key]);
12 | return env;
13 | }, {
14 | // Useful for determining whether we’re running in production mode.
15 | // Most importantly, it switches React into the correct mode.
16 | 'NODE_ENV': JSON.stringify(
17 | process.env.NODE_ENV || 'development'
18 | ),
19 | // Useful for resolving the correct path to static assets in `public`.
20 | // For example,
.
21 | // This should only be used as an escape hatch. Normally you would put
22 | // images into the `src` and `import` them in code to get their paths.
23 | 'PUBLIC_URL': JSON.stringify(publicUrl)
24 | });
25 | return {'process.env': processEnv};
26 | }
27 |
28 | module.exports = getClientEnvironment;
29 |
--------------------------------------------------------------------------------
/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var fs = require('fs');
3 |
4 | // Make sure any symlinks in the project folder are resolved:
5 | // https://github.com/facebookincubator/create-react-app/issues/637
6 | var appDirectory = fs.realpathSync(process.cwd());
7 | function resolveApp(relativePath) {
8 | return path.resolve(appDirectory, relativePath);
9 | }
10 |
11 | // We support resolving modules according to `NODE_PATH`.
12 | // This lets you use absolute paths in imports inside large monorepos:
13 | // https://github.com/facebookincubator/create-react-app/issues/253.
14 |
15 | // It works similar to `NODE_PATH` in Node itself:
16 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
17 |
18 | // We will export `nodePaths` as an array of absolute paths.
19 | // It will then be used by Webpack configs.
20 | // Jest doesn’t need this because it already handles `NODE_PATH` out of the box.
21 |
22 | var nodePaths = (process.env.NODE_PATH || '')
23 | .split(process.platform === 'win32' ? ';' : ':')
24 | .filter(Boolean)
25 | .map(resolveApp);
26 |
27 | // config after eject: we're in ./config/
28 | module.exports = {
29 | appBuild: resolveApp('build'),
30 | appPublic: resolveApp('public'),
31 | appHtml: resolveApp('public/index.html'),
32 | appIndexJs: resolveApp('src/index.js'),
33 | appPackageJson: resolveApp('package.json'),
34 | appSrc: resolveApp('src'),
35 | testsSetup: resolveApp('src/setupTests.js'),
36 | appNodeModules: resolveApp('node_modules'),
37 | ownNodeModules: resolveApp('node_modules'),
38 | nodePaths: nodePaths
39 | };
40 |
41 |
42 |
43 | // config before publish: we're in ./packages/react-scripts/config/
44 | if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) {
45 | module.exports = {
46 | appBuild: resolveOwn('../../../build'),
47 | appPublic: resolveOwn('../template/public'),
48 | appHtml: resolveOwn('../template/public/index.html'),
49 | appIndexJs: resolveOwn('../template/src/index.js'),
50 | appPackageJson: resolveOwn('../package.json'),
51 | appSrc: resolveOwn('../template/src'),
52 | testsSetup: resolveOwn('../template/src/setupTests.js'),
53 | appNodeModules: resolveOwn('../node_modules'),
54 | ownNodeModules: resolveOwn('../node_modules'),
55 | nodePaths: nodePaths
56 | };
57 | }
58 |
--------------------------------------------------------------------------------
/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/config/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var autoprefixer = require('autoprefixer');
3 | var webpack = require('webpack');
4 | var findCacheDir = require('find-cache-dir');
5 | var HtmlWebpackPlugin = require('html-webpack-plugin');
6 | var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
7 | var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
8 | var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
9 | var getClientEnvironment = require('./env');
10 | var paths = require('./paths');
11 |
12 | // Webpack uses `publicPath` to determine where the app is being served from.
13 | // In development, we always serve from the root. This makes config easier.
14 | var publicPath = '/';
15 | // `publicUrl` is just like `publicPath`, but we will provide it to our app
16 | // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
17 | // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
18 | var publicUrl = '';
19 | // Get environment variables to inject into our app.
20 | var env = getClientEnvironment(publicUrl);
21 |
22 | // This is the development configuration.
23 | // It is focused on developer experience and fast rebuilds.
24 | // The production configuration is different and lives in a separate file.
25 | module.exports = {
26 | // This makes the bundle appear split into separate modules in the devtools.
27 | // We don't use source maps here because they can be confusing:
28 | // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875
29 | // You may want 'cheap-module-source-map' instead if you prefer source maps.
30 | devtool: 'eval',
31 | // These are the "entry points" to our application.
32 | // This means they will be the "root" imports that are included in JS bundle.
33 | // The first two entry points enable "hot" CSS and auto-refreshes for JS.
34 | entry: [
35 | // Include an alternative client for WebpackDevServer. A client's job is to
36 | // connect to WebpackDevServer by a socket and get notified about changes.
37 | // When you save a file, the client will either apply hot updates (in case
38 | // of CSS changes), or refresh the page (in case of JS changes). When you
39 | // make a syntax error, this client will display a syntax error overlay.
40 | // Note: instead of the default WebpackDevServer client, we use a custom one
41 | // to bring better experience for Create React App users. You can replace
42 | // the line below with these two lines if you prefer the stock client:
43 | // require.resolve('webpack-dev-server/client') + '?/',
44 | // require.resolve('webpack/hot/dev-server'),
45 | require.resolve('react-dev-utils/webpackHotDevClient'),
46 | // We ship a few polyfills by default:
47 | require.resolve('./polyfills'),
48 | // Finally, this is your app's code:
49 | paths.appIndexJs
50 | // We include the app code last so that if there is a runtime error during
51 | // initialization, it doesn't blow up the WebpackDevServer client, and
52 | // changing JS code would still trigger a refresh.
53 | ],
54 | output: {
55 | // Next line is not used in dev but WebpackDevServer crashes without it:
56 | path: paths.appBuild,
57 | // Add /* filename */ comments to generated require()s in the output.
58 | pathinfo: true,
59 | // This does not produce a real file. It's just the virtual path that is
60 | // served by WebpackDevServer in development. This is the JS bundle
61 | // containing code from all our entry points, and the Webpack runtime.
62 | filename: 'static/js/bundle.js',
63 | // This is the URL that app is served from. We use "/" in development.
64 | publicPath: publicPath
65 | },
66 | resolve: {
67 | // This allows you to set a fallback for where Webpack should look for modules.
68 | // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
69 | // We use `fallback` instead of `root` because we want `node_modules` to "win"
70 | // if there any conflicts. This matches Node resolution mechanism.
71 | // https://github.com/facebookincubator/create-react-app/issues/253
72 | fallback: paths.nodePaths,
73 | // These are the reasonable defaults supported by the Node ecosystem.
74 | // We also include JSX as a common component filename extension to support
75 | // some tools, although we do not recommend using it, see:
76 | // https://github.com/facebookincubator/create-react-app/issues/290
77 | extensions: ['.js', '.json', '.jsx', ''],
78 | alias: {
79 | // Support React Native Web
80 | // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
81 | 'react-native': 'react-native-web'
82 | }
83 | },
84 |
85 | module: {
86 | // First, run the linter.
87 | // It's important to do this before Babel processes the JS.
88 | preLoaders: [
89 | {
90 | test: /\.(js|jsx)$/,
91 | loader: 'eslint',
92 | include: paths.appSrc,
93 | }
94 | ],
95 | loaders: [
96 | // Process JS with Babel.
97 | {
98 | test: /\.(js|jsx)$/,
99 | include: paths.appSrc,
100 | loader: 'babel',
101 | query: {
102 |
103 | // This is a feature of `babel-loader` for webpack (not Babel itself).
104 | // It enables caching results in ./node_modules/.cache/react-scripts/
105 | // directory for faster rebuilds. We use findCacheDir() because of:
106 | // https://github.com/facebookincubator/create-react-app/issues/483
107 | cacheDirectory: findCacheDir({
108 | name: 'react-scripts'
109 | })
110 | }
111 | },
112 | // "postcss" loader applies autoprefixer to our CSS.
113 | // "css" loader resolves paths in CSS and adds assets as dependencies.
114 | // "style" loader turns CSS into JS modules that inject