mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-06-16 18:29:08 +00:00
flowtyped everything, some functional, safety, and structural changes
This commit is contained in:
parent
6f3eca7a64
commit
d2aecb38ca
92 changed files with 17554 additions and 1440 deletions
5
UI/.babelrc
Normal file
5
UI/.babelrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"presets": [
|
||||
"next/babel", "@babel/preset-flow"
|
||||
]
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
|
||||
export const colors = {
|
||||
white: '#efefef',
|
||||
c9: '#EBD6D4',
|
||||
|
@ -12,7 +15,7 @@ export const colors = {
|
|||
}
|
||||
|
||||
const getColors = () => {
|
||||
Object.keys(colors).map(key => {
|
||||
return Object.keys(colors).map(key => {
|
||||
const nk = key.replace(/c([0-9])/, '$1')
|
||||
return `--c-${nk}: ${colors[key]};`
|
||||
}).join(' \n')
|
||||
|
@ -26,6 +29,18 @@ body {
|
|||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* prevent FOUC */
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wf-active body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// FOUC guard if we take too long
|
||||
.force-active body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.font-sans-serif {
|
||||
|
|
11
UI/components/header/auth.js
Normal file
11
UI/components/header/auth.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import HeaderBarCommon from './common'
|
||||
|
||||
const HeaderBarAuth: React.StatelessFunctionalComponent<{}> = () => (
|
||||
<HeaderBarCommon>
|
||||
hi
|
||||
</HeaderBarCommon>
|
||||
)
|
||||
|
||||
export default HeaderBarAuth
|
14
UI/components/header/common.js
Normal file
14
UI/components/header/common.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
|
||||
export type CommonProps = {
|
||||
children: React.Element<any>
|
||||
}
|
||||
|
||||
const HeaderBarCommon: React.StatelessFunctionalComponent<CommonProps> = ({ children }) => (
|
||||
<div>
|
||||
{ children }
|
||||
</div>
|
||||
)
|
||||
|
||||
export default HeaderBarCommon
|
11
UI/components/header/unauth.js
Normal file
11
UI/components/header/unauth.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import HeaderBarCommon from './common'
|
||||
|
||||
const HeaderBarUnauth: React.StatelessFunctionalComponent<{}> = () => (
|
||||
<HeaderBarCommon>
|
||||
hi
|
||||
</HeaderBarCommon>
|
||||
)
|
||||
|
||||
export default HeaderBarUnauth
|
36
UI/components/social-cards.js
Normal file
36
UI/components/social-cards.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import NextHead from 'next/head'
|
||||
|
||||
export type SocialCardProps = {
|
||||
title?: string,
|
||||
description?: string,
|
||||
image?: string,
|
||||
imageSize?: number
|
||||
}
|
||||
|
||||
const defaultProps: SocialCardProps = {
|
||||
title: 'Roleypoly',
|
||||
description: 'Tame your Discord roles.',
|
||||
image: 'https://rp.kat.cafe/static/social.png',
|
||||
imageSize: 200
|
||||
}
|
||||
|
||||
const SocialCards: React.StatelessFunctionalComponent<SocialCardProps> = (props) => {
|
||||
props = {
|
||||
...defaultProps,
|
||||
...props
|
||||
}
|
||||
|
||||
return <NextHead>
|
||||
<meta key='og:title' property='og:title' content={props.title} />
|
||||
<meta key='og:description' property='og:description' content={props.description} />
|
||||
<meta key='twitter:card' name='twitter:card' content='summary_large_image' />
|
||||
<meta key='twitter:image' name='twitter:image' content={props.image} />
|
||||
<meta key='og:image' property='og:image' content={props.image} />
|
||||
<meta key='og:image:width' property='og:image:width' content={props.imageSize} />
|
||||
<meta key='og:image:height' property='og:image:height' content={props.imageSize} />
|
||||
</NextHead>
|
||||
}
|
||||
|
||||
export default SocialCards
|
15
UI/config/redux.js
Normal file
15
UI/config/redux.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { composeWithDevTools } from 'redux-devtools-extension'
|
||||
import thunkMiddleware from 'redux-thunk'
|
||||
import withNextRedux from 'next-redux-wrapper'
|
||||
import { rootReducer } from 'fast-redux'
|
||||
|
||||
export const initStore = (initialState = {}) => {
|
||||
return createStore(
|
||||
rootReducer,
|
||||
initialState,
|
||||
composeWithDevTools(applyMiddleware(thunkMiddleware))
|
||||
)
|
||||
}
|
||||
|
||||
export const withRedux = (comp) => withNextRedux(initStore)(comp)
|
4
UI/config/rpc.js
Normal file
4
UI/config/rpc.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
// @flow
|
||||
import RPCClient from '../rpc'
|
||||
|
||||
export default (new RPCClient({ forceDev: false })).rpc
|
30
UI/containers/header-bar.js
Normal file
30
UI/containers/header-bar.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { withRedux } from '../config/redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { connect } from 'react-redux'
|
||||
import { namespaceConfig } from 'fast-redux'
|
||||
import * as User from './user'
|
||||
|
||||
type Props = {
|
||||
user: User.User
|
||||
}
|
||||
|
||||
const HeaderBarAuth = dynamic(() => import('../components/header/auth'))
|
||||
const HeaderBarUnauth = dynamic(() => import('../components/header/unauth'))
|
||||
|
||||
const HeaderBar: React.StatelessFunctionalComponent<Props> = () => {
|
||||
// if ()
|
||||
return null
|
||||
}
|
||||
|
||||
const mapStateToProps = (state): Props => {
|
||||
return {}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return bindActionCreators({ }, dispatch)
|
||||
}
|
||||
|
||||
export default withRedux(connect(mapStateToProps, mapDispatchToProps)(HeaderBar))
|
32
UI/containers/user.js
Normal file
32
UI/containers/user.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// @flow
|
||||
import { namespaceConfig } from 'fast-redux'
|
||||
|
||||
export type User = {
|
||||
id: string,
|
||||
username: string,
|
||||
discriminator: string,
|
||||
avatar: string,
|
||||
nicknameCache: {
|
||||
[server: string]: string
|
||||
}
|
||||
}
|
||||
|
||||
export type UserState = {
|
||||
currentUser: User | null,
|
||||
userCache: {
|
||||
[id: string]: User
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: UserState = {
|
||||
currentUser: null,
|
||||
userCache: {}
|
||||
}
|
||||
|
||||
export const {
|
||||
action, getState: getUserStore
|
||||
} = namespaceConfig('userStore', DEFAULT_STATE)
|
||||
|
||||
export const getCurrentUser = () => async (dispatch: Function) => {
|
||||
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import * as React from 'react'
|
||||
import App, { Container } from 'next/app'
|
||||
import Head from 'next/head'
|
||||
import GlobalColors from '../components/global-colors'
|
||||
import SocialCards from '../components/social-cards'
|
||||
// import RPCClient from '../rpc'
|
||||
|
||||
class RoleypolyApp extends App {
|
||||
static async getInitialProps ({ Component, ctx }) {
|
||||
|
@ -15,6 +18,7 @@ class RoleypolyApp extends App {
|
|||
|
||||
componentDidMount () {
|
||||
this.loadTypekit(document)
|
||||
this.waitForFOUC()
|
||||
}
|
||||
|
||||
loadTypekit (d) {
|
||||
|
@ -42,14 +46,26 @@ class RoleypolyApp extends App {
|
|||
s.parentNode.insertBefore(tk, s)
|
||||
}
|
||||
|
||||
// wait one second, add FOUC de-protection.
|
||||
waitForFOUC () {
|
||||
setTimeout(() => {
|
||||
document.documentElement.className += ' force-active'//
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { Component, pageProps, router } = this.props
|
||||
const { Component, pageProps, router, rpc } = this.props
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Head />
|
||||
<Head>
|
||||
<meta charSet='utf-8' />
|
||||
<title key='title'>Roleypoly</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||
</Head>
|
||||
<GlobalColors />
|
||||
<Component {...pageProps} router={router} />
|
||||
<SocialCards />
|
||||
<Component {...pageProps} router={router} rpc={rpc} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
const Server = ({ router: { query: { id } } }) => (
|
||||
<div>
|
||||
{id}
|
||||
</div>
|
||||
)
|
||||
// @flow
|
||||
import * as React from 'react'
|
||||
import Head from 'next/head'
|
||||
import type { PageProps } from '../../types'
|
||||
import SocialCards from '../../components/social-cards'
|
||||
|
||||
export default Server
|
||||
export default class Server extends React.Component<PageProps> {
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title key='title'>server name!</title>
|
||||
</Head>
|
||||
<SocialCards title={'server test'} />
|
||||
hello {this.props.router.query.id}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,24 +5,24 @@ import Nav from '../components/nav'
|
|||
|
||||
const Home = () => (
|
||||
<div>
|
||||
<Head title="Home" />
|
||||
<Head title='Home' />
|
||||
<Nav />
|
||||
|
||||
<div className="hero">
|
||||
<h1 className="title">Welcome to Next!</h1>
|
||||
<p className="description">
|
||||
<div className='hero'>
|
||||
<h1 className='title'>Welcome to Next!</h1>
|
||||
<p className='description'>
|
||||
To get started, edit <code>pages/index.js</code> and save to reload.
|
||||
</p>
|
||||
|
||||
<div className="row">
|
||||
<Link href="https://github.com/zeit/next.js#getting-started">
|
||||
<a className="card">
|
||||
<div className='row'>
|
||||
<Link href='https://github.com/zeit/next.js#getting-started'>
|
||||
<a className='card'>
|
||||
<h3>Getting Started →</h3>
|
||||
<p>Learn more about Next on Github and in their examples</p>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="https://open.segment.com/create-next-app">
|
||||
<a className="card">
|
||||
<Link href='https://open.segment.com/create-next-app'>
|
||||
<a className='card'>
|
||||
<h3>Examples →</h3>
|
||||
<p>
|
||||
Find other example boilerplates on the{' '}
|
||||
|
@ -30,8 +30,8 @@ const Home = () => (
|
|||
</p>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="https://github.com/segmentio/create-next-app">
|
||||
<a className="card">
|
||||
<Link href='https://github.com/segmentio/create-next-app'>
|
||||
<a className='card'>
|
||||
<h3>Create Next App →</h3>
|
||||
<p>Was this tool helpful? Let us know how we can improve it</p>
|
||||
</a>
|
||||
|
|
24
UI/pages/testrpc.js
Normal file
24
UI/pages/testrpc.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as React from 'react'
|
||||
import RPC from '../config/rpc'
|
||||
|
||||
export default class TestRPC extends React.Component {
|
||||
static async getInitialProps (ctx) {
|
||||
return {
|
||||
// hello: await RPC.hello('world')
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
window.$RPC = RPC
|
||||
}
|
||||
|
||||
componentDidCatch (error, errorInfo) {
|
||||
if (error) {
|
||||
console.log(error, errorInfo)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div>hello, { this.props.hello }</div>
|
||||
}
|
||||
}
|
106
UI/rpc/index.js
Normal file
106
UI/rpc/index.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
// @flow
|
||||
import superagent from 'superagent'
|
||||
import RPCError from '../../rpc/_error'
|
||||
|
||||
export type RPCResponse = {
|
||||
response?: mixed,
|
||||
hash?: string,
|
||||
|
||||
// error stuff
|
||||
error?: boolean,
|
||||
msg?: string,
|
||||
trace?: string
|
||||
}
|
||||
|
||||
export type RPCRequest = {
|
||||
fn: string,
|
||||
args: mixed[]
|
||||
}
|
||||
|
||||
export default class RPCClient {
|
||||
dev: boolean = false
|
||||
baseUrl: string
|
||||
firstKnownHash: string
|
||||
recentHash: string
|
||||
|
||||
rpc: {
|
||||
[fn: string]: (...args: any[]) => Promise<mixed> | string
|
||||
} = {}
|
||||
|
||||
__rpcAvailable: Array<{
|
||||
name: string,
|
||||
args: number
|
||||
}> = []
|
||||
|
||||
constructor ({ forceDev, baseUrl = '/api/_rpc' }: { forceDev?: boolean, baseUrl?: string } = {}) {
|
||||
this.baseUrl = (process.env.APP_URL || '') + baseUrl
|
||||
|
||||
if (forceDev != null) {
|
||||
this.dev = forceDev
|
||||
} else {
|
||||
this.dev = process.env.NODE_ENV === 'development'
|
||||
}
|
||||
|
||||
this.rpc = new Proxy({
|
||||
toJSON () {
|
||||
return '{}'
|
||||
}
|
||||
}, { get: this.__rpcCall, has: this.__checkCall, ownKeys: this.__listCalls, delete: () => {} })
|
||||
|
||||
if (this.dev) {
|
||||
this.updateCalls()
|
||||
}
|
||||
}
|
||||
|
||||
async updateCalls () {
|
||||
// this is for development only. doing in prod is probably dumb.
|
||||
const rsp = await superagent.get(this.baseUrl)
|
||||
if (rsp.status !== 200) {
|
||||
console.error(rsp)
|
||||
return
|
||||
}
|
||||
|
||||
const { hash, available } = rsp.body
|
||||
|
||||
this.__rpcAvailable = available
|
||||
if (this.firstKnownHash == null) {
|
||||
this.firstKnownHash = hash
|
||||
}
|
||||
|
||||
this.recentHash = hash
|
||||
|
||||
// just kinda prefill. none of these get called anyway.
|
||||
// and don't matter in prod either.
|
||||
for (let { name } of available) {
|
||||
this.rpc[name] = async () => {}
|
||||
}
|
||||
}
|
||||
|
||||
async call (fn: string, ...args: any[]): mixed {
|
||||
const req: RPCRequest = { fn, args }
|
||||
const rsp = await superagent.post(this.baseUrl).send(req).ok(() => true)
|
||||
const body: RPCResponse = rsp.body
|
||||
if (body.error === true) {
|
||||
throw RPCError.fromResponse(body, rsp.status)
|
||||
}
|
||||
|
||||
if (body.hash != null) {
|
||||
if (this.firstKnownHash == null) {
|
||||
this.firstKnownHash = body.hash
|
||||
}
|
||||
|
||||
this.recentHash = body.hash
|
||||
|
||||
if (this.firstKnownHash !== this.recentHash) {
|
||||
this.updateCalls()
|
||||
}
|
||||
}
|
||||
|
||||
return body.response
|
||||
}
|
||||
|
||||
// PROXY HANDLERS
|
||||
__rpcCall = (_: {}, fn: string) => this.call.bind(this, fn)
|
||||
__checkCall = (_: {}, fn: string) => this.dev ? this.__listCalls(_).includes(fn) : true
|
||||
__listCalls = (_: {}): string[] => this.__rpcAvailable.map(x => x.name)
|
||||
}
|
8
UI/types.js
Normal file
8
UI/types.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
// @flow
|
||||
export type PageProps = {
|
||||
router: {
|
||||
query: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue