Skip to content

Commit

Permalink
Merge pull request #135 from TNG/random-card
Browse files Browse the repository at this point in the history
New page to draw random cards
  • Loading branch information
ghost91- authored Dec 12, 2024
2 parents b2036ff + 9c800c2 commit 26dc843
Show file tree
Hide file tree
Showing 33 changed files with 236 additions and 67 deletions.
12 changes: 12 additions & 0 deletions apps/client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# @eop/client

## 1.1.0

### Minor Changes

- Draw a random card.

### Patch Changes

- Updated dependencies
- @eop/shared@1.1.0
- @eop/cornucopia-cards@1.1.0

## 1.0.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@eop/client",
"type": "module",
"version": "1.0.1",
"version": "1.1.0",
"main": "src/client/index.tsx",
"scripts": {
"build": "tsc -b tsconfig.app.json && vite build",
Expand Down
Binary file modified apps/client/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions apps/client/src/components/dealtcard/dealtcard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import type { Card } from '@eop/shared';
interface DealtCardProps {
gameMode: GameMode;
card: Card;
isAlignedRight?: boolean;
}

const DealtCard: React.FC<DealtCardProps> = ({ gameMode, card }) => {
const DealtCard: React.FC<DealtCardProps> = ({
gameMode,
card,
isAlignedRight = false,
}) => {
const roundedClass =
gameMode === GameMode.CUMULUS ? `card-rounded-cumulus` : `card-rounded`;
const translationClass =
gameMode === GameMode.EOMLSEC ? `card-translate-left` : ``;
return (
<div
className={`playing-card ${getCardCssClass(
gameMode,
card,
)} active ${roundedClass} scaled-big ${translationClass}`}
)} active ${roundedClass} scaled-big ${isAlignedRight ? `aligned-right` : ``} `}
/>
);
};
Expand Down
12 changes: 7 additions & 5 deletions apps/client/src/components/footer/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ type FooterProps = {
};

const Footer: FC<FooterProps> = ({ short = false }) => (
<small className="text-white-50">
<small className="text-black-50">
v{packageJson.version}
{!short && (
<>
<span>
{' '}
- made with{' '}
<FontAwesomeIcon icon={faHeart} style={{ color: '#00cc00' }} /> at
Careem and{' '}
<a href="https://www.tngtech.com/en/">TNG Technology Consulting</a> -
Elevation of Privilege was originally invented at Microsoft,
Cornucopia was developed at OWASP, Cumulus was started at{' '}
&nbsp;
<a href="https://www.tngtech.com/en/">
TNG Technology Consulting
</a>{' '}
and Careem - Elevation of Privilege was originally invented at
Microsoft, Cornucopia was developed at OWASP, Cumulus was started at{' '}
<a href="https://www.tngtech.com/en/">TNG Technology Consulting</a>,
Elevation of MLsec was developed at{' '}
<a href="https://www.kantega.no/">Kantega AS</a>.
Expand Down
3 changes: 3 additions & 0 deletions apps/client/src/components/logo/logo.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.logo {
cursor: pointer;
}
2 changes: 2 additions & 0 deletions apps/client/src/components/logo/logo.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type React from 'react';
import { useNavigate } from 'react-router-dom';
import classes from './logo.module.css';

const Logo: React.FC = () => {
const navigate = useNavigate();

return (
<img
className={classes['logo']}
src="logo.png"
alt="logo"
height="120px"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.card-deck-selector-container {
display: flex;
flex-wrap: wrap;
justify-content: start;
}
.card-deck-selection {
width: 15rem;
cursor: pointer;
}

.card-container {
display: flex;
position: inherit;
justify-content: center;
height: 600px;
}
64 changes: 64 additions & 0 deletions apps/client/src/components/randomcarddisplay/randomCardDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import { CARD_DECKS, GameMode, SUITS } from '@eop/shared';
import { FC, useState } from 'react';
import DealtCard from '../dealtcard/dealtcard';
import classes from './randomCardDisplay.module.css';
import { Button, FormGroup, Input, Label } from 'reactstrap';

const allDecks = Object.keys(CARD_DECKS) as GameMode[];
const RandomCardDisplay: FC = () => {
const [selectedDecks, setSelectedDecks] = useState<GameMode[]>(allDecks);
const selectableCards = selectedDecks.flatMap((deck) =>
SUITS.flatMap((suit) =>
CARD_DECKS[deck][suit].cards.map((card) => ({
card,
gameMode: deck,
})),
),
);
const getRandomSelectableCard = () =>
selectableCards[Math.floor(Math.random() * selectableCards.length)];
const [selectedCard, setSelectedCard] = useState(getRandomSelectableCard());
const selectCard = () => setSelectedCard(getRandomSelectableCard());
const toggleCardDeck = (deck: GameMode) =>
setSelectedDecks((selectedDecks) =>
selectedDecks.includes(deck)
? selectedDecks.filter((selectedDeck) => selectedDeck !== deck)
: [...selectedDecks, deck],
);

return (
<>
<FormGroup check className={classes['card-deck-selector-container']}>
{allDecks.map((deck) => (
<Label
check
className={classes['card-deck-selection']}
key={`card-deck-selector-${deck}`}
>
<Input
id="radio-button-default-model"
type="checkbox"
onChange={() => toggleCardDeck(deck)}
checked={selectedDecks.includes(deck)}
/>
{deck}
</Label>
))}
</FormGroup>
{selectedCard && (
<div className={classes['card-container']}>
<DealtCard
gameMode={selectedCard.gameMode}
card={selectedCard.card}
/>
</div>
)}
<Button block size="lg" color="primary" onClick={selectCard}>
New Card
</Button>
</>
);
};

export default RandomCardDisplay;
9 changes: 9 additions & 0 deletions apps/client/src/components/sidebar/sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@
margin-top: 3%;
margin-bottom: 1%;
}

.dealt-card-container {
position: relative;
}

.aligned-right {
position: absolute;
right: 0;
}
13 changes: 9 additions & 4 deletions apps/client/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const Sidebar: FC<SidebarProps> = ({
secret={secret}
block
size="lg"
color="success"
color="secondary"
apiEndpoint="download"
>
Download Model
Expand All @@ -66,7 +66,7 @@ const Sidebar: FC<SidebarProps> = ({
secret={secret}
block
size="lg"
color="warning"
color="secondary"
apiEndpoint="download/text"
>
Download Threats
Expand Down Expand Up @@ -96,8 +96,13 @@ const Sidebar: FC<SidebarProps> = ({
Pass
</Button>
)}

<DealtCard card={dealtCard} gameMode={G.gameMode} />
<div className="dealt-card-container">
<DealtCard
card={dealtCard}
gameMode={G.gameMode}
isAlignedRight={true}
/>
</div>
</div>
);
};
Expand Down
5 changes: 4 additions & 1 deletion apps/client/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import About from './pages/about';
import App from './pages/app';
import Create from './pages/create';
import About from './pages/about';
import RandomCard from './pages/random-card';

import './styles/index.css';
import 'bootstrap/dist/css/bootstrap.min.css';

const container = document.getElementById('root');
Expand All @@ -14,6 +16,7 @@ const router = createBrowserRouter([
{ path: '/:matchID/:playerID/:credentials', element: <App /> },
{ path: '/', element: <Create /> },
{ path: '/about', element: <About /> },
{ path: '/random-card', element: <RandomCard /> },
]);

root.render(<RouterProvider router={router} />);
2 changes: 0 additions & 2 deletions apps/client/src/pages/about.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import '../styles/about.css';

import type React from 'react';
import type { FC } from 'react';
import { Card, CardBody, CardHeader, Col, Container, Row } from 'reactstrap';
Expand Down
40 changes: 16 additions & 24 deletions apps/client/src/pages/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
import type { PlayerID } from 'boardgame.io';
import _ from 'lodash';
import React, { ChangeEvent } from 'react';
import { Link } from 'react-router-dom';
import {
Button,
Card,
Expand Down Expand Up @@ -256,7 +255,7 @@ class Create extends React.Component<CreateProps, CreateState> {

formatAllLinks(): string {
return (
'You have been invited to a game of Elevation of Privilege:\n\n' +
'You have been invited to a threat modeling game:\n\n' +
Array(this.state.players)
.fill(0)
.map((_, i) => {
Expand All @@ -270,19 +269,6 @@ class Create extends React.Component<CreateProps, CreateState> {
const cardBody = !this.state.created ? (
<div>
<Banner />
<p>
Elevation of Privilege (EoP) is the easy way to get started and learn
threat modeling. It is a card game that developers, architects or
security experts can play.
</p>
<p>
To learn more about the game, navigate to the{' '}
<Link to="/about">about page</Link>.
</p>
<small className="text-secondary">
To start playing, select the number of players and enter their names.
</small>
<hr />
<Form>
<FormGroup row>
<Label for="players" sm={2}>
Expand Down Expand Up @@ -488,18 +474,26 @@ class Create extends React.Component<CreateProps, CreateState> {
<Button
block
size="lg"
color="warning"
color="primary"
disabled={this.state.creating || !this.isFormValid()}
onClick={this.createGame.bind(this)}
>
Proceed
</Button>
</Form>
<hr />
<small className="text-secondary">
Players will be able to join the game with the links that are
generated after you proceed.
</small>
<p className="centered">
Alternatively, if you do not want to play a full game you can just
select a few random cards.
</p>
<Button
block
size="lg"
color="secondary"
onClick={() => (window.location.href = `/random-card`)}
>
Draw a random card
</Button>
</div>
) : (
<div>
Expand Down Expand Up @@ -551,7 +545,7 @@ class Create extends React.Component<CreateProps, CreateState> {
<hr />
<CopyButton
text={this.formatAllLinks()}
color="warning"
color="secondary"
block
size="lg"
>
Expand All @@ -576,9 +570,7 @@ class Create extends React.Component<CreateProps, CreateState> {
<Logo />
</div>
<Card className="create-card">
<CardHeader className="text-center">
Elevation of Privilege
</CardHeader>
<CardHeader className="text-center">Threat Modeling</CardHeader>
<CardBody>{cardBody}</CardBody>
</Card>
</Col>
Expand Down
38 changes: 38 additions & 0 deletions apps/client/src/pages/random-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { FC } from 'react';
import { Card, CardBody, CardHeader, Col, Container, Row } from 'reactstrap';
import Banner from '../components/banner/banner';

import Footer from '../components/footer/footer';
import Logo from '../components/logo/logo';
import RandomCardDisplay from '../components/randomcarddisplay/randomCardDisplay';

const RandomCard: FC = () => {
return (
<div>
<Banner />
<Container className="about" fluid>
<Row style={{ paddingTop: '20px' }}>
<Col sm="12" md={{ size: 6, offset: 3 }}>
<div className="text-center">
<Logo />
</div>
<Card>
<CardHeader className="text-center">Threat Modeling</CardHeader>
<CardBody>
<h1>Random Card</h1>
<RandomCardDisplay />
</CardBody>
</Card>
</Col>
</Row>
<Row>
<Col sm="12" md={{ size: 6, offset: 3 }} className="text-center">
<Footer />
</Col>
</Row>
</Container>
</div>
);
};

export default RandomCard;
3 changes: 0 additions & 3 deletions apps/client/src/styles/about.css

This file was deleted.

4 changes: 0 additions & 4 deletions apps/client/src/styles/cards.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@
border-radius: 25px;
}

.card-translate-left {
margin-left: -5rem;
}

.playingCardsContainer {
position: fixed;
bottom: 0;
Expand Down
Loading

0 comments on commit 26dc843

Please sign in to comment.