app: refactoring app to TS and removing lots of unused props

This commit is contained in:
Hunter Miller 2022-01-26 12:21:19 -06:00
parent a9867c6522
commit 0abf7eecfe
16 changed files with 693 additions and 560 deletions

View File

@ -5,6 +5,6 @@ module.exports = {
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-class-properties',
'react-hot-loader/babel'
'react-refresh/babel'
]
};

View File

@ -1,7 +1,7 @@
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const urbitrc = require('./urbitrc');
const _ = require('lodash');
const { execSync } = require('child_process');
@ -47,7 +47,7 @@ if(urbitrc.URL) {
module.exports = {
mode: 'development',
entry: {
app: './src/index.js'
app: './src/index.tsx'
// serviceworker: './src/serviceworker.js'
},
module: {
@ -59,15 +59,14 @@ module.exports = {
options: {
presets: ['@babel/preset-env', '@babel/typescript', ['@babel/preset-react', {
runtime: 'automatic',
development: true,
importSource: '@welldone-software/why-did-you-render'
development: true
}]],
plugins: [
'@babel/transform-runtime',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-class-properties',
'react-hot-loader/babel'
'react-refresh/babel'
]
}
},
@ -115,7 +114,8 @@ module.exports = {
new HtmlWebpackPlugin({
title: 'Groups',
template: './public/index.html'
})
}),
new ReactRefreshWebpackPlugin()
],
watch: true,
output: {

View File

@ -75,6 +75,7 @@
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"@babel/preset-typescript": "^7.12.7",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@storybook/addon-actions": "^6.2.9",
"@storybook/addon-essentials": "^6.2.9",
"@storybook/addon-links": "^6.2.9",
@ -89,7 +90,6 @@
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.24.0",
"@urbit/eslint-config": "^1.0.0",
"@welldone-software/why-did-you-render": "^6.1.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"babel-loader": "^8.2.2",
@ -107,7 +107,6 @@
"lint-staged": "^11.0.0",
"loki": "^0.28.1",
"moment-locales-webpack-plugin": "^1.2.0",
"react-hot-loader": "^4.13.0",
"sass": "^1.32.5",
"sass-loader": "^8.0.2",
"storybook-addon-designs": "^6.0.0",
@ -3937,28 +3936,31 @@
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
"integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==",
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz",
"integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==",
"dev": true,
"dependencies": {
"ansi-html": "^0.0.7",
"ansi-html-community": "^0.0.8",
"common-path-prefix": "^3.0.0",
"core-js-pure": "^3.8.1",
"error-stack-parser": "^2.0.6",
"html-entities": "^1.2.1",
"native-url": "^0.2.6",
"schema-utils": "^2.6.5",
"find-up": "^5.0.0",
"html-entities": "^2.1.0",
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0",
"source-map": "^0.7.3"
},
"engines": {
"node": ">= 10.x"
"node": ">= 10.13"
},
"peerDependencies": {
"@types/webpack": "4.x",
"react-refresh": ">=0.8.3 <0.10.0",
"@types/webpack": "4.x || 5.x",
"react-refresh": ">=0.10.0 <1.0.0",
"sockjs-client": "^1.4.0",
"type-fest": "^0.13.1",
"type-fest": ">=0.17.0 <3.0.0",
"webpack": ">=4.43.0 <6.0.0",
"webpack-dev-server": "3.x",
"webpack-dev-server": "3.x || 4.x",
"webpack-hot-middleware": "2.x",
"webpack-plugin-serve": "0.x || 1.x"
},
@ -3983,6 +3985,120 @@
}
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/html-entities": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
"integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
"dev": true
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/json5": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.5"
},
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
},
"engines": {
"node": ">=8.9.0"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"dependencies": {
"p-locate": "^5.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"dependencies": {
"p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@ -6598,6 +6714,53 @@
"node": ">=8"
}
},
"node_modules/@storybook/react/node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
"integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==",
"dev": true,
"dependencies": {
"ansi-html": "^0.0.7",
"error-stack-parser": "^2.0.6",
"html-entities": "^1.2.1",
"native-url": "^0.2.6",
"schema-utils": "^2.6.5",
"source-map": "^0.7.3"
},
"engines": {
"node": ">= 10.x"
},
"peerDependencies": {
"@types/webpack": "4.x",
"react-refresh": ">=0.8.3 <0.10.0",
"sockjs-client": "^1.4.0",
"type-fest": "^0.13.1",
"webpack": ">=4.43.0 <6.0.0",
"webpack-dev-server": "3.x",
"webpack-hot-middleware": "2.x",
"webpack-plugin-serve": "0.x || 1.x"
},
"peerDependenciesMeta": {
"@types/webpack": {
"optional": true
},
"sockjs-client": {
"optional": true
},
"type-fest": {
"optional": true
},
"webpack-dev-server": {
"optional": true
},
"webpack-hot-middleware": {
"optional": true
},
"webpack-plugin-serve": {
"optional": true
}
}
},
"node_modules/@storybook/react/node_modules/@storybook/semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz",
@ -6614,6 +6777,38 @@
"node": ">=10"
}
},
"node_modules/@storybook/react/node_modules/react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@storybook/react/node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/@storybook/react/node_modules/type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@storybook/router": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.3.3.tgz",
@ -7821,18 +8016,6 @@
"@xtuc/long": "4.2.2"
}
},
"node_modules/@welldone-software/why-did-you-render": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-6.2.0.tgz",
"integrity": "sha512-ViwaE09Vgb0yXzyZuGTWCmWy/nBRAEGyztMdFYuxIgmL8yoXX5TVMCfieiJGdRQQPiDUznlYmcu0lu8kN1lwtQ==",
"dev": true,
"dependencies": {
"lodash": "^4"
},
"peerDependencies": {
"react": "^16 || ^17"
}
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -8075,6 +8258,18 @@
"ansi-html": "bin/ansi-html"
}
},
"node_modules/ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
"dev": true,
"engines": [
"node >= 0.8.0"
],
"bin": {
"ansi-html": "bin/ansi-html"
}
},
"node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
@ -9403,6 +9598,15 @@
"node": ">=8"
}
},
"node_modules/boxen/node_modules/type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -10943,6 +11147,12 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/common-path-prefix": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
"dev": true
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@ -24572,44 +24782,6 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
},
"node_modules/react-hot-loader": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.0.tgz",
"integrity": "sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==",
"dev": true,
"dependencies": {
"fast-levenshtein": "^2.0.6",
"global": "^4.3.0",
"hoist-non-react-statics": "^3.3.0",
"loader-utils": "^1.1.0",
"prop-types": "^15.6.1",
"react-lifecycles-compat": "^3.0.4",
"shallowequal": "^1.1.0",
"source-map": "^0.7.3"
},
"engines": {
"node": ">= 6"
},
"peerDependencies": {
"@types/react": "^15.0.0 || ^16.0.0 || ^17.0.0 ",
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 ",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 "
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-hot-loader/node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/react-inspector": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz",
@ -24745,10 +24917,11 @@
}
},
"node_modules/react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
"dev": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -24917,6 +25090,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/read-pkg-up/node_modules/type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/read-pkg/node_modules/type-fest": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
@ -29008,12 +29190,17 @@
}
},
"node_modules/type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.10.0.tgz",
"integrity": "sha512-u2yreDMllFI3VCpWt0rKrGs/E2LO0YHBwiiOIj+ilQh9+ALMaa4lNBSdoDvuHN3cbKcYk9L1BXP49x9RT+o/SA==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/type-is": {
@ -34644,19 +34831,96 @@
}
},
"@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
"integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==",
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz",
"integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==",
"dev": true,
"requires": {
"ansi-html": "^0.0.7",
"ansi-html-community": "^0.0.8",
"common-path-prefix": "^3.0.0",
"core-js-pure": "^3.8.1",
"error-stack-parser": "^2.0.6",
"html-entities": "^1.2.1",
"native-url": "^0.2.6",
"schema-utils": "^2.6.5",
"find-up": "^5.0.0",
"html-entities": "^2.1.0",
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0",
"source-map": "^0.7.3"
},
"dependencies": {
"find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"requires": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
}
},
"html-entities": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
"integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
"dev": true
},
"json5": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"requires": {
"p-locate": "^5.0.0"
}
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"requires": {
"yocto-queue": "^0.1.0"
}
},
"p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"requires": {
"p-limit": "^3.0.2"
}
},
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@ -36424,6 +36688,20 @@
"webpack": "4"
},
"dependencies": {
"@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
"integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==",
"dev": true,
"requires": {
"ansi-html": "^0.0.7",
"error-stack-parser": "^2.0.6",
"html-entities": "^1.2.1",
"native-url": "^0.2.6",
"schema-utils": "^2.6.5",
"source-map": "^0.7.3"
}
},
"@storybook/semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz",
@ -36433,6 +36711,26 @@
"core-js": "^3.6.5",
"find-up": "^4.1.0"
}
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
"dev": true
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
},
"type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"dev": true,
"optional": true,
"peer": true
}
}
},
@ -37534,15 +37832,6 @@
"@xtuc/long": "4.2.2"
}
},
"@welldone-software/why-did-you-render": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-6.2.0.tgz",
"integrity": "sha512-ViwaE09Vgb0yXzyZuGTWCmWy/nBRAEGyztMdFYuxIgmL8yoXX5TVMCfieiJGdRQQPiDUznlYmcu0lu8kN1lwtQ==",
"dev": true,
"requires": {
"lodash": "^4"
}
},
"@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -37732,6 +38021,12 @@
"integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
"dev": true
},
"ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
"dev": true
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
@ -38777,6 +39072,12 @@
"requires": {
"has-flag": "^4.0.0"
}
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
@ -39977,6 +40278,12 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"common-path-prefix": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
"dev": true
},
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@ -50488,30 +50795,6 @@
}
}
},
"react-hot-loader": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.0.tgz",
"integrity": "sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==",
"dev": true,
"requires": {
"fast-levenshtein": "^2.0.6",
"global": "^4.3.0",
"hoist-non-react-statics": "^3.3.0",
"loader-utils": "^1.1.0",
"prop-types": "^15.6.1",
"react-lifecycles-compat": "^3.0.4",
"shallowequal": "^1.1.0",
"source-map": "^0.7.3"
},
"dependencies": {
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
"react-inspector": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz",
@ -50629,10 +50912,11 @@
}
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
"dev": true
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
"dev": true,
"peer": true
},
"react-router": {
"version": "5.2.0",
@ -50766,6 +51050,14 @@
"find-up": "^4.1.0",
"read-pkg": "^5.2.0",
"type-fest": "^0.8.1"
},
"dependencies": {
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
"readable-stream": {
@ -53938,10 +54230,12 @@
"dev": true
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.10.0.tgz",
"integrity": "sha512-u2yreDMllFI3VCpWt0rKrGs/E2LO0YHBwiiOIj+ilQh9+ALMaa4lNBSdoDvuHN3cbKcYk9L1BXP49x9RT+o/SA==",
"dev": true,
"optional": true,
"peer": true
},
"type-is": {
"version": "1.6.18",

View File

@ -71,6 +71,7 @@
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"@babel/preset-typescript": "^7.12.7",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@storybook/addon-actions": "^6.2.9",
"@storybook/addon-essentials": "^6.2.9",
"@storybook/addon-links": "^6.2.9",
@ -102,7 +103,6 @@
"lint-staged": "^11.0.0",
"loki": "^0.28.1",
"moment-locales-webpack-plugin": "^1.2.0",
"react-hot-loader": "^4.13.0",
"sass": "^1.32.5",
"sass-loader": "^8.0.2",
"storybook-addon-designs": "^6.0.0",

View File

@ -0,0 +1,52 @@
import dark from '@tlon/indigo-dark';
import light from '@tlon/indigo-light';
import { useEffect } from 'react';
import useLocalState, { selectLocalState } from '../state/local';
import useSettingsState, { selectDisplayState } from '../state/settings';
const selLocal = selectLocalState(['dark', 'set']);
export function useThemeWatcher() {
const { set, dark: isDark } = useLocalState(selLocal);
const display = useSettingsState(selectDisplayState);
const theme = ((isDark && display.theme == 'auto') || display.theme == 'dark') ? dark : light;
useEffect(() => {
const updateTheme = (e: MediaQueryListEvent) => set(s => ({ dark: e.matches }));
const updateMobile = (e: MediaQueryListEvent) => set(s => ({ mobile: e.matches }));
const updateSmall = (e: MediaQueryListEvent) => set(s => ({ breaks: { sm: e.matches } }));
const updateMedium = (e: MediaQueryListEvent) => set(s => ({ breaks: { md: e.matches } }));
const updateLarge = (e: MediaQueryListEvent) => set(s => ({ breaks: { lg: e.matches } }));
const themeWatcher = window.matchMedia('(prefers-color-scheme: dark)');
const mobileWatcher = window.matchMedia(`(max-width: ${theme.breakpoints[0]})`);
const smallWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[0]})`);
const mediumWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[1]})`);
const largeWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[2]})`);
themeWatcher.addEventListener('change', updateTheme);
mobileWatcher.addEventListener('change', updateMobile);
smallWatcher.addEventListener('change', updateSmall);
mediumWatcher.addEventListener('change', updateMedium);
largeWatcher.addEventListener('change', updateLarge);
updateTheme({ matches: themeWatcher.matches } as MediaQueryListEvent);
updateMobile({ matches: mobileWatcher.matches } as MediaQueryListEvent);
updateSmall({ matches: smallWatcher.matches } as MediaQueryListEvent);
updateMedium({ matches: mediumWatcher.matches } as MediaQueryListEvent);
updateLarge({ matches: largeWatcher.matches } as MediaQueryListEvent);
return () => {
themeWatcher.removeEventListener('change', updateTheme);
mobileWatcher.removeEventListener('change', updateMobile);
smallWatcher.removeEventListener('change', updateSmall);
mediumWatcher.removeEventListener('change', updateMedium);
largeWatcher.removeEventListener('change', updateLarge);
};
}, []);
return {
display,
theme
};
}

View File

@ -1,250 +0,0 @@
import dark from '@tlon/indigo-dark';
import light from '@tlon/indigo-light';
import Mousetrap from 'mousetrap';
import shallow from 'zustand/shallow';
import 'mousetrap-global-bind';
import * as React from 'react';
import Helmet from 'react-helmet';
import 'react-hot-loader';
import { hot } from 'react-hot-loader/root';
import { Router, withRouter } from 'react-router-dom';
import styled, { ThemeProvider } from 'styled-components';
import gcpManager from '~/logic/lib/gcpManager';
import { svgDataURL } from '~/logic/lib/util';
import history from '~/logic/lib/history';
import withState from '~/logic/lib/withState';
import useContactState, { favicon } from '~/logic/state/contact';
import useLocalState from '~/logic/state/local';
import useSettingsState from '~/logic/state/settings';
import useGraphState from '~/logic/state/graph';
import { ShortcutContextProvider } from '~/logic/lib/shortcutContext';
import ErrorBoundary from '~/views/components/ErrorBoundary';
import './apps/chat/css/custom.css';
import Omnibox from './components/leap/Omnibox';
import StatusBar from './components/StatusBar';
import './css/fonts.css';
import './css/indigo-static.css';
import { Content } from './landscape/components/Content';
import './landscape/css/custom.css';
import { bootstrapApi } from '~/logic/api/bootstrap';
import { uxToHex } from '@urbit/api';
function ensureValidHex(color) {
if (!color)
return '#000000';
const isUx = color.startsWith('0x');
const parsedColor = isUx ? uxToHex(color) : color;
return parsedColor.startsWith('#') ? parsedColor : `#${parsedColor}`;
}
const Root = withState(styled.div`
font-family: ${p => p.theme.fonts.sans};
height: 100%;
width: 100%;
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
padding-top: env(safe-area-inset-top, 0px);
padding-bottom: env(safe-area-inset-bottom, 0px);
margin: 0;
${p => p.display.backgroundType === 'url' ? `
background-image: url('${p.display.background}');
background-size: cover;
` : p.display.backgroundType === 'color' ? `
background-color: ${ensureValidHex(p.display.background)};
` : `background-color: ${p.theme.colors.white};`
}
display: flex;
flex-flow: column nowrap;
touch-action: none;
* {
scrollbar-width: thin;
scrollbar-color: ${ p => p.theme.colors.gray } transparent;
}
/* Works on Chrome/Edge/Safari */
*::-webkit-scrollbar {
width: 6px;
height: 6px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: ${ p => p.theme.colors.gray };
border-radius: 1rem;
border: 0px solid transparent;
}
`, [
[useSettingsState, ['display']]
]);
const StatusBarWithRouter = withRouter(StatusBar);
class App extends React.Component {
constructor(props) {
super(props);
this.ship = window.ship;
this.updateTheme = this.updateTheme.bind(this);
this.updateMobile = this.updateMobile.bind(this);
}
componentDidMount() {
bootstrapApi();
this.props.getShallowChildren(`~${window.ship}`, 'dm-inbox');
const theme = this.getTheme();
setTimeout(() => {
// Something about how the store works doesn't like changing it
// before the app has actually rendered, hence the timeout.
this.themeWatcher = window.matchMedia('(prefers-color-scheme: dark)');
this.mobileWatcher = window.matchMedia(`(max-width: ${theme.breakpoints[0]})`);
this.smallWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[0]})`);
this.mediumWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[1]})`);
this.largeWatcher = window.matchMedia(`(min-width: ${theme.breakpoints[2]})`);
// TODO: addListener is deprecated, but safari 13 requires it
this.themeWatcher.addListener(this.updateTheme);
this.mobileWatcher.addListener(this.updateMobile);
this.smallWatcher.addListener(this.updateSmall);
this.mediumWatcher.addListener(this.updateMedium);
this.largeWatcher.addListener(this.updateLarge);
this.updateMobile(this.mobileWatcher);
this.updateSmall(this.updateSmall);
this.updateTheme(this.themeWatcher);
this.updateMedium(this.mediumWatcher);
this.updateLarge(this.largeWatcher);
}, 500);
this.props.getAll();
gcpManager.start();
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
e.preventDefault();
e.stopImmediatePropagation();
this.props.toggleOmnibox();
});
}
componentWillUnmount() {
this.themeWatcher.removeListener(this.updateTheme);
this.mobileWatcher.removeListener(this.updateMobile);
this.smallWatcher.removeListener(this.updateSmall);
this.mediumWatcher.removeListener(this.updateMedium);
this.largeWatcher.removeListener(this.updateLarge);
}
updateTheme(e) {
this.props.set((state) => {
state.dark = e.matches;
});
}
updateMobile(e) {
this.props.set((state) => {
state.mobile = e.matches;
});
}
updateSmall = (e) => {
this.props.set((state) => {
state.breaks.sm = e.matches;
});
}
updateMedium = (e) => {
this.props.set((state) => {
state.breaks.md = e.matches;
});
}
updateLarge = (e) => {
this.props.set((state) => {
state.breaks.lg = e.matches;
});
}
getTheme() {
const { props } = this;
return ((props.dark && props?.display?.theme == 'auto') ||
props?.display?.theme == 'dark'
) ? dark : light;
}
render() {
const theme = this.getTheme();
const { ourContact } = this.props;
return (
<ThemeProvider theme={theme}>
<ShortcutContextProvider>
<Helmet>
{window.ship.length < 14
? <link rel="icon" type="image/svg+xml" href={svgDataURL(favicon())} />
: null}
</Helmet>
<Root>
<Router history={history}>
<ErrorBoundary>
<StatusBarWithRouter
props={this.props}
ourContact={ourContact}
connection={'foo'}
subscription={this.subscription}
ship={this.ship}
/>
</ErrorBoundary>
<ErrorBoundary>
<Omnibox
show={this.props.omniboxShown}
toggle={this.props.toggleOmnibox}
/>
</ErrorBoundary>
<ErrorBoundary>
<Content
ship={this.ship}
subscription={this.subscription}
connection={'aa'}
/>
</ErrorBoundary>
</Router>
</Root>
<div id="portal-root" />
</ShortcutContextProvider>
</ThemeProvider>
);
}
}
const WarmApp = process.env.NODE_ENV === 'production' ? App : hot(App);
const selContacts = s => s.contacts[`~${window.ship}`];
const selLocal = s => [s.set, s.omniboxShown, s.toggleOmnibox, s.dark];
const selSettings = s => [s.display, s.getAll];
const selGraph = s => s.getShallowChildren;
const WithApp = React.forwardRef((props, ref) => {
const ourContact = useContactState(selContacts);
const [display, getAll] = useSettingsState(selSettings, shallow);
const [setLocal, omniboxShown, toggleOmnibox, dark] = useLocalState(selLocal);
const getShallowChildren = useGraphState(selGraph);
return (
<WarmApp
ref={ref}
ourContact={ourContact}
display={display}
getAll={getAll}
set={setLocal}
dark={dark}
getShallowChildren={getShallowChildren}
toggleOmnibox={toggleOmnibox}
omniboxShown={omniboxShown}
/>
);
});
WarmApp.whyDidYouRender = true;
export default WithApp;

View File

@ -0,0 +1,137 @@
import Mousetrap from 'mousetrap';
import shallow from 'zustand/shallow';
import 'mousetrap-global-bind';
import * as React from 'react';
import Helmet from 'react-helmet';
import { Router, withRouter } from 'react-router-dom';
import styled, { ThemeProvider } from 'styled-components';
import gcpManager from '~/logic/lib/gcpManager';
import { svgDataURL } from '~/logic/lib/util';
import history from '~/logic/lib/history';
import { favicon } from '~/logic/state/contact';
import useLocalState, { selectLocalState } from '~/logic/state/local';
import useSettingsState, { selectSettingsState, SettingsState } from '~/logic/state/settings';
import useGraphState, { GraphState } from '~/logic/state/graph';
import { ShortcutContextProvider } from '~/logic/lib/shortcutContext';
import ErrorBoundary from '~/views/components/ErrorBoundary';
import './apps/chat/css/custom.css';
import Omnibox from './components/leap/Omnibox';
import StatusBar from './components/StatusBar';
import './css/fonts.css';
import './css/indigo-static.css';
import { Content } from './landscape/components/Content';
import './landscape/css/custom.css';
import { bootstrapApi } from '~/logic/api/bootstrap';
import { uxToHex } from '@urbit/api';
import { useThemeWatcher } from '~/logic/lib/useThemeWatcher';
function ensureValidHex(color) {
if (!color)
return '#000000';
const isUx = color.startsWith('0x');
const parsedColor = isUx ? uxToHex(color) : color;
return parsedColor.startsWith('#') ? parsedColor : `#${parsedColor}`;
}
interface RootProps {
display: SettingsState['display'];
}
const Root = styled.div<RootProps>`
font-family: ${p => p.theme.fonts.sans};
height: 100%;
width: 100%;
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
padding-top: env(safe-area-inset-top, 0px);
padding-bottom: env(safe-area-inset-bottom, 0px);
margin: 0;
${p => p.display.backgroundType === 'url' ? `
background-image: url('${p.display.background}');
background-size: cover;
` : p.display.backgroundType === 'color' ? `
background-color: ${ensureValidHex(p.display.background)};
` : `background-color: ${p.theme.colors.white};`
}
display: flex;
flex-flow: column nowrap;
touch-action: none;
* {
scrollbar-width: thin;
scrollbar-color: ${ p => p.theme.colors.gray } transparent;
}
/* Works on Chrome/Edge/Safari */
*::-webkit-scrollbar {
width: 6px;
height: 6px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: ${ p => p.theme.colors.gray };
border-radius: 1rem;
border: 0px solid transparent;
}
`;
const StatusBarWithRouter = withRouter(StatusBar);
const selLocal = selectLocalState(['toggleOmnibox']);
const selSettings = selectSettingsState(['display', 'getAll']);
const selGraph = (s: GraphState) => s.getShallowChildren;
const App: React.FunctionComponent = () => {
const { getAll } = useSettingsState(selSettings, shallow);
const { toggleOmnibox } = useLocalState(selLocal);
const getShallowChildren = useGraphState(selGraph);
const { theme, display } = useThemeWatcher();
React.useEffect(() => {
bootstrapApi();
getShallowChildren(`~${window.ship}`, 'dm-inbox');
getAll();
gcpManager.start();
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
e.preventDefault();
e.stopImmediatePropagation();
toggleOmnibox();
});
}, []);
return (
<ThemeProvider theme={theme}>
<ShortcutContextProvider>
<Helmet>
{window.ship.length < 14
? <link rel="icon" type="image/svg+xml" href={svgDataURL(favicon())} />
: null}
</Helmet>
<Root display={display}>
<Router history={history}>
<ErrorBoundary>
<StatusBarWithRouter />
</ErrorBoundary>
<ErrorBoundary>
<Omnibox />
</ErrorBoundary>
<ErrorBoundary>
<Content />
</ErrorBoundary>
</Router>
</Root>
<div id="portal-root" />
</ShortcutContextProvider>
</ThemeProvider>
);
};
export default App;

View File

@ -1,52 +0,0 @@
import { Center, Text } from '@tlon/indigo-react';
import { GraphConfig, joinGraph } from '@urbit/api';
import React, { ReactElement } from 'react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { deSig } from '~/logic/lib/util';
import useGraphState from '~/logic/state/graph';
import useMetadataState from '~/logic/state/metadata';
import airlock from '~/logic/api';
const GraphApp = (): ReactElement => {
const associations= useMetadataState(state => state.associations);
const graphKeys = useGraphState(state => state.graphKeys);
const history = useHistory();
return (
<Switch>
<Route exact path="/~graph/join/ship/:ship/:name/:module?"
render={(props) => {
const resource =
`${deSig(props.match.params.ship)}/${props.match.params.name}`;
const { ship, name } = props.match.params;
const path = `/ship/~${deSig(ship)}/${name}`;
const association = associations.graph[path];
const autoJoin = () => {
try {
airlock.thread(joinGraph(
`~${deSig(props.match.params.ship)}`,
props.match.params.name
));
} catch(err) {
setTimeout(autoJoin, 2000);
}
};
if(!graphKeys.has(resource)) {
autoJoin();
} else if(Boolean(association) && 'graph' in association.metadata.config) {
history.push(`/~landscape/home/resource/${(association.metadata.config as GraphConfig).graph}${path}`);
}
return (
<Center width="100%" height="100%">
<Text fontSize={1}>Redirecting...</Text>
</Center>
);
}}
/>
</Switch>
);
};
export default GraphApp;

View File

@ -1,18 +1,18 @@
/* eslint-disable max-lines-per-function */
import { Box, Icon, Row, Text, Button } from "@tlon/indigo-react";
import React, { ReactElement } from "react";
import { Helmet } from "react-helmet";
import { Route, useHistory } from "react-router-dom";
import styled from "styled-components";
import useHarkState from "~/logic/state/hark";
import useSettingsState, { selectCalmState } from "~/logic/state/settings";
import Groups from "./components/Groups";
import { NewGroup } from "~/views/landscape/components/NewGroup";
import ModalButton from "./components/ModalButton";
import Tiles from "./components/tiles";
import Tile from "./components/tiles/tile";
import "./css/custom.css";
import { Join, JoinRoute } from "~/views/landscape/components/Join/Join";
import { Box, Icon, Row, Text, Button } from '@tlon/indigo-react';
import React, { ReactElement } from 'react';
import { Helmet } from 'react-helmet';
import { Route, useHistory } from 'react-router-dom';
import styled from 'styled-components';
import useHarkState from '~/logic/state/hark';
import useSettingsState, { selectCalmState } from '~/logic/state/settings';
import Groups from './components/Groups';
import { NewGroup } from '~/views/landscape/components/NewGroup';
import ModalButton from './components/ModalButton';
import Tiles from './components/tiles';
import Tile from './components/tiles/tile';
import './css/custom.css';
import { JoinRoute } from '~/views/landscape/components/Join/Join';
const ScrollbarLessBox = styled(Box)`
scrollbar-width: none !important;
@ -22,12 +22,8 @@ const ScrollbarLessBox = styled(Box)`
}
`;
interface LaunchAppProps {
connection: string;
}
export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
const notificationsCount = useHarkState((state) => state.notificationsCount);
export const LaunchApp = (): ReactElement | null => {
const notificationsCount = useHarkState(state => state.notificationsCount);
const calmState = useSettingsState(selectCalmState);
const { hideUtilities, hideGroups } = calmState;
const history = useHistory();
@ -36,22 +32,22 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
<>
<Helmet defer={false}>
<title>
{notificationsCount ? `(${String(notificationsCount)}) ` : ""}Groups
{notificationsCount ? `(${String(notificationsCount)}) ` : ''}Groups
</title>
</Helmet>
<Route path="/join/:ship/:name">
<Route path='/join/:ship/:name'>
<JoinRoute modal />
</Route>
<ScrollbarLessBox
height="100%"
overflowY="scroll"
display="flex"
flexDirection="column"
height='100%'
overflowY='scroll'
display='flex'
flexDirection='column'
>
<Box
mx={2}
display="grid"
gridTemplateColumns="repeat(auto-fill, minmax(128px, 1fr))"
display='grid'
gridTemplateColumns='repeat(auto-fill, minmax(128px, 1fr))'
gridGap={3}
p={2}
pt={0}
@ -59,22 +55,22 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
{!hideUtilities && (
<>
<Tile
bg="white"
color="scales.black20"
to="/~landscape/home"
bg='white'
color='scales.black20'
to='/~landscape/home'
p={0}
>
<Box
p={2}
height="100%"
width="100%"
bg="scales.black20"
height='100%'
width='100%'
bg='scales.black20'
border={1}
borderColor="lightGray"
borderColor='lightGray'
>
<Row alignItems="center">
<Icon color="black" icon="Home" />
<Text ml={2} mt="1px" color="black">
<Row alignItems='center'>
<Icon color='black' icon='Home' />
<Text ml={2} mt='1px' color='black'>
My Channels
</Text>
</Row>
@ -82,10 +78,10 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
</Tile>
<Tiles />
<ModalButton
icon="Plus"
bg="white"
color="black"
text="New Group"
icon='Plus'
bg='white'
color='black'
text='New Group'
style={{ gridColumnStart: 1 }}
>
<NewGroup />
@ -94,11 +90,11 @@ export const LaunchApp = (props: LaunchAppProps): ReactElement | null => {
border={0}
p={0}
borderRadius={2}
onClick={() => history.push({ search: "?join-kind=group" })}
onClick={() => history.push({ search: '?join-kind=group' })}
>
<Row backgroundColor="white" gapX="2" p={2} height="100%" width="100%" alignItems="center">
<Icon icon="BootNode" />
<Text fontWeight="medium" whiteSpace="nowrap">Join Group</Text>
<Row backgroundColor='white' gapX='2' p={2} height='100%' width='100%' alignItems='center'>
<Icon icon='BootNode' />
<Text fontWeight='medium' whiteSpace='nowrap'>Join Group</Text>
</Row>
</Button>
</>

View File

@ -37,7 +37,7 @@ export function NavLink({
);
}
export default function NotificationsScreen(props: any): ReactElement {
export default function NotificationsScreen(): ReactElement {
const relativePath = (p: string) => baseUrl + p;
const notificationsCount = useHarkState(state => state.notificationsCount);

View File

@ -6,7 +6,7 @@ import useContactState from '~/logic/state/contact';
import useHarkState from '~/logic/state/hark';
import { Profile } from './components/Profile';
export default function ProfileScreen(props: any) {
export default function ProfileScreen() {
const contacts = useContactState(state => state.contacts);
const notificationsCount = useHarkState(state => state.notificationsCount);
return (

View File

@ -68,7 +68,7 @@ function SettingsItem(props: { children: ReactNode }) {
);
}
export default function SettingsScreen(props: any) {
export default function SettingsScreen() {
const location = useLocation();
const hash = location.hash.slice(1);
const notificationsCount = useHarkState(state => state.notificationsCount);
@ -126,12 +126,7 @@ return;
</Col>
<Col flexGrow={1} overflowY='auto'>
<SettingsItem>
{hash === 'notifications' && (
<NotificationPreferences
{...props}
graphConfig={props.notificationsGraphConfig}
/>
)}
{hash === 'notifications' && <NotificationPreferences />}
{hash === 'display' && <DisplayForm />}
{hash === 'dm' && <DmSettings />}
{hash === 'shortcuts' && <ShortcutSettings />}

View File

@ -22,8 +22,8 @@ import useHarkState from '~/logic/state/hark';
const localSel = selectLocalState(['toggleOmnibox']);
const StatusBar = (props) => {
const { ship } = props;
const StatusBar = () => {
const ship = window.ship;
const ourContact = useContactState(state => state.contacts[`~${ship}`]);
const metaKey = window.navigator.platform.includes('Mac') ? '⌘' : 'Ctrl+';
const { toggleOmnibox } = useLocalState(localSel);
@ -64,7 +64,6 @@ const StatusBar = (props) => {
borderColor='lightGray'
mr={2}
px={2}
{...props}
>
<Icon icon='Dashboard' color='black' />
</Button>

View File

@ -3,7 +3,6 @@ import { omit } from 'lodash';
import Mousetrap from 'mousetrap';
import fuzzy from 'fuzzy';
import _ from 'lodash';
import f from 'lodash/fp';
import React, {
ReactElement, useCallback,
useEffect, useMemo,
@ -17,30 +16,24 @@ import defaultApps from '~/logic/lib/default-apps';
import makeIndex, { OmniboxItem } from '~/logic/lib/omnibox';
import { useOutsideClick } from '~/logic/lib/useOutsideClick';
import { deSig } from '~/logic/lib/util';
import useLocalState from '~/logic/state/local';
import useContactState from '~/logic/state/contact';
import useGroupState from '~/logic/state/group';
import useHarkState from '~/logic/state/hark';
import useInviteState from '~/logic/state/invite';
import useLaunchState from '~/logic/state/launch';
import { withLocalState } from '~/logic/state/local';
import useMetadataState from '~/logic/state/metadata';
import useSettingsState, { SettingsState } from '~/logic/state/settings';
import { Portal } from '../Portal';
import OmniboxInput from './OmniboxInput';
import OmniboxResult from './OmniboxResult';
interface OmniboxProps {
show: boolean;
toggle: () => void;
notifications: number;
}
import { selectLocalState } from '~/logic/state/local';
const SEARCHED_CATEGORIES = [
'commands',
'ships',
'other',
'groups',
'subscriptions',
'subscriptions'
];
const settingsSel = (s: SettingsState) => s.leap;
const CAT_LIMIT = 6;
@ -50,20 +43,22 @@ const CAT_LIMIT = 6;
*/
function flattenCattegoryMap(cats: string[], catMap: Map<string, OmniboxItem[]>) {
let res = [] as OmniboxItem[];
cats.forEach(cat => {
cats.forEach((cat) => {
res = res.concat(_.take(catMap.get(cat), CAT_LIMIT));
});
return res;
}
export function Omnibox(props: OmniboxProps): ReactElement {
const selOmnibox = selectLocalState(['omniboxShown', 'toggleOmnibox']);
export function Omnibox(): ReactElement {
const location = useLocation();
const history = useHistory();
const leapConfig = useSettingsState(settingsSel);
const omniboxRef = useRef<HTMLDivElement | null>(null);
const inputRef = useRef<HTMLInputElement | null>(null);
const { omniboxShown: show, toggleOmnibox: toggle } = useLocalState(selOmnibox);
const [query, setQuery] = useState('');
const [selected, setSelected] = useState<[] | [string, string]>([]);
@ -102,17 +97,17 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}, [selectedGroup, leapConfig, contacts, associations, groups]);
const onOutsideClick = useCallback(() => {
props.show && props.toggle();
}, [props.show, props.toggle]);
show && toggle();
}, [show, toggle]);
useOutsideClick(omniboxRef, onOutsideClick);
// handle omnibox show
useEffect(() => {
if (!props.show) {
if (!show) {
return;
}
Mousetrap.bind('escape', props.toggle);
Mousetrap.bind('escape', toggle);
const touchstart = new Event('touchstart');
// @ts-ignore ref typings
inputRef?.current?.input?.dispatchEvent(touchstart);
@ -122,7 +117,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
Mousetrap.unbind('escape');
setQuery('');
};
}, [props.show]);
}, [show]);
const initialResults = useMemo(() => {
return new Map<string, OmniboxItem[]>(
@ -145,7 +140,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}
const q = query.toLowerCase();
const resultsMap = new Map<string, OmniboxItem[]>();
let categoryMaxes: Record<string, number> = {};
const categoryMaxes: Record<string, number> = {};
SEARCHED_CATEGORIES.map((category) => {
const categoryIndex = index.get(category);
@ -156,7 +151,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
.reduce((a,b) => Math.max(a,b), 0);
resultsMap.set(category, fuzzied.map(a => a.original));
});
let order = Object.entries(categoryMaxes)
const order = Object.entries(categoryMaxes)
.sort(([,a],[,b]) => b - a)
.map(([id]) => id);
return [resultsMap, order];
@ -164,7 +159,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
const navigate = useCallback(
(app: string, link: string, shift: boolean) => {
props.toggle();
toggle();
if (
defaultApps.includes(app.toLowerCase()) ||
app === 'profile' ||
@ -177,20 +172,20 @@ export function Omnibox(props: OmniboxProps): ReactElement {
if(shift && app === 'profile') {
// TODO: hacky, fix
link = link.replace('~profile', '~landscape/messages/dm');
}
}
if(link.startsWith('?')) {
history.push({
search: link
});
} else {
history.push(link);
}
} else {
window.location.href = link;
}
},
[history, props.toggle]
[history, toggle]
);
const setPreviousSelected = useCallback(() => {
@ -249,8 +244,8 @@ export function Omnibox(props: OmniboxProps): ReactElement {
if (query.length > 0) {
setQuery('');
return;
} else if (props.show) {
props.toggle();
} else if (show) {
toggle();
return;
}
}
@ -268,7 +263,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}
if (evt.key === 'Enter') {
evt.preventDefault();
let values = flattenCattegoryMap(categoryOrder, results);
const values = flattenCattegoryMap(categoryOrder, results);
if (selected.length) {
navigate(selected[0], selected[1], evt.shiftKey);
} else if (values.length === 0) {
@ -283,11 +278,11 @@ export function Omnibox(props: OmniboxProps): ReactElement {
}
},
[
props.toggle,
toggle,
selected,
navigate,
query,
props.show,
show,
results,
categoryOrder,
setPreviousSelected,
@ -296,7 +291,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
);
useEffect(() => {
const flattenedResultLinks: [string, string][] =
const flattenedResultLinks: [string, string][] =
flattenCattegoryMap(categoryOrder, results)
.map(result => [result.app, result.link]);
if (!flattenedResultLinks.includes(selected as [string, string])) {
@ -308,24 +303,6 @@ export function Omnibox(props: OmniboxProps): ReactElement {
setQuery(event.target.value);
}, []);
// Sort Omnibox results alphabetically
const sortResults = (
a: Record<'title', string>,
b: Record<'title', string>
) => {
// Do not sort unless searching (preserves order of menu actions)
if (query === '') {
return 0;
}
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
};
const renderResults = useCallback(() => {
return (
<Box
@ -389,7 +366,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
top={0}
right={0}
zIndex={11}
display={props.show ? 'block' : 'none'}
display={show ? 'block' : 'none'}
>
<Row justifyContent='center'>
<Box
@ -419,5 +396,5 @@ export function Omnibox(props: OmniboxProps): ReactElement {
</Portal>
);
}
// @ts-ignore investigate zustand types
export default withLocalState(Omnibox, ['toggleOmnibox', 'omniboxShown']);
export default Omnibox;

View File

@ -24,10 +24,9 @@ const Landscape = React.lazy(() => import('~/views/landscape/index'));
const Settings = React.lazy(() => import('~/views/apps/settings/settings'));
const Profile = React.lazy(() => import('~/views/apps/profile/profile'));
const Notifications = React.lazy(() => import('~/views/apps/notifications/notifications'));
const GraphApp = React.lazy(() => import('../../apps/graph/App'));
const ErrorComponent = React.lazy(() => import('~/views/components/Error'));
export const Content = (props) => {
export const Content = () => {
const history = useHistory();
const location = useLocation();
const mdLoaded = useMetadataState(s => s.loaded);
@ -81,39 +80,25 @@ export const Content = (props) => {
<Switch>
<Route
exact
path="/" render={p => (
<LaunchApp
location={p.location}
match={p.match}
{...props}
/>
)}
path="/"
component={LaunchApp}
/>
<Route path='/~landscape'>
<Landscape />
</Route>
<Route
path="/~profile"
render={ p => (
<Profile
{...props}
/>
)}
component={Profile}
/>
<Route
path="/~settings"
render={ p => (
<Settings {...props} />
)}
component={Settings}
/>
<Route
path="/~notifications"
render={ p => (
<Notifications {...props} />
)}
component={Notifications}
/>
<GraphApp path="/~graph" {...props} />
<PermalinkRoutes {...props} />
<PermalinkRoutes />
<Route
render={p => (