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/timing": "^2.0.0",
"@avocado/topdown": "^2.0.0",
"@humus/universe": "^1.0.0",
"@inlet/react-pixi": "^6.0.7",
"@latus/core": "2.0.0",
"@latus/db": "2.0.0",

View File

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

View File

@ -8,3 +8,19 @@ body {
position: relative;
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 React from 'react';
import {
Link,
} from 'react-router-dom';
import Universes from '../universes';
const 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>
<Universes />
<Link
className="local__create"
to="/title/local/create"
>
+ Create a new universe
</Link>
<Universes isLocal />
</div>
);

View File

@ -1,10 +1,23 @@
.local__title {
font-family: var(--thick-title-font-family);
font-size: 2em;
margin-left: 2em;
font-size: 4em;
margin-left: 1em;
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 {
margin: 4em;
margin-top: 2em;
}

View File

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

View File

@ -1,13 +1,30 @@
import './index.scss';
import React from 'react';
import {
Link,
} from 'react-router-dom';
import Universes from '../universes';
const Servers = () => (
<div className="servers">
<h2 className="servers__title">Servers</h2>
<Universes />
<Link
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>
);

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

View File

@ -6,15 +6,39 @@ import {
Link,
} from 'react-router-dom';
const Universe = ({universe: {isOnline, title, uuid}}) => (
<Link className="universes-universe" to={`/universe/${uuid}`}>
<h3>{title}</h3>
<span>{isOnline ? '✔️' : '❌'}</span>
</Link>
);
const Universe = ({
universe: {
address,
isOnline,
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.shape({
address: PropTypes.string,
isOnline: PropTypes.bool,
title: PropTypes.string,
uuid: PropTypes.string,

View File

@ -1,13 +1,27 @@
@import 'scss/colors.scss';
.universes-universe {
background-color: rgba(0, 0, 0, 0.5);
align-items: baseline;
color: lighten($color-active, 20%);
display: flex;
font-family: var(--thick-title-font-family);
justify-content: space-between;
margin-bottom: 1em;
padding: 2em;
text-decoration: none;
&:hover {
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 {universesByLocalitySelector, universesSelector} from '@humus/universe';
import {useSelector} from '@latus/redux';
import PropTypes from 'prop-types';
import React from 'react';
import {
Link,
Redirect,
} from 'react-router-dom';
import useIsNative from 'hooks/use-is-native';
const Universe = () => (
<div className="universe">
<div className="universe__muted">
{useIsNative && (
<Link className="universe__back" to="/title">Back to title</Link>
)}
<h2 className="universe__title">{'{UNIVERSE_NAME}'}</h2>
<button className="universe__play" type="button">Play</button>
<p className="universe__attribution">
Art by
{' '}
<a
href="https://www.artstation.com/simonkono"
rel="noreferrer"
target="_blank"
>
Simon Kono
</a>
</p>
const Universe = ({match: {params: {uuid}}}) => {
const isNative = useIsNative();
const universes = useSelector(universesSelector);
const remoteUniverses = useSelector((state) => universesByLocalitySelector(state, false));
const uuids = Object.keys(remoteUniverses);
if (!uuid && uuids.length === 0) {
return <Redirect to="/" />;
}
const universe = uuid ? universes[uuid] : universes[uuids.pop()];
if (!universe) {
return <Redirect to="/" />;
}
return (
<div className="universe">
<div className="universe__muted">
{isNative && (
<Link
className="back"
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>
);
);
};
Universe.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
uuid: PropTypes.string,
}),
}).isRequired,
};
export default Universe;

View File

@ -6,32 +6,16 @@
}
.universe__muted {
background-color: rgba(0, 0, 0, 0.25);
background-color: rgba(0, 0, 0, 0.5);
height: 100%;
position: absolute;
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 {
font-family: var(--thick--title-font-family);
font-family: var(--thick-title-font-family);
font-size: 4em;
margin: 1em;
-webkit-text-stroke: 1.5px black;
margin: 2em 1em;
}
.universe__play {

View File

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

View File

@ -150,10 +150,15 @@ fieldset {
}
button, .button {
background: #222222;
border: 1px solid rgba(255, 255, 255, 0.1);
background-color: rgba(0, 0, 0, 0.65);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
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 {

View File

@ -1086,6 +1086,14 @@
object-assign "^4.1.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":
version "6.0.7"
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":
version "2.0.0"
resolved "https://npm.i12e.cha0s.io/@latus%2fredux/-/redux-2.0.0.tgz#e74c4040fd4958e77c3f9a4a0c77a4538bf6fbeb"
integrity sha512-npKxsLEQdDNg6aAANGInuZeBjOZdQsKySezv+MEjOqVgo7yurwDogXNRKPGb9mqjzaH4D4ugcCDAGBLLY5CvFg==
resolved "https://npm.i12e.cha0s.io/@latus%2fredux/-/redux-2.0.0.tgz#10fee1fd1073ef12fff02294ee09c5362d2cc8b7"
integrity sha512-4DfJbZAfOOR7QV0Y9lcJ8MZhBWc+kYG5ngH6fWAhzhG41XIcOE/H3E6K3J6xX5Y/RCr9/qcuSSDwE3ReEkYT/Q==
dependencies:
"@latus/core" "2.0.0"
"@reduxjs/toolkit" "^1.5.0"

View File

@ -1,5 +1,5 @@
{
"name": "@latus/package",
"name": "@humus/package",
"version": "1.0.0",
"main": "index.js",
"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