flow: universes

This commit is contained in:
cha0s 2021-01-07 23:33:49 -06:00
parent 40a05a7ea4
commit b29b9d7a05
27 changed files with 6646 additions and 84 deletions

View File

@ -28,6 +28,7 @@
"@avocado/sound": "^1.0.0", "@avocado/sound": "^1.0.0",
"@avocado/timing": "^2.0.0", "@avocado/timing": "^2.0.0",
"@avocado/topdown": "^2.0.0", "@avocado/topdown": "^2.0.0",
"@humus/universe": "^1.0.0",
"@inlet/react-pixi": "^6.0.7", "@inlet/react-pixi": "^6.0.7",
"@latus/core": "2.0.0", "@latus/core": "2.0.0",
"@latus/db": "2.0.0", "@latus/db": "2.0.0",

View File

@ -63,9 +63,7 @@ const Humus = ({history}) => {
<Route path="/login"> <Route path="/login">
{isLoggedIn ? <Redirect to="/title" /> : Login} {isLoggedIn ? <Redirect to="/title" /> : Login}
</Route> </Route>
<Route path="/universe"> <Route path={['/universe/:uuid', '/universe']} component={Universe} />
<Universe />
</Route>
{isNative ? <Route path="/title"><Title /></Route> : <Redirect to="/universe" />} {isNative ? <Route path="/title"><Title /></Route> : <Redirect to="/universe" />}
</Switch> </Switch>
</Ui> </Ui>

View File

@ -8,3 +8,19 @@ body {
position: relative; position: relative;
width: 100vw; width: 100vw;
} }
.back {
color: white;
font-family: var(--thick-title-font-family);
font-size: 1.5em;
position: absolute;
left: 3em;
text-decoration: none;
top: 3em;
-webkit-text-stroke: 0.25px black;
}
.back__arrow {
letter-spacing: -0.25em;
margin-right: 0.25em;
}

View File

@ -1,13 +1,30 @@
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
import {
Link,
} from 'react-router-dom';
import Universes from '../universes'; import Universes from '../universes';
const Local = () => ( const Local = () => (
<div className="local"> <div className="local">
<Link
className="back"
to="/title/main"
>
<span className="back__arrow">&lt;-</span>
{' '}
Back
</Link>
<h2 className="local__title">Local universes</h2> <h2 className="local__title">Local universes</h2>
<Universes /> <Link
className="local__create"
to="/title/local/create"
>
+ Create a new universe
</Link>
<Universes isLocal />
</div> </div>
); );

View File

@ -1,10 +1,23 @@
.local__title { .local__title {
font-family: var(--thick-title-font-family); font-family: var(--thick-title-font-family);
font-size: 2em; font-size: 4em;
margin-left: 2em; margin-left: 1em;
margin-top: 2em; margin-top: 2em;
} }
.local__create {
color: white;
display: inline-block;
font-family: var(--title-font-family);
font-size: 1.5em;
margin-top: 1em;
margin-left: 2.75em;
padding: 0.5em;
padding-left: 1em;
text-decoration: none;
}
.local > .universes { .local > .universes {
margin: 4em; margin: 4em;
margin-top: 2em;
} }

View File

@ -1,5 +1,6 @@
.title-main__title { .title-main__title {
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.2);
font-family: var(--scribbles-font-family); font-family: var(--scribbles-font-family);
font-size: 12em; font-size: 12em;
left: 25%; left: 25%;
@ -30,8 +31,8 @@
.title-main__button { .title-main__button {
display: block; display: block;
font-size: 3em; font-size: 3em;
padding: 0.25em; padding: 0.5em 1.5em;
width: 100%; width: 100%;
text-align: left; text-align: left;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
} }

View File

@ -1,13 +1,30 @@
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
import {
Link,
} from 'react-router-dom';
import Universes from '../universes'; import Universes from '../universes';
const Servers = () => ( const Servers = () => (
<div className="servers"> <div className="servers">
<h2 className="servers__title">Servers</h2> <Link
<Universes /> className="back"
to="/title/main"
>
<span className="back__arrow">&lt;-</span>
{' '}
Back
</Link>
<h2 className="servers__title">Remote server universes</h2>
<Link
className="servers__connect"
to="/title/servers/connect"
>
+ Connect to a new universe
</Link>
<Universes isLocal={false} />
</div> </div>
); );

View File

@ -0,0 +1,23 @@
.servers__title {
font-family: var(--thick-title-font-family);
font-size: 4em;
margin-left: 1em;
margin-top: 2em;
}
.servers__connect {
color: white;
display: inline-block;
font-family: var(--title-font-family);
font-size: 1.5em;
margin-top: 1em;
margin-left: 2.75em;
padding: 0.5em;
padding-left: 1em;
text-decoration: none;
}
.servers > .universes {
margin: 4em;
margin-top: 2em;
}

View File

@ -1,29 +1,26 @@
import './index.scss'; import './index.scss';
import {universesByLocalitySelector} from '@humus/universe';
import {useSelector} from '@latus/redux';
import {hot} from 'react-hot-loader'; import {hot} from 'react-hot-loader';
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Universe from './universe'; import Universe from './universe';
const universes = [ const Universes = ({isLocal}) => {
{ const universes = useSelector((state) => universesByLocalitySelector(state, isLocal));
isOnline: true, return (
title: "cha0s's universe", <div className="universes">
uuid: '2543c30e-3749-4c08-a0b2-c50137a39c4a', {Object.entries(universes).map(([uuid, universe]) => (
}, <Universe key={uuid} universe={{...universe, uuid}} />
{ ))}
isOnline: false, </div>
title: 'random universe', );
uuid: 'c41ddaac-89c2-46a4-b3e5-1d634a1a7c36', };
},
];
const Universes = () => ( Universes.propTypes = {
<div className="universes"> isLocal: PropTypes.bool.isRequired,
{universes.map((universe) => ( };
<Universe key={universe.uuid} universe={universe} />
))}
</div>
);
export default hot(module)(Universes); export default hot(module)(Universes);

View File

@ -6,15 +6,39 @@ import {
Link, Link,
} from 'react-router-dom'; } from 'react-router-dom';
const Universe = ({universe: {isOnline, title, uuid}}) => ( const Universe = ({
<Link className="universes-universe" to={`/universe/${uuid}`}> universe: {
<h3>{title}</h3> address,
<span>{isOnline ? '✔️' : '❌'}</span> isOnline,
</Link> title,
); uuid,
},
}) => {
const [host, port] = address.split(':');
return (
<Link className="button universes-universe" to={`/universe/${uuid}`}>
<h3>{title}</h3>
{address && (
<span className="universes-universe__address">
[
<span className="universes-universe__host">{host}</span>
{port && (
<span className="universes-universe__port">
:
{port}
</span>
)}
]
</span>
)}
<span>{isOnline ? '✔️' : '❌'}</span>
</Link>
);
};
Universe.propTypes = { Universe.propTypes = {
universe: PropTypes.shape({ universe: PropTypes.shape({
address: PropTypes.string,
isOnline: PropTypes.bool, isOnline: PropTypes.bool,
title: PropTypes.string, title: PropTypes.string,
uuid: PropTypes.string, uuid: PropTypes.string,

View File

@ -1,13 +1,27 @@
@import 'scss/colors.scss';
.universes-universe { .universes-universe {
background-color: rgba(0, 0, 0, 0.5); align-items: baseline;
color: lighten($color-active, 20%);
display: flex; display: flex;
font-family: var(--thick-title-font-family); font-family: var(--thick-title-font-family);
justify-content: space-between; justify-content: space-between;
margin-bottom: 1em; margin-bottom: 1em;
padding: 2em; padding: 2em;
text-decoration: none;
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.75); background-color: rgba(0, 0, 0, 0.75);
} }
} }
.universes-universe__address {
color: #fff;
font-family: monospace;
font-size: 1.5em;
margin-right: auto;
margin-left: 0.5em;
opacity: 0.7;
}
.universes-universe__port {
opacity: 0.7;
}

View File

@ -1,33 +1,54 @@
import './index.scss'; import './index.scss';
import {universesByLocalitySelector, universesSelector} from '@humus/universe';
import {useSelector} from '@latus/redux';
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import { import {
Link, Link,
Redirect,
} from 'react-router-dom'; } from 'react-router-dom';
import useIsNative from 'hooks/use-is-native'; import useIsNative from 'hooks/use-is-native';
const Universe = () => ( const Universe = ({match: {params: {uuid}}}) => {
<div className="universe"> const isNative = useIsNative();
<div className="universe__muted"> const universes = useSelector(universesSelector);
{useIsNative && ( const remoteUniverses = useSelector((state) => universesByLocalitySelector(state, false));
<Link className="universe__back" to="/title">Back to title</Link> const uuids = Object.keys(remoteUniverses);
)} if (!uuid && uuids.length === 0) {
<h2 className="universe__title">{'{UNIVERSE_NAME}'}</h2> return <Redirect to="/" />;
<button className="universe__play" type="button">Play</button> }
<p className="universe__attribution"> const universe = uuid ? universes[uuid] : universes[uuids.pop()];
Art by if (!universe) {
{' '} return <Redirect to="/" />;
<a }
href="https://www.artstation.com/simonkono" return (
rel="noreferrer" <div className="universe">
target="_blank" <div className="universe__muted">
> {isNative && (
Simon Kono <Link
</a> className="back"
</p> to={universe.address ? '/title/servers' : '/title/local'}
>
<span className="back__arrow">&lt;-</span>
{' '}
Back
</Link>
)}
<h2 className="universe__title">{universe.title}</h2>
<button className="universe__play" type="button">Play</button>
</div>
</div> </div>
</div> );
); };
Universe.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
uuid: PropTypes.string,
}),
}).isRequired,
};
export default Universe; export default Universe;

View File

@ -6,32 +6,16 @@
} }
.universe__muted { .universe__muted {
background-color: rgba(0, 0, 0, 0.25); background-color: rgba(0, 0, 0, 0.5);
height: 100%; height: 100%;
position: absolute; position: absolute;
width: 100%; width: 100%;
} }
.universe__back {
color: white;
font-size: 1.5em;
position: absolute;
left: 3em;
top: 1em;
-webkit-text-stroke: 0.25px black;
}
.universe__attribution {
position: absolute;
bottom: 1em;
left: 1em;
}
.universe__title { .universe__title {
font-family: var(--thick--title-font-family); font-family: var(--thick-title-font-family);
font-size: 4em; font-size: 4em;
margin: 1em; margin: 2em 1em;
-webkit-text-stroke: 1.5px black;
} }
.universe__play { .universe__play {

View File

@ -17,7 +17,7 @@ const Index = () => (
export default { export default {
hooks: { hooks: {
'@latus/react/components': () => Index, '@latus/react/components': () => Index,
'@latus/redux/client/slices': () => ({ '@latus/redux/slices': () => ({
router: connectRouter(history), router: connectRouter(history),
}), }),
'@latus/redux/store': (options) => { '@latus/redux/store': (options) => {

View File

@ -150,10 +150,15 @@ fieldset {
} }
button, .button { button, .button {
background: #222222; background-color: rgba(0, 0, 0, 0.65);
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff; color: #ffffff;
font-size: 100%; font-size: 100%;
text-decoration: none;
transition: background-color 0.2s;
&:hover {
background-color: rgba(0, 0, 0, 0.85);
}
} }
button, .button, input[type="checkbox"], input[type="checkbox"] + label { button, .button, input[type="checkbox"], input[type="checkbox"] + label {

View File

@ -1086,6 +1086,14 @@
object-assign "^4.1.1" object-assign "^4.1.1"
scheduler "^0.20.1" scheduler "^0.20.1"
"@humus/universe@^1.0.0":
version "1.0.0"
resolved "https://npm.i12e.cha0s.io/@humus%2funiverse/-/universe-1.0.0.tgz#7072c22ea3dbaf94dc1aae4f374fa334f2387d05"
integrity sha512-a8axM6QtzS2V0fcA2dh5FUrGVToMYYz+JAmkPA/N+4yLRChVpTVyFIWu6qwrsy1rPbEaMuvo7ZT844zeytQ0aw==
dependencies:
"@latus/redux" "^2.0.0"
debug "4.3.1"
"@inlet/react-pixi@^6.0.7": "@inlet/react-pixi@^6.0.7":
version "6.0.7" version "6.0.7"
resolved "https://npm.i12e.cha0s.io/@inlet%2freact-pixi/-/react-pixi-6.0.7.tgz#0b05a85893213b78962c1cbe9c5016f3c183f032" resolved "https://npm.i12e.cha0s.io/@inlet%2freact-pixi/-/react-pixi-6.0.7.tgz#0b05a85893213b78962c1cbe9c5016f3c183f032"
@ -1172,8 +1180,8 @@
"@latus/redux@^2.0.0": "@latus/redux@^2.0.0":
version "2.0.0" version "2.0.0"
resolved "https://npm.i12e.cha0s.io/@latus%2fredux/-/redux-2.0.0.tgz#e74c4040fd4958e77c3f9a4a0c77a4538bf6fbeb" resolved "https://npm.i12e.cha0s.io/@latus%2fredux/-/redux-2.0.0.tgz#10fee1fd1073ef12fff02294ee09c5362d2cc8b7"
integrity sha512-npKxsLEQdDNg6aAANGInuZeBjOZdQsKySezv+MEjOqVgo7yurwDogXNRKPGb9mqjzaH4D4ugcCDAGBLLY5CvFg== integrity sha512-4DfJbZAfOOR7QV0Y9lcJ8MZhBWc+kYG5ngH6fWAhzhG41XIcOE/H3E6K3J6xX5Y/RCr9/qcuSSDwE3ReEkYT/Q==
dependencies: dependencies:
"@latus/core" "2.0.0" "@latus/core" "2.0.0"
"@reduxjs/toolkit" "^1.5.0" "@reduxjs/toolkit" "^1.5.0"

View File

@ -1,5 +1,5 @@
{ {
"name": "@latus/package", "name": "@humus/package",
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"author": "cha0s", "author": "cha0s",

View File

@ -0,0 +1 @@
module.exports = require('../../config/.eslintrc');

6
packages/universe/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
**/*.js
**/*.map
!/.*
!/webpack.config.js
!src/**/*.js
!/test/**/*.js

View File

@ -0,0 +1 @@
module.exports = require('../../config/.neutrinorc');

View File

@ -0,0 +1,44 @@
{
"name": "@humus/universe",
"version": "1.0.0",
"main": "index.js",
"author": "cha0s",
"license": "MIT",
"scripts": {
"build": "NODE_PATH=./node_modules webpack --mode production",
"clean": "rm -rf yarn.lock node_modules && yarn",
"dev": "NODE_PATH=./node_modules webpack --mode development",
"forcepub": "npm unpublish --force $(node -e 'const {name, version} = require(`./package.json`); process.stdout.write(`${name}@${version}`)') && npm publish",
"link": "node -e \"Object.keys(require('./package.json').dependencies).filter((m) => 0 === m.indexOf('@latus/')).forEach((m) => require('child_process').spawn('yarn', ['link', m]));\"",
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
"test": "NODE_PATH=./node_modules mocha --config ../../config/.mocharc.js",
"unlink": "node -e \"Object.keys(require('./package.json').dependencies).filter((m) => 0 === m.indexOf('@latus/')).forEach((m) => require('child_process').spawn('yarn', ['unlink', m]));\" && yarn install --force",
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
},
"files": [
"index.js",
"index.js.map",
"test.js",
"test.js.map"
],
"dependencies": {
"@latus/redux": "^2.0.0",
"debug": "4.3.1"
},
"devDependencies": {
"@neutrinojs/airbnb-base": "^9.4.0",
"@neutrinojs/banner": "^9.4.0",
"@neutrinojs/copy": "9.4.0",
"@neutrinojs/mocha": "^9.4.0",
"@neutrinojs/react": "^9.4.0",
"chai": "4.2.0",
"eslint": "^7",
"eslint-import-resolver-webpack": "0.13.0",
"glob": "7.1.6",
"mocha": "^8",
"neutrino": "^9.4.0",
"source-map-support": "0.5.19",
"webpack": "^4",
"webpack-cli": "^3"
}
}

View File

@ -0,0 +1,11 @@
import {universes} from './state';
export * from './state';
export default {
hooks: {
'@latus/redux/slices': () => ({
universes,
}),
},
};

View File

@ -0,0 +1,2 @@
export * from './universes';
export {default as universes} from './universes';

View File

@ -0,0 +1,46 @@
import {
createSelector,
createSlice,
} from '@latus/redux';
export const universesSelector = (state) => state.universes;
export const universesByLocalitySelector = createSelector(
[universesSelector, (_, isLocal) => isLocal],
(universes, isLocal_) => Object.fromEntries(
Object.entries(universes).filter(([, {address}]) => !address === isLocal_),
),
);
export const universeSelector = createSelector(
[universesSelector, (_, uuid) => uuid],
(universes, uuid) => uuid && universes[uuid],
);
const slice = createSlice({
name: 'humus/universes',
initialState: {
'2543c30e-3749-4c08-a0b2-c50137a39c4a': {
address: '',
isOnline: true,
title: "cha0s's universe",
},
'c41ddaac-89c2-46a4-b3e5-1d634a1a7c36': {
address: 'humus.cha0s.io:32340',
isOnline: false,
title: 'random universe',
},
},
/* eslint-disable no-param-reassign */
extraReducers: {
},
reducers: {
},
/* eslint-enable no-param-reassign */
});
slice.reducer.subscription = slice.reducer;
// export const {
// } = slice.actions;
export default slice.reducer;

View File

@ -0,0 +1,9 @@
import {expect} from 'chai';
const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.be.true;
})
});

View File

@ -0,0 +1,3 @@
const neutrino = require('neutrino');
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();

6300
packages/universe/yarn.lock Normal file

File diff suppressed because it is too large Load Diff