├── .dockerignore ├── .env ├── .gitignore ├── .travis.yml ├── Dockerfile ├── README.md ├── bin └── version-assets.js ├── client ├── js │ ├── api.js │ ├── app.js │ ├── components │ │ ├── auth │ │ │ ├── login.js │ │ │ ├── register.js │ │ │ └── user-panel.js │ │ ├── circle.js │ │ ├── copy-button.js │ │ ├── display.js │ │ ├── header.js │ │ ├── health.js │ │ ├── help.js │ │ ├── hyperdrive │ │ │ ├── client.js │ │ │ └── index.js │ │ ├── import-queue.js │ │ ├── list.js │ │ ├── login-button.js │ │ └── preview.js │ ├── defaults.js │ ├── elements │ │ ├── 404 │ │ │ └── index.js │ │ ├── add-files │ │ │ └── index.js │ │ ├── button │ │ │ └── index.js │ │ ├── delete-button │ │ │ └── index.js │ │ ├── error │ │ │ └── index.js │ │ ├── footer │ │ │ └── index.js │ │ ├── gravatar │ │ │ └── index.js │ │ ├── home-section │ │ │ └── index.js │ │ ├── hyperdrive-stats │ │ │ └── index.js │ │ ├── icon │ │ │ └── index.js │ │ ├── import-button │ │ │ └── index.js │ │ ├── loader-icon │ │ │ └── index.js │ │ ├── loading │ │ │ └── index.js │ │ └── message │ │ │ └── index.js │ ├── models │ │ ├── archive.js │ │ ├── defaults.js │ │ ├── message.js │ │ ├── preview.js │ │ ├── profile.js │ │ └── township.js │ ├── pages │ │ ├── archive │ │ │ ├── index.js │ │ │ └── webrtc.js │ │ ├── auth │ │ │ ├── delete-account.js │ │ │ ├── edit-profile.js │ │ │ ├── login.js │ │ │ ├── profile.js │ │ │ ├── register.js │ │ │ └── reset-password.js │ │ ├── download.js │ │ ├── fourohfour.js │ │ ├── landing │ │ │ └── index.js │ │ ├── publish │ │ │ └── index.js │ │ └── wrapper.js │ └── plugins │ │ └── analytics.js └── scss │ ├── app.scss │ └── imports │ ├── _base.scss │ ├── _block-create.scss │ ├── _buttons.scss │ ├── _error-page.scss │ ├── _file-system.scss │ ├── _fonts.scss │ ├── _grid.scss │ ├── _horizontal-rule.scss │ ├── _layout.scss │ ├── _panel.scss │ ├── _sections.scss │ ├── _status-bar.scss │ └── _variables.scss ├── config ├── config.production.js ├── config.test.js └── default.js ├── docker-compose.yml ├── docs ├── api.md ├── contributing.md └── deployment.md ├── package.json ├── public ├── dat-paper.pdf ├── fonts │ ├── Source+Code+Pro_400_normal.svg │ ├── Source+Code+Pro_400_normal.ttf │ ├── Source+Code+Pro_400_normal.woff │ ├── Source+Code+Pro_500_normal.ttf │ ├── Source+Code+Pro_500_normal.woff │ ├── Source+Sans+Pro_400_normal.svg │ ├── Source+Sans+Pro_400_normal.ttf │ ├── Source+Sans+Pro_400_normal.woff │ ├── Source+Sans+Pro_700_normal.ttf │ └── Source+Sans+Pro_700_normal.woff └── img │ ├── bg-landing-page.svg │ ├── blog │ ├── preview-file.png │ └── preview-filelist.png │ ├── clipboard.svg │ ├── codeforscience.png │ ├── create-new-dat.svg │ ├── dat-data-logo.png │ ├── dat-data-logo.svg │ ├── dat-gif.gif │ ├── dat-hexagon.svg │ ├── dat-terminal.svg │ ├── download.svg │ ├── eop.png │ ├── example-california.svg │ ├── example-densho.png │ ├── example-osm-2.svg │ ├── example-osm.svg │ ├── favicon.ico │ ├── knight.png │ ├── link.svg │ ├── logo-dat-desktop-dark.svg │ ├── moore.png │ ├── nasa-logo.svg │ ├── open-in-desktop.svg │ ├── question.svg │ ├── screenshot-dat-desktop-empty.png │ ├── screenshot-dat-desktop-import-dat.png │ ├── screenshot-dat-desktop.png │ ├── sloan.png │ └── terminal-icon.svg ├── scripts ├── add-dats-for-user.js └── user-and-dat.js ├── server ├── cli.js ├── config.js ├── index.js ├── page.js └── router.js └── tests ├── e2e-webrtc └── connect.js ├── e2e ├── preview.js ├── server.js └── user.js ├── fixtures ├── dat.json ├── hello.csv ├── testingfolder │ └── hello.txt └── whitelist.txt ├── globals.js ├── helpers.js ├── new-dat.js ├── nightwatch.json ├── package.json ├── test.sh └── unit └── api.js /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | selenium-debug.log 5 | dat.land 6 | *township.db 7 | sqlite.db 8 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | TAG=latest 2 | NODE_ENV=production 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bundle.css 2 | package-lock.json 3 | .DS_Store 4 | node_modules/ 5 | data/* 6 | public/css/* 7 | public/js/app.js 8 | public/js/app.min.js 9 | public/js/app.min.*.js 10 | server/page-debug.js 11 | .tmp-deploy 12 | npm-debug.log 13 | REVISION 14 | version.json 15 | reports/ 16 | selenium-debug.log 17 | dat.land 18 | township.db 19 | sqlite.db 20 | config.local.js 21 | public/rendered 22 | invited-users 23 | secrets 24 | archiver 25 | .datcache/ 26 | config/config.development.js 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | services: 4 | - docker 5 | dist: trusty 6 | node_js: 7 | - 6 8 | 9 | env: 10 | global: 11 | - TAG=travis-${TRAVIS_BUILD_NUMBER} 12 | - NODE_ENV=test 13 | 14 | install: 15 | - TAG=latest docker-compose pull 16 | - echo travis_fold:start:docker-compose-build 17 | - docker-compose build 18 | - echo travis_fold:end:docker-compose-build 19 | - sh -c 'cd tests && npm i' 20 | 21 | script: 22 | - docker-compose up -d newdat && sleep 10 23 | - docker-compose run --rm datbase sh -c 'npm i --only=dev --loglevel warn && npm run test' 24 | - docker-compose run --rm nightwatch 25 | 26 | after_success: 27 | - if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then 28 | if [[ "$TRAVIS_BRANCH" == "master" || "$TRAVIS_BRANCH" == "beta" || "$TRAVIS_BRANCH" == "released" ]]; then 29 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"; 30 | docker tag datproject/datbase:travis-${TRAVIS_BUILD_NUMBER} datproject/datbase:$TRAVIS_BRANCH; 31 | docker push datproject/datbase:$TRAVIS_BRANCH; 32 | fi; fi 33 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.9 2 | EXPOSE 80 3 | EXPOSE 25 4 | 5 | ENV PORT 80 6 | ENV NODE_ENV development 7 | 8 | ENV TOWNSHIP_SECRET "some secret string here" 9 | ENV DATADIR /data 10 | VOLUME /data 11 | 12 | RUN mkdir -p /usr/src/app 13 | WORKDIR /usr/src/app 14 | COPY package.json /usr/src/app/ 15 | RUN npm install --production --loglevel warn 16 | COPY . /usr/src/app 17 | RUN npm run build-js-prod && npm run build-css && npm run minify && npm run version 18 | 19 | # do docker exec: npm run database 20 | 21 | CMD npm run database && DEBUG=dat-registry npm run server 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![deprecated](http://badges.github.io/stability-badges/dist/deprecated.svg)](https://dat-ecosystem.org/) 2 | 3 | More info on active projects and modules at [dat-ecosystem.org](https://dat-ecosystem.org/) 4 | 5 | --- 6 | 7 | # datBase 8 | 9 | Open data powered by Dat. Future-friendly apps for your research data pipeline. Hosted at [http://datbase.org](http://datbase.org). 10 | 11 | [![Build Status](https://travis-ci.org/datproject/datBase.svg?branch=master)](https://travis-ci.org/datproject/datBase) 12 | 13 | ## Features 14 | 15 | * Preview the files in a dat in the browser. 16 | * Download individual files from dats. 17 | * Create short links for dats with user accounts. 18 | 19 | ## Setup 20 | 21 | 0. Clone this repository, then copy the configuration file: 22 | 23 | ``` 24 | cp config/default.js config/config.development.js 25 | ``` 26 | 27 | 1. Install the dependencies: 28 | 29 | ``` 30 | npm install 31 | ``` 32 | 33 | Create the database 34 | 35 | ``` 36 | npm run database 37 | ``` 38 | 39 | Start the server 40 | ``` 41 | npm start 42 | ``` 43 | 44 | ## Configuration 45 | 46 | 47 | ### Secret key 48 | 49 | Each deployment should have a different secret key. You want to set the secret key for generating password hashes and salts. 50 | 51 | Set the secret key by using the `TOWNSHIP_SECRET` environment variable. 52 | 53 | ### Default location of account and sqlite databases 54 | 55 | Specify where you want data for the app (databases and also by default the archiver) to be located. By default, all the data will be stored in `./data`. If you'd like the data to be stored somewhere else, add a `data` key: 56 | 57 | ``` 58 | { 59 | data: '/path/to/my/data' 60 | } 61 | ``` 62 | 63 | ### Closed beta 64 | 65 | To create a closed beta, add the `whitelist` key with the path to a newline-delimited list of emails allowed to sign up. Default value `false` allows anyone to register an account. 66 | 67 | ``` 68 | { whitelist: '/path/to/my/list/of/folks.txt'} 69 | ``` 70 | 71 | `folks.txt` should have a list of valid emails, each separated by a new line character. For example: 72 | 73 | ``` 74 | pamlikesdata@gmail.com 75 | robert.singletown@sbcglobal.netw 76 | ``` 77 | 78 | ### Location of cached and archived dat data 79 | 80 | You can set the location where dat data is cached on the filesystem. By default it is stored in the `data` directory (above), in the `archiver` subdirectory. You can change this by using the `archiver` key: 81 | 82 | ``` 83 | { archiver: '/mnt1/bigdisk/archiver-data' } 84 | ``` 85 | 86 | ### Mixpanel account 87 | 88 | The site will report basic information to Mixpanel if you have an account. It will by default use the environment variable `MIXPANEL_KEY`. 89 | 90 | This can also be set in the configuration file by using the `mixpanel` key: 91 | 92 | ``` 93 | { mixpanel: '' } 94 | ``` 95 | 96 | ### Advanced password security 97 | 98 | If you want to have advanced security for generating passwords, you can use ES512 keys, for example. Generate the keys using [this tutorial](https://connect2id.com/products/nimbus-jose-jwt/openssl-key-generation) and set their locations in the configuration file. 99 | 100 | ``` 101 | { 102 | township: { 103 | db: 'township.db', 104 | publicKey: path.join('secrets', 'ecdsa-p521-public.pem'), 105 | privateKey: path.join('secrets', 'ecdsa-p521-private.pem'), 106 | algorithm: 'ES512' 107 | } 108 | } 109 | ``` 110 | -------------------------------------------------------------------------------- /bin/version-assets.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var fs = require('fs') 3 | var Version = require('node-version-assets') 4 | 5 | // productionize `server/page.js` by updating asset references 6 | // `main.css` -> 'main.min.css' 7 | // `app.js` -> `app.min.js` 8 | // re-name original, un-productionized `page.js` to `page-debug.html` 9 | var page = 'server/page.js' 10 | var pageContents = fs.readFileSync(page, 'utf8') 11 | fs.renameSync(page, 'server/page-debug.js') 12 | 13 | var prod = pageContents 14 | .replace(/public\/css\/app.css/gmi, 'public/css/app.min.css') 15 | .replace(/public\/js\/app.js/gmi, 'public/js/app.min.js') 16 | fs.writeFileSync(page, prod, 'utf8') 17 | 18 | // version `app.min.js` and `main.min.js` by appending md5 hash to filename 19 | // & update references to files in `server/page.js` 20 | var versionInstance = new Version({ 21 | assets: [ 22 | 'public/js/app.min.js', 23 | 'public/css/app.min.css' 24 | ], 25 | grepFiles: [ 26 | page 27 | ], 28 | keepOriginal: true, 29 | keepOldVersions: false 30 | }) 31 | 32 | versionInstance.run() 33 | -------------------------------------------------------------------------------- /client/js/api.js: -------------------------------------------------------------------------------- 1 | var api = require('dat-registry') 2 | 3 | module.exports = function () { 4 | if (!module.parent) { 5 | return api({server: window.location.origin, apiPath: '/api/v1'}) 6 | } 7 | return 8 | } 9 | -------------------------------------------------------------------------------- /client/js/app.js: -------------------------------------------------------------------------------- 1 | const choo = require('choo') 2 | const persist = require('choo-persist') 3 | const logger = require('choo-log') 4 | const css = require('sheetify') 5 | const defaults = require('./models/defaults') 6 | const app = choo() 7 | 8 | // define models: 9 | var key = module.parent ? '' : window.location.origin 10 | app.use(persist({name: 'choo-hypertracker' + key})) 11 | if (process.env.NODE_ENV !== 'production') { 12 | app.use(logger()) 13 | } 14 | app.use(require('./defaults')(defaults)) 15 | app.use(require('./models/archive')) 16 | app.use(require('./models/township')) 17 | app.use(require('./models/profile')) 18 | app.use(require('./models/message')) 19 | app.use(require('./models/preview')) 20 | app.use(require('./plugins/analytics')) 21 | 22 | css('tachyons') 23 | css('dat-colors') 24 | 25 | // define routes: 26 | app.route('/publish', require('./pages/publish')) 27 | app.route('/register', require('./pages/auth/register')) 28 | app.route('/login', require('./pages/auth/login')) 29 | app.route('/reset-password', require('./pages/auth/reset-password')) 30 | app.route('/404', require('./pages/fourohfour')) 31 | app.route('/view', require('./pages/archive')) 32 | app.route('/download/:archiveKey', require('./pages/download')) 33 | app.route('/profile/edit', require('./pages/auth/edit-profile')) 34 | app.route('/profile/delete', require('./pages/auth/delete-account')) 35 | app.route('/dat://:archiveKey', require('./pages/archive')) 36 | app.route('/dat://:archiveKey/contents', require('./pages/archive')) 37 | app.route('/dat://:archiveKey/contents/*', require('./pages/archive')) 38 | app.route('/:username/:dataset', require('./pages/archive')) 39 | app.route('/:username/:dataset/*', require('./pages/archive')) 40 | app.route('/:username', require('./pages/auth/profile')) 41 | app.route('/', require('./pages/landing')) 42 | 43 | app.defaults = defaults 44 | 45 | if (module.parent) { 46 | module.exports = app 47 | } else { 48 | app.mount('#app-root') 49 | } 50 | -------------------------------------------------------------------------------- /client/js/components/auth/login.js: -------------------------------------------------------------------------------- 1 | const html = require('choo/html') 2 | const css = require('sheetify') 3 | const form = require('get-form-data') 4 | 5 | const login = (state, emit) => { 6 | function onSubmit (e) { 7 | const data = form(e.target) 8 | emit('township:login', data) 9 | e.preventDefault() 10 | return false 11 | } 12 | 13 | var styles = css` 14 | :host { 15 | .error { 16 | font-size: .875rem; 17 | font-weight: normal; 18 | color: $color-red; 19 | } 20 | } 21 | ` 22 | 23 | 24 | return html`
25 |
26 |

Log In

27 |
28 |
${state.township.error}
29 |

30 | 36 |

37 |

38 | 44 |

45 |

46 | 47 |

48 |

49 | Forgot Password? 50 | No Account yet? Register » 51 |

52 |
53 |
54 |
` 55 | } 56 | 57 | module.exports = login 58 | -------------------------------------------------------------------------------- /client/js/components/auth/register.js: -------------------------------------------------------------------------------- 1 | const html = require('choo/html') 2 | const form = require('get-form-data') 3 | 4 | const register = (state, emit) => { 5 | function onSubmit (e) { 6 | const data = form(e.target) 7 | emit('township:register', data) 8 | e.preventDefault() 9 | return false 10 | } 11 | 12 | return html`
13 |
14 |

Create a New Account

15 |
16 |
${state.township.error}
17 |

18 | 24 |

25 |

26 | 32 |

33 |

34 | 40 |

41 |

42 | 43 |

44 |

45 | Already Have an Account? Log In » 46 |

47 |
48 |
49 |
` 50 | } 51 | 52 | module.exports = register 53 | -------------------------------------------------------------------------------- /client/js/components/auth/user-panel.js: -------------------------------------------------------------------------------- 1 | const css = require('sheetify') 2 | const html = require('choo/html') 3 | 4 | const prefix = css` 5 | :host { 6 | position: absolute; 7 | right: 0; 8 | top: 3.75rem; 9 | z-index: 100; 10 | min-width: 18rem; 11 | padding: 1rem; 12 | background-color: var(--color-white); 13 | color: var(--color-neutral-80); 14 | box-shadow: 0 0 .75rem rgba(0,0,0,.25); 15 | .gravatar { 16 | border-radius: 50%; 17 | width: 3rem; 18 | height: 3rem; 19 | display: block; 20 | margin: 0 .5rem 0 0; 21 | border: 2px solid var(--color-neutral-04); 22 | } 23 | 24 | .content { 25 | margin-top: .5rem; 26 | margin-bottom: .5rem; 27 | padding-top: .5rem; 28 | padding-bottom: .5rem; 29 | border-top: 1px solid var(--color-neutral-10); 30 | border-bottom: 1px solid var(--color-neutral-10); 31 | } 32 | .close-button { 33 | position: absolute; 34 | right: .5rem; 35 | top: .5rem; 36 | display: block; 37 | overflow: hidden; 38 | color: var(--color-neutral-20); 39 | &:hover, &:focus { 40 | color: var(--color-neutral-40); 41 | } 42 | svg { 43 | fill: currentColor; 44 | max-width: 1.5rem; 45 | max-height: 1.5rem; 46 | } 47 | } 48 | ul { 49 | padding-left: 0; 50 | border-top: 1px solid var(--color-neutral-20); 51 | a { 52 | display: block; 53 | color: var(--color-neutral-60); 54 | &:hover, &:focus { 55 | color: var(--color-neutral-80); 56 | } 57 | } 58 | li { 59 | margin-top: .5rem; 60 | margin-bottom: .5rem; 61 | } 62 | &:hover, &:focus { 63 | .delete-btn { 64 | visibility: visible; 65 | } 66 | } 67 | svg { 68 | fill: currentColor; 69 | max-width: 1rem; 70 | max-height: 1.5rem; 71 | } 72 | } 73 | 74 | } 75 | ` 76 | 77 | module.exports = function (state, emit) { 78 | if (!state.township.username) return 79 | 80 | return html`
81 | emit('township:sidePanel')}> 82 | 83 | 84 | 85 | 86 |
87 |
88 | Signed in as ${state.township.profile.username} 89 |
90 |
91 | 97 |
` 98 | } 99 | -------------------------------------------------------------------------------- /client/js/components/circle.js: -------------------------------------------------------------------------------- 1 | const html = require('choo/html') 2 | const css = require('sheetify') 3 | 4 | const circle = (prog) => { 5 | const prefix = css` 6 | .dat-progress-circle { 7 | margin-right: 10px; 8 | margin-top: 10px; 9 | position: relative; 10 | display: inline-block; 11 | width: 90px; 12 | height: 90px; 13 | line-height: 90px; 14 | border-radius: 50%; 15 | background: #394b5b; 16 | background-image: -webkit-linear-gradient(left, transparent 50%, #2980B9 0); 17 | background-image: linear-gradient(to right, transparent 50%, #2980B9 0); 18 | color: transparent; 19 | text-align: center; 20 | -webkit-animation: done 100.1s linear infinite; 21 | animation: done 100.1s linear infinite; 22 | -webkit-animation-play-state: paused; 23 | animation-play-state: paused; 24 | } 25 | 26 | .dat-progress-circle:hover { 27 | box-shadow: 0 1px 1rem rgba(0, 0, 0, 0.3); 28 | } 29 | 30 | @-webkit-keyframes spin { 31 | to { 32 | -webkit-transform: rotate(0.5turn); 33 | transform: rotate(0.5turn); 34 | } 35 | } 36 | 37 | @keyframes spin { 38 | to { 39 | -webkit-transform: rotate(0.5turn); 40 | transform: rotate(0.5turn); 41 | } 42 | } 43 | 44 | @-webkit-keyframes bg { 45 | 50% { 46 | background: #2980B9; 47 | } 48 | } 49 | 50 | @keyframes bg { 51 | 50% { 52 | background: #2980B9; 53 | } 54 | } 55 | 56 | @-webkit-keyframes done { 57 | 0% { 58 | background-color: #394b5b; 59 | } 60 | 99% { 61 | background-color: #394b5b; 62 | } 63 | 100% { 64 | background-color: #35B44F; 65 | } 66 | } 67 | 68 | @keyframes done { 69 | 0% { 70 | background-color: #394b5b; 71 | } 72 | 99% { 73 | background-color: #394b5b; 74 | } 75 | 100% { 76 | background-color: #35B44F; 77 | } 78 | } 79 | 80 | @keyframes bounce-once { 81 | 0% { 82 | transform: scale(1); 83 | } 84 | 50% { 85 | transform: scale(1.2); 86 | } 87 | 100% { 88 | transform: scale(1); 89 | } 90 | } 91 | 92 | .bounce-once { 93 | animation: bounce-once 0.5s cubic-bezier(0.320, -0.280, 0.760, 1.310) forwards; 94 | } 95 | 96 | .dat-progress-circle::before { 97 | content: ''; 98 | position: absolute; 99 | top: 0; 100 | left: 50%; 101 | width: 50%; 102 | height: 100%; 103 | border-radius: 0 100% 100% 0 / 50%; 104 | background-color: inherit; 105 | -webkit-transform-origin: left; 106 | transform-origin: left; 107 | -webkit-animation: spin 50s linear infinite, bg 100s step-end infinite; 108 | animation: spin 50s linear infinite, bg 100s step-end infinite; 109 | -webkit-animation-play-state: paused; 110 | animation-play-state: paused; 111 | -webkit-animation-delay: inherit; 112 | animation-delay: inherit; 113 | } 114 | 115 | .dat-progress-circle__progress { 116 | position: absolute; 117 | background-color: #65737F; 118 | width: 78px; 119 | height: 78px; 120 | top: 6px; 121 | left: 6px; 122 | z-index: 3; 123 | border-radius: 50%; 124 | overflow: hidden; 125 | color: white; 126 | } 127 | 128 | .dat-progress-circle__progress span { 129 | position: relative; 130 | top:-7px; 131 | } 132 | ` 133 | 134 | return html` 135 |
136 |
137 | ${prog === 100 ? 100 : prog.toFixed(2)}% 138 |
139 |
140 | ` 141 | } 142 | 143 | module.exports = circle 144 | -------------------------------------------------------------------------------- /client/js/components/copy-button.js: -------------------------------------------------------------------------------- 1 | const html = require('choo/html') 2 | const css = require('sheetify') 3 | const Clipboard = module.parent ? null : require('clipboard') 4 | 5 | var copyButton = css` 6 | :host { 7 | display: inline-block; 8 | line-height: 1.25; 9 | padding: 1rem; 10 | font-size: .875rem; 11 | background-color: transparent; 12 | color: var(--color-neutral-60); 13 | .btn__icon-img { 14 | width: 1.25rem; 15 | max-height: 1rem; 16 | } 17 | } 18 | ` 19 | 20 | module.exports = function (text, emit) { 21 | var el = html` 22 | 23 |
24 | 25 | Copy Link 26 |
27 |
28 | ` 29 | if (module.parent) return el 30 | var clipboard = new Clipboard('a.clipboard') 31 | clipboard.on('success', function () { 32 | emit('message:success', 'Link copied to clipboard') 33 | }) 34 | return el 35 | } 36 | -------------------------------------------------------------------------------- /client/js/components/display.js: -------------------------------------------------------------------------------- 1 | const fourohfour = require('../elements/404') 2 | const html = require('choo/html') 3 | 4 | module.exports = function (state, emit) { 5 | var display = html`
6 | 7 | ${fourohfour({ 8 | icon: 'loader', 9 | header: 'Loading...', 10 | body: 'This could take a second..', 11 | link: false 12 | })} 13 |
` 14 | if (module.parent) return display 15 | const entryName = state.preview.entry && state.preview.entry.name 16 | 17 | if (state.preview.error) { 18 | if (!state.preview.isPanelOpen) { 19 | emit('preview:openPanel', {}) 20 | } 21 | return fourohfour({ 22 | icon: state.preview.error.icon, 23 | header: state.preview.error.message, 24 | body: state.preview.error.body || `${entryName} cannot be rendered.`, 25 | link: false 26 | }) 27 | } 28 | if (!entryName) return display 29 | if (!state.preview.isPanelOpen) return emit('preview:openPanel', {}) 30 | if (state.preview.entry.size > (1048576 * 10)) { 31 | return fourohfour({ 32 | header: 'Cannot preview', 33 | body: 'This file is too big, use the desktop app or CLI.', 34 | link: false 35 | }) 36 | } 37 | return html`