├── .devcontainer ├── Dockerfile ├── devcontainer.json └── library-scripts │ └── node-debian.sh ├── .editorconfig ├── .github └── workflows │ ├── azure-static-web-apps-purple-mushroom-0656edc10.yml │ ├── playwright-latest.yml │ ├── playwright-onDemand.yml │ └── playwright-scheduled.yml ├── .gitignore ├── .nvmrc ├── .prettierrc ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── api ├── .funcignore ├── .gitignore ├── .vscode │ └── extensions.json ├── get-character │ ├── function.json │ └── index.ts ├── host.json ├── package-lock.json ├── package.json ├── save-character │ ├── function.json │ └── index.ts └── tsconfig.json ├── config-overrides.js ├── docs └── action.gif ├── package-lock.json ├── package.json ├── playwright.config.ts ├── public ├── android-icon-144x144.png ├── android-icon-192x192.png ├── android-icon-36x36.png ├── android-icon-48x48.png ├── android-icon-72x72.png ├── android-icon-96x96.png ├── apple-icon-114x114.png ├── apple-icon-120x120.png ├── apple-icon-144x144.png ├── apple-icon-152x152.png ├── apple-icon-180x180.png ├── apple-icon-57x57.png ├── apple-icon-60x60.png ├── apple-icon-72x72.png ├── apple-icon-76x76.png ├── apple-icon-precomposed.png ├── apple-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon-96x96.png ├── favicon.ico ├── index.html ├── manifest.json ├── ms-icon-144x144.png ├── ms-icon-150x150.png ├── ms-icon-310x310.png ├── ms-icon-70x70.png ├── robots.txt └── staticwebapp.config.json ├── src ├── App.css ├── App.test.tsx ├── App.tsx ├── components │ ├── Character │ │ ├── base.tsx │ │ ├── index.tsx │ │ ├── layers │ │ │ ├── accessories.tsx │ │ │ ├── bottom.tsx │ │ │ ├── eyewear.tsx │ │ │ ├── facial-hair.tsx │ │ │ ├── hair.tsx │ │ │ ├── shoes.tsx │ │ │ └── top.tsx │ │ └── styles.js │ ├── CharacterOptions │ │ ├── accessories │ │ │ ├── apple │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── art │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── backpack │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── bag │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── branch │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── briefcase │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── burger │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── camera │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── crab │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── docker-whale │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── index.ts │ │ │ ├── keyboard │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── laptop │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── linux │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── magnifier │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── money │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── mug │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── parrot │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── pepsi │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── radio │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── ramen │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── ruby │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── satellite │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── skateboard │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── stetoscope │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── suitcase │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── tennis │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── tie │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── wheel │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ ├── bottoms │ │ │ ├── bathrobe │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── dress │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── index.ts │ │ │ ├── kilt │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── maxi-skirt │ │ │ │ ├── colors.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── mini-skirt │ │ │ │ ├── colors.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── pants │ │ │ │ ├── colors.ts │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── prosthetic │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ ├── eyewear │ │ │ ├── eyewear-1 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── eyewear-2 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── eyewear-3 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── eyewear-4 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── eyewear-5 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── eyewear-6 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── index.ts │ │ ├── facial-hair │ │ │ ├── colors.ts │ │ │ ├── facial-hair-1 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── facial-hair-2 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── facial-hair-3 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── facial-hair-4 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── facial-hair-5 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── index.ts │ │ ├── hair │ │ │ ├── colors.ts │ │ │ ├── hair-1 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-10 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-11 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-12 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-13 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-2 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-3 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-4 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-5 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-6 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-7 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-8 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── hair-9 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── index.ts │ │ ├── no-selection.tsx │ │ ├── shoes │ │ │ ├── index.ts │ │ │ ├── shoe-1 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-2 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-3 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-4 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-5 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-6 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-7 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ ├── shoe-8 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ │ └── shoe-9 │ │ │ │ ├── index.ts │ │ │ │ ├── layer.tsx │ │ │ │ └── thumb.tsx │ │ ├── skin │ │ │ └── index.ts │ │ └── tops │ │ │ ├── hoodie │ │ │ ├── colors.ts │ │ │ ├── index.tsx │ │ │ ├── layer.tsx │ │ │ └── thumb.tsx │ │ │ ├── index.ts │ │ │ ├── jacket │ │ │ ├── colors.ts │ │ │ ├── index.tsx │ │ │ ├── layer.tsx │ │ │ └── thumb.tsx │ │ │ ├── shirt │ │ │ ├── colors.ts │ │ │ ├── index.tsx │ │ │ ├── layer.tsx │ │ │ └── thumb.tsx │ │ │ └── t-shirt │ │ │ ├── colors.ts │ │ │ ├── index.tsx │ │ │ ├── layer.tsx │ │ │ └── thumb.tsx │ ├── CharacterRandomizer │ │ ├── character-looks.ts │ │ ├── index.tsx │ │ └── styles.js │ ├── CompanySizeRange │ │ ├── index.tsx │ │ └── styles.ts │ ├── DropdownSelect │ │ ├── arrow-down.svg │ │ ├── index.tsx │ │ └── styles.ts │ ├── HorizontalScroller │ │ ├── index.tsx │ │ └── styles.js │ ├── IdleCountdown │ │ ├── index.tsx │ │ └── styles.js │ ├── Logo │ │ ├── index.tsx │ │ ├── logo.svg │ │ └── styles.js │ ├── OptionPanels │ │ ├── accessories-panel.tsx │ │ ├── body-panel.tsx │ │ ├── bottom-panel.tsx │ │ ├── index.tsx │ │ ├── styles.js │ │ └── top-panel.tsx │ ├── Progress │ │ ├── index.tsx │ │ └── styles.js │ ├── Selectables │ │ ├── option-color-selectable.tsx │ │ ├── option-style-selectable.tsx │ │ └── styles.ts │ ├── StartOver │ │ ├── index.tsx │ │ └── styles.js │ ├── StatGrader │ │ ├── index.tsx │ │ └── styles.ts │ ├── StatPanels │ │ ├── checkmark.tsx │ │ ├── choose-stats.tsx │ │ ├── distribute-points.tsx │ │ ├── evaluate-arrow.tsx │ │ ├── index.tsx │ │ ├── stat-options.ts │ │ └── styles.ts │ ├── Stepper │ │ ├── NextButton.tsx │ │ ├── PrevButton.tsx │ │ ├── StepperFooter.tsx │ │ ├── arrow-back.svg │ │ ├── index.tsx │ │ └── styles.ts │ └── TabSwitcher │ │ └── index.tsx ├── fonts │ └── Silkscreen │ │ ├── Silkscreen.eot │ │ ├── Silkscreen.ttf │ │ ├── Silkscreen.woff │ │ └── Silkscreen.woff2 ├── graphics │ ├── BG_default.svg │ ├── background.svg │ ├── briefcase.svg │ ├── floorlight.tsx │ ├── floppy.svg │ ├── lightbeam.tsx │ ├── lightbulb.svg │ ├── lightning-bolt.svg │ ├── logo.svg │ └── spotlight.svg ├── hooks │ ├── use-click-outside.tsx │ ├── use-interval.ts │ └── use-tab-indicator.tsx ├── icons │ ├── cursor-click.png │ ├── cursor.png │ └── trashcan.svg ├── index.css ├── index.tsx ├── interfaces │ ├── Colors.ts │ ├── IAction.ts │ ├── IBasicInfo.ts │ ├── ICharacter.ts │ ├── IStats.ts │ ├── IStoreState.ts │ └── IUiState.ts ├── react-app-env.d.ts ├── redux │ ├── character │ │ ├── character.actions.ts │ │ ├── character.reducer.ts │ │ ├── character.types.ts │ │ └── index.ts │ ├── createAction.ts │ ├── index.ts │ ├── info │ │ ├── index.ts │ │ ├── info.actions.ts │ │ ├── info.reducer.ts │ │ └── info.types.ts │ ├── stats │ │ ├── index.ts │ │ ├── stats.actions.ts │ │ ├── stats.reducer.ts │ │ └── stats.types.ts │ └── ui │ │ ├── index.ts │ │ ├── ui.actions.ts │ │ ├── ui.reducer.ts │ │ └── ui.types.ts ├── serviceWorker.ts ├── utils │ ├── config.ts │ ├── event-emitter.ts │ ├── format-character-data.ts │ ├── selection-utils.ts │ └── style-utils.ts └── views │ ├── BasicInfo │ ├── index.tsx │ └── styles.js │ ├── Character │ └── index.tsx │ ├── Configurator │ ├── BG_character.svg │ ├── index.tsx │ └── styles.js │ ├── EndScreen │ ├── arrow-down.tsx │ ├── index.tsx │ └── styles.ts │ ├── GameOver │ ├── index.tsx │ ├── styles.ts │ └── title.tsx │ ├── IdleScreen │ ├── index.tsx │ └── styles.js │ ├── Start │ ├── index.tsx │ └── styles.js │ └── Stats │ ├── index.tsx │ └── styles.ts ├── tests ├── Test.README.md └── playwright.spec.ts ├── tsconfig.json └── tsconfig.paths.json /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Find the Dockerfile for mcr.microsoft.com/azure-functions/python:3.0-python3.8-core-tools at this URL 2 | # https://github.com/Azure/azure-functions-docker/blob/master/host/3.0/buster/amd64/python/python38/python38-core-tools.Dockerfile 3 | FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8-core-tools 4 | 5 | ENV NVM_DIR="/usr/local/share/nvm" 6 | ENV NVM_SYMLINK_CURRENT=true \ 7 | PATH=${NVM_DIR}/current/bin:${PATH} 8 | COPY library-scripts/node-debian.sh /tmp/library-scripts/ 9 | RUN apt-get update && bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Startup Adventurer", 3 | "dockerFile": "Dockerfile", 4 | "forwardPorts": [7071, 5500], 5 | 6 | "settings": { 7 | "terminal.integrated.shell.linux": "/bin/bash" 8 | }, 9 | 10 | "extensions": [ 11 | "ms-azuretools.vscode-azurefunctions", 12 | "ms-azuretools.vscode-azurestaticwebapps", 13 | "dbaeumer.vscode-eslint", 14 | "esbenp.prettier-vscode", 15 | "github.vscode-pull-request-github", 16 | "visualstudioexptteam.vscodeintellicode" 17 | ], 18 | 19 | "postCreateCommand": ". ${NVM_DIR}/nvm.sh && nvm install --lts", 20 | 21 | "remoteUser": "vscode" 22 | } 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*.{js,jsx,ts,tsx,json,scss,css,html}] 3 | charset = utf-8 4 | indent_style = space 5 | indent_size = 2 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true -------------------------------------------------------------------------------- /.github/workflows/azure-static-web-apps-purple-mushroom-0656edc10.yml: -------------------------------------------------------------------------------- 1 | name: Azure Static Web Apps CI/CD 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, synchronize, reopened, closed] 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build_and_deploy_job: 14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') 15 | runs-on: ubuntu-latest 16 | name: Build and Deploy Job 17 | steps: 18 | - uses: actions/checkout@v2 19 | with: 20 | submodules: true 21 | - name: Build And Deploy 22 | id: builddeploy 23 | uses: Azure/static-web-apps-deploy@v1 24 | with: 25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PURPLE_MUSHROOM_0656EDC10 }} 26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) 27 | action: "upload" 28 | ###### Repository/Build Configurations - These values can be configured to match you app requirements. ###### 29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig 30 | app_location: "/" # App source code path 31 | api_location: "api" # Api source code path - optional 32 | output_location: "build" # Built app content directory - optional 33 | ###### End of Repository/Build Configurations ###### 34 | 35 | close_pull_request_job: 36 | if: github.event_name == 'pull_request' && github.event.action == 'closed' 37 | runs-on: ubuntu-latest 38 | name: Close Pull Request Job 39 | steps: 40 | - name: Close Pull Request 41 | id: closepullrequest 42 | uses: Azure/static-web-apps-deploy@v1 43 | with: 44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PURPLE_MUSHROOM_0656EDC10 }} 45 | action: "close" 46 | -------------------------------------------------------------------------------- /.github/workflows/playwright-latest.yml: -------------------------------------------------------------------------------- 1 | # This action runs playwright tests nightly and on push to main to give the latest status of the main branch 2 | 3 | name: Latest Playwright test 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow nightly and on push to the main branch 8 | push: 9 | branches: [ "main" ] 10 | schedule: 11 | # nightly 12 | - cron: '0 0 * * *' 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | # This workflow builds and runs the playwright tests 17 | test: 18 | # The type of runner that the job will run on 19 | runs-on: ubuntu-latest 20 | 21 | strategy: 22 | matrix: 23 | node-version: [14.x, 16.x, 18.x] 24 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 25 | 26 | steps: 27 | - uses: actions/checkout@v3 28 | - uses: actions/setup-node@v3 29 | - name: Install dependencies 30 | run: npm ci --legacy-peer-deps 31 | - name: Install Playwright 32 | run: npx playwright install --with-deps 33 | - name: Build production build 34 | run: npm run build 35 | - name: Run your tests 36 | run: npm run playwright_test 37 | - name: Upload HTML report as Artifact 38 | uses: actions/upload-artifact@v2 39 | if: always() 40 | with: 41 | name: run-report 42 | path: pw-report/ -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "printWidth": 120, 4 | "singleQuotes": false, 5 | "stylelintIntegration": true, 6 | "bracketSpacing": true 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "npm start", 6 | "name": "Run frontend", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | }, 10 | { 11 | "command": "npm start", 12 | "name": "Run backend", 13 | "request": "launch", 14 | "type": "node-terminal", 15 | "cwd": "${workspaceFolder}/api" 16 | } 17 | ], 18 | "compounds": [ 19 | { 20 | "name": "Run full stack", 21 | "configurations": ["Run frontend", "Run backend"] 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Aaron Powell, Andrew Harvey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Startup Adventurer 2 | 3 | [![Playwright tests](https://github.com/staticwebdev/StartupAdventurer/actions/workflows/playwright-latest.yml/badge.svg)](https://github.com/staticwebdev/StartupAdventurer/actions/workflows/playwright-latest.yml) 4 | 5 | Welcome to Startup Adventurer a character creator allowing you to build your own avatar and imbue it with skills which line up with your own startup adventurer. 6 | 7 | Startup Adventurer demonstrates how you can create an application that can be deployed to [Azure Static Web Apps](https://docs.microsoft.com/azure/static-web-apps/?WT.mc_id=startup-18441-aapowell). 8 | 9 | Learn more about how we built it [on our blog](https://devblogs.microsoft.com/startups/simplifying-web-apps-with-static-web-apps?WT.mc_id=startup-18441-aapowell), and [create your own avatar today](https://purple-mushroom-0656edc10.azurestaticapps.net)! 10 | 11 | ![Startup Adventurer](./docs/action.gif) 12 | -------------------------------------------------------------------------------- /api/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | csx 4 | .vs 5 | edge 6 | Publish 7 | 8 | *.user 9 | *.suo 10 | *.cscfg 11 | *.Cache 12 | project.lock.json 13 | 14 | /packages 15 | /TestResults 16 | 17 | /tools/NuGet.exe 18 | /App_Data 19 | /secrets 20 | /data 21 | .secrets 22 | appsettings.json 23 | local.settings.json 24 | 25 | node_modules 26 | dist 27 | 28 | # Local python packages 29 | .python_packages/ 30 | 31 | # Python Environments 32 | .env 33 | .venv 34 | env/ 35 | venv/ 36 | ENV/ 37 | env.bak/ 38 | venv.bak/ 39 | 40 | # Byte-compiled / optimized / DLL files 41 | __pycache__/ 42 | *.py[cod] 43 | *$py.class -------------------------------------------------------------------------------- /api/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } -------------------------------------------------------------------------------- /api/get-character/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": ["get"], 9 | "route": "get-character/{id:guid}" 10 | }, 11 | { 12 | "type": "http", 13 | "direction": "out", 14 | "name": "res" 15 | }, 16 | { 17 | "type": "cosmosDB", 18 | "name": "character", 19 | "databaseName": "StartupAdventurer", 20 | "collectionName": "Characters", 21 | "connectionStringSetting": "StartupAdventurer_COSMOSDB", 22 | "direction": "in", 23 | "Id": "{id}" 24 | } 25 | ], 26 | "scriptFile": "../dist/get-character/index.js" 27 | } 28 | -------------------------------------------------------------------------------- /api/get-character/index.ts: -------------------------------------------------------------------------------- 1 | import { AzureFunction, Context, HttpRequest } from "@azure/functions"; 2 | 3 | const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest, character: any): Promise { 4 | context.log(`Getting character from id ${req.url}`); 5 | 6 | if (!character) { 7 | context.res = { 8 | status: 404, 9 | }; 10 | } else { 11 | const { _etag, _rid, _self, _ts, ...char } = character; 12 | context.res = { 13 | body: char, 14 | }; 15 | } 16 | }; 17 | 18 | export default httpTrigger; 19 | -------------------------------------------------------------------------------- /api/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[1.*, 2.0.0)" 14 | } 15 | } -------------------------------------------------------------------------------- /api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "version": "", 4 | "scripts": { 5 | "build": "tsc", 6 | "build:production": "npm run prestart && npm prune --production", 7 | "watch": "tsc --w", 8 | "prestart": "npm run build && func extensions install", 9 | "start:host": "func start", 10 | "start": "npm-run-all --parallel start:host watch", 11 | "test": "echo \"No tests yet...\"" 12 | }, 13 | "description": "", 14 | "devDependencies": { 15 | "@azure/functions": "^1.2.3", 16 | "@types/uuid": "^8.3.0", 17 | "azure-functions-core-tools": "^3.0.3388", 18 | "npm-run-all": "^4.1.5", 19 | "typescript": "^4.2.3" 20 | }, 21 | "dependencies": { 22 | "react-dom": "^17.0.2", 23 | "uuid": "^8.3.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /api/save-character/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": ["post"] 9 | }, 10 | { 11 | "type": "http", 12 | "direction": "out", 13 | "name": "res" 14 | }, 15 | { 16 | "name": "character", 17 | "type": "cosmosDB", 18 | "databaseName": "StartupAdventurer", 19 | "collectionName": "Characters", 20 | "createIfNotExists": true, 21 | "connectionStringSetting": "StartupAdventurer_COSMOSDB", 22 | "direction": "out" 23 | } 24 | ], 25 | "scriptFile": "../dist/save-character/index.js" 26 | } 27 | -------------------------------------------------------------------------------- /api/save-character/index.ts: -------------------------------------------------------------------------------- 1 | import { AzureFunction, Context, HttpRequest } from "@azure/functions"; 2 | import { v4 as uuid } from "uuid"; 3 | 4 | const notIn = (obj: any, key: string) => !(key in obj); 5 | 6 | const isValidCharacter = (character: { [key: string]: any }) => { 7 | if (!character) { 8 | return false; 9 | } 10 | const notInCharacter = notIn.bind(null, character); 11 | // test for top-level fields 12 | if ( 13 | notInCharacter("appearance") || 14 | notInCharacter("stats") || 15 | notInCharacter("companyInfo") || 16 | notInCharacter("startedAt") || 17 | notInCharacter("completedAt") 18 | ) { 19 | return false; 20 | } 21 | 22 | const notInAppearance = notIn.bind(null, character.appearance); 23 | 24 | if ( 25 | notInAppearance("hair") || 26 | notInAppearance("facialHair") || 27 | notInAppearance("skin") || 28 | notInAppearance("eyewear") || 29 | notInAppearance("t-shirt") || 30 | notInAppearance("shirt") || 31 | notInAppearance("jacket") || 32 | notInAppearance("hoodie") || 33 | notInAppearance("bottom-clothes") || 34 | notInAppearance("shoes") 35 | ) { 36 | return false; 37 | } 38 | 39 | return true; 40 | }; 41 | 42 | const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise { 43 | const character = req.body; 44 | 45 | if (!isValidCharacter(character)) { 46 | context.res = { 47 | status: 400, 48 | body: "Invalid character data", 49 | }; 50 | } else { 51 | character.id = uuid(); 52 | context.bindings.character = character; 53 | context.res = { 54 | // status: 200, /* Defaults to 200 */ 55 | body: { 56 | success: true, 57 | public_url: `${process.env.SHORT_URL || "https://avtr.ms"}/${character.id}`, 58 | }, 59 | }; 60 | } 61 | }; 62 | 63 | export default httpTrigger; 64 | -------------------------------------------------------------------------------- /api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "sourceMap": true, 8 | "strict": false 9 | } 10 | } -------------------------------------------------------------------------------- /config-overrides.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = function override(config, env) { 4 | //do stuff with the webpack config... 5 | config.resolve.alias = { 6 | "~": path.resolve("./"), 7 | "@": path.resolve("./src"), 8 | }; 9 | return config; 10 | }; 11 | -------------------------------------------------------------------------------- /docs/action.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/docs/action.gif -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { PlaywrightTestConfig } from '@playwright/test'; 2 | const config: PlaywrightTestConfig = { 3 | testDir: "./tests", 4 | use: { 5 | baseURL: "http://localhost:3000/", 6 | trace: 'on' 7 | }, 8 | reporter: [ 9 | ['html', { outputFolder: 'pw-report' }], 10 | ['json', { outputFolder: 'pw-report', outputFile: 'report.json' }] 11 | ], 12 | webServer: { 13 | command: 'npm run start', 14 | port: 3000, 15 | timeout: 120 * 1000, 16 | reuseExistingServer: !process.env.CI, 17 | }, 18 | }; 19 | export default config; -------------------------------------------------------------------------------- /public/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-144x144.png -------------------------------------------------------------------------------- /public/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-192x192.png -------------------------------------------------------------------------------- /public/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-36x36.png -------------------------------------------------------------------------------- /public/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-48x48.png -------------------------------------------------------------------------------- /public/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-72x72.png -------------------------------------------------------------------------------- /public/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/android-icon-96x96.png -------------------------------------------------------------------------------- /public/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-114x114.png -------------------------------------------------------------------------------- /public/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-120x120.png -------------------------------------------------------------------------------- /public/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-144x144.png -------------------------------------------------------------------------------- /public/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-152x152.png -------------------------------------------------------------------------------- /public/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-180x180.png -------------------------------------------------------------------------------- /public/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-57x57.png -------------------------------------------------------------------------------- /public/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-60x60.png -------------------------------------------------------------------------------- /public/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-72x72.png -------------------------------------------------------------------------------- /public/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-76x76.png -------------------------------------------------------------------------------- /public/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/apple-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/favicon-96x96.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/favicon.ico -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Startup Adventurer", 3 | "name": "Startup Adventurer - a Startup avatar creator", 4 | "icons": [ 5 | { 6 | "src": "\/android-icon-36x36.png", 7 | "sizes": "36x36", 8 | "type": "image\/png", 9 | "density": "0.75" 10 | }, 11 | { 12 | "src": "\/android-icon-48x48.png", 13 | "sizes": "48x48", 14 | "type": "image\/png", 15 | "density": "1.0" 16 | }, 17 | { 18 | "src": "\/android-icon-72x72.png", 19 | "sizes": "72x72", 20 | "type": "image\/png", 21 | "density": "1.5" 22 | }, 23 | { 24 | "src": "\/android-icon-96x96.png", 25 | "sizes": "96x96", 26 | "type": "image\/png", 27 | "density": "2.0" 28 | }, 29 | { 30 | "src": "\/android-icon-144x144.png", 31 | "sizes": "144x144", 32 | "type": "image\/png", 33 | "density": "3.0" 34 | }, 35 | { 36 | "src": "\/android-icon-192x192.png", 37 | "sizes": "192x192", 38 | "type": "image\/png", 39 | "density": "4.0" 40 | } 41 | ], 42 | "start_url": ".", 43 | "display": "standalone", 44 | "theme_color": "#000000", 45 | "background_color": "#ffffff" 46 | } 47 | -------------------------------------------------------------------------------- /public/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/ms-icon-144x144.png -------------------------------------------------------------------------------- /public/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/ms-icon-150x150.png -------------------------------------------------------------------------------- /public/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/ms-icon-310x310.png -------------------------------------------------------------------------------- /public/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/public/ms-icon-70x70.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /public/staticwebapp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | { 4 | "route": "/logged-in", 5 | "rewrite": "/index.html" 6 | } 7 | ], 8 | "navigationFallback": { 9 | "rewrite": "/index.html", 10 | "exclude": ["/js/*", "/static/*", "/api/*"] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .app { 2 | background-color: #272727; 3 | background-image: url("./graphics/background.svg"); 4 | background-repeat: no-repeat; 5 | background-size: cover; 6 | height: 3000px; 7 | left: 50%; 8 | overflow: hidden; 9 | position: fixed; 10 | top: 50%; 11 | transform-origin: center center; 12 | transform: translate(-50%, -50%); 13 | width: 4500px; 14 | } 15 | 16 | .logo { 17 | height: auto; 18 | left: 103px; 19 | position: absolute; 20 | top: 124px; 21 | width: 815px; 22 | z-index: 99; 23 | } 24 | 25 | .stepper.basic-info .stepper-nav { 26 | opacity: 0; 27 | } 28 | 29 | .stepper.basic-info .next-button, 30 | .stepper.configure .next-button, 31 | .stepper.stats .next-button { 32 | width: 1504px; 33 | } 34 | 35 | .stepper.configure .stepper-nav, 36 | .stepper.stats .stepper-nav { 37 | z-index: 9; 38 | } 39 | 40 | .briefcase-icon { 41 | background-image: url("./graphics/briefcase.svg"); 42 | background-position: center; 43 | background-repeat: no-repeat; 44 | background-size: contain; 45 | } 46 | .floppy-icon { 47 | background-image: url("./graphics/floppy.svg"); 48 | background-position: center; 49 | background-repeat: no-repeat; 50 | background-size: contain; 51 | } 52 | .lightning-bolt-icon { 53 | background-image: url("./graphics/lightning-bolt.svg"); 54 | background-position: center; 55 | background-repeat: no-repeat; 56 | background-size: contain; 57 | } 58 | .lightbulb-icon { 59 | background-image: url("./graphics/lightbulb.svg"); 60 | background-position: center; 61 | background-repeat: no-repeat; 62 | background-size: contain; 63 | } 64 | 65 | .view-quide-text { 66 | color: #ffffff; 67 | font-size: 60px; 68 | left: 1004px; 69 | margin: 0; 70 | opacity: 0; 71 | position: fixed; 72 | top: 200px; 73 | } 74 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/Character/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { CharacterContainer } from "./styles"; 3 | import CharacterBase from "./base"; 4 | 5 | import Hair from "./layers/hair"; 6 | import Shoes from "./layers/shoes"; 7 | import Bottoms from "./layers/bottom"; 8 | import Tops from "./layers/top"; 9 | import FacialHair from "./layers/facial-hair"; 10 | import Eyewear from "./layers/eyewear"; 11 | import Accessories from "./layers/accessories"; 12 | import { useSelector } from "react-redux"; 13 | import { IStoreState } from "@/interfaces/IStoreState"; 14 | 15 | const Character = () => { 16 | const { skinColor, bottom, tops, shoes, accessories, hair, eyewear, facialHair } = useSelector((store: IStoreState) => store.character); 17 | const hasProsthetic = !!bottom && bottom.style && bottom.style === "prosthetic"; 18 | 19 | return ( 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default Character; 35 | -------------------------------------------------------------------------------- /src/components/Character/layers/accessories.tsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react"; 2 | import accessories from "@/components/CharacterOptions/accessories"; 3 | 4 | import get from "lodash-es/get"; 5 | 6 | interface IProps { 7 | selectedAccessories?: string[] 8 | } 9 | 10 | const CharacterAccessories = ({ selectedAccessories = [] }: IProps) => { 11 | 12 | const getLayer = (key: string, i: number) => { 13 | const layer = get(accessories, [key, "layer"]); 14 | 15 | if (typeof layer === "function") return {layer()}; 16 | 17 | return null; 18 | }; 19 | 20 | return {!!selectedAccessories && selectedAccessories.map(getLayer)}; 21 | }; 22 | 23 | export default CharacterAccessories; 24 | -------------------------------------------------------------------------------- /src/components/Character/layers/bottom.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import bottoms from "@/components/CharacterOptions/bottoms"; 3 | import get from "lodash-es/get"; 4 | import { ICharacter } from "@/interfaces/ICharacter"; 5 | interface IProps { 6 | selected?: ICharacter["bottom"] 7 | } 8 | 9 | const BottomLayer = ({ selected: selectedBottom }: IProps) => { 10 | const activeLayer = selectedBottom ? get(bottoms, [selectedBottom.style, "layer"]) : null; 11 | 12 | return ( 13 | 14 | {activeLayer ? activeLayer({ colors: get(selectedBottom, ["color", "palette"]) }) : null} 15 | 16 | ); 17 | }; 18 | 19 | export default BottomLayer; 20 | -------------------------------------------------------------------------------- /src/components/Character/layers/eyewear.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import eyewear from "@/components/CharacterOptions/eyewear"; 3 | import get from "lodash-es/get"; 4 | import camelCase from "lodash-es/camelCase"; 5 | 6 | const Eyewear = ({ selected: selectedEyewear = "" }) => { 7 | const activeLayer = get(eyewear, [camelCase(selectedEyewear), "layer"]); 8 | 9 | return {activeLayer ? activeLayer() : null}; 10 | }; 11 | 12 | export default Eyewear; 13 | -------------------------------------------------------------------------------- /src/components/Character/layers/facial-hair.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import facialHair from "@/components/CharacterOptions/facial-hair"; 3 | import get from "lodash-es/get"; 4 | import camelCase from "lodash-es/camelCase"; 5 | import { ICharacter } from "@/interfaces/ICharacter"; 6 | 7 | interface IProps { 8 | selected?: ICharacter["facialHair"] 9 | } 10 | 11 | const FacialHairLayer = ({ selected }: IProps) => { 12 | const activeLayer = get(facialHair, [camelCase(selected?.style), "layer"]); 13 | 14 | return ( 15 | 16 | {activeLayer ? activeLayer({ colors: get(selected?.color, ["palette"]) }) : null} 17 | 18 | ); 19 | }; 20 | 21 | export default FacialHairLayer; 22 | -------------------------------------------------------------------------------- /src/components/Character/layers/hair.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import hair from "@/components/CharacterOptions/hair"; 3 | import get from "lodash-es/get"; 4 | import { ICharacter } from "@/interfaces/ICharacter"; 5 | 6 | interface IProps { 7 | selected?: ICharacter["hair"] 8 | } 9 | 10 | const HairLayer = ({ selected }: IProps) => { 11 | const activeLayer = selected?.style ? get(hair, [selected?.style, "layer"]) : null; 12 | 13 | return {activeLayer ? activeLayer({ colors: get(selected?.color, ["palette"]) }) : null}; 14 | }; 15 | 16 | export default HairLayer; 17 | -------------------------------------------------------------------------------- /src/components/Character/layers/shoes.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import shoes from "@/components/CharacterOptions/shoes"; 3 | 4 | const shoeLayers = shoes.map((shoe, i: number) => ({ 5 | name: `shoe-${i + 1}`, 6 | component: shoe.layer, 7 | })); 8 | 9 | const ShoeLayer = ({ selectedShoes = "" }) => { 10 | 11 | const getShoeByName = (name: string) => shoeLayers.filter(shoe => shoe && shoe.name === name)[0]; 12 | 13 | const getLayer = (active: string) => { 14 | const shoe = getShoeByName(active); 15 | return shoe ? shoe.component() : null; 16 | }; 17 | 18 | return {getLayer(selectedShoes)}; 19 | }; 20 | 21 | export default ShoeLayer; 22 | -------------------------------------------------------------------------------- /src/components/Character/layers/top.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import tops from "@/components/CharacterOptions/tops"; 3 | 4 | import isEmpty from "lodash-es/isEmpty"; 5 | import get from "lodash-es/get"; 6 | import { ICharacter } from "@/interfaces/ICharacter"; 7 | 8 | interface IProps { selected?: ICharacter["tops"] } 9 | 10 | const CharacterTop = ({ selected }: IProps) => { 11 | const { hoodie, jacket, shirt, tshirt } = tops; 12 | 13 | return ( 14 | 15 | {!isEmpty(selected?.tshirt) && tshirt.layer({ colors: get(selected?.tshirt, "palette") })} 16 | {!isEmpty(selected?.shirt) && shirt.layer({ colors: get(selected?.shirt, "palette") })} 17 | {!isEmpty(selected?.jacket) && jacket.layer({ colors: get(selected?.jacket, "palette") })} 18 | {!isEmpty(selected?.hoodie) && hoodie.layer({ colors: get(selected?.hoodie, "palette") })} 19 | 20 | ); 21 | }; 22 | 23 | export default CharacterTop; 24 | -------------------------------------------------------------------------------- /src/components/Character/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import clsx from "clsx"; 3 | 4 | export const CharacterContainer = styled.div.attrs(props => ({ 5 | className: clsx("character-container"), 6 | }))` 7 | filter: brightness(0); 8 | height: 2310px; 9 | margin-left: auto; 10 | position: relative; 11 | right: 40px; 12 | top: 110px; 13 | width: 1530px; 14 | 15 | .stats & { 16 | filter: brightness(1); 17 | } 18 | 19 | > svg { 20 | display: block; 21 | height: 100%; 22 | left: 0; 23 | top: 0; 24 | width: 100%; 25 | } 26 | 27 | #character-base { 28 | position: relative; 29 | z-index: 0; 30 | } 31 | `; 32 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/apple/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "apple", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/apple/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Apple = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default Apple; 24 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/apple/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const AppleThumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default AppleThumb; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/art/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "art", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/art/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArtLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default ArtLayer; 27 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/art/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArtThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | export default ArtThumb; 32 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/backpack/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "backpack", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/bag/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "bag", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/bag/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Bag = () => { 4 | return ( 5 | 6 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default Bag; 27 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/bag/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const BagThumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | }; 23 | 24 | export default BagThumb; 25 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/branch/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "branch", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/branch/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const BranchLayer = () => { 4 | return ( 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default BranchLayer; 26 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/branch/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const BranchThumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default BranchThumb; 33 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/briefcase/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "briefcase", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/briefcase/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Briefcase = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default Briefcase; 22 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/briefcase/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const BriefcaseThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default BriefcaseThumb; 22 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/burger/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "burger", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/camera/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "camera", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/camera/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Camera = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default Camera; 26 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/crab/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "crab", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/crab/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const CrabLayer = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default CrabLayer; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/crab/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const CrabThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default CrabThumb; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/docker-whale/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "dockerWhale", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/docker-whale/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DockerLayer = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default DockerLayer; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/docker-whale/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DockerThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default DockerThumb; 33 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/index.ts: -------------------------------------------------------------------------------- 1 | import apple from "./apple"; 2 | import art from "./art"; 3 | import backpack from "./backpack"; 4 | import bag from "./bag"; 5 | import branch from "./branch"; 6 | import briefcase from "./briefcase"; 7 | import burger from "./burger"; 8 | import camera from "./camera"; 9 | import crab from "./crab"; 10 | import dockerWhale from "./docker-whale"; 11 | import keyboard from "./keyboard"; 12 | import laptop from "./laptop"; 13 | import linux from "./linux"; 14 | import magnifier from "./magnifier"; 15 | import moneybag from "./money"; 16 | import mug from "./mug"; 17 | import parrot from "./parrot"; 18 | import pepsi from "./pepsi"; 19 | import radio from "./radio"; 20 | import ramen from "./ramen"; 21 | import ruby from "./ruby"; 22 | import satellite from "./satellite"; 23 | import skateboard from "./skateboard"; 24 | import stetoscope from "./stetoscope"; 25 | import suitcase from "./suitcase"; 26 | import tennis from "./tennis"; 27 | import tie from "./tie"; 28 | import wheel from "./wheel"; 29 | 30 | const info = { 31 | apple, 32 | art, 33 | backpack, 34 | bag, 35 | branch, 36 | briefcase, 37 | burger, 38 | camera, 39 | crab, 40 | dockerWhale, 41 | keyboard, 42 | laptop, 43 | linux, 44 | magnifier, 45 | moneybag, 46 | mug, 47 | parrot, 48 | pepsi, 49 | radio, 50 | ramen, 51 | ruby, 52 | satellite, 53 | skateboard, 54 | stetoscope, 55 | suitcase, 56 | tennis, 57 | tie, 58 | wheel, 59 | }; 60 | 61 | export default info; 62 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/keyboard/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "keyboard", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/laptop/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "laptop", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/laptop/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Laptop = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default Laptop; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/laptop/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LaptopThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | export default LaptopThumb; 17 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/linux/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "linux", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/linux/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LinuxLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | }; 34 | 35 | export default LinuxLayer; 36 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/linux/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LinuxThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | }; 34 | 35 | export default LinuxThumb; 36 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/magnifier/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "magnifier", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/magnifier/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const MagnifierLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default MagnifierLayer; 29 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/magnifier/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const MagnifierThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | }; 26 | 27 | export default MagnifierThumb; 28 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/money/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "moneybag", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/mug/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "mug", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/mug/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Mug = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | export default Mug; 17 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/mug/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const MugThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | ); 17 | }; 18 | 19 | export default MugThumb; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/parrot/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "parrot", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/parrot/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ParrotLayer = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default ParrotLayer; 38 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/pepsi/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "pepsi", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/pepsi/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PepsiLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default PepsiLayer; 26 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/pepsi/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PepsiThumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default PepsiThumb; 27 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/radio/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "radio", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ramen/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "ramen", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ramen/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const RamenLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | ); 28 | }; 29 | 30 | export default RamenLayer; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ramen/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const RamenThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 26 | 27 | ); 28 | }; 29 | 30 | export default RamenThumb; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ruby/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "ruby", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ruby/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const RubyLayer = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default RubyLayer; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/ruby/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const RubyThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default RubyThumb; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/satellite/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "satellite", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/skateboard/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "skateboard", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/stetoscope/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "stetoscope", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/stetoscope/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Stetoscope = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default Stetoscope; 21 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/stetoscope/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const StetoscopeThumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | 22 | export default StetoscopeThumb; 23 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/suitcase/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "suitcase", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/tennis/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "tennis", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/tie/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "tie", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/tie/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Tie = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default Tie; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/tie/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const TieThumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default TieThumb; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/wheel/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "wheel", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/accessories/wheel/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const WheelLayer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default WheelLayer; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/bathrobe/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "bathrobe", layer, thumb, colors: {} }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/dress/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "dress", layer, thumb, colors: {} }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/index.ts: -------------------------------------------------------------------------------- 1 | import pants from "./pants"; 2 | import maxiSkirt from "./maxi-skirt"; 3 | import miniSkirt from "./mini-skirt"; 4 | import kilt from "./kilt"; 5 | import prosthetic from "./prosthetic"; 6 | import dress from "./dress"; 7 | import bathrobe from "./bathrobe"; 8 | 9 | const bottoms = { 10 | pants, 11 | maxiSkirt, 12 | miniSkirt, 13 | kilt, 14 | prosthetic, 15 | bathrobe, 16 | dress, 17 | }; 18 | 19 | export default bottoms; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/kilt/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "kilt", thumb, layer, colors: {} }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/maxi-skirt/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const maxiSkirtColors: IColorOptions = { 4 | "maxi-skirt-taurus": ["#343434", "#212121", "#000000"], 5 | "maxi-skirt-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "maxi-skirt-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "maxi-skirt-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "maxi-skirt-libra": ["#68217A", "#581C6B", "#442359"], 9 | "maxi-skirt-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "maxi-skirt-virgo": ["#00188f", "#001972", "#021f49"], 11 | "maxi-skirt-scorpio": ["#D4EDFF", "#B4D1E3", "#99BBCB"], 12 | }; 13 | 14 | export const defaultColor = maxiSkirtColors["maxi-skirt-scorpio"]; 15 | export default maxiSkirtColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/maxi-skirt/index.ts: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { name: "maxi-skirt", defaultColor, colors, thumb, layer }; 6 | export default info; 7 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/mini-skirt/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const miniSkirtColors: IColorOptions = { 4 | "mini-skirt-taurus": ["#343434", "#212121", "#000000"], 5 | "mini-skirt-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "mini-skirt-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "mini-skirt-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "mini-skirt-libra": ["#68217A", "#581C6B", "#442359"], 9 | "mini-skirt-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "mini-skirt-virgo": ["#00188f", "#001972", "#021f49"], 11 | "mini-skirt-scorpio": ["#D4EDFF", "#B4D1E3", "#99BBCB"], 12 | }; 13 | 14 | export const defaultColor = miniSkirtColors["mini-skirt-taurus"]; 15 | export default miniSkirtColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/mini-skirt/index.ts: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { name: "mini-skirt", defaultColor, colors, thumb, layer }; 6 | export default info; 7 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/pants/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const pantsColors: IColorOptions = { 4 | "pants-taurus": ["#343434", "#212121", "#000000"], 5 | "pants-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "pants-cancer": ["#3D5172", "#30435E", "#253549"], 7 | "pants-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "pants-libra": ["#4C301D", "#382315", "#1E130B"], 9 | "pants-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "pants-virgo": ["#D4EDFF", "#B4D1E3", "#99BBCB"], 11 | "pants-scorpio": ["#008272", "#006859", "#005244"], 12 | }; 13 | 14 | export const defaultColor = pantsColors["pants-cancer"]; 15 | 16 | export default pantsColors; 17 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/pants/index.ts: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { name: "pants", defaultColor, colors, thumb, layer }; 6 | export default info; 7 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/bottoms/prosthetic/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "prosthetic", thumb, layer, colors: {} }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-1/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-1", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-1/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear1 = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default Eyewear1; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-1/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear1Thumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default Eyewear1Thumb; 19 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-2/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-2", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-2/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear2 = () => { 4 | return ( 5 | 6 | 10 | 14 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 43 | ); 44 | }; 45 | 46 | export default Eyewear2; 47 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-2/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear2Thumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 15 | 16 | 17 | 21 | 25 | 26 | 27 | 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default Eyewear2Thumb; 37 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-3/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-3", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-3/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear3 = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | export default Eyewear3; 18 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-3/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear3Thumb = () => { 4 | return ( 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default Eyewear3Thumb; 24 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-4/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-4", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-4/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear4 = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default Eyewear4; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-4/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear4Thumb = () => { 4 | return ( 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default Eyewear4Thumb; 22 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-5/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-5", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-5/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear5Layer = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default Eyewear5Layer; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-5/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear5Thumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default Eyewear5Thumb; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-6/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "eyewear-6", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-6/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear6Layer = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default Eyewear6Layer; 14 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/eyewear-6/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Eyewear6Thumb = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default Eyewear6Thumb; 14 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/eyewear/index.ts: -------------------------------------------------------------------------------- 1 | import eyewear1 from "./eyewear-1"; 2 | import eyewear2 from "./eyewear-2"; 3 | import eyewear3 from "./eyewear-3"; 4 | import eyewear4 from "./eyewear-4"; 5 | import eyewear5 from "./eyewear-5"; 6 | import eyewear6 from "./eyewear-6"; 7 | 8 | const info = { eyewear1, eyewear2, eyewear3, eyewear4, eyewear5, eyewear6 }; 9 | export default info; 10 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const facialHairColors: IColorOptions = { 4 | "facial-hair-taurus": ["#343434", "#212121", "#000000"], 5 | "facial-hair-gemini": ["#603218", "#4F2814", "#422011"], 6 | "facial-hair-cancer": ["#FCE1B1", "#E8C589", "#DBAC6E"], 7 | "facial-hair-virgo": ["#FFD521", "#EAC31C", "#D3A12C"], 8 | "facial-hair-scorpio": ["#EAEAEA", "#D8D8D8", "#C4C4C4"], 9 | }; 10 | 11 | export const defaultColor = facialHairColors["facial-hair-gemini"]; 12 | export const defaultColorObject = { name: "facial-hair-gemini", palette: defaultColor }; 13 | export default facialHairColors; 14 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-1/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "facial-hair-1", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-1/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const FacialHair1 = ({ colors = defaultColor }: IProps = {}) => { 10 | const [color1, color2, color3] = colors; 11 | return ( 12 | 13 | 17 | 21 | 25 | 26 | ); 27 | }; 28 | 29 | export default FacialHair1; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-2/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "facial-hair-2", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-2/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const FacialHair2 = ({ colors = defaultColor }: IProps = {}) => { 10 | const [color1, color2, color3] = colors; 11 | return ( 12 | 13 | 17 | 21 | 25 | 29 | 33 | 37 | 38 | ); 39 | }; 40 | 41 | export default FacialHair2; 42 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-3/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "facial-hair-3", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-3/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const FacialHair3 = ({ colors = defaultColor }: IProps = {}) => { 10 | const [color1, color2, color3] = colors; 11 | return ( 12 | 13 | 17 | 21 | 25 | 29 | 33 | 37 | 38 | ); 39 | }; 40 | 41 | export default FacialHair3; 42 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-4/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "facial-hair-4", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-5/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "facial-hair-5", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/facial-hair-5/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const FacialHair5 = ({ colors = defaultColor }: IProps = {}) => { 10 | const [color1, color2, color3] = colors; 11 | return ( 12 | 13 | 17 | 21 | 25 | 29 | 33 | 37 | 38 | ); 39 | }; 40 | 41 | export default FacialHair5; 42 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/facial-hair/index.ts: -------------------------------------------------------------------------------- 1 | import facialHair1 from "./facial-hair-1"; 2 | import facialHair2 from "./facial-hair-2"; 3 | import facialHair3 from "./facial-hair-3"; 4 | import facialHair4 from "./facial-hair-4"; 5 | import facialHair5 from "./facial-hair-5"; 6 | 7 | const info = { facialHair1, facialHair2, facialHair3, facialHair4, facialHair5 }; 8 | export default info; 9 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/colors.ts: -------------------------------------------------------------------------------- 1 | import { Colors } from "@/interfaces/Colors"; 2 | 3 | interface IColorOptions { 4 | [key: string]: Colors; 5 | } 6 | 7 | const hairColors: IColorOptions = { 8 | "hair-gemini": ["#603218", "#4F2814", "#422011"], 9 | "hair-taurus": ["#343434", "#212121", "#000000"], 10 | "hair-cancer": ["#FCE1B1", "#E8C589", "#DBAC6E"], 11 | "hair-leo": ["#FF7B5C", "#E56E57", "#C1594C"], 12 | "hair-libra": ["#EF97DF", "#E281D5", "#C96FBC"], 13 | "hair-virgo": ["#4850E5", "#3442C6", "#283899"], 14 | "hair-scorpio": ["#EAEAEA", "#D8D8D8", "#C4C4C4"], 15 | }; 16 | 17 | export const defaultColor = hairColors["hair-gemini"]; 18 | export const defaultColorObject = { name: "hair-gemini", palette: defaultColor }; 19 | export default hairColors; 20 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-1/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair1", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-10/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair10", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-11/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair11", thumb, layer }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-12/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair12", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-12/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const Hair12 = ({ colors = defaultColor }: IProps = {}) => { 10 | return ( 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 30 | 31 | ); 32 | }; 33 | 34 | export default Hair12; 35 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-13/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair13", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-2/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair2", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-3/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair3", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-4/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair4", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-5/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair5", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-6/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair6", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-7/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair7", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-7/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { defaultColor } from "../colors"; 3 | import { Colors } from "@/interfaces/Colors"; 4 | 5 | interface IProps { 6 | colors?: Colors; 7 | } 8 | 9 | const Hair7 = ({ colors = defaultColor }: IProps = {}) => { 10 | const [color1, color2, color3] = colors; 11 | return ( 12 | 13 | 17 | 21 | 22 | 26 | 27 | ); 28 | }; 29 | 30 | export default Hair7; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-8/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair8", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/hair-9/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "hair9", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/hair/index.ts: -------------------------------------------------------------------------------- 1 | import hair1 from "./hair-1"; 2 | import hair2 from "./hair-2"; 3 | import hair3 from "./hair-3"; 4 | import hair4 from "./hair-4"; 5 | import hair5 from "./hair-5"; 6 | import hair6 from "./hair-6"; 7 | import hair7 from "./hair-7"; 8 | import hair8 from "./hair-8"; 9 | import hair9 from "./hair-9"; 10 | import hair10 from "./hair-10"; 11 | import hair11 from "./hair-11"; 12 | import hair12 from "./hair-12"; 13 | import hair13 from "./hair-13"; 14 | 15 | const options = { hair1, hair2, hair3, hair4, hair5, hair6, hair7, hair8, hair9, hair10, hair11, hair12, hair13 }; 16 | export default options; 17 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/no-selection.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default (): JSX.Element => ( 4 | 5 | 6 | 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/index.ts: -------------------------------------------------------------------------------- 1 | import shoe1 from "./shoe-1"; 2 | import shoe2 from "./shoe-2"; 3 | import shoe3 from "./shoe-3"; 4 | import shoe4 from "./shoe-4"; 5 | import shoe5 from "./shoe-5"; 6 | import shoe6 from "./shoe-6"; 7 | import shoe7 from "./shoe-7"; 8 | import shoe8 from "./shoe-8"; 9 | import shoe9 from "./shoe-9"; 10 | 11 | const shoes = [shoe1, shoe2, shoe3, shoe4, shoe5, shoe6, shoe7, shoe8, shoe9]; 12 | 13 | export default shoes; 14 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-1/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-1", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-1/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe1Thumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 15 | 16 | 17 | 18 | 19 | 23 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default Shoe1Thumb; 33 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-2/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-2", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-3/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-3", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-3/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe3Thumb = () => { 4 | return ( 5 | 6 | 7 | 11 | 15 | 16 | 17 | 21 | 22 | 23 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default Shoe3Thumb; 33 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-4/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-4", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-4/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe4 = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default Shoe4; 27 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-4/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe4Thumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default Shoe4Thumb; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-5/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-5", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-5/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe5Layer = () => { 4 | return ( 5 | 6 | 10 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default Shoe5Layer; 35 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-5/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe5Thumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default Shoe5Thumb; 38 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-6/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-6", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-6/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe6Layer = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | }; 26 | 27 | export default Shoe6Layer; 28 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-6/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe6Thumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default Shoe6Thumb; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-7/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-7", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-8/index.ts: -------------------------------------------------------------------------------- 1 | import thumb from "./thumb"; 2 | import layer from "./layer"; 3 | 4 | const info = { name: "shoe-8", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-8/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe8Layer = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default Shoe8Layer; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-8/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe8Thumb = () => { 4 | return ( 5 | 6 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | 30 | export default Shoe8Thumb; 31 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-9/index.ts: -------------------------------------------------------------------------------- 1 | import layer from "./layer"; 2 | import thumb from "./thumb"; 3 | 4 | const info = { name: "shoe-9", layer, thumb }; 5 | export default info; 6 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-9/layer.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe9Layer = () => { 4 | return ( 5 | 6 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default Shoe9Layer; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/shoes/shoe-9/thumb.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Shoe9Thumb = () => { 4 | return ( 5 | 6 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default Shoe9Thumb; 30 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/skin/index.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const skinColors: IColorOptions = { 4 | "skin-taurus": ["#FFEBE1", "#EFD9CE", "#E0CBC1", "#68605a"], 5 | "skin-gemini": ["#F6CCA7", "#DDBA9E", "#C4A385", "#533e2f"], 6 | "skin-cancer": ["#B78869", "#9E715A", "#7C5B45", "#3d2617"], 7 | "skin-leo": ["#A46135", "#894D2F", "#663D32", "#3d2617"], 8 | "skin-libra": ["#5B4234", "#412E22", "#2E1D17", "#000000"], 9 | "skin-lisa": ["#FFD521", "#EAC31C", "#D3A12C"], 10 | }; 11 | 12 | export const defaultColor = skinColors["skin-cancer"]; 13 | export const defaultColorObject = { name: "skin-cancer", palette: defaultColor }; 14 | export default skinColors; 15 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/hoodie/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const hoodieColors: IColorOptions = { 4 | "hoodie-taurus": ["#343434", "#212121", "#000000"], 5 | "hoodie-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "hoodie-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "hoodie-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "hoodie-libra": ["#68217A", "#581C6B", "#442359"], 9 | "hoodie-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "hoodie-virgo": ["#00188f", "#001972", "#021f49"], 11 | "hoodie-scorpio": ["#008272", "#006859", "#005E4E"], 12 | }; 13 | 14 | export const defaultColor = hoodieColors["hoodie-lisa"]; 15 | export default hoodieColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/hoodie/index.tsx: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { colors, defaultColor, name: "hoodie", thumb, layer }; 6 | export default info; 7 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/index.ts: -------------------------------------------------------------------------------- 1 | import tshirt from "./t-shirt"; 2 | import shirt from "./shirt"; 3 | import jacket from "./jacket"; 4 | import hoodie from "./hoodie"; 5 | 6 | const tops = { 7 | tshirt, 8 | shirt, 9 | jacket, 10 | hoodie, 11 | }; 12 | 13 | export default tops; 14 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/jacket/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const jacketColors: IColorOptions = { 4 | "jacket-taurus": ["#343434", "#212121", "#000000"], 5 | "jacket-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "jacket-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "jacket-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "jacket-libra": ["#4C301D", "#382315", "#1E130B"], 9 | "jacket-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "jacket-virgo": ["#154387", "#0F3A6D", "#0B2E51"], 11 | "jacket-scorpio": ["#008272", "#006859", "#005E4E"], 12 | }; 13 | 14 | export const defaultColor = jacketColors["jacket-taurus"]; 15 | export default jacketColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/jacket/index.tsx: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { colors, defaultColor, name: "jacket", thumb, layer }; 6 | 7 | export default info; 8 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/shirt/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const shirtColors: IColorOptions = { 4 | "shirt-taurus": ["#343434", "#212121", "#000000"], 5 | "shirt-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "shirt-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "shirt-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "shirt-libra": ["#68217A", "#581C6B", "#442359"], 9 | "shirt-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "shirt-virgo": ["#00188f", "#001972", "#021f49"], 11 | "shirt-scorpio": ["#D4EDFF", "#B4D1E3", "#99BBCB"], 12 | }; 13 | 14 | export const defaultColor = shirtColors["shirt-scorpio"]; 15 | export default shirtColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/shirt/index.tsx: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const info = { colors, defaultColor, name: "shirt", thumb, layer }; 6 | 7 | export default info; 8 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/t-shirt/colors.ts: -------------------------------------------------------------------------------- 1 | import { IColorOptions } from "@/interfaces/Colors"; 2 | 3 | const tshirtColors: IColorOptions = { 4 | "t-shirt-taurus": ["#343434", "#212121", "#000000"], 5 | "t-shirt-gemini": ["#FFFFFF", "#EAEAEA", "#D8D8D8"], 6 | "t-shirt-cancer": ["#FFB900", "#EFA500", "#D68F00"], 7 | "t-shirt-leo": ["#F472D0", "#D665BB", "#BA54AB"], 8 | "t-shirt-libra": ["#68217A", "#581C6B", "#442359"], 9 | "t-shirt-lisa": ["#BA141A", "#A3131D", "#8C101C"], 10 | "t-shirt-virgo": ["#00188f", "#001972", "#021f49"], 11 | "t-shirt-scorpio": ["#008272", "#006859", "#005E4E"], 12 | }; 13 | 14 | export const defaultColor = tshirtColors["t-shirt-taurus"]; 15 | export default tshirtColors; 16 | -------------------------------------------------------------------------------- /src/components/CharacterOptions/tops/t-shirt/index.tsx: -------------------------------------------------------------------------------- 1 | import colors, { defaultColor } from "./colors"; 2 | import thumb from "./thumb"; 3 | import layer from "./layer"; 4 | 5 | const tshirt = { colors, defaultColor, name: "t-shirt", thumb, layer }; 6 | export default tshirt; 7 | -------------------------------------------------------------------------------- /src/components/CharacterRandomizer/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const Container = styled.div` 4 | left: 300px; 5 | max-width: 1480px; 6 | position: relative; 7 | top: 650px; 8 | 9 | svg { 10 | display: block; 11 | height: auto; 12 | width: 100%; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /src/components/DropdownSelect/arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/DropdownSelect/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { RefObject, useRef, useState } from "react"; 2 | import noop from "lodash-es/noop"; 3 | import kebabCase from "lodash-es/kebabCase"; 4 | import useOnClickOutside from "@/hooks/use-click-outside"; 5 | import { Dropdown, DropdownToggle, DropdownContent, Option } from "./styles"; 6 | import arrow from "./arrow-down.svg"; 7 | 8 | interface IProps { 9 | onSelect: (item: string) => void; 10 | items: string[]; 11 | selectedItems?: string[]; 12 | buttonText?: string | undefined; 13 | [key: string]: any; 14 | } 15 | 16 | const DropdownSelect = ({ 17 | onSelect = noop, 18 | items = [], 19 | buttonText = "Select", 20 | selectedItems = [], 21 | ...restProps 22 | }: IProps) => { 23 | const [isOpen, setOpen] = useState(false); 24 | const containerRef: RefObject = useRef(null); 25 | const toggle = () => setOpen(state => !state); 26 | 27 | useOnClickOutside(containerRef, () => setOpen(false)); 28 | 29 | const selectItem = (item: string) => { 30 | onSelect(item); 31 | setOpen(false); 32 | }; 33 | 34 | const isActive = (item: string) => selectedItems.indexOf(item) !== -1; 35 | const hasSelection = !!selectedItems && selectedItems.length > 0; 36 | 37 | return ( 38 | 39 | 40 | {buttonText} 41 | 42 | v 43 | 44 | 45 | {isOpen && ( 46 | 47 | {items.map((item: string, i: number) => ( 48 | 51 | ))} 52 | 53 | )} 54 | 55 | ); 56 | }; 57 | 58 | export default DropdownSelect; 59 | -------------------------------------------------------------------------------- /src/components/HorizontalScroller/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ScrollContainer } from "./styles"; 3 | 4 | interface IProps { 5 | children: React.ReactChildren | React.ReactChild | any; 6 | } 7 | 8 | const HorizontalScroller = ({ children }: IProps) => { 9 | return ( 10 |
11 | {children} 12 |
13 | ); 14 | }; 15 | 16 | export default HorizontalScroller; 17 | -------------------------------------------------------------------------------- /src/components/HorizontalScroller/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const ScrollContainer = styled.div.attrs(() => ({ 4 | className: "scroller horizontal-scroller", 5 | }))` 6 | display: flex; 7 | flex-wrap: nowrap; 8 | padding-left: 49px; 9 | -webkit-overflow-scrolling: touch; 10 | white-space: nowrap; 11 | width: 100%; 12 | 13 | ::-webkit-scrollbar { 14 | display: none; 15 | } 16 | 17 | &::after { 18 | content: ""; 19 | display: block; 20 | flex: 0 0 20px; 21 | width: 20px; 22 | } 23 | `; 24 | -------------------------------------------------------------------------------- /src/components/IdleCountdown/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import useInterval from "@/hooks/use-interval"; 3 | import { Remaining } from "./styles"; 4 | import noop from "lodash-es/noop"; 5 | 6 | const IdleCountdown = ({ afterComplete = noop, timeout = 30 }) => { 7 | const [remaining, setRemaining] = useState(timeout); 8 | const [running, setRunning] = useState(true); 9 | const [isCritical, setCritical] = useState(false); 10 | 11 | useInterval( 12 | () => { 13 | if (remaining === 0) { 14 | setRunning(false); 15 | afterComplete(); 16 | } else { 17 | if (remaining <= 6) { 18 | setCritical(true); 19 | } 20 | setRemaining(s => s - 1); 21 | } 22 | }, 23 | running ? 1000 : null 24 | ); 25 | 26 | return ( 27 | 28 | Returning to idle screen in {remaining} 29 | s 30 |
31 | Touch screen to continue 32 |
33 | ); 34 | }; 35 | 36 | export default IdleCountdown; 37 | -------------------------------------------------------------------------------- /src/components/IdleCountdown/styles.js: -------------------------------------------------------------------------------- 1 | import styled, { keyframes } from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | 4 | const warn = keyframes` 5 | 0%, 100% { 6 | transform: scale(1) translateY(0); 7 | } 8 | 50% { 9 | transform: scale(1.05) translateY(-40px); 10 | } 11 | `; 12 | 13 | export const Remaining = styled.p` 14 | bottom: 80px; 15 | color: ${colors.black}; 16 | font-size: 40px; 17 | background: ${colors.white}; 18 | box-shadow: 0px 21px 0px ${colors.darkBlue}; 19 | padding: 50px; 20 | text-align: center; 21 | position: fixed; 22 | right: 80px; 23 | z-index: 99999; 24 | 25 | &.critical { 26 | animation: ${warn} 500ms linear forwards; 27 | animation-iteration-count: 2; 28 | } 29 | `; 30 | -------------------------------------------------------------------------------- /src/components/Logo/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const LogoContainer = styled.div` 4 | height: 0; 5 | padding-bottom: 56.25%; 6 | position: relative; 7 | 8 | svg { 9 | display: block; 10 | height: 100%; 11 | left: 0; 12 | position: absolute; 13 | top: 0; 14 | width: 100%; 15 | } 16 | `; 17 | 18 | export const LogoWrapper = styled.div.attrs(() => ({ 19 | className: "logo", 20 | }))` 21 | overflow: hidden; 22 | `; 23 | -------------------------------------------------------------------------------- /src/components/OptionPanels/accessories-panel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { OptionPanel } from "./styles"; 3 | 4 | import accessories from "@/components/CharacterOptions/accessories"; 5 | import OptionStyleSelectable from "@/components/Selectables/option-style-selectable"; 6 | 7 | import toArray from "lodash-es/toArray"; 8 | import { Dispatch } from "redux"; 9 | import { useDispatch, useSelector } from "react-redux"; 10 | 11 | import { setAccessory } from "@/redux/character/character.actions"; 12 | 13 | import { IStoreState } from "@/interfaces/IStoreState"; 14 | 15 | const AccessoriesPanel = () => { 16 | const dispatch: Dispatch = useDispatch(); 17 | 18 | const { accessories: selectedAccessories } = useSelector((store: IStoreState) => store.character); 19 | 20 | const accessoryOptions = toArray(accessories).map(({ name, thumb }) => ({ 21 | value: name, 22 | thumb, 23 | })); 24 | 25 | return ( 26 | 27 | dispatch(setAccessory(undefined))} 31 | onStyleClicked={style => dispatch(setAccessory(style))} 32 | selectedStyle={selectedAccessories} 33 | className="accessories" 34 | /> 35 | 36 | ); 37 | }; 38 | 39 | export default AccessoriesPanel; 40 | -------------------------------------------------------------------------------- /src/components/OptionPanels/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import TabSwitcher, { Tab, TabPanel } from "@/components/TabSwitcher"; 3 | import { Tabs, OptionsContainer } from "./styles"; 4 | import BodyPanel from "./body-panel"; 5 | import TopPanel from "./top-panel"; 6 | import BottomPanel from "./bottom-panel"; 7 | import AccessoriesPanel from "./accessories-panel"; 8 | 9 | const OptionPanels = () => { 10 | return ( 11 | 12 | 13 | 14 | Body 15 | Top style 16 | Bottom style 17 | Accessories 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default OptionPanels; 38 | -------------------------------------------------------------------------------- /src/components/Progress/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ProgressBar } from "./styles"; 3 | 4 | const Progress = ({ step = 1 }) => { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | = 1 ? 1 : 0.3} /> 18 | = 2 ? 1 : 0.3} /> 19 | = 3 ? 1 : 0.3} /> 20 | = 4 ? 1 : 0.3} /> 21 | 22 | 23 | 24 | ); 25 | }; 26 | 27 | export default Progress; 28 | -------------------------------------------------------------------------------- /src/components/Progress/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | 4 | export const ProgressBar = styled.div` 5 | height: 89px; 6 | display: flex; 7 | margin-left: 300px; 8 | 9 | span { 10 | background: ${colors.white}; 11 | display: inline-block; 12 | flex: 1 0 auto; 13 | margin-right: 25px; 14 | 15 | &:last-of-type { 16 | margin-right: 0; 17 | } 18 | } 19 | `; 20 | -------------------------------------------------------------------------------- /src/components/StartOver/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StartOverButton } from "./styles"; 3 | import trashcan from "@/icons/trashcan.svg"; 4 | import { Dispatch } from "redux"; 5 | import { useDispatch } from "react-redux"; 6 | import { uiActions } from "@/redux/ui"; 7 | 8 | const StartOver = () => { 9 | const dispatch: Dispatch = useDispatch(); 10 | 11 | const startOver = () => { 12 | dispatch(uiActions.startOver()); 13 | }; 14 | 15 | return ( 16 | 17 | Start over{" "} 18 | 19 | trashcan icon 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default StartOver; 26 | -------------------------------------------------------------------------------- /src/components/StartOver/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | 4 | export const StartOverButton = styled.button.attrs(() => ({ 5 | className: "start-over-button hoverable", 6 | }))` 7 | -webkit-appearance: none; 8 | -moz-appearance: none; 9 | background: rgba(0, 0, 0, 0); 10 | border: 0; 11 | color: ${colors.white}; 12 | display: block; 13 | font-size: 60px; 14 | padding: 30px; 15 | position: fixed; 16 | top: 140px; 17 | right: 262px; 18 | z-index: 99; 19 | 20 | &:focus { 21 | outline: 10px solid ${colors.green}; 22 | } 23 | 24 | span { 25 | display: inline-block; 26 | margin-left: 30px; 27 | vertical-align: middle; 28 | width: 63px; 29 | } 30 | 31 | img { 32 | display: block; 33 | width: 100%; 34 | } 35 | `; 36 | -------------------------------------------------------------------------------- /src/components/StatGrader/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { GraderContainer, GradingButtons, GradingButton, Points, SkillName, SkillIcon } from "./styles"; 3 | import { Dispatch } from "redux"; 4 | import { useDispatch } from "react-redux"; 5 | import { IGradedStat } from "@/interfaces/IStats"; 6 | import { statsActions } from "@/redux/stats"; 7 | import { resolveIcon } from "@/components/StatPanels/stat-options"; 8 | import clsx from "clsx"; 9 | 10 | interface IProps { 11 | stat: IGradedStat; 12 | canIncrease?: boolean; 13 | [key: string]: any; 14 | } 15 | 16 | const StatGrader = ({ stat, canIncrease = false, ...rest }: IProps) => { 17 | const dispatch: Dispatch = useDispatch(); 18 | 19 | const increase = () => { 20 | dispatch(statsActions.addStatPoint(stat)); 21 | }; 22 | 23 | const decrease = () => { 24 | dispatch(statsActions.removeStatPoint(stat)); 25 | }; 26 | 27 | const className = resolveIcon(stat.category); 28 | 29 | return ( 30 | 31 | 32 | {stat && stat.name} 33 | {stat && stat.level} 34 | 35 | 36 | 42 | 43 | 44 | ); 45 | }; 46 | 47 | export default StatGrader; 48 | -------------------------------------------------------------------------------- /src/components/StatPanels/checkmark.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Checkmark = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default Checkmark; 20 | -------------------------------------------------------------------------------- /src/components/StatPanels/distribute-points.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StatsPanel, Title, Grading, Remaining } from "./styles"; 3 | import StatGrader from "@/components/StatGrader"; 4 | import { useSelector } from "react-redux"; 5 | import { IStoreState } from "@/interfaces/IStoreState"; 6 | 7 | const DistributePoints = () => { 8 | const { gradedStats, statPointsAvailable, totalStatPoints } = useSelector((store: IStoreState) => store.stats); 9 | 10 | return ( 11 | 12 | Distribute {totalStatPoints} points 13 | 14 | {gradedStats.map(({ name, category, level }, index: number) => ( 15 | 20 | ))} 21 | 22 | {!!statPointsAvailable && Points remaining: {statPointsAvailable}} 23 | 24 | ); 25 | }; 26 | 27 | export default DistributePoints; 28 | -------------------------------------------------------------------------------- /src/components/StatPanels/evaluate-arrow.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const EvaluateArrow = () => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | export default EvaluateArrow; 18 | -------------------------------------------------------------------------------- /src/components/StatPanels/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import TabSwitcher, { Tab, TabPanel } from "@/components/TabSwitcher"; 3 | import { Tabs, StatsContainer } from "./styles"; 4 | import ChoosePanel from "./choose-stats"; 5 | import DistributePanel from "./distribute-points"; 6 | import { useSelector } from "react-redux"; 7 | import { IStoreState } from "@/interfaces/IStoreState"; 8 | 9 | const OptionPanels = () => { 10 | const { selectedStats } = useSelector((store: IStoreState) => store.stats); 11 | 12 | return ( 13 | 14 | 15 | 16 | Select your skills 17 | 18 | Distribute points 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | }; 32 | 33 | export default OptionPanels; 34 | -------------------------------------------------------------------------------- /src/components/StatPanels/stat-options.ts: -------------------------------------------------------------------------------- 1 | const statOptions = [ 2 | { 3 | category: "Classic", 4 | icon: "lightning-bolt-icon", 5 | options: ["Charisma", "Constitution", "Dexterity", "Intelligence", "Perception", "Speed", "Strength", "Wisdom"], 6 | }, 7 | { 8 | category: "Industries", 9 | icon: "briefcase-icon", 10 | options: ["Fintech", "HealthTech", "InfoSec", "Proptech", "Retail"], 11 | }, 12 | { 13 | category: "Startup Skills", 14 | icon: "lightbulb-icon", 15 | options: [ 16 | "Architecture", 17 | "Bootstrapping", 18 | "Business Development", 19 | "Business Operations", 20 | "Data Analysis", 21 | "DevOps", 22 | "Finances", 23 | "Investor Relations", 24 | "Marketing", 25 | "Machine Learning", 26 | "Networking", 27 | "Passion", 28 | "Patience", 29 | "Product", 30 | "Purpose", 31 | "Resilience", 32 | "Sales", 33 | "Security", 34 | "Shipping", 35 | "Strategy", 36 | ], 37 | }, 38 | { 39 | category: "Technology", 40 | icon: "floppy-icon", 41 | options: [ 42 | ".NET", 43 | "Azure", 44 | "C", 45 | "C#", 46 | "C++", 47 | "Clojure", 48 | "Containers", 49 | "Debian", 50 | "Docker", 51 | "Elixir", 52 | "Erlang", 53 | "F#", 54 | "Golang", 55 | "Java", 56 | "JavaScript", 57 | "Kafka", 58 | "Kubernetes", 59 | "Linux", 60 | "NodeJS", 61 | "PHP", 62 | "Python", 63 | "Rails", 64 | "React", 65 | "Ruby", 66 | "Rust", 67 | "Scala", 68 | "Serverless", 69 | "Tensorflow", 70 | "Ubuntu", 71 | "Vue", 72 | "Windows", 73 | ], 74 | }, 75 | ]; 76 | 77 | export const resolveIcon = (category: string): string => { 78 | try { 79 | return statOptions.filter(opt => opt && opt.category === category)[0].icon; 80 | } catch (e) { 81 | return ""; 82 | } 83 | }; 84 | 85 | export default statOptions; 86 | -------------------------------------------------------------------------------- /src/components/Stepper/NextButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Next } from "./styles"; 3 | import { Dispatch } from "redux"; 4 | import { useDispatch } from "react-redux"; 5 | import { uiActions } from "@/redux/ui"; 6 | import arrow from "./arrow-back.svg"; 7 | 8 | interface IProps { 9 | disabled?: boolean; 10 | [key: string]: any; 11 | } 12 | 13 | const NextButton = ({ disabled = false, children, beforeNext, ...restProps }: IProps) => { 14 | const dispatch: Dispatch = useDispatch(); 15 | const navigateNext = async () => { 16 | if (beforeNext) { 17 | await beforeNext(); 18 | } 19 | dispatch(uiActions.navigateNext()); 20 | }; 21 | 22 | return ( 23 | 24 | {!!children ? children : null} 25 | 26 | -> 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default NextButton; 33 | -------------------------------------------------------------------------------- /src/components/Stepper/PrevButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Prev } from "./styles"; 3 | import { Dispatch } from "redux"; 4 | import { useDispatch, useSelector } from "react-redux"; 5 | import { uiActions } from "@/redux/ui"; 6 | import { IStoreState } from "@/interfaces/IStoreState"; 7 | 8 | interface IProps { 9 | disabled?: boolean; 10 | [key: string]: any; 11 | } 12 | 13 | const PrevButton = ({ disabled = false, children, ...restProps }: IProps) => { 14 | const dispatch: Dispatch = useDispatch(); 15 | const { totalSteps, currentStep } = useSelector((store: IStoreState) => store.ui); 16 | const navigatePrev = () => { 17 | /* if user is about to navigate to first screen, show "game over?" screen */ 18 | if (totalSteps > 1 && currentStep === 1) { 19 | dispatch(uiActions.startOver()); 20 | } else { 21 | dispatch(uiActions.navigatePrev()); 22 | } 23 | }; 24 | 25 | return ( 26 | 27 | {!!children ? children : null} 28 | 29 | ); 30 | }; 31 | 32 | export default PrevButton; 33 | -------------------------------------------------------------------------------- /src/components/Stepper/StepperFooter.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StepperNav } from "./styles"; 3 | import PrevButton from "./PrevButton"; 4 | import NextButton from "./NextButton"; 5 | import ProgressBar from "@/components/Progress"; 6 | import { useSelector } from "react-redux"; 7 | import { IStoreState } from "@/interfaces/IStoreState"; 8 | 9 | interface IProps { 10 | nextDisabled?: boolean; 11 | prevDisabled?: boolean; 12 | nextHtml?: any; 13 | beforeNext?: any; 14 | beforePrev?: any; 15 | } 16 | 17 | const StepperFooter = ({ 18 | nextDisabled = false, 19 | prevDisabled = false, 20 | nextHtml = "Next", 21 | beforeNext = undefined, 22 | beforePrev = undefined, 23 | }: IProps) => { 24 | const { currentStep } = useSelector((store: IStoreState) => store.ui); 25 | 26 | return ( 27 | 28 |
29 | 30 | 31 |
32 | 33 | {nextHtml} 34 | 35 |
36 | ); 37 | }; 38 | 39 | export default StepperFooter; 40 | -------------------------------------------------------------------------------- /src/components/Stepper/arrow-back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Stepper/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useSelector, useDispatch } from "react-redux"; 3 | import { Dispatch } from "redux"; 4 | import { uiActions } from "@/redux/ui"; 5 | import clsx from "clsx"; 6 | import { IStoreState } from "@/interfaces/IStoreState"; 7 | 8 | interface IStep { 9 | component: React.ComponentClass | any; 10 | name?: string; 11 | nextButtonText?: string; 12 | } 13 | 14 | interface IProps { 15 | steps: IStep[]; 16 | } 17 | 18 | const Stepper = ({ steps }: IProps) => { 19 | const { currentStep } = useSelector((store: IStoreState) => store.ui); 20 | const dispatch: Dispatch = useDispatch(); 21 | 22 | useEffect(() => { 23 | dispatch(uiActions.setTotalSteps(steps.length)); 24 | }, [steps.length, dispatch]); 25 | 26 | const { component: Component, name } = steps[currentStep]; 27 | 28 | return ( 29 |
30 |
31 | 32 |
33 |
34 | ); 35 | }; 36 | 37 | export default Stepper; 38 | -------------------------------------------------------------------------------- /src/components/Stepper/styles.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors, buttonShine } from "@/utils/style-utils"; 3 | import backArrow from "./arrow-back.svg"; 4 | 5 | export const StepperNav = styled.div.attrs(() => ({ 6 | className: "stepper-nav", 7 | }))` 8 | bottom: 232px; 9 | display: flex; 10 | justify-content: space-between; 11 | padding: 0 292px 0 224px; 12 | position: fixed; 13 | left: 0; 14 | width: 100%; 15 | `; 16 | 17 | const Button = styled.button` 18 | align-items: center; 19 | background-color: ${colors.white}; 20 | border: 7px solid ${colors.lightGrey}; 21 | border-radius: 0; 22 | box-shadow: 0px 7px 0px ${colors.darkBlue}; 23 | font-size: 60px; 24 | display: flex; 25 | height: 176px; 26 | justify-content: space-between; 27 | margin: 0; 28 | padding: 0; 29 | 30 | &:focus { 31 | outline: 10px solid ${colors.green}; 32 | } 33 | 34 | &:active { 35 | background-color: ${colors.lightGrey}; 36 | } 37 | 38 | &:disabled { 39 | color: ${colors.black}; 40 | opacity: 0.6; 41 | pointer-events: none; 42 | } 43 | `; 44 | 45 | export const Prev = styled(Button).attrs(() => ({ 46 | className: "prev-button", 47 | }))` 48 | background-image: url(${backArrow}); 49 | background-position: center; 50 | background-repeat: no-repeat; 51 | background-size: 70px 49px; 52 | width: 176px; 53 | `; 54 | 55 | export const Next = styled(Button).attrs(() => ({ 56 | className: "next-button", 57 | }))` 58 | padding: 0 80px; 59 | 60 | .icon { 61 | display: inline-block; 62 | margin-left: 40px; 63 | transform: rotate(180deg); 64 | vertical-align: center; 65 | width: 70px; 66 | 67 | img { 68 | display: block; 69 | width: 100%; 70 | } 71 | } 72 | 73 | &:not([disabled]) { 74 | ${buttonShine} 75 | } 76 | `; 77 | -------------------------------------------------------------------------------- /src/fonts/Silkscreen/Silkscreen.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/fonts/Silkscreen/Silkscreen.eot -------------------------------------------------------------------------------- /src/fonts/Silkscreen/Silkscreen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/fonts/Silkscreen/Silkscreen.ttf -------------------------------------------------------------------------------- /src/fonts/Silkscreen/Silkscreen.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/fonts/Silkscreen/Silkscreen.woff -------------------------------------------------------------------------------- /src/fonts/Silkscreen/Silkscreen.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/fonts/Silkscreen/Silkscreen.woff2 -------------------------------------------------------------------------------- /src/graphics/lightbeam.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Lightbeam = (props: any) => { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | }; 13 | 14 | export default Lightbeam; 15 | -------------------------------------------------------------------------------- /src/hooks/use-click-outside.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, RefObject } from "react"; 2 | 3 | const useOnClickOutside = (ref: RefObject, handler: (e?: MouseEvent | TouchEvent) => void) => { 4 | useEffect(() => { 5 | const listener = (event: MouseEvent | TouchEvent) => { 6 | const target = event.target as HTMLElement; 7 | // Do nothing if clicking ref's element or descendent elements 8 | if (!ref.current || ref.current.contains(target)) { 9 | return; 10 | } 11 | 12 | handler(event); 13 | }; 14 | 15 | document.addEventListener("mousedown", listener); 16 | document.addEventListener("touchstart", listener); 17 | 18 | return () => { 19 | document.removeEventListener("mousedown", listener); 20 | document.removeEventListener("touchstart", listener); 21 | }; 22 | }, [ref, handler]); 23 | }; 24 | 25 | export default useOnClickOutside; 26 | -------------------------------------------------------------------------------- /src/hooks/use-interval.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | import noop from "lodash-es/noop"; 3 | 4 | const useInterval = (callback: typeof noop, delay: number | null) => { 5 | const savedCallback = useRef(noop); 6 | 7 | // Remember the latest function. 8 | useEffect(() => { 9 | savedCallback.current = callback; 10 | }, [callback]); 11 | 12 | // Set up the interval. 13 | useEffect(() => { 14 | function tick() { 15 | savedCallback.current(); 16 | } 17 | if (delay !== null) { 18 | let id = setInterval(tick, delay); 19 | return () => clearInterval(id); 20 | } 21 | }, [delay]); 22 | }; 23 | 24 | export default useInterval; 25 | -------------------------------------------------------------------------------- /src/icons/cursor-click.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/icons/cursor-click.png -------------------------------------------------------------------------------- /src/icons/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticwebdev/StartupAdventurer/16e628e636c47aa21674ce80d9babdac8b10fa34/src/icons/cursor.png -------------------------------------------------------------------------------- /src/icons/trashcan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Silkscreen"; 3 | src: url("./fonts/Silkscreen/Silkscreen.eot"); 4 | src: local("Silkscreen"), url("./fonts/Silkscreen/Silkscreen.eot#iefix") format("embedded-opentype"), 5 | url("./fonts/Silkscreen/Silkscreen.woff2") format("woff2"), 6 | url("./fonts/Silkscreen/Silkscreen.woff") format("woff"); 7 | font-display: swap; 8 | font-style: normal; 9 | font-weight: normal; 10 | } 11 | 12 | *, 13 | *::before, 14 | *::after { 15 | box-sizing: border-box; 16 | font-family: "Silkscreen"; 17 | user-select: none; 18 | } 19 | 20 | body { 21 | background: #121212; 22 | font-family: "Silkscreen"; 23 | -moz-osx-font-smoothing: grayscale; 24 | -webkit-font-smoothing: antialiased; 25 | height: 100%; 26 | margin: 0; 27 | overscroll-behavior: none; 28 | position: fixed; 29 | width: 100%; 30 | } 31 | 32 | #root { 33 | height: 100%; 34 | overscroll-behavior: none; 35 | position: fixed; 36 | touch-action: none; 37 | width: 100%; 38 | } 39 | 40 | .hoverable, 41 | button { 42 | cursor: pointer; 43 | } 44 | 45 | span.flash { 46 | pointer-events: none; 47 | } 48 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import * as serviceWorker from "./serviceWorker"; 6 | import { createStore, Store, compose } from "redux"; 7 | import { Provider } from "react-redux"; 8 | import { reducers } from "@/redux"; 9 | import { IStoreState } from "@/interfaces/IStoreState"; 10 | import { UserInfoContextProvider } from "@aaronpowell/react-static-web-apps-auth"; 11 | 12 | const composeEnhancers = 13 | (process.env.NODE_ENV !== "production" && (window.top as any)["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"]) || compose; 14 | 15 | const store: Store = createStore(reducers(), composeEnhancers()); 16 | 17 | const rootNode = document.getElementById("root"); 18 | ReactDOM.render( 19 | 20 | 21 | 22 | 23 | , 24 | rootNode 25 | ); 26 | 27 | // If you want your app to work offline and load faster, you can change 28 | // unregister() to register() below. Note this comes with some pitfalls. 29 | // Learn more about service workers: https://bit.ly/CRA-PWA 30 | serviceWorker.unregister(); 31 | -------------------------------------------------------------------------------- /src/interfaces/Colors.ts: -------------------------------------------------------------------------------- 1 | export type Colors = string[]; 2 | export interface IColorSet { 3 | name: string; 4 | palette?: Colors; 5 | } 6 | export interface IColorOptions { 7 | [key: string]: Colors; 8 | } 9 | -------------------------------------------------------------------------------- /src/interfaces/IAction.ts: -------------------------------------------------------------------------------- 1 | export interface IAction { 2 | type: string; 3 | payload: any; 4 | [key: string]: any; 5 | } 6 | -------------------------------------------------------------------------------- /src/interfaces/IBasicInfo.ts: -------------------------------------------------------------------------------- 1 | export interface IBasicInfo { 2 | businessCategory: string | undefined; 3 | companySize: string | undefined; 4 | funding: string | undefined; 5 | role: string | undefined; 6 | [key: string]: any; 7 | } 8 | -------------------------------------------------------------------------------- /src/interfaces/ICharacter.ts: -------------------------------------------------------------------------------- 1 | import { IColorSet } from "./Colors" 2 | 3 | export interface ICharacter { 4 | bottom?: IStyledSelection; 5 | tops?: { 6 | hoodie?: IColorSet; 7 | tshirt?: IColorSet; 8 | shirt?: IColorSet; 9 | jacket?: IColorSet; 10 | }; 11 | shoes?: string; // This should probably be a type 12 | accessories?: string[]; 13 | eyewear?: string; 14 | hair?: Partial>; 15 | facialHair: Partial>; 16 | skinColor: IColorSet; 17 | 18 | startedAt?: string; 19 | completedAt?: string; 20 | viewedOptionTabs: string[]; 21 | } 22 | 23 | export type TopStyle = "hoodie" | "jacket" | "tshirt" | "shirt" 24 | export type ColoredBottomStyle = "pants" | "maxiSkirt" | "miniSkirt" 25 | export type OtherBottomStyle = "kilt" | "prosthetic" | "bathrobe" | "dress" 26 | export type BottomStyle = ColoredBottomStyle | OtherBottomStyle 27 | 28 | 29 | export interface IStyledSelection { 30 | style: Styles, 31 | color?: IColorSet 32 | } 33 | 34 | export interface IColoredSelection { 35 | color?: IColorSet 36 | } -------------------------------------------------------------------------------- /src/interfaces/IStats.ts: -------------------------------------------------------------------------------- 1 | export interface IStat { 2 | category: string; 3 | name: string; 4 | } 5 | 6 | export interface IGradedStat extends IStat { 7 | level: number; 8 | } 9 | 10 | export interface IStatsState { 11 | selectedStats: IStat[]; 12 | statPointsAvailable: number; 13 | gradedStats: IGradedStat[]; 14 | totalStatPoints: number; 15 | } 16 | -------------------------------------------------------------------------------- /src/interfaces/IStoreState.ts: -------------------------------------------------------------------------------- 1 | import { ICharacter } from "./ICharacter"; 2 | import { IBasicInfo } from "./IBasicInfo"; 3 | import { IStatsState } from "./IStats"; 4 | import { IUiState } from "./IUiState"; 5 | 6 | export interface IStoreState { 7 | character: ICharacter; 8 | info: IBasicInfo; 9 | stats: IStatsState; 10 | ui: IUiState; 11 | } 12 | -------------------------------------------------------------------------------- /src/interfaces/IUiState.ts: -------------------------------------------------------------------------------- 1 | export interface IUiState { 2 | currentStep: number; 3 | isEnd: boolean; 4 | isStart: boolean; 5 | isIdle: boolean; 6 | isCharacterDisplay: boolean; 7 | showGameOver: boolean; 8 | totalSteps: number; 9 | [key: string]: any; 10 | } 11 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/redux/character/index.ts: -------------------------------------------------------------------------------- 1 | import character from "./character.reducer"; 2 | import * as characterActions from "./character.actions"; 3 | 4 | export { character, characterActions }; 5 | -------------------------------------------------------------------------------- /src/redux/createAction.ts: -------------------------------------------------------------------------------- 1 | export interface Action { 2 | readonly type: T; 3 | readonly payload: P; 4 | } 5 | 6 | export function createAction(type: T, payload: P): Action { 7 | return { type, payload }; 8 | } -------------------------------------------------------------------------------- /src/redux/index.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import { character } from "./character"; 3 | import { info } from "./info"; 4 | import { ui } from "./ui"; 5 | import { stats } from "./stats"; 6 | 7 | export const reducers = () => 8 | combineReducers({ 9 | character, 10 | info, 11 | stats, 12 | ui, 13 | }); 14 | -------------------------------------------------------------------------------- /src/redux/info/index.ts: -------------------------------------------------------------------------------- 1 | import info from "./info.reducer"; 2 | import * as infoActions from "./info.actions"; 3 | 4 | export { info, infoActions }; 5 | -------------------------------------------------------------------------------- /src/redux/info/info.actions.ts: -------------------------------------------------------------------------------- 1 | import { SET_BUSINESS_CATEGORY, SET_COMPANY_SIZE, SET_ROLE, SET_FUNDING, RESET_INFO } from "./info.types"; 2 | 3 | import { IAction } from "@/interfaces/IAction"; 4 | 5 | export const setBusinessCategory = (category: string | undefined): IAction => ({ 6 | type: SET_BUSINESS_CATEGORY, 7 | payload: { category }, 8 | }); 9 | 10 | export const setCompanySize = (size: string | undefined): IAction => ({ 11 | type: SET_COMPANY_SIZE, 12 | payload: { size }, 13 | }); 14 | 15 | export const setRole = (role: string | undefined): IAction => ({ 16 | type: SET_ROLE, 17 | payload: { role }, 18 | }); 19 | 20 | export const setFunding = (funding: string | undefined): IAction => ({ 21 | type: SET_FUNDING, 22 | payload: { funding }, 23 | }); 24 | 25 | export const resetInfo = (): IAction => ({ 26 | type: RESET_INFO, 27 | payload: {}, 28 | }); 29 | -------------------------------------------------------------------------------- /src/redux/info/info.reducer.ts: -------------------------------------------------------------------------------- 1 | import { SET_BUSINESS_CATEGORY, SET_COMPANY_SIZE, SET_ROLE, SET_FUNDING, RESET_INFO } from "./info.types"; 2 | 3 | import { IAction } from "@/interfaces/IAction"; 4 | import { IBasicInfo } from "@/interfaces/IBasicInfo"; 5 | 6 | const initialState: IBasicInfo = { 7 | businessCategory: undefined, 8 | companySize: "11-25", 9 | funding: undefined, 10 | role: undefined, 11 | }; 12 | 13 | const reducer = (state: IBasicInfo = initialState, { type, payload }: IAction) => { 14 | switch (type) { 15 | case SET_BUSINESS_CATEGORY: 16 | return { 17 | ...state, 18 | businessCategory: payload.category, 19 | }; 20 | 21 | case SET_COMPANY_SIZE: 22 | return { 23 | ...state, 24 | companySize: payload.size, 25 | }; 26 | 27 | case SET_ROLE: 28 | return { 29 | ...state, 30 | role: payload.role, 31 | }; 32 | 33 | case SET_FUNDING: 34 | return { 35 | ...state, 36 | funding: payload.funding, 37 | }; 38 | 39 | case RESET_INFO: 40 | return initialState; 41 | 42 | default: 43 | return state; 44 | } 45 | }; 46 | 47 | export default reducer; 48 | -------------------------------------------------------------------------------- /src/redux/info/info.types.ts: -------------------------------------------------------------------------------- 1 | export const SET_BUSINESS_CATEGORY: string = "info/ADD_BUSINESS_CATEGORY"; 2 | export const SET_COMPANY_SIZE: string = "info/SET_COMPANY_SIZE"; 3 | export const SET_ROLE: string = "info/SET_ROLE"; 4 | export const SET_FUNDING: string = "info/SET_FUNDING"; 5 | export const RESET_INFO: string = "info/RESET_INFO"; 6 | -------------------------------------------------------------------------------- /src/redux/stats/index.ts: -------------------------------------------------------------------------------- 1 | import stats from "./stats.reducer"; 2 | import * as statsActions from "./stats.actions"; 3 | 4 | export { stats, statsActions }; 5 | -------------------------------------------------------------------------------- /src/redux/stats/stats.actions.ts: -------------------------------------------------------------------------------- 1 | import { IAction } from "@/interfaces/IAction"; 2 | import { IStat, IGradedStat } from "@/interfaces/IStats"; 3 | import { ADD_STAT, RESET_STATS, ADD_STAT_POINT, REMOVE_STAT_POINT } from "./stats.types"; 4 | 5 | export const addStat = (stat: IStat): IAction => ({ 6 | type: ADD_STAT, 7 | payload: { stat }, 8 | }); 9 | 10 | export const addStatPoint = (stat: IGradedStat): IAction => ({ 11 | type: ADD_STAT_POINT, 12 | payload: { stat }, 13 | }); 14 | 15 | export const removeStatPoint = (stat: IGradedStat): IAction => ({ 16 | type: REMOVE_STAT_POINT, 17 | payload: { stat }, 18 | }); 19 | 20 | export const resetStats = (): IAction => ({ 21 | type: RESET_STATS, 22 | payload: {}, 23 | }); 24 | -------------------------------------------------------------------------------- /src/redux/stats/stats.types.ts: -------------------------------------------------------------------------------- 1 | export const ADD_STAT: string = "stats/ADD_STAT"; 2 | export const ADD_STAT_POINT: string = "stats/ADD_STAT_POINT"; 3 | export const REMOVE_STAT_POINT: string = "stats/REMOVE_STAT_POINT"; 4 | export const RESET_STATS: string = "stats/RESET_STATS"; 5 | -------------------------------------------------------------------------------- /src/redux/ui/index.ts: -------------------------------------------------------------------------------- 1 | import * as uiActions from "./ui.actions"; 2 | import ui from "./ui.reducer"; 3 | 4 | export { ui, uiActions }; 5 | -------------------------------------------------------------------------------- /src/redux/ui/ui.actions.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NAVIGATE_NEXT, 3 | NAVIGATE_PREV, 4 | NAVIGATE_TO, 5 | SET_TOTAL_STEPS, 6 | RESET_UI, 7 | START_OVER, 8 | CONTINUE_BUILD, 9 | SET_IDLE, 10 | DISPLAY_CHARACTER, 11 | } from "./ui.types"; 12 | import { IAction } from "@/interfaces/IAction"; 13 | 14 | export const navigateNext = (): IAction => ({ 15 | type: NAVIGATE_NEXT, 16 | payload: {}, 17 | }); 18 | 19 | export const navigateTo = (step: number): IAction => ({ 20 | type: NAVIGATE_TO, 21 | payload: { step }, 22 | }); 23 | 24 | export const navigatePrev = (): IAction => ({ 25 | type: NAVIGATE_PREV, 26 | payload: {}, 27 | }); 28 | 29 | export const setTotalSteps = (steps: number): IAction => ({ 30 | type: SET_TOTAL_STEPS, 31 | payload: { steps }, 32 | }); 33 | 34 | export const resetUi = (): IAction => ({ 35 | type: RESET_UI, 36 | payload: {}, 37 | }); 38 | 39 | export const startOver = (): IAction => ({ 40 | type: START_OVER, 41 | payload: {}, 42 | }); 43 | 44 | export const continueBuild = (): IAction => ({ 45 | type: CONTINUE_BUILD, 46 | payload: {}, 47 | }); 48 | 49 | export const setIdle = (idle: boolean): IAction => ({ 50 | type: SET_IDLE, 51 | payload: { idle }, 52 | }); 53 | 54 | export const displayCharacter = (): IAction => ({ 55 | type: DISPLAY_CHARACTER, 56 | payload: {}, 57 | }); 58 | -------------------------------------------------------------------------------- /src/redux/ui/ui.types.ts: -------------------------------------------------------------------------------- 1 | export const NAVIGATE_NEXT: string = "ui/NAVIGATE_NEXT"; 2 | export const NAVIGATE_TO: string = "ui/NAVIGATE_TO"; 3 | export const NAVIGATE_PREV: string = "ui/NAVIGATE_PREV"; 4 | export const START_OVER: string = "ui/START_OVER"; 5 | export const SET_TOTAL_STEPS: string = "ui/SET_TOTAL_STEPS"; 6 | export const SET_IDLE: string = "ui/SET_IDLE"; 7 | 8 | export const RESET_UI: string = "ui/RESET_UI"; 9 | export const CONTINUE_BUILD: string = "ui/CONTINUE_BUILD"; 10 | export const DISPLAY_CHARACTER: string = "ui/DISPLAY_CHARACTER"; 11 | -------------------------------------------------------------------------------- /src/utils/config.ts: -------------------------------------------------------------------------------- 1 | export class Config { 2 | get eventID() { 3 | return this._eventIDFromStorage() || "unknown"; 4 | } 5 | 6 | persistEventID() { 7 | let params = new URLSearchParams(window.location.search); 8 | let eventParam = params.get("eventID") as string; 9 | if (eventParam) { 10 | this._writeEventIDToStorage(eventParam); 11 | } 12 | } 13 | 14 | // TODO: I fully realise that this should be probably be pulled into Redux. Right now the likely race conditions are 15 | // limited and my patience for dealing with redux boilerplate is even more limited. 16 | _eventIDFromStorage() { 17 | return window.localStorage.getItem("StartupAdventurer_eventID"); 18 | } 19 | 20 | _writeEventIDToStorage(eventID: string) { 21 | window.localStorage.setItem("StartupAdventurer_eventID", eventID); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/event-emitter.ts: -------------------------------------------------------------------------------- 1 | import noop from "lodash-es/noop"; 2 | 3 | interface IEventEmitter { 4 | events: { [key: string]: typeof noop[] }; 5 | emit: typeof noop; 6 | subscribe: typeof noop; 7 | } 8 | 9 | const EventEmitter: IEventEmitter = { 10 | events: {}, 11 | emit: function(event: string, data: any) { 12 | if (!this.events[event]) return; 13 | this.events[event].forEach((callback: typeof noop) => callback(data)); 14 | }, 15 | subscribe: function(event: string, callback: typeof noop) { 16 | if (!this.events[event]) this.events[event] = []; 17 | this.events[event].push(callback); 18 | }, 19 | }; 20 | 21 | export default EventEmitter; 22 | -------------------------------------------------------------------------------- /src/utils/selection-utils.ts: -------------------------------------------------------------------------------- 1 | import { Colors, IColorOptions } from "@/interfaces/Colors"; 2 | import isEqual from "lodash-es/isEqual"; 3 | import isEmpty from "lodash-es/isEmpty"; 4 | 5 | export interface IColorSet { 6 | name: string; 7 | palette?: Colors; 8 | } 9 | 10 | export const getColorSet = (colorPalette: Colors, colorOptions: IColorOptions): IColorSet => { 11 | if (!colorPalette || !colorOptions) return { name: "" }; 12 | 13 | const name = Object.keys(colorOptions).filter(key => isEqual(colorOptions[key], colorPalette))[0] || ""; 14 | 15 | return { 16 | name, 17 | palette: colorPalette, 18 | }; 19 | }; 20 | 21 | export const decideNextSet = ( 22 | activeSet: IColorSet | undefined, 23 | newSet: IColorSet | undefined 24 | ): IColorSet | undefined => { 25 | return !isEmpty(activeSet) ? undefined : newSet; 26 | }; 27 | -------------------------------------------------------------------------------- /src/utils/style-utils.ts: -------------------------------------------------------------------------------- 1 | import { keyframes, css } from "styled-components"; 2 | 3 | export const colors = { 4 | base: "#272727", 5 | black: "#000000", 6 | darkBlue: "#00547D", 7 | darkGreen: "#008076", 8 | darkGrey: "#333333", 9 | green: "#00a99d", 10 | grey: "#D6D6D6", 11 | lightGrey: "#EBEBEB", 12 | offWhite: "#FAFAFA", 13 | pink: "#F472D0", 14 | white: "#FFFFFF", 15 | }; 16 | 17 | export const responsiveSize = (min: number, max: number, minScreen: number = 992, maxScreen: number = 4500): string => { 18 | return `calc(${min}px + (${max} - ${min}) * ((100vw - ${minScreen}px) / (${maxScreen} - ${minScreen})))`; 19 | }; 20 | 21 | const shine = keyframes` 22 | 0% { 23 | opacity: 0; 24 | transform: skew(-20deg) translateX(-100%); 25 | } 26 | 10% { 27 | opacity: 0.61; 28 | transform: skew(-20deg) translateX(-100%); 29 | } 30 | 50% { 31 | opacity: 0.61; 32 | transform: skew(-20deg) translateX(calc(100% + 60px)); 33 | } 34 | 51%, 100% { 35 | opacity: 0; 36 | transform: skew(-20deg) translateX(100%); 37 | } 38 | `; 39 | 40 | export const buttonShine = css` 41 | overflow: hidden; 42 | position: relative; 43 | 44 | &::before { 45 | animation: ${shine} 4s linear infinite; 46 | background-image: linear-gradient( 47 | to right, 48 | rgba(255, 255, 255, 0) 0px, 49 | #99feec 180px, 50 | rgba(255, 255, 255, 0) 180px 51 | ); 52 | content: ""; 53 | display: block; 54 | height: 100%; 55 | opacity: 0.61; 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | transform: skew(-20deg); 60 | width: 100%; 61 | } 62 | `; 63 | -------------------------------------------------------------------------------- /src/views/Configurator/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | 4 | export const Spotlight = styled.div` 5 | backface-visibility: visible; 6 | height: 112%; 7 | left: -95px; 8 | overflow: visible; 9 | position: absolute; 10 | top: -233px; 11 | transform-style: flat; 12 | transform: none !important; 13 | width: 133%; 14 | 15 | svg { 16 | height: 100%; 17 | left: 0; 18 | opacity: 0; 19 | position: absolute; 20 | right: 0; 21 | top: 0; 22 | width: 100%; 23 | 24 | &.lightbeam { 25 | mix-blend-mode: soft-light; 26 | } 27 | } 28 | `; 29 | 30 | export const ConfiguratorWrapper = styled.div` 31 | color: ${colors.white}; 32 | display: flex; 33 | flex-wrap: wrap; 34 | height: 100%; 35 | justify-content: space-between; 36 | left: 0; 37 | padding: 170px 292px 170px 224px; 38 | position: absolute; 39 | top: 0; 40 | width: 100%; 41 | z-index: 3; 42 | `; 43 | -------------------------------------------------------------------------------- /src/views/EndScreen/arrow-down.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowDown = () => { 4 | return ( 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default ArrowDown; 27 | -------------------------------------------------------------------------------- /src/views/GameOver/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { GameOverContainer, TitleContainer, GameOverButtons, Button } from "./styles"; 3 | import Title from "./title"; 4 | import { Dispatch } from "redux"; 5 | import { useDispatch } from "react-redux"; 6 | import { characterActions } from "@/redux/character"; 7 | import { infoActions } from "@/redux/info"; 8 | import { uiActions } from "@/redux/ui"; 9 | import { statsActions } from "@/redux/stats"; 10 | 11 | const GameOver = () => { 12 | const dispatch: Dispatch = useDispatch(); 13 | 14 | const setGameOver = () => { 15 | dispatch(characterActions.resetCharacter()); 16 | dispatch(infoActions.resetInfo()); 17 | dispatch(uiActions.resetUi()); 18 | dispatch(statsActions.resetStats()); 19 | }; 20 | 21 | const continueBuild = () => { 22 | dispatch(uiActions.continueBuild()); 23 | }; 24 | 25 | return ( 26 | 27 | 28 | 29 | </TitleContainer> 30 | <GameOverButtons> 31 | <Button onClick={continueBuild}>No, continue experience</Button> 32 | <Button primary onClick={setGameOver}> 33 | Yes, stop this! 34 | </Button> 35 | </GameOverButtons> 36 | </GameOverContainer> 37 | ); 38 | }; 39 | 40 | export default GameOver; 41 | -------------------------------------------------------------------------------- /src/views/GameOver/styles.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | import bg from "@/graphics/background.svg"; 4 | 5 | export const GameOverContainer = styled.div` 6 | align-items: center; 7 | background-image: url(${bg}); 8 | background-repeat: no-repeat; 9 | background-size: cover; 10 | display: flex; 11 | flex-direction: column; 12 | height: 100%; 13 | justify-content: center; 14 | left: 0; 15 | position: fixed; 16 | top: 0; 17 | width: 100%; 18 | z-index: 9999; 19 | `; 20 | 21 | export const TitleContainer = styled.div` 22 | margin: 0 0 296px; 23 | `; 24 | 25 | export const GameOverButtons = styled.div` 26 | align-items: center; 27 | display: flex; 28 | justify-content: center; 29 | `; 30 | 31 | interface IButtonProps { 32 | primary?: boolean; 33 | } 34 | 35 | export const Button = styled.button<IButtonProps>` 36 | align-items: center; 37 | background-color: ${props => (props.primary ? colors.green : colors.white)}; 38 | border: 7px solid ${props => (props.primary ? colors.darkGreen : colors.lightGrey)}; 39 | border-radius: 0; 40 | box-shadow: 0px 7px 0px ${colors.darkBlue}; 41 | color: ${props => (props.primary ? colors.white : colors.black)}; 42 | font-size: 60px; 43 | display: flex; 44 | height: 176px; 45 | justify-content: center; 46 | margin: 0 45px; 47 | outline: none; 48 | padding: 0 40px; 49 | width: 1090px; 50 | 51 | &:active { 52 | background-color: ${props => (props.primary ? colors.darkGreen : colors.lightGrey)}; 53 | } 54 | `; 55 | -------------------------------------------------------------------------------- /src/views/Start/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors, buttonShine } from "@/utils/style-utils"; 3 | 4 | export const StartContainer = styled.div` 5 | align-items: center; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: flex-end; 9 | opacity: 0; 10 | padding: 300px 0; 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | width: 100%; 15 | height: 100%; 16 | `; 17 | 18 | export const StartChapters = styled.div` 19 | margin: 0 auto 190px; 20 | max-width: 3045px; 21 | 22 | p { 23 | color: ${colors.white}; 24 | font-size: 100px; 25 | line-height: 1.1; 26 | text-align: center; 27 | 28 | span { 29 | opacity: 0; 30 | } 31 | 32 | &:first-of-type { 33 | span:nth-of-type(-n + 5) { 34 | color: ${colors.green}; 35 | } 36 | } 37 | &:last-of-type { 38 | span:nth-of-type(-n + 6) { 39 | color: ${colors.green}; 40 | } 41 | } 42 | } 43 | `; 44 | 45 | export const StartButton = styled.button` 46 | align-items: center; 47 | background-color: ${colors.white}; 48 | border: 7px solid ${colors.lightGrey}; 49 | border-radius: 0; 50 | box-shadow: 0px 7px 0px ${colors.darkBlue}; 51 | font-size: 60px; 52 | display: flex; 53 | height: 176px; 54 | margin: 0 0 200px; 55 | opacity: 0; 56 | padding: 0 80px; 57 | 58 | ${buttonShine} 59 | 60 | &:focus { 61 | border: none; 62 | outline: 10px solid ${colors.green}; 63 | } 64 | 65 | &:active { 66 | background-color: ${colors.lightGrey}; 67 | } 68 | 69 | a { 70 | text-decoration: none; 71 | 72 | color: #000; 73 | 74 | &:visited { 75 | color: #000; 76 | } 77 | } 78 | `; 79 | -------------------------------------------------------------------------------- /src/views/Stats/styles.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { colors } from "@/utils/style-utils"; 3 | 4 | export const Spotlight = styled.div` 5 | backface-visibility: visible; 6 | height: 112%; 7 | left: -95px; 8 | overflow: visible; 9 | position: absolute; 10 | top: -233px; 11 | transform-style: flat; 12 | transform: none !important; 13 | width: 133%; 14 | 15 | svg { 16 | height: 100%; 17 | left: 0; 18 | position: absolute; 19 | right: 0; 20 | top: 0; 21 | width: 100%; 22 | 23 | &.lightbeam { 24 | mix-blend-mode: soft-light; 25 | } 26 | } 27 | `; 28 | 29 | export const StatsWrapper = styled.div` 30 | color: ${colors.white}; 31 | display: flex; 32 | flex-wrap: wrap; 33 | height: 100%; 34 | justify-content: space-between; 35 | left: 0; 36 | padding: 170px 292px 170px 224px; 37 | position: absolute; 38 | top: 0; 39 | width: 100%; 40 | z-index: 3; 41 | `; 42 | -------------------------------------------------------------------------------- /tests/Test.README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | To run react-app-rewired tests use the command `npm run test`. To run playwright tests run `npm run playwright_test`. In order to run tests npm install had to be changed to `npm install --legacy-peer-deps`, sample no longer works with `npm install` because react-compound-slider uses an outdated version of react. -------------------------------------------------------------------------------- /tests/playwright.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | 3 | test('basic test', async ({ page }) => { 4 | await page.goto('/'); 5 | await page.waitForSelector('h2'); 6 | await expect(page.locator('h2')).toContainText('Create your own'); 7 | }) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.paths", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "lib": [ 6 | "dom", 7 | "dom.iterable", 8 | "esnext" 9 | ], 10 | "allowJs": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react", 22 | "noFallthroughCasesInSwitch": true 23 | }, 24 | "include": [ 25 | "src" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["*"], 6 | "@/*": ["src/*"] 7 | } 8 | } 9 | } 10 | --------------------------------------------------------------------------------