Browse Source

feat: Use emotion for css

v2.0.0rc
Dale 7 months ago
parent
commit
28be90246c
Signed by: Deiru GPG Key ID: AA250C0277B927E1
30 changed files with 1045 additions and 643 deletions
  1. +1
    -0
      .gitignore
  2. +5
    -1
      package.json
  3. +17
    -0
      src/assets/style-vars.ts
  4. +45
    -5
      src/components/App.tsx
  5. +0
    -24
      src/components/Dropdown.module.css
  6. +28
    -0
      src/components/Dropdown.styles.ts
  7. +2
    -2
      src/components/Dropdown.tsx
  8. +0
    -60
      src/components/Menu.module.css
  9. +58
    -0
      src/components/Menu.styles.ts
  10. +3
    -3
      src/components/Menu.tsx
  11. +0
    -22
      src/components/Playback.module.css
  12. +27
    -0
      src/components/Playback.styles.ts
  13. +5
    -5
      src/components/Playback.tsx
  14. +18
    -20
      src/components/Renderer/Image.styles.ts
  15. +1
    -1
      src/components/Renderer/Image.tsx
  16. +4
    -4
      src/components/Renderer/index.tsx
  17. +0
    -265
      src/components/Renderer/style.module.css
  18. +224
    -0
      src/components/Renderer/styles.ts
  19. +0
    -162
      src/components/SkillTree.module.css
  20. +156
    -0
      src/components/SkillTree.styles.ts
  21. +3
    -3
      src/components/SkillTree.tsx
  22. +9
    -9
      src/engine/Engine.ts
  23. +2
    -1
      src/engine/index.ts
  24. +1
    -1
      src/engine/lib/store.ts
  25. +0
    -0
      src/engine/lib/utils.ts
  26. +4
    -1
      src/engine/types.ts
  27. +0
    -41
      src/index.css
  28. +2
    -3
      src/index.tsx
  29. +2
    -1
      tsconfig.json
  30. +428
    -9
      yarn.lock

+ 1
- 0
.gitignore View File

@ -6,6 +6,7 @@
.idea
*.log
tmp/
lib/
*.tern-port
node_modules/


+ 5
- 1
package.json View File

@ -15,15 +15,18 @@
"build": "./node_modules/.bin/webpack --config webpack.config.js"
},
"dependencies": {
"@emotion/core": "^10.0.35",
"classnames": "^2.2.6",
"debounce": "^1.2.0",
"emotion": "^10.0.27",
"ramda": "^0.27.1",
"react": "^16.13.1",
"react-click-outside-hook": "^1.1.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.1",
"react-toastify": "^6.0.8",
"redux": "^4.0.5"
"redux": "^4.0.5",
"styled-components": "^5.2.0"
},
"devDependencies": {
"@types/classnames": "^2.2.10",
@ -33,6 +36,7 @@
"@types/react-click-outside-hook": "^1.0.0",
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",
"@types/styled-components": "^5.1.3",
"css-loader": "^4.2.2",
"file-loader": "^6.1.0",
"html-webpack-plugin": "^4.4.1",


+ 17
- 0
src/assets/style-vars.ts View File

@ -0,0 +1,17 @@
export const MainBgColor = 'rgb(243, 223, 193)';
export const MainBgColorDark = 'rgb(144, 87, 18)';
export const MainTextColor = 'rgb(26, 28, 26)';
export const MainErrorColor = 'rgb(232, 91, 30)';
export const MainSuccessColor = 'rgb(123, 189, 70)';
export const colors = {
MainBgColor,
MainBgColorDark,
MainTextColor,
MainErrorColor,
MainSuccessColor,
};
export default {
colors,
};

+ 45
- 5
src/components/App.tsx View File

@ -1,19 +1,45 @@
import React, { useMemo } from 'react';
import { Global, css } from '@emotion/core';
import styled from 'styled-components';
import { colors } from '../assets/style-vars'
import Playback from './Playback';
import { Renderer } from './Renderer';
import createEngine from '@/engine';
import { Engine } from '@/engine/Engine';
import createEngine from '../engine';
import { Engine } from '../engine/Engine';
import { Provider } from 'react-redux';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css'
import { EngineConfig } from '@/engine/types';
import { EngineConfig } from '../engine/types';
type AppProps<GS = object, MT = undefined, ST extends string = string> = {
config: EngineConfig<GS, MT, ST>
}
const StyledToastContainer = styled(ToastContainer)`
.Toastify__toast {
background: ${colors.MainBgColor};
color: ${colors.MainTextColor};
}
.Toastify__progress-bar--default {
background: ${colors.MainBgColorDark};
}
.Toastify__progress-bar--success {
background: ${colors.MainSuccessColor};
}
.Toastify__progress-bar--error {
background: ${colors.MainErrorColor};
}
.Toastify__close-button {
color: ${colors.MainTextColor};
}
`;
export default <GS, MT, ST extends string, >({ config }: AppProps<GS, MT, ST>) => {
const engine: Engine<GS, MT, ST> = useMemo(
() => createEngine<GS, MT, ST>(config, config.reducer),
@ -22,6 +48,20 @@ export default <GS, MT, ST extends string, >({ config }: AppProps<GS, MT, ST>) =
return (
<>
<Global styles={css`
@font-face {
font-family: 'Antic Slab Regular';
src: url('./assets/fonts/AnticSlab-Regular.woff2') format('woff2');
}
body {
font-family: "Antic Slab Regular";
font-size: 1.5rem;
color: ${colors.MainTextColor};
background-color: ${colors.MainBgColor};
font-weight: 400;
}
`} />
<Provider store={engine.store}>
<Playback engine={engine} engineConfig={config}>
{(_, config, backlog, location, time, next) => {
@ -29,7 +69,7 @@ export default <GS, MT, ST extends string, >({ config }: AppProps<GS, MT, ST>) =
}}
</Playback>
</Provider>
<ToastContainer />
<StyledToastContainer />
</>
);
}

+ 0
- 24
src/components/Dropdown.module.css View File

@ -1,24 +0,0 @@
.dropdownContainer {
position: relative;
}
.dropdownContent {
display: flex;
top: calc(100% + 5px);
position: absolute;
border: 2px solid var(--MainBgColorDark);
background-color: var(--MainBgColor);
box-sizing: border-box;
transition: all 0.3s ease-in;
padding: 5px;
opacity: 0;
z-index: 1;
}
.activateContainer {
cursor: pointer;
}
.dropdownContentOpen {
opacity: 1;
transition: all 0.3s ease-in;
}

+ 28
- 0
src/components/Dropdown.styles.ts View File

@ -0,0 +1,28 @@
import { css, cx } from 'emotion';
import { colors } from '../assets/style-vars';
export const dropdownContainer = css`
position: relative;
`;
export const dropdownContent = css`
display: flex;
top: calc(100% + 5px);
position: absolute;
border: 2px solid ${colors.MainBgColorDark};
background-color: ${colors.MainBgColor};
box-sizing: border-box;
transition: all 0.3s ease-in;
padding: 5px;
opacity: 0;
z-index: 1;
`
export const activateContainer = css`
cursor: pointer;
`;
export const dropdownContentOpen = css`
opacity: 1;
transition: all 0.3s ease-in;
`;

+ 2
- 2
src/components/Dropdown.tsx View File

@ -1,7 +1,7 @@
import React, { FC, useState, useEffect } from 'react';
import React, { FC, useState } from 'react';
import cn from 'classnames';
import styles from './Dropdown.module.css';
import * as styles from './Dropdown.styles';
import { useClickOutside } from 'react-click-outside-hook';
type ActivateFn = (toggleDropdown: () => void, label?: string, isOpen?: boolean) => React.ReactNode;


+ 0
- 60
src/components/Menu.module.css View File

@ -1,60 +0,0 @@
.menuContainer {
}
.menuItem {
font-weight: bold;
position: relative;
padding: 0.75em 15px 0.80em 15px;
border: none;
display: block;
width: 100%;
text-align: left;
font-family: inherit;
background-color: transparent;
}
.menuItem.start {
font-size: 1.5em;
}
.menuItem.load {
font-size: 1.17em;
}
.menuItem::after {
content: '';
height: 100%;
position: absolute;
background-color: var(--MainBgColorDark);
width: 0;
z-index: -1;
transition: width 0.1s ease-out;
top: 0;
left: 0;
}
.menuItem:hover {
color: var(--MainBgColor);
cursor: pointer;
}
.menuItem:hover::after {
width: 100%;
transition: width 0.3s ease-in;
}
.menuTitle {
padding: 15px;
border-bottom: 2px dashed var(--MainBgColorDark);
}
.menuTitle > h1 {
margin: 0;
}
.menuTitle > h1 > small {
font-size: 1.4rem;
display: inline-block;
}

+ 58
- 0
src/components/Menu.styles.ts View File

@ -0,0 +1,58 @@
import { css } from 'emotion';
import { colors } from '../assets/style-vars';
const menuItem = css`
font-weight: bold;
position: relative;
padding: 0.75em 15px 0.80em 15px;
border: none;
display: block;
width: 100%;
text-align: left;
font-family: inherit;
background-color: transparent;
&.start {
font-size: 1.5em;
}
&.load {
font-size: 1.17em;
}
&:hover {
color: ${colors.MainBgColor};
cursor: pointer;
}
&::after {
content: '';
height: 100%;
position: absolute;
background-color: ${colors.MainBgColorDark};
width: 0;
z-index: -1;
transition: width 0.1s ease-out;
top: 0;
left: 0;
}
&:hover::after {
width: 100%;
transition: width 0.3s ease-in;
}
`;
const menuTitle = css`
padding: 15px;
border-bottom: 2px dashed ${colors.MainBgColorDark};
& > h1 {
margin: 0;
}
& > h1 > small {
font-size: 1.4rem;
display: inline-block;
}
`;
export default {
menuItem,
menuTitle,
start: 'start',
load: 'load',
}

+ 3
- 3
src/components/Menu.tsx View File

@ -1,7 +1,7 @@
import React, { FC } from 'react';
import cn from 'classnames';
import styles from './Menu.module.css';
import styles from './Menu.styles';
type Props = {
startGame: () => void;
@ -9,7 +9,7 @@ type Props = {
}
const Menu: FC<Props> = ({ startGame, loadGame }) => (
<div className={styles.menuContainer}>
<>
<div className={styles.menuTitle}>
<h1>
Discoteque Demo <br />
@ -18,7 +18,7 @@ const Menu: FC<Props> = ({ startGame, loadGame }) => (
</div>
<button className={cn(styles.menuItem, styles.start)} onClick={startGame}>Start Game</button>
<button className={cn(styles.menuItem, styles.load)} onClick={loadGame}>Load Game</button>
</div>
</>
);
export default Menu;

+ 0
- 22
src/components/Playback.module.css View File

@ -1,22 +0,0 @@
.playbackContainer {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
}
.playbackRestart {
color: var(--MainBgColorDark);
cursor: pointer;
}
.playbackRestart:hover {
text-decoration: underline;
}
@media(max-width: 799px) {
.playbackRestart {
margin-bottom: 50px;
}
}

+ 27
- 0
src/components/Playback.styles.ts View File

@ -0,0 +1,27 @@
import { css } from 'emotion';
import { colors } from '../assets/style-vars';
const playbackContainer = css`
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
`;
const playbackRestart = css`
color: ${colors.MainBgColorDark};
cursor: pointer;
@media (min-width: 799px) {
margin-bottom: 50px;
}
&:hover {
text-decoration: underline;
}
`;
export default {
playbackContainer,
playbackRestart,
}

+ 5
- 5
src/components/Playback.tsx View File

@ -1,12 +1,12 @@
import React, { useEffect } from 'react';
import React from 'react';
import * as R from 'ramda';
import { Engine } from '@/engine/Engine';
import { Engine } from '../engine/Engine';
import styles from '@/components/Playback.module.css';
import { ILine, ILineOption, Chrono, ILocation, EngineConfig } from '@/engine/types';
import styles from '../components/Playback.styles';
import { ILine, ILineOption, Chrono, ILocation, EngineConfig } from '../engine/types';
import { useSelector, useDispatch } from 'react-redux';
import { setState, stateSelector } from '@/engine/lib/store';
import { setState, stateSelector } from '../engine/lib/store';
type PlaybackRenderFn<GS = any, MT = undefined, ST extends string = string> = (
engine: Engine<GS, MT, ST>,


src/components/Renderer/Image.module.css → src/components/Renderer/Image.styles.ts View File


+ 1
- 1
src/components/Renderer/Image.tsx View File

@ -1,6 +1,6 @@
import React, { FC } from 'react';
import styles from './Image.module.css';
import * as styles from './Image.styles';
import cn from 'classnames';


+ 4
- 4
src/components/Renderer/index.tsx View File

@ -2,11 +2,11 @@ import React from 'react';
import * as R from 'ramda';
import { useSelector, useDispatch } from 'react-redux';
import styles from './style.module.css';
import { stateSelector as engineStateSelector, gameStateSelector, setState, initState, resetState } from '@/engine/lib/store';
import { IActor, ILine, ILineOption, ILocation, EngineState, Chrono, EngineConfig } from '@/engine/types';
import * as styles from './styles';
import { stateSelector as engineStateSelector, gameStateSelector, setState, initState, resetState } from '../../engine/lib/store';
import { IActor, ILine, ILineOption, ILocation, EngineState, Chrono, EngineConfig } from '../../engine/types';
import { toast } from 'react-toastify';
import SkillTree from '@/components/SkillTree';
import SkillTree from '../../components/SkillTree';
import Image from './Image';
import Dropdown from '../Dropdown';


+ 0
- 265
src/components/Renderer/style.module.css View File

@ -1,265 +0,0 @@
.rendererContainer {
width: 100%;
max-width: 800px;
max-height: 600px;
height: 100%;
display: flex;
flex-direction: column;
border-radius: 6px;
position: relative;
border: 4px solid var(--MainTextColor);
box-sizing: border-box;
}
.textContainer {
display: flex;
height: 100%;
overflow-y: auto;
}
.textList {
list-style: none;
margin: 0;
padding-left: 0;
margin: 15px;
}
.textList > li::before {
content: '>';
display: inline-block;
width: 40px;
text-align: center;
}
.textList > li {
position: relative;
}
.textList > li::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
background-color: var(--MainBgColor);
animation: lineSlide 0.6s normal forwards linear;
animation-iteration-count: 1;
}
@keyframes lineSlide {
from {
width: 100%;
}
to {
width: 0;
}
}
@keyframes lineSlideSuccess {
from {
width: 100%;
color: initial;
}
50% {
color: var(--MainSuccessColor);
}
to {
width: 0;
color: initial;
}
}
@keyframes lineSlideFail {
from {
width: 100%;
color: initial;
}
50% {
color: var(--MainFailColor);
}
to {
width: 0;
color: initial;
}
}
.textList > li:last-of-type {
margin-bottom: 15px;
}
.optionsContainer {
display: flex;
height: 200px;
overflow-y: auto;
align-items: center;
border-top: 2px dashed var(--MainBgColorDark);
padding: 0;
}
.optionsList {
margin: 0;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.optionsList > div {
width: 100%;
cursor: pointer;
position: relative;
transition: color 0.4s linear;
box-sizing: border-box;
border-bottom: 2px solid var(--MainBgColorDark);
padding: 5px 15px 5px 15px;
}
.optionsList > div:last-of-type {
border-bottom: 0;
}
.optionsList > div::before {
content: '';
background-color: var(--MainBgColorDark);
position: absolute;
top: 0;
left: 0;
display: inline-block;
z-index: -1;
width: 0;
height: 100%;
transition: width 0.4s linear;
}
.optionsList > div:hover {
color: var(--MainBgColor);
}
.optionsList > div:hover::before {
width: 100%;
}
.optionsNext {
height: 100%;
width: 100%;
display: flex;
color: var(--MainBgColorDark);
font-weight: bold;
letter-spacing: 10px;
text-transform: uppercase;
font-size: 2rem;
justify-content: center;
align-items: center;
cursor: pointer;
user-select: none;
transition: border 0.3s ease-in;
position: relative;
overflow: hidden;
text-align: center;
}
.optionsNext:after {
content: "";
background: var(--MainBgColorDark);
display: block;
position: absolute;
padding-top: 300%;
padding-left: 350%;
margin-left: -20px!important;
margin-top: -120%;
opacity: 0;
transition: all 1s;
}
.optionsNext:focus {
outline: none;
}
.optionsNext:active:after {
padding: 0;
margin: 0;
opacity: 1;
transition: 0s
}
.toolbarContainer {
width: 100%;
border-bottom: 2px dashed var(--MainBgColorDark);
padding: 15px;
position: relative;
box-sizing: border-box;
justify-content: space-between;
display: flex;
min-height: 30px;
}
.toolbarTools {
align-self: flex-start;
border-right: 1px solid var(--MainBgColorDark);
margin-right: 5px;
padding-right: 2px;
height: 100%;
display: inline-flex;
align-items: center;
}
.toolbarTools > .toolbarButtons {
display: flex;
flex-direction: column;
}
.toolbarButtons > .toolbarSpacer {
display: block;
height: 35px;
background-color: var(--MainBgColorDark);
border: 2px dashed var(--MainBgColorDark);
box-sizing: border-box;
magrin: 10px 0 10px 0;
}
.toolbarStatus {
align-self: flex-end;
text-align: left;
border-right: 1px solid var(--MainBgColorDark);
margin-right: 5px;
padding-right: 2px;
height: 100%;
display: inline-flex;
align-items: center;
flex: 2;
}
.toolbarTime {
text-align: right;
height: 100%;
display: inline-flex;
align-items: center;
}
.toolbarButtons > span {
display: inline-flex;
width: 100%;
transition: all 0.2s linear;
cursor: pointer;
border-bottom: 1px solid var(--MainBgColorDark);
}
.toolbarButtons > span:last-of-type {
border-bottom: 0;
}
.toolbarButtons > span:hover {
background-color: var(--MainBgColorDark);
color: var(--MainBgColor);
}
@media(max-width: 799px) {
.rendererContainer {
max-height: unset;
border-radius: 0;
}
.optionsList > div {
padding-top: 15px;
padding-bottom: 15px;
}
}

+ 224
- 0
src/components/Renderer/styles.ts View File

@ -0,0 +1,224 @@
import { css, keyframes } from 'emotion';
import { colors } from '../../assets/style-vars';
export const rendererContainer = css`
width: 100%;
max-width: 800px;
max-height: 600px;
height: 100%;
display: flex;
flex-direction: column;
border-radius: 6px;
position: relative;
border: 4px solid ${colors.MainTextColor};
box-sizing: border-box;
@media(max-width: 799px) {
max-height: unset;
border-radius: 0;
}
`;
export const textContainer = css`
display: flex;
height: 100%;
overflow-y: auto;
`;
const lineSlide = keyframes`
from {
width: 100%;
}
to {
width: 0;
}
`;
export const textList = css`
list-style: none;
margin: 0;
padding-left: 0;
margin: 15px;
& > li {
position: relative;
&::before {
content: '>';
display: inline-block;
width: 40px;
text-align: center;
}
&::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
background-color: ${colors.MainBgColor};
animation: ${lineSlide} 0.6s normal forwards linear;
animation-iteration-count: 1;
}
&:last-of-type {
margin-bottom: 15px;
}
}
`
export const optionsContainer = css`
display: flex;
height: 200px;
overflow-y: auto;
align-items: center;
border-top: 2px dashed ${colors.MainBgColorDark};
padding: 0;
`
export const optionsList = css`
margin: 0;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
& > div {
width: 100%;
cursor: pointer;
position: relative;
transition: color 0.4s linear;
box-sizing: border-box;
border-bottom: 2px solid ${colors.MainBgColorDark};
padding: 5px 15px 5px 15px;
@media(max-width: 799px) {
padding-top: 15px;
padding-bottom: 15px;
}
&:last-of-type {
border-bottom: 0;
}
&:hover {
color: ${colors.MainBgColor};
}
&::before {
content: '';
background-color: ${colors.MainBgColorDark};
position: absolute;
top: 0;
left: 0;
display: inline-block;
z-index: -1;
width: 0;
height: 100%;
transition: width 0.4s linear;
}
&:hover::before {
width: 100%;
}
}
`;
export const optionsNext = css`
height: 100%;
width: 100%;
display: flex;
color: ${colors.MainBgColorDark};
font-weight: bold;
letter-spacing: 10px;
text-transform: uppercase;
font-size: 2rem;
justify-content: center;
align-items: center;
cursor: pointer;
user-select: none;
transition: border 0.3s ease-in;
position: relative;
overflow: hidden;
text-align: center;
&::after {
content: "";
background: ${colors.MainBgColorDark};
display: block;
position: absolute;
padding-top: 300%;
padding-left: 350%;
margin-left: -20px!important;
margin-top: -120%;
opacity: 0;
transition: all 1s;
}
&:focus {
outline: none;
}
&:active::after {
padding: 0;
margin: 0;
opacity: 1;
transition: 0s
}
`;
export const toolbarContainer = css`
width: 100%;
border-bottom: 2px dashed ${colors.MainBgColorDark};
padding: 15px;
position: relative;
box-sizing: border-box;
justify-content: space-between;
display: flex;
min-height: 30px;
`;
export const toolbarTools = css`
align-self: flex-start;
border-right: 1px solid ${colors.MainBgColorDark};
margin-right: 5px;
padding-right: 2px;
height: 100%;
display: inline-flex;
align-items: center;
& > .toolbarButtons {
display: flex;
flex-direction: column;
& > .toolbarSpacer {
display: block;
height: 35px;
background-color: ${colors.MainBgColorDark};
border: 2px dashed ${colors.MainBgColorDark};
box-sizing: border-box;
magrin: 10px 0 10px 0;
}
& > span {
display: inline-flex;
width: 100%;
transition: all 0.2s linear;
cursor: pointer;
border-bottom: 1px solid ${colors.MainBgColorDark};
&:last-of-type {
border-bottom: 0;
}
&:hover {
background-color: ${colors.MainBgColorDark};
color: ${colors.MainBgColor};
}
}
}
`;
export const toolbarButtons = 'toolbarButtons';
export const toolbarSpacer = 'toolbarSpacer';
export const toolbarStatus = css`
align-self: flex-end;
text-align: left;
border-right: 1px solid ${colors.MainBgColorDark};
margin-right: 5px;
padding-right: 2px;
height: 100%;
display: inline-flex;
align-items: center;
flex: 2;
`;
export const toolbarTime = css`
text-align: right;
height: 100%;
display: inline-flex;
align-items: center;
`;

+ 0
- 162
src/components/SkillTree.module.css View File

@ -1,162 +0,0 @@
.skillList {
list-style: none;
padding: 0;
margin: 0;
}
.skillTree {
display: flex;
flex-direction: column;
height: 100%;
}
.skillItem {
width: 100%;
display: flex;
justify-content: space-between;
font-size: 2.5rem;
padding: 10px 15px 10px 15px;
border-bottom: 1px solid black;
margin-bottom: 10px;
box-sizing: border-box;
flex-direction: column;
}
.skillDesc {
box-sizing: border-box;
font-size: 1.4rem;
transition: all 0.4s linear;
padding: 10px 0 0 0;
}
.skillDescClosed {
height: 0;
opacity: 0;
transition: all 0.4s linear;
}
.skillDescOpen {
height: 100%;
opacity: 1;
transition: all 0.4s linear;
}
.skillItem:last-of-type {
margin-bottom: 0;
border-bottom: 0;
}
.skillRow {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.skillButton {
font-size: 2.5rem;
width: 3.5rem;
background: transparent;
border: 1px solid black;
border-radius: 6px;
cursor: pointer;
color: var(--MainBgColorDark);
transition: all 0.3s ease-in;
}
.skillButton:hover {
background-color: var(--MainBgColorDark);
color: var(--MainBgColor);
transition: all 0.3s ease-out;
}
.skillButton.disabled {
cursor: default;
color: black;
border: none;
opacity: 0;
}
.skillButton:focus {
outline: none;
}
.skillValue {
margin-left: 10px;
margin-right: 10px;
width: 2rem;
text-align: center;
display: inline-block;
color: var(--MainBgColorDark);
}
.skillHeader {
display: flex;
justify-content: space-between;
border-bottom: 2px dashed var(--MainBgColorDark);
padding: 15px;
margin-bottom: 0.67rem;
}
/* 0.67 */
.skillHeader > h1 {
margin: 0;
}
.skillHeader > h1 > small {
font-size: 1.3rem;
display: inline-block;
}
.skillHeader > div {
display: flex;
align-items: center;
font-size: 1.8rem;
}
.skillName {
text-transform: capitalize;
}
.skillNameClick {
cursor: pointer;
color: var(--MainBgColorDark);
text-decoration: underline;
}
.skillConfirm {
font-size: 2.5rem;
letter-spacing: 10px;
background: transparent;
font-family: inherit;
font-weight: bold;
cursor: pointer;
border: none;
border-top: 2px dashed var(--MainBgColorDark);
width: 100%;
text-align: center;
color: var(--MainBgColorDark);
margin-top: auto;
padding: 15px;
transition: all 0.3s ease-in;
}
.skillConfirm:hover {
background-color: var(--MainBgColorDark);
color: var(--MainBgColor);
transition: all 0.3s ease-out;
}
@media(max-width: 799px) {
.skillName {
font-size: 1.8rem;
}
.skillValue {
font-size: 2rem;
margin: 0;
}
.skillButton {
font-size: 2rem;
width: 2.5rem;
}
}

+ 156
- 0
src/components/SkillTree.styles.ts View File

@ -0,0 +1,156 @@
import { css } from 'emotion';
import { colors } from '../assets/style-vars';
export const skillList = css`
list-style: none;
padding: 0;
margin: 0;
`;
export const skillTree = css`
display: flex;
flex-direction: column;
height: 100%;
`;
export const skillItem = css`
width: 100%;
display: flex;
justify-content: space-between;
font-size: 2.5rem;
padding: 10px 15px 10px 15px;
border-bottom: 1px solid black;
margin-bottom: 10px;
box-sizing: border-box;
flex-direction: column;
&:last-of-type {
margin-bottom: 0;
border-bottom: 0;
}
`;
export const skillDesc = css`
box-sizing: border-box;
font-size: 1.4rem;
transition: all 0.4s linear;
padding: 10px 0 0 0;
`;
export const skillDescClosed = css`
height: 0;
opacity: 0;
transition: all 0.4s linear;
`;
export const skillDescOpen = css`
height: 100%;
opacity: 1;
transition: all 0.4s linear;
`;
export const skillRow = css`
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
`;
export const skillButton = css`
font-size: 2.5rem;
width: 3.5rem;
background: transparent;
border: 1px solid black;
border-radius: 6px;
cursor: pointer;
color: ${colors.MainBgColorDark};
transition: all 0.3s ease-in;
&:hover {
background-color: ${colors.MainBgColorDark};
color: ${colors.MainBgColor};
transition: all 0.3s ease-out;
}
&.disabled {
cursor: default;
color: black;
border: none;
opacity: 0;
}
&:focus {
outline: none;
}
@media(max-width: 799px) {
font-size: 2rem;
width: 2.5rem;
}
`;
export const skillValue = css`
margin-left: 10px;
margin-right: 10px;
width: 2rem;
text-align: center;
display: inline-block;
color: ${colors.MainBgColorDark};
@media(max-width: 799px) {
font-size: 2rem;
margin: 0;
}
`;
export const skillHeader = css`
display: flex;
justify-content: space-between;
border-bottom: 2px dashed ${colors.MainBgColorDark};
padding: 15px;
margin-bottom: 0.67rem;
& > h1 {
margin: 0;
& > small {
font-size: 1.3rem;
display: inline-block;
}
}
& > div {
display: flex;
align-items: center;
font-size: 1.8rem;
}
}
`;
export const skillName = css`
text-transform: capitalize;
@media(max-width: 799px) {
font-size: 1.8rem;
}
`;
export const skillNameClick = css`
cursor: pointer;
color: ${colors.MainBgColorDark};
text-decoration: underline;
`;
export const skillConfirm = css`
font-size: 2.5rem;
letter-spacing: 10px;
background: transparent;
font-family: inherit;
font-weight: bold;
cursor: pointer;
border: none;
border-top: 2px dashed ${colors.MainBgColorDark};
width: 100%;
text-align: center;
color: $(colors.MainBgColorDark);
margin-top: auto;
padding: 15px;
transition: all 0.3s ease-in;
&:hover {
background-color: ${colors.MainBgColorDark};
color: ${colors.MainBgColor};
transition: all 0.3s ease-out;
}
`;
export const disabled = 'disabled';

+ 3
- 3
src/components/SkillTree.tsx View File

@ -1,10 +1,10 @@
import React, { FC, useState, useMemo } from 'react';
import * as R from 'ramda';
import styles from './SkillTree.module.css';
import * as styles from './SkillTree.styles';
import { useDispatch, useSelector } from 'react-redux';
import { stateSelector, setSkill, setSkillpoints, setState } from '@/engine/lib/store';
import { EngineState } from '@/engine/types';
import { stateSelector, setSkill, setSkillpoints, setState } from '../engine/lib/store';
import { EngineState } from '../engine/types';
import cn from 'classnames';


+ 9
- 9
src/engine/Engine.ts View File

@ -1,5 +1,5 @@
import * as R from 'ramda';
import { ILineOption, EngineState, ILineRaw, ILine, INode, LineFn, IActor, ILocation, Chrono, DayCycleFn } from './types';
import { ILineOption, EngineState, ILineRaw, ILine, INode, LineFn, IActor, ILocation, Chrono, EngineConfig } from './types';
import makeStore, * as actions from './lib/store';
import { Reducer, CombinedState, Store } from 'redux';
@ -13,9 +13,9 @@ const isLocation = <GS = object, MT = undefined>(node?: INode<GS, MT> | null): n
export class Engine<GS = object, MT = undefined, ST extends string = string> {
store: EngineStore<GS, MT, ST>;
onDayCycle: DayCycleFn;
public constructor(state: EngineState<GS, MT, ST>, gameReducer: Reducer, onDayCycle: DayCycleFn) {
this.onDayCycle = onDayCycle;
config: EngineConfig<GS, MT, ST>;
public constructor(state: EngineState<GS, MT, ST>, gameReducer: Reducer, config: EngineConfig<GS, MT, ST>) {
this.config = config;
this.store = makeStore(gameReducer) as EngineStore<GS, MT, ST>;
this.store.dispatch(actions.initEngineState(state))
const firstLine = this.currentLine || this.next(this.gameState);
@ -34,7 +34,7 @@ export class Engine<GS = object, MT = undefined, ST extends string = string> {
const gameState = this.gameState;
const line = R.pathOr<ILineRaw<GS, MT> | LineFn<GS, MT> | null>(null, [this.state.node, 'lines', this.state.line], this.state.nodeMap);
if (line && typeof line === 'function') {
return this.augmentLine(line(this.state, gameState, this.store.dispatch))
return this.augmentLine(line(this.state, gameState, this.store.dispatch, this.config))
}
return this.augmentLine(line);
}
@ -69,7 +69,7 @@ export class Engine<GS = object, MT = undefined, ST extends string = string> {
this.switchLocation(node);
}
if (typeof nextLine === 'function') {
const result = this.augmentLine(nextLine(this.state, gameState, this.store.dispatch));
const result = this.augmentLine(nextLine(this.state, gameState, this.store.dispatch, this.config));
const defaultTime = result?.actor ? 1 : 0;
this.store.dispatch(actions.advanceTime(result?.time || defaultTime));
const line = result
@ -90,12 +90,12 @@ export class Engine<GS = object, MT = undefined, ST extends string = string> {
this.store.dispatch(actions.advanceLine(line));
const nextLine = this.currentNode?.lines[line];
const chrono = this.currentTime;
if (chrono && chrono.time === 1440) {
const newChrono = this.onDayCycle(chrono);
if (chrono && chrono.time === 1440 && this.config.onDayCycle) {
const newChrono = this.config.onDayCycle(chrono);
this.store.dispatch(actions.setChrono(newChrono));
}
if (typeof nextLine === 'function') {
const line = this.augmentLine(nextLine(this.state, gameState, this.store.dispatch));
const line = this.augmentLine(nextLine(this.state, gameState, this.store.dispatch, this.config));
const defaultTime = line?.actor ? 1 : 0;
this.store.dispatch(actions.advanceTime(line?.time || defaultTime));
return line ? [line] : this.next(gameState);


+ 2
- 1
src/engine/index.ts View File

@ -22,5 +22,6 @@ export default <GS = object, MT = undefined, ST extends string = string>(config:
isOver: false,
}
}
return new Engine<GS, MT, ST>(state, reducer, config.onDayCycle || defaultDayCycleFn);
const supplyConfig = R.merge(config, { onDayCycle: defaultDayCycleFn });
return new Engine<GS, MT, ST>(state, reducer, supplyConfig);
}

+ 1
- 1
src/engine/lib/store.ts View File

@ -1,6 +1,6 @@
import * as R from 'ramda';
import { createStore, Reducer, combineReducers } from 'redux';
import { EngineState, Chrono } from '@/engine/types';
import { EngineState, Chrono } from 'discoteque/lib/engine/types';
type INIT = 'INIT';
type ENGINE_INIT = 'INIT-ENGINE';


+ 0
- 0
src/engine/lib/utils.ts View File


+ 4
- 1
src/engine/types.ts View File

@ -14,7 +14,10 @@ export interface ILineRaw<ST, MT = undefined> {
meta?: MT;
time?: number;
}
export type LineFn<ST = any, MT = undefined, SST extends string = string> = (engineState: EngineState<ST, MT, SST>, gameState: ST, gameDispatch: Dispatch<any>) => ILineRaw<ST, MT> | null | void;
export type LineFn<ST = any, MT = undefined, SST extends string = string, CF = EngineConfig<ST, MT, SST>> =
(engineState: EngineState<ST, MT, SST>, gameState: ST, gameDispatch: Dispatch<any>, config: CF) =>
ILineRaw<ST, MT> | null | void;
export type BuiltinNodeKind = 'node' | 'actor' | 'location';
export interface INode<GS = object, MT = undefined, KT = BuiltinNodeKind> {


+ 0
- 41
src/index.css View File

@ -1,41 +0,0 @@
@font-face {
font-family: 'Antic Slab Regular';
src: url('./assets/fonts/AnticSlab-Regular.woff2') format('woff2');
}
body {
font-family: "Antic Slab Regular";
font-size: 1.5rem;
color: var(--MainTextColor);
background-color: var(--MainBgColor);
font-weight: 400;
}
:root {
--MainBgColor: rgb(243, 223, 193);
--MainBgColorDark: rgb(144, 87, 18);
--MainTextColor: rgb(26, 28, 26);
--MainErrorColor: rgb(232, 91, 30);
--MainSuccessColor: rgb(123, 189, 70);
}
.Toastify__toast {
background: var(--MainBgColor);
color: var(--MainTextColor);
}
.Toastify__progress-bar--default {
background: var(--MainBgColorDark);
}
.Toastify__progress-bar--success {
background: var(--MainSuccessColor);
}
.Toastify__progress-bar--error {
background: var(--MainErrorColor);
}
.Toastify__close-button {
color: var(--MainTextColor);
}

+ 2
- 3
src/index.tsx View File

@ -1,10 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from '@/components/App';
import App from './components/App';
import '@/index.css';
import { EngineConfig } from '@/engine/types';
import { EngineConfig } from './engine/types';
function initApp<GS = object, MT = undefined, ST extends string = string>(config: EngineConfig<GS, MT, ST>) {
ReactDOM.render(<App<GS, MT, ST> config={config} />, document.getElementById('root'));


+ 2
- 1
tsconfig.json View File

@ -21,10 +21,11 @@
"strictNullChecks": true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
"discoteque/lib/*": ["src/*"]
},
"plugins": [
{


+ 428
- 9
yarn.lock View File

@ -2,13 +2,202 @@
# yarn lockfile v1
"@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/generator@^7.11.5":
version "7.11.6"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620"
integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==
dependencies:
"@babel/types" "^7.11.5"
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.0.0":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
dependencies:
"@babel/types" "^7.10.4"
"@babel/helper-function-name@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
dependencies:
"@babel/helper-get-function-arity" "^7.10.4"
"@babel/template" "^7.10.4"
"@babel/types" "^7.10.4"
"@babel/helper-get-function-arity@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
dependencies:
"@babel/types" "^7.10.4"
"@babel/helper-module-imports@^7.0.0":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
dependencies:
"@babel/types" "^7.10.4"
"@babel/helper-split-export-declaration@^7.11.0":
version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f"
integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==
dependencies:
"@babel/types" "^7.11.0"
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/highlight@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
dependencies:
"@babel/helper-validator-identifier" "^7.10.4"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.10.4", "@babel/parser@^7.11.5":
version "7.11.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037"
integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==
"@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/parser" "^7.10.4"
"@babel/types" "^7.10.4"
"@babel/traverse@^7.4.5":
version "7.11.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3"
integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/generator" "^7.11.5"
"@babel/helper-function-name" "^7.10.4"
"@babel/helper-split-export-declaration" "^7.11.0"
"@babel/parser" "^7.11.5"
"@babel/types" "^7.11.5"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.19"
"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5":
version "7.11.5"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d"
integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==
dependencies:
"@babel/helper-validator-identifier" "^7.10.4"
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@emotion/cache@^10.0.27":
version "10.0.29"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
dependencies:
"@emotion/sheet" "0.9.4"
"@emotion/stylis" "0.8.5"
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
"@emotion/core@^10.0.35":
version "10.0.35"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.35.tgz#513fcf2e22cd4dfe9d3894ed138c9d7a859af9b3"
integrity sha512-sH++vJCdk025fBlRZSAhkRlSUoqSqgCzYf5fMOmqqi3bM6how+sQpg3hkgJonj8GxXM4WbD7dRO+4tegDB9fUw==
dependencies:
"@babel/runtime" "^7.5.5"
"@emotion/cache" "^10.0.27"
"@emotion/css" "^10.0.27"
"@emotion/serialize" "^0.11.15"
"@emotion/sheet" "0.9.4"
"@emotion/utils" "0.11.3"
"@emotion/css@^10.0.27":
version "10.0.27"
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
dependencies:
"@emotion/serialize" "^0.11.15"
"@emotion/utils" "0.11.3"
babel-plugin-emotion "^10.0.27"
"@emotion/hash@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/is-prop-valid@^0.8.8":
version "0.8.8"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
dependencies:
"@emotion/memoize" "0.7.4"
"@emotion/memoize@0.7.4":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
dependencies:
"@emotion/hash" "0.8.0"
"@emotion/memoize" "0.7.4"
"@emotion/unitless" "0.7.5"
"@emotion/utils" "0.11.3"
csstype "^2.5.7"
"@emotion/sheet@0.9.4":
version &