├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── manifest.json └── index.html ├── docs ├── writegen_demo.gif ├── workflow.md └── writegenJSGuide.md ├── src ├── App.js ├── LoadingIndicator.js ├── index.css ├── index.js ├── App.css ├── InvertedInputSlider.js ├── Main.js ├── InputSlider.js ├── serviceWorker.js └── WriteGenForm.js ├── .gitignore ├── README.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/logo512.png -------------------------------------------------------------------------------- /docs/writegen_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/docs/writegen_demo.gif -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimzers/writegen/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | 4 | import Main from './Main' 5 | 6 | function App() { 7 | return ( 8 |
9 |
10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /src/LoadingIndicator.js: -------------------------------------------------------------------------------- 1 | import LinearProgress from "@material-ui/core/LinearProgress"; 2 | import React from "react"; 3 | 4 | export default function LoadingIndicator(props) { 5 | 6 | const loading = props.isLoading; 7 | 8 | return ( 9 |
10 | {!loading ? '' : 11 | } 12 |
13 | ) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | .idea 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # Local Netlify folder 27 | .netlify -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | import 'fontsource-roboto'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | 15 | // If you want your app to work offline and load faster, you can change 16 | // unregister() to register() below. Note this comes with some pitfalls. 17 | // Learn more about service workers: https://bit.ly/CRA-PWA 18 | serviceWorker.unregister(); 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WriteGen - Your personal AI Writer! 2 | 3 | ##### _WriteGen is an AI powered writer that allows you to become more productive and have fun. It comes loaded with many themes to help you to fully express yourself!_ 4 | 5 | ![WriteGen Demo](docs/writegen_demo.gif) 6 | 7 | ## How to use: 8 | 9 | Go to our [website](https://writegen.com) and follow the instructions there. **NOTE:** Writing might take **1-5 minutes**, please be patient! 10 | 11 | ## Coming Soon: 12 | 13 | - Different writer themes (If you have any suggestions, feel free to make a request here: https://github.com/jimzers/writegen/issues/new) 14 | - AI Voiceovers 15 | 16 | ## Acknowledgments 17 | 18 | Thanks to Sebastian for helping me out with this project. 19 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "WriteGen", 3 | "name": "WriteGen: An AI Powered Writer!", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "apple-touch-icon.png", 12 | "type": "image/png", 13 | "sizes": "180x180" 14 | }, 15 | { 16 | "src": "android-chrome-192x192.png", 17 | "type": "image/png", 18 | "sizes": "192x192" 19 | }, 20 | { 21 | "src": "android-chrome-512x512.png", 22 | "type": "image/png", 23 | "sizes": "512x512" 24 | } 25 | ], 26 | "start_url": ".", 27 | "display": "standalone", 28 | "theme_color": "#20948B", 29 | "background_color": "#fafafa" 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "writegen-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.10.2", 7 | "@material-ui/icons": "^4.9.1", 8 | "@material-ui/lab": "^4.0.0-alpha.56", 9 | "@testing-library/jest-dom": "^4.2.4", 10 | "@testing-library/react": "^9.3.2", 11 | "@testing-library/user-event": "^7.1.2", 12 | "axios": "^0.19.2", 13 | "fontsource-roboto": "^2.1.4", 14 | "react": "^16.13.1", 15 | "react-dom": "^16.13.1", 16 | "react-scripts": "3.4.1" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/workflow.md: -------------------------------------------------------------------------------- 1 | # Project Workflow 2 | 3 | Having an organized project workflow is important for keeping the project somewhat organized. Here's a workflow to follow: 4 | 5 | ##### Important rule of thumb: Don't rewrite the history!!! That means NO `git push -f` 6 | 7 | ## When you have a feature / bug fix you need to work on: 8 | 9 | 1. Create your own branch 10 | 2. Write the code 11 | 3. Make a pull request for your branch 12 | 4. Get pull request reviewed 13 | 5. Merge into master branch 14 | 15 | ## Creating your own branch 16 | 17 | ```shell script 18 | # update master branch locally 19 | git checkout master 20 | git fetch 21 | git rebase origin/master 22 | 23 | # create branch 24 | git checkout -b branch-name 25 | 26 | # change your files, drink some coffee, spill coffee on keyboard... do whatever 27 | 28 | # add any specific files if not committing everything: 29 | git add file/path/here 30 | 31 | # commit (add -a for all changed files, --verbose for an overview of changes made) 32 | git commit -m "commit message here" 33 | 34 | # push to github, only need to do '--set-upstream' once. also replaceable with -u 35 | git push --set-upstream origin branch-name 36 | ``` 37 | 38 | ## Pulling the latest master changes to your branch 39 | 40 | Note: do this before sending a pull request into master! 41 | 42 | ```shell script 43 | # make sure code is up to date: 44 | git fetch 45 | git checkout branch-name 46 | git rebase origin/branch-name 47 | 48 | # merge in the latest master code 49 | git merge origin/master 50 | 51 | # resolve any merge conflict here 52 | 53 | # should say that you're ahead of origin now 54 | git status 55 | 56 | git push 57 | ``` 58 | 59 | Good luck gitting! 60 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 19 | 20 | 29 | WriteGen 30 | 31 | 32 | 33 |
34 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/InvertedInputSlider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {makeStyles} from '@material-ui/core/styles'; 3 | import Grid from '@material-ui/core/Grid'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import Slider from '@material-ui/core/Slider'; 6 | import Input from '@material-ui/core/Input'; 7 | import FormatTextdirectionLToRIcon from '@material-ui/icons/FormatTextdirectionLToR'; 8 | 9 | const useStyles = makeStyles({ 10 | root: { 11 | width: 250, 12 | }, 13 | input: { 14 | width: 55, 15 | }, 16 | }); 17 | 18 | export default function InvertedInputSlider(props) { 19 | const classes = useStyles(); 20 | const value = props.data.MinSampleLen; 21 | const setValue = props.data.setMinSampleLen; 22 | const maxValue = props.data.MaxSampleLen; 23 | 24 | const isDisabled = props.data["isDisabled"]; 25 | // console.log("the value: " + value) 26 | 27 | const handleSliderChange = (event, newValue) => { 28 | setValue(newValue); 29 | }; 30 | 31 | const handleInputChange = (event) => { 32 | setValue(event.target.value === '' ? '' : Number(event.target.value)); 33 | }; 34 | 35 | const handleBlur = () => { 36 | if (value < 300) { 37 | setValue(300); 38 | } else if (value > maxValue) { 39 | setValue(maxValue); 40 | } 41 | }; 42 | 43 | return ( 44 |
45 | 46 | {props.props["InputTitle"]} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 65 | 80 | 81 | 82 |
83 | ); 84 | } -------------------------------------------------------------------------------- /src/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CssBaseline from '@material-ui/core/CssBaseline'; 3 | import Typography from '@material-ui/core/Typography'; 4 | import {makeStyles} from '@material-ui/core/styles'; 5 | import Container from '@material-ui/core/Container'; 6 | import Link from '@material-ui/core/Link'; 7 | import WriteGenForm from "./WriteGenForm"; 8 | // import createMuiTheme from "@material-ui/core/styles/createMuiTheme"; 9 | 10 | function Copyright() { 11 | return ( 12 | 13 | {'Copyright © '} 14 | 15 | Adam Lee 16 | {' '} 17 | {new Date().getFullYear()} 18 | {'.'} 19 | 20 | ); 21 | } 22 | 23 | // const muiTheme = createMuiTheme({ 24 | // spacing: 2 25 | // }) 26 | 27 | const useStyles = makeStyles((theme) => ({ 28 | root: { 29 | display: 'flex', 30 | flexDirection: 'column', 31 | minHeight: '100vh', 32 | }, 33 | main: { 34 | marginTop: theme.spacing(8), 35 | marginBottom: theme.spacing(2), 36 | }, 37 | body: { 38 | marginBottom: theme.spacing(3) 39 | }, 40 | footer: { 41 | padding: theme.spacing(3, 2), 42 | marginTop: 'auto', 43 | backgroundColor: 44 | theme.palette.type === 'light' ? theme.palette.grey[200] : theme.palette.grey[800], 45 | }, 46 | })); 47 | 48 | export default function Main() { 49 | const classes = useStyles(); 50 | 51 | return ( 52 |
53 | 54 | 55 | 56 | WriteGen 57 | 58 | 59 | {'Your own personal writer!'} 60 | 61 | 62 | {'WriteGen uses AI to write passages for you. But it needs your help! '} 63 | {'Type in some text below and press submit to see your short story!'} 64 | 65 | 66 | 67 | 68 | 69 | 80 |
81 | ); 82 | } -------------------------------------------------------------------------------- /src/InputSlider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {makeStyles} from '@material-ui/core/styles'; 3 | import Grid from '@material-ui/core/Grid'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import Slider from '@material-ui/core/Slider'; 6 | import Input from '@material-ui/core/Input'; 7 | import FormatTextdirectionLToRIcon from '@material-ui/icons/FormatTextdirectionLToR'; 8 | import LoopIcon from '@material-ui/icons/Loop'; 9 | import HourglassEmptyIcon from '@material-ui/icons/HourglassEmpty'; 10 | 11 | const useStyles = makeStyles({ 12 | root: { 13 | width: 250, 14 | }, 15 | input: { 16 | width: 55, 17 | }, 18 | }); 19 | 20 | const iconMap = { 21 | 1: , 22 | 2: , 23 | 3: 24 | } 25 | 26 | export default function InputSlider(props) { 27 | const classes = useStyles(); 28 | 29 | const title = props.props["InputTitle"]; 30 | const value = props.data["topValue"]; 31 | const setValue = props.data["setTopValue"]; 32 | const minValue = props.props["minVal"]; 33 | const maxLimit = props.props["maxVal"]; 34 | const stepVal = props.props["step"]; 35 | 36 | const icon = iconMap[props.props["icon"]]; 37 | 38 | const isDisabled = props.data["isDisabled"]; 39 | 40 | // console.log("the value: " + value) 41 | 42 | const handleSliderChange = (event, newValue) => { 43 | setValue(newValue); 44 | }; 45 | 46 | const handleInputChange = (event) => { 47 | setValue(event.target.value === '' ? '' : Number(event.target.value)); 48 | }; 49 | 50 | const handleBlur = () => { 51 | if (value < minValue) { 52 | setValue(minValue); 53 | 54 | } else if (value > maxLimit) { 55 | setValue(maxLimit); 56 | } 57 | }; 58 | 59 | return ( 60 |
61 | 62 | {title} 63 | 64 | 65 | 66 | {icon} 67 | 68 | 69 | 78 | 79 | 80 | 95 | 96 | 97 |
98 | ); 99 | } -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /docs/writegenJSGuide.md: -------------------------------------------------------------------------------- 1 | # WriteGen JavaScript Style Guide 2 | 3 | 4 | ## Table of Contents 5 | * [Whitespace](#whitespace) 6 | * [Column Limit](#columns) 7 | * [Import Statements](#import) 8 | * [Creating New Lines](#newlines) 9 | * [Commenting](#comments) 10 | * [Example Code](#examples) 11 | 12 | 13 | ## Whitespace 14 | - With the exception of function calls, every opening parentheses must have whitespace before it, and every closing parentheses must have whitespace following [it.](#whitespaceExample1) 15 | 16 | ``` 17 | for (int i = 0; i < array.length; i++) { 18 | text += array[i] +
; 19 | } 20 | ``` 21 | 22 | - Equal signs should have whitespaces on [either side.](#whitespaceExample2) 23 | 24 | ``` 25 | var num = 6; 26 | ``` 27 | 28 | - For consistency and readability, four spaces will equal a tab, and we should do our best to utilize spaces instead of tabs. 29 | 30 | 31 | 32 | ## Column Limit 33 | - With the exception of the use of strings, avoid line widths longer than 100 characters. 34 | - When using code as object attributes, function parameters, styling attributes, etc. that exceeds the character limit, make sure that each attribute is aligned and separate onto a [new line](#split). 35 | 36 | ``` 37 | function someExtremelyLongFunctionName ( 38 | writingGeneratorName, articleTitle, articlePictureCaption) { 39 | // example for splitting up parameters onto a new line 40 | } 41 | ``` 42 | 43 | 44 | ## Import Statements 45 | - Place all import statements above all non-import statements in order to avoid [any surprises.](#importsBefore) 46 | 47 | ``` 48 | // bad example 49 | import Question from "./question" 50 | 51 | function App () { 52 | 53 | } 54 | 55 | import Answer from "./answer" 56 | 57 | // good example 58 | import Header from "./header" 59 | import Content from "./content" 60 | import Footer from "./footer" 61 | 62 | function AppTwo () { 63 |
64 | 65 |