commit
2ba546d94c
3
.prettierrc
Normal file
3
.prettierrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
11
package-lock.json
generated
Normal file
11
package-lock.json
generated
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"requires": true,
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"three": {
|
||||||
|
"version": "0.119.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/three/-/three-0.119.1.tgz",
|
||||||
|
"integrity": "sha512-GHyh/RiUfQ5VTiWIVRRTANYoXc1PFB1y+jDVRTb649nif1uX1F06PT1TKU3k2+F/MN4UJ3PWvQB53fY2OqKqKw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
webclient/.dockerignore
Normal file
1
webclient/.dockerignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
11
webclient/Dockerfile
Normal file
11
webclient/Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
FROM node:14
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm i
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "run", "start"]
|
4
webclient/docker.sh
Executable file
4
webclient/docker.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
docker build . -t spaceport-client
|
||||||
|
docker run -v $PWD:/usr/src/app spaceport-client
|
||||||
|
# npm install
|
||||||
|
# npm run start
|
14528
webclient/package-lock.json
generated
Normal file
14528
webclient/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,7 @@
|
||||||
"react-to-print": "~2.5.1",
|
"react-to-print": "~2.5.1",
|
||||||
"recharts": "~1.8.5",
|
"recharts": "~1.8.5",
|
||||||
"semantic-ui-react": "~0.88.2",
|
"semantic-ui-react": "~0.88.2",
|
||||||
|
"three": "^0.119.1",
|
||||||
"serialize-javascript": "^3.1.0"
|
"serialize-javascript": "^3.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -1,46 +1,100 @@
|
||||||
import React from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
import { Container, Icon } from 'semantic-ui-react';
|
import { Container, Icon } from 'semantic-ui-react';
|
||||||
|
|
||||||
export function Footer() {
|
import { scene } from './spaceport/scene';
|
||||||
|
|
||||||
|
export const Footer = () => {
|
||||||
|
const footerRef = useRef();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!footerRef.current) return;
|
||||||
|
if (footerRef.current.clientWidth < 650) return
|
||||||
|
scene({ ref: footerRef });
|
||||||
|
}, [footerRef]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='footer'>
|
<div className="footer" ref={footerRef}>
|
||||||
<Container>
|
<Container className="footer-content">
|
||||||
<p>
|
<p>
|
||||||
<img alt='site logo' src='/logo-short.svg' className='logo' />
|
<img
|
||||||
|
alt="site logo"
|
||||||
|
src="/logo-short.svg"
|
||||||
|
className="logo"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className='text'>
|
<p className="text">
|
||||||
Contact us: <a href='mailto:info@protospace.ca' target='_blank' rel='noopener noreferrer'>info@protospace.ca</a>
|
Contact us:{' '}
|
||||||
|
<a
|
||||||
|
href="mailto:info@protospace.ca"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
info@protospace.ca
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className='text'>
|
<p className="text">
|
||||||
Created and hosted by Protospace members for Protospace members.
|
Created and hosted by Protospace members for Protospace
|
||||||
|
members.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className='text'>
|
<p className="text">
|
||||||
Spaceport is free and open-source software. <a href='https://github.com/Protospace/spaceport' target='_blank' rel='noopener noreferrer'>Click here</a> to view the source code and license.
|
Spaceport is free and open-source software.{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/Protospace/spaceport"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Click here
|
||||||
|
</a>{' '}
|
||||||
|
to view the source code and license.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href='https://instagram.com/protospace' target='_blank' rel='noopener noreferrer' aria-label='link to our instagram'>
|
<a
|
||||||
<Icon name='instagram' size='large' />
|
href="https://instagram.com/protospace"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="link to our instagram"
|
||||||
|
>
|
||||||
|
<Icon name="instagram" size="large" />
|
||||||
</a>
|
</a>
|
||||||
<a href='https://twitter.com/protospace' target='_blank' rel='noopener noreferrer' aria-label='link to our twitter'>
|
<a
|
||||||
<Icon name='twitter' size='large' />
|
href="https://twitter.com/protospace"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="link to our twitter"
|
||||||
|
>
|
||||||
|
<Icon name="twitter" size="large" />
|
||||||
</a>
|
</a>
|
||||||
<a href='https://youtube.com/user/calgaryprotospace/playlists' target='_blank' rel='noopener noreferrer' aria-label='link to our youtube'>
|
<a
|
||||||
<Icon name='youtube' size='large' />
|
href="https://youtube.com/user/calgaryprotospace/playlists"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="link to our youtube"
|
||||||
|
>
|
||||||
|
<Icon name="youtube" size="large" />
|
||||||
</a>
|
</a>
|
||||||
<a href='https://github.com/Protospace' target='_blank' rel='noopener noreferrer' aria-label='link to our github'>
|
<a
|
||||||
<Icon name='github' size='large' />
|
href="https://github.com/Protospace"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="link to our github"
|
||||||
|
>
|
||||||
|
<Icon name="github" size="large" />
|
||||||
</a>
|
</a>
|
||||||
<a href='https://docs.my.protospace.ca' target='_blank' rel='noopener noreferrer' aria-label='link to our docs'>
|
<a
|
||||||
<Icon name='book' size='large' />
|
href="https://docs.my.protospace.ca"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="link to our docs"
|
||||||
|
>
|
||||||
|
<Icon name="book" size="large" />
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>© 2020 Calgary Protospace Ltd.</p>
|
<p>© 2020 Calgary Protospace Ltd.</p>
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
html, body {
|
html,
|
||||||
|
body {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -43,7 +44,7 @@ body {
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topPadding > .ui.container{
|
.topPadding > .ui.container {
|
||||||
min-height: 45rem;
|
min-height: 45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +67,9 @@ body {
|
||||||
padding-bottom: 24rem;
|
padding-bottom: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-editor, .class-editor, .transaction-editor {
|
.course-editor,
|
||||||
|
.class-editor,
|
||||||
|
.transaction-editor {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,12 +119,23 @@ body {
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
margin-top: -20rem;
|
margin-top: -20rem;
|
||||||
|
|
||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* grid bottom */
|
||||||
|
.footer canvas {
|
||||||
|
grid-row: 1/2;
|
||||||
|
grid-column: 1/2;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grid top */
|
||||||
.footer .container {
|
.footer .container {
|
||||||
|
z-index: 99;
|
||||||
|
grid-row: 1/2;
|
||||||
|
grid-column: 1/2;
|
||||||
padding-top: 3rem;
|
padding-top: 3rem;
|
||||||
padding-bottom: 3rem;
|
padding-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
@ -150,3 +164,23 @@ body {
|
||||||
margin-left: -3.5px;
|
margin-left: -3.5px;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.darkmode-layer,
|
||||||
|
.darkmode-toggle {
|
||||||
|
z-index: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmode--activated .ui.image {
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
filter: brightness(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmode--activated i.green.circle.icon,
|
||||||
|
.darkmode--activated i.yellow.circle.icon,
|
||||||
|
.darkmode--activated i.red.circle.icon {
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmode--activated .footer {
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
}
|
||||||
|
|
63
webclient/src/spaceport/Ship.js
Normal file
63
webclient/src/spaceport/Ship.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
const SHIP_SIZE = 1;
|
||||||
|
|
||||||
|
export class Ship {
|
||||||
|
constructor() {
|
||||||
|
this.life = Math.random() * 5 + 7;
|
||||||
|
this.flyIn = true;
|
||||||
|
|
||||||
|
const shipGeo = new THREE.BoxGeometry(
|
||||||
|
SHIP_SIZE * 0.1,
|
||||||
|
SHIP_SIZE * 0.1,
|
||||||
|
SHIP_SIZE
|
||||||
|
);
|
||||||
|
this.mesh = new THREE.Mesh(
|
||||||
|
shipGeo,
|
||||||
|
new THREE.MeshStandardMaterial(0xff0000, { flatShading: true })
|
||||||
|
);
|
||||||
|
this.y = (Math.random() - 0.5) * 2;
|
||||||
|
|
||||||
|
this.hue = Math.floor(Math.random() * 360);
|
||||||
|
|
||||||
|
this.mesh.material.color.set(
|
||||||
|
new THREE.Color(`hsl(${this.hue},10%,40%)`)
|
||||||
|
);
|
||||||
|
this.mesh.position.x = (Math.random() - 0.5) * 2;
|
||||||
|
this.mesh.position.y = this.y;
|
||||||
|
this.mesh.position.z = -105 + Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
|
update({ deltaTime }) {
|
||||||
|
if (this.flyIn) {
|
||||||
|
this.mesh.scale.z = 10;
|
||||||
|
this.mesh.position.z += 4.75;
|
||||||
|
|
||||||
|
// ship accelerating decreasing
|
||||||
|
// checvk if in space
|
||||||
|
if (this.mesh.position.z > -1 && this.flyIn) {
|
||||||
|
this.flyIn = false;
|
||||||
|
this.mesh.scale.z = 0.5;
|
||||||
|
this.mesh.material.color.set(
|
||||||
|
new THREE.Color(`hsl(${this.hue},0%,30%)`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.mesh.scale.z = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.life -= deltaTime;
|
||||||
|
|
||||||
|
this.mesh.position.y = this.y + Math.sin(this.life + this.y) * 0.02;
|
||||||
|
|
||||||
|
if (this.life < 0) {
|
||||||
|
const a = Math.abs(this.life);
|
||||||
|
this.mesh.position.z += a * 2;
|
||||||
|
this.mesh.scale.z = a * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mesh.position.z > 55) {
|
||||||
|
this.kill = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
webclient/src/spaceport/scene.js
Normal file
92
webclient/src/spaceport/scene.js
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import * as THREE from 'three/build/three.module';
|
||||||
|
import { Ship } from './Ship';
|
||||||
|
|
||||||
|
export const scene = ({ ref }) => {
|
||||||
|
// TODO: add waves of ships
|
||||||
|
// TODO: add stars
|
||||||
|
// TODO: use aspect ratio to determine space docking point
|
||||||
|
|
||||||
|
let t = 0.01;
|
||||||
|
const shipInterval = 2;
|
||||||
|
let nextShip = shipInterval;
|
||||||
|
|
||||||
|
var scene = new THREE.Scene();
|
||||||
|
|
||||||
|
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||||
|
|
||||||
|
const width = ref.current.clientWidth;
|
||||||
|
const height = ref.current.clientHeight;
|
||||||
|
|
||||||
|
renderer.setSize(width, height);
|
||||||
|
|
||||||
|
const camera = new THREE.PerspectiveCamera(65, width / height, 0.01, 1000);
|
||||||
|
|
||||||
|
camera.position.set(3, 0.5, 5);
|
||||||
|
camera.lookAt(new THREE.Vector3(-9, 0, 3));
|
||||||
|
scene.add(camera);
|
||||||
|
|
||||||
|
ref.current.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
const light = new THREE.DirectionalLight('#fff', 1);
|
||||||
|
light.position.x = 3;
|
||||||
|
light.position.z = 1;
|
||||||
|
scene.add(light);
|
||||||
|
|
||||||
|
var sphere = new THREE.SphereBufferGeometry(1);
|
||||||
|
var object = new THREE.Mesh(
|
||||||
|
sphere,
|
||||||
|
new THREE.MeshStandardMaterial(0xff0000, { flatShading: true })
|
||||||
|
);
|
||||||
|
var boxHelp = new THREE.BoxHelper(object, 0xffff00);
|
||||||
|
// scene.add(boxHelp);
|
||||||
|
|
||||||
|
let ships = [];
|
||||||
|
const ship = new Ship();
|
||||||
|
scene.add(ship.mesh);
|
||||||
|
ships.push(ship);
|
||||||
|
|
||||||
|
const animate = () => {
|
||||||
|
const deltaTime = 0.075;
|
||||||
|
t += deltaTime;
|
||||||
|
|
||||||
|
// register mouse event for 'onmove'
|
||||||
|
// get mouse x & y
|
||||||
|
// const mu = mousex / ref.width
|
||||||
|
// const mv = mousey / ref.heigh
|
||||||
|
|
||||||
|
// camera.x = sin(mu * Math.PI * 2)
|
||||||
|
// camera.z = cos(mu * Math.PI * 2)
|
||||||
|
|
||||||
|
if (t > nextShip) {
|
||||||
|
const ship = new Ship();
|
||||||
|
scene.add(ship.mesh);
|
||||||
|
ships.push(ship);
|
||||||
|
nextShip += shipInterval + (Math.random() - 0.5) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ship of ships) {
|
||||||
|
ship.update({ deltaTime });
|
||||||
|
if (ship.kill) {
|
||||||
|
scene.remove(ship.mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ships = ships.filter((s) => !s.kill);
|
||||||
|
|
||||||
|
window.addEventListener('resize', onWindowResize);
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
console.log(ref.current.clientWidth, ref.current.clientHeight)
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
renderer.setSize(ref.current.clientWidth, ref.current.clientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
animate();
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
|
@ -10478,6 +10478,11 @@ text-table@0.2.0, text-table@^0.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||||
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
||||||
|
|
||||||
|
three@^0.119.1:
|
||||||
|
version "0.119.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/three/-/three-0.119.1.tgz#9d979a082c4cd9622af8e3498a8dfa026a619332"
|
||||||
|
integrity sha512-GHyh/RiUfQ5VTiWIVRRTANYoXc1PFB1y+jDVRTb649nif1uX1F06PT1TKU3k2+F/MN4UJ3PWvQB53fY2OqKqKw==
|
||||||
|
|
||||||
throat@^4.0.0:
|
throat@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
|
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user